通过 Clozure CL 与 Windows API 交互

Mic*_*rus 5 common-lisp ffi ccl

我想通过 Clozure CL 的外部函数接口调用 Windows API 函数,但我遇到了一些问题,因为我找到的文档相当稀缺。

作为一个足够丰富的示例,我尝试调用SHGetKnownFolderPath。它的签名是

HRESULT SHGetKnownFolderPath(const GUID &rfid, DWORD dwFlags,
                             HANDLE hToken, PWSTR *ppszPath   );
Run Code Online (Sandbox Code Playgroud)

获取入口点

我可以使用以下命令来获取函数的入口点:

(open-shared-library "shell32.dll")
> #<SHLIB SHELL32.dll #x1234>
(external "SHGetKnownFolderPath")
> #<EXTERNAL-ENTRY-POINT "SHGetKnownFolderPath" (#x12345) SHELL32.dll #x123456>
Run Code Online (Sandbox Code Playgroud)

获取/设置正确的方法签名

以下是我认为调用它的一般步骤,但我不确定每个步骤是如何进行的:

  • 检索 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))
Run Code Online (Sandbox Code Playgroud)

其中仍然存在各种未知的函数和函数调用需要在 C/FFI 和 Lisp 之间进行转换。

附录

我对Windows API非常熟悉,并且做过其他语言的Win32 API调用。我还设法在 CLisp 中实现这一点,在某种程度上,因为我遇到了 Windows 中 CLisp 的 Unicode 支持不佳的问题(我最终只得到了路径的第一个字符,因为 CLisp 读取 UTF-16 字符串作为 ASCII)。

我所关注的问题是 CCL 中有哪些功能可以实现这项工作。任何正确方向的帮助将不胜感激。