Winapi CFFI和win32剪贴板访问

Winapi CFFI和win32剪贴板访问,winapi,common-lisp,cffi,Winapi,Common Lisp,Cffi,我是Common Lisp的新手,在上面做了一些实验。 我正在努力获取对windows剪贴板的访问权限,然后我找到了以下参考: 这是完美的,除了它是为CLISP FFI量身定做的,我希望它能与CFFI合作。 然后我尝试转换代码,部分成功,但例程有问题 (获取剪辑字符串),在WinXP上使用Clozure CL 1.10进行测试(!): 测试课文:有太空服会旅行吗 ??(获取剪辑字符串) 错误:“Have Space Suit Will Travel”值不是预期的类型(无符号字节32)。 执行时

我是Common Lisp的新手,在上面做了一些实验。 我正在努力获取对windows剪贴板的访问权限,然后我找到了以下参考:

这是完美的,除了它是为CLISP FFI量身定做的,我希望它能与CFFI合作。 然后我尝试转换代码,部分成功,但例程有问题 (获取剪辑字符串),在WinXP上使用Clozure CL 1.10进行测试(!):

测试课文:有太空服会旅行吗

??(获取剪辑字符串)

错误:“Have Space Suit Will Travel”值不是预期的类型(无符号字节32)。 执行时:GLOBAL-LOCK-STRING,进程内侦听器(1)。 键入:POP to abort,:R以获取可用重新启动的列表。 类型:?其他选择

我想我没有在CFFI上得到类型的东西(尽管我读过手册),也没有在CLISP上得到原始处方。有人有什么提示吗? 以下命令序列可以工作,但恐怕不安全:

(open-clip 0)
(get-clip 1)
(close-clip 0)
(打开剪辑0) (获取剪辑1) (关闭剪辑0)

代码如下:

(ql:quickload :cffi)


(cffi:load-foreign-library "user32.dll")

(cffi:load-foreign-library "kernel32.dll")

(cffi:load-foreign-library "msvcrt.dll")


(cffi:defcfun ("GetClipboardData" get-clip) :string

(uformat  :unsigned-int))


(cffi:defcfun ("OpenClipboard" open-clip) :int

  (hOwner  :unsigned-int))


(cffi:defcfun ("CloseClipboard" close-clip) :int


      (hOwner  :unsigned-int))


(cffi:defcfun ("EmptyClipboard" empty-clip) :int)


(cffi:defcfun ("SetClipboardData" set-clip) :int

  (data  :unsigned-int)

  (format :unsigned-int))


(cffi:defcfun ("GlobalAlloc" global-alloc) :int

  (flags  :unsigned-int)

  (numbytes :unsigned-int))


(cffi:defcfun ("GlobalLock" global-lock) :unsigned-int

  (typ  :unsigned-int))


(cffi:defcfun ("GlobalLock" global-lock-string) :string 

  (typ  :unsigned-int))


(cffi:defcfun ("GlobalUnlock" global-unlock) :int

  (typ  :unsigned-int))


(cffi:defcfun ("memcpy" memcpy) :int

  (dest  :unsigned-int)

  (src :string) 

  (coun :unsigned-int))



(defun get-clip-string ()

          (open-clip 0)

          (let* ((h (get-clip 1)) (s (global-lock-string h)))

                 (global-unlock h) (close-clip 0) s))


(defun set-clip-string (s)

          (let* ((slen (+ 1 (length s)))(newh (global-alloc 8194 slen))

(newp (global-lock newh)))

          (memcpy newp s (+ 1 slen)) (global-unlock newh) (open-clip 0)

(set-clip 1 newh) (close-clip 0)))

错误出现在用于
GetClipboardData
的返回类型和用于
GlobalLock
GlobalUnlock
的参数类型中。您可以定义
GetClipboardData
来返回字符串,但在C中,
GetClipboardData
返回一个
句柄
,该句柄被定义为指向
void
的指针,
GlobalLock
GlobalUnlock
接受的参数也是一个
句柄
。将C函数定义更改为:

(cffi:defcfun ("GetClipboardData" get-clip) :pointer
    (uformat  :unsigned-int))

(cffi:defcfun ("GlobalLock" global-lock-string) :string 
    (type  :pointer))

(cffi:defcfun ("GlobalUnlock" global-unlock) :int
    (type  :pointer))
…问题就消失了

如果要使用
set clip string
,还需要修复其他
global lock-*
函数和
memcpy

不过,还有另一个错误:当您键入更正整个程序以便也可以调用
set clip string
函数时,
set clip string
似乎只能将字符串放在Lisp进程本地的剪贴板上(我在Win7上通过SLIME使用SBCL的控制台构建)。假设你复制了
,太空服将带着记事本进入剪贴板。然后试试这个:

CL-USER> (set-clip-string "MY CLIPBOARD")
1
CL-USER> (get-clip-string)
"MY CLIPBOARD"
所以它似乎起了作用。但是,如果您尝试使用ShiftIns从剪贴板粘贴到EMACS,您会得到:

CL-USER> Have Space Suit-Will Travel
因此,真正的剪贴板仍然有记事本放在那里的内容,而您的Lisp程序只有一个私有剪贴板,不能用于将数据复制到其他程序,甚至不能复制到承载它的EMACS会话

之所以会发生这种情况,是因为调用
openclip
后,
set clip string
需要调用
empty clip


此外,这些Windows调用中的每一个都可能失败,但您的代码不会检查失败或处理错误。

如果没有太多深入的了解,我建议您找出
:string
(无符号字节32)
之间的关系,并可能更改为其他内容;例如,可能Windows API正在返回
(无符号字节16)
(无符号字节8)
字符。非常感谢!现在我明白了,我需要了解多少:-)奇怪的是,函数global unlock中的参数类型:pointer只对get clip string过程有效-我需要保留一个单独的函数,参数为:unsigned int for set clip string。。。get clip的返回类型更改为:指针也正常工作。再次感谢!