3

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

https://groups.google.com/forum/#!topic/comp.lang.lisp/hyNqn2QhUY0

这是完美的,除了它是为 CLISP FFI 量身定制的,我希望它与 CFFI 一起使用。然后我尝试转换代码,并部分成功,但例程(get-clip-string)存在问题,在 WinXP(!)上使用 Clozure CL 1.10 进行测试:

测试文本:拥有太空服-Will Travel

? (获取剪辑字符串)

错误:值“拥有太空服-将旅行”不是预期的类型(UNSIGNED-BYTE 32)。执行时:GLOBAL-LOCK-STRING,在进程监听器(1)中。键入 :POP 以中止, :R 以获取可用重新启动的列表。类型 :?其他选项。

我想我没有得到 CFFI 上的类型(虽然我已经阅读了手册),或者 CLISP 上的原始处方。有人提示吗?以下命令序列有效,但恐怕这不安全:

(open-clip 0)
(get-clip 1)
(close-clip 0)

(open-clip 0) (get-clip 1) (close-clip 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)))
4

1 回答 1

0

错误在于您用于的返回类型和用于andGetClipboardData的参数类型。您定义返回一个字符串,但在 C 中,返回 a ,它被定义为指向 的指针,并且and接受的参数也是 a 。将您的 C 函数定义更改为:GlobalLockGlobalUnlockGetClipboardDataGetClipboardDataHANDLEvoidGlobalLockGlobalUnlockHANDLE

(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))

...问题就消失了。

您还需要修复其他global-lock-*功能,memcpy如果您想使用set-clip-string.

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

CL-USER> (set-clip-string "MY CLIPBOARD")
1
CL-USER> (get-clip-string)
"MY CLIPBOARD"

所以它似乎奏效了。但是,如果您尝试使用从剪贴板粘贴到 EMACS 中ShiftIns,您会得到:

CL-USER> Have Space Suit-Will Travel

所以真正的剪贴板仍然有记事本放在那里的东西,而你的 Lisp 程序只有一个私有剪贴板,不能用于将数据复制到其他程序,甚至是托管它的 EMACS 会话。

发生这种情况是因为set-clip-string需要在调用empty-clip后调用open-clip

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

于 2015-10-10T08:50:35.570 回答