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 でテストしました (!):

テストテキスト: 宇宙服を持っている-意志旅行

? (get-clip-string)

エラー: 値 "Have Space Suit-Will Travel" は予期されたタイプ (UNSIGNED-BYTE 32) ではありません。実行中: GLOBAL-LOCK-STRING、プロセス listener(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

エラーは、 に使用した戻り値の型と および に使用しGetClipboardDataた引数の型にGlobalLockありますGlobalUnlock。文字列を返すように定義しますGetClipboardDataが、C では、へのポインターとして定義されている をGetClipboardData返します。また、およびで受け入れられる引数もです。C 関数の定義を次のように変更します。HANDLEvoidGlobalLockGlobalUnlockHANDLE

(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-clipopen-clip

また、これらの Windows 呼び出しはすべて失敗する可能性がありますが、コードは失敗をチェックしたり、エラーを処理したりしません。

于 2015-10-10T08:50:35.570 に答える