我想通过 Clozure CL 的外部函数接口调用 Windows API 函数,但我遇到了一些问题,因为我能够找到的文档相当稀缺。
作为一个足够丰富的例子,我试图调用SHGetKnownFolderPath。它的签名是
HRESULT SHGetKnownFolderPath(const GUID &rfid, DWORD dwFlags,
HANDLE hToken, PWSTR *ppszPath );
获取入口点
我可以使用以下内容来获取函数的入口点:
(open-shared-library "shell32.dll")
> #<SHLIB SHELL32.dll #x1234>
(external "SHGetKnownFolderPath")
> #<EXTERNAL-ENTRY-POINT "SHGetKnownFolderPath" (#x12345) SHELL32.dll #x123456>
获取/设置正确的方法签名
这是我认为调用它的一般步骤,但我不确定每个步骤如何:
- 检索 CCL 为该函数生成的签名,以便我知道如何调用它。
- 使用
external-call
. - 定义一个 FFI 结构或类来保存
GUID
(第一个参数)viadef-foreign-type
或相关构造。 - 调用后,使用
CoTaskMemFree
释放 指向的内存*ppszPath
。
猜测最终代码的形式
我对最终代码的一般形式的猜测是
(defun get-known-folder (guid)
(let ((ffi-guid (allocate-ffi-memory-from-guid guid))
(ffi-path ffi-version-of-nil)
(path nil))
(external-call "SHGetKnownFolderPath" ...) ;; Pass ffi-guid and ffi-path by reference.
(setf path (convert-cstring-to-string ffi-path))
(external-call "CoTaskMemFree" ...) ;; Free ffi-path.
path))
在 C/FFI 和 Lisp 之间仍有各种未知函数和函数调用进行转换。
附录
我对 Windows API 非常熟悉,并且已经完成了其他语言的 Win32 API 调用。我还设法让这个在 CLisp 中工作,在某种程度上,因为我遇到了 Windows 中 CLisp 的 Unicode 支持不佳的问题(我最终只得到了路径的第一个字符,因为 CLisp 读取 UTF-16 字符串作为ASCII)。
我坚持的一点是 CCL 中有什么功能可以完成这项工作。任何在正确方向上的帮助将不胜感激。