2015-10-08 3 views
2

Я новичок в Common Lisp и сделал несколько экспериментов на нем. Я изо всех сил старался, чтобы получить доступ к буферу обмена окон, то я нашел эту ссылку:CFFI и win32 доступ к буфером обмена

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

Это было прекрасно, за исключением того, что было специально для CLISP FFI, и я хотел его работать с CFFI. Затем я попытался преобразовать код, и частично удастся, но есть проблема с обычной (получить-клип-строку), тестирование с Clozure CL 1.10 на WinXP (!):

испытания текст: Have Space соответствующей защиты Будет ли перемещаться

? (Получить клип-нить)

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) (получить-клип 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' и' (unsigned-byte 32) 'связаны друг с другом и, возможно, переходят на что-то другое; например, возможно, Windows API возвращает символы '(unsigned-byte 16)' или '(unsigned-byte 8)'. – BRFennPocock

ответ

0

ошибка в типе возврата, который вы использовали для GetClipboardData и тип аргумента, который вы использовали для GlobalLock и GlobalUnlock. Вы определяете GetClipboardData для возврата строки, но в C GetClipboardData возвращает HANDLE, который определяется как указатель на void, а аргумент, принятый GlobalLock и GlobalUnlock, также является 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)) 

... и проблема уходит.

Также необходимо исправить другие функции global-lock-*, а также memcpy, если вы хотите использовать set-clip-string.

Есть еще одна ошибка: при вводе-исправлении всей программы, так что функция set-clip-string также может быть вызвана, то set-clip-string, похоже, может помещать строку в буфер обмена, который является локальным для процесса Lisp (Я использую консольную сборку SBCL через SLIME на Win7). Предположим, вы скопировали 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 

Так реальный буфер обмена все еще имеет то, что Notepad поставить там, и ваша Lisp программа имеет только который не может использоваться для копирования данных в другие программы, даже в сеанс EMACS, который его размещает.

Это происходит потому, что set-clip-string необходимо позвонить по телефону empty-clip после звонка open-clip.

Кроме того, каждый из этих вызовов Windows может выйти из строя, но ваш код не проверяет наличие ошибок или ошибок.

+0

Большое спасибо! Теперь я вижу, сколько мне нужно узнать :-) – rand

+0

Большое спасибо! Теперь я вижу, насколько мне нужно учиться :-) Как ни странно, тип аргумента: указатель в функции global-unlock работал только на процедуру get-clip-string - мне нужно было сохранить отдельную функцию с аргументом: unsigned-int for set-clip-string ... Возвращаемый тип get-clip изменен на: указатель также работал правильно. Еще раз спасибо! – rand

Смежные вопросы