2015-10-08 96 views
2

我是Common Lisp的新手,並對它做了一些實驗。 我努力獲得一些訪問到Windows剪貼板,然後我發現這個參考:CFFI和win32剪貼板訪問

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

這是完美的,除了它是爲CLISP FFI量身定做的,我希望它與CFFI工作。 然後我試圖將代碼轉換,部分成功,但有一個與常規 (獲得夾弦),與Clozure CL 1.10在WinXP測試的問題(!):

測試文字:足夠的空間Suit- Will Travel

? (獲得夾弦)

Error: The value "Have Space Suit-Will Travel" is not of the expected type (UNSIGNED-BYTE 32). While executing: GLOBAL-LOCK-STRING, in process listener(1). Type :POP to abort, :R for a list of available restarts. Type :? for other options.

我覺得我沒有拿到樣東西上CFFI(雖然我讀過的手冊),或在CLISP原來的處方。有人有任何提示? 下面的命令序列工作,但恐怕不是安全:

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

(開夾0) (GET-夾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))) 
+0

沒有很大的啓示,我會建議搞清楚如何':string'和'(無符號字節32)'正相關,且可能更改到別的東西;例如,也許Windows API正在返回'(無符號字節16)'或'(無符號字節8)'字符。 – BRFennPocock

回答

0

的錯誤是在你使用GetClipboardData的返回類型和你用於GlobalLockGlobalUnlock參數的類型。您定義GetClipboardData返回一個字符串,但在C中,GetClipboardData返回一個HANDLE,它定義爲指向void的指針,接受的參數爲GlobalLockGlobalUnlock也是HANDLE。將您的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的控制檯版本)。假設您使用記事本將Have Space Suit-Will Travel複製到剪貼板。然後試試這個:

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

所以它似乎工作。不過,如果你嘗試使用從剪貼板粘貼到Emacs,您可以:

CL-USER> Have Space Suit-Will Travel 

所以真正剪貼板還有什麼記事本放在那裏,而你的Lisp程序只有一個私人剪貼板不能用於將數據複製到其他程序,甚至不是用於託管它的EMACS會話。

發生這種情況是因爲set-clip-string在致電open-clip之後需要致電empty-clip

而且,這些窗口的每一個來電可以失敗,但你的代碼不檢查故障或處理錯誤。

+0

非常感謝!現在我明白了,我需要學習多少:-) – rand

+0

非常感謝!現在我明白了,我需要學習多少:-)奇怪的參數類型:函數global-unlock中的指針只能用於過程get-clip-string - 我需要使用參數保留一個單獨的函數:unsigned-int for set-clip-string ... get-clip的返回類型更改爲:指針也正常工作。再次感謝! – rand