这个 Chez Scheme FFI 调用 user32.dll 的 SendInput 有什么问题?

huangapple go评论54阅读模式
英文:

What's wrong with this Chez Scheme FFI call to user32.dll SendInput?

问题

我之前从未在Chez Scheme的FFI中遇到过任何问题,它对你输入的内容非常宽容,但我似乎无法使这个函数不抛出错误。

目标是简单地模拟按下和释放左Windows键。

以下是你的代码的翻译部分:

(load-shared-object "user32.dll")

(define-ftype win32-input-ftype
  (struct (type unsigned-long)
          (mi (union (dx long)
                     (dy long)
                     (mouseData unsigned-long)
                     (dwFlags unsigned-long)
                     (time unsigned-long)
                     (dwExtraInfo uptr)))
          (ki (union (wVk unsigned-short)
                     (wScan unsigned-short)
                     (dwFlags unsigned-long)
                     (time unsigned-long)
                     (dwExtraInfo uptr)))
          (hi (union (uMsg unsigned-long)
                     (wParamL unsigned-short)
                     (wParamH unsigned-short))))) 
;; 从MSDN获取的结构信息
;; dwExtraInfo 实际上是一个 (* unsigned-long) ,但创建一个设置为0的虚拟ulong指针也没有效果。在其他ffi调用的工作代码中,一个可空的uptr也可以互换使用。

(define-ftype input-array-ftype
  (array 2 win32-input-ftype)) ;; win32-input-ftype/INPUT[2]

(define send-input-fp
  (foreign-procedure "SendInput"
                     (unsigned-int
                      (* input-array-ftype)
                      int)
                     unsigned-int)) 
;; 从MSDN定义SendInput的签名

(define input-array
  (make-ftype-pointer input-array-ftype
   (foreign-alloc (ftype-sizeof input-array-ftype)))) 
;; 分配包含结构体的数组,并创建指向它的指针

(ftype-set! input-array-ftype
            (0 type) input-array 1) ;; input_array[0].type = 1;
(ftype-set! input-array-ftype
            (0 ki wVk) input-array #x5B) ;; input_array[0].ki.wVk = 0x5B;
(ftype-set! input-array-ftype
            (0 ki wScan) input-array 0) ;; input_array[0].ki.wScan = 0;
(ftype-set! input-array-ftype
            (0 ki dwFlags) input-array 0) ;; input_array[0].ki.dwFlags = 0;
(ftype-set! input-array-ftype
            (0 ki time) input-array 0) ;; input_array[0].ki.time = 0;
(ftype-set! input-array-ftype
            (0 ki dwExtraInfo) input-array 0) ;; input_array[0].dwExtraInfo = NULL;

(ftype-set! input-array-ftype
            (1 type) input-array 1) ;; input_array[1].type = 1
(ftype-set! input-array-ftype
            (1 ki wVk) input-array #x5B) ;; input_array[1].ki.wVk = 0x5B;
(ftype-set! input-array-ftype
            (1 ki wScan) input-array 0) ;; input_array[1].ki.wScan = 0;
(ftype-set! input-array-ftype
            (1 ki dwFlags) input-array 2) ;; input_array[1].ki.dwFlags = 2;
(ftype-set! input-array-ftype
            (1 ki time) input-array 0) ;; input_array[1].ki.time = 0;
(ftype-set! input-array-ftype
            (1 ki dwExtraInfo) input-array 0) ;; input_array[1].ki.dwExtraInfo = NULL;

(display (send-input-fp 2 input-array
            (ftype-sizeof win32-input-ftype)))

;; 所有事件都返回0,表示失败,并且GetLastError为87,表示无效的参数。
;; 递归遍历结构表明它们都按预期分配,而ftype-sizeof也在预期范围内。

以下是你要模仿的工作中的C++代码的翻译部分:

(define (press-windows-key)
  (let ((inputs (make-c-struct-array 'input 2)))
    (c-struct-set! inputs 0 'type 1)
    (c-struct-set! inputs 0 'ki.wVk #x5B)
    (c-struct-set! inputs 0 'ki.wScan 0)
    (c-struct-set! inputs 0 'ki.time 0)
    (c-struct-set! inputs 0 'ki.dwFlags 0)
    (c-struct-set! inputs 0 'ki.dwExtraInfo 0)

    (c-struct-set! inputs 1 'type 1)
    (c-struct-set! inputs 1 'ki.wVk #x5B)
    (c-struct-set! inputs 1 'ki.wScan 0)
    (c-struct-set! inputs 1 'ki.time 0)
    (c-struct-set! inputs 1 'ki.dwFlags 2)
    (c-struct-set! inputs 1 'ki.dwExtraInfo 0)

    (let ((uSent (send-input-fp 2 inputs (c-struct-sizeof 'input))))
      (display uSent)))))

希望这有助于你解决问题!如果有其他问题,请随时提问。

英文:

I've never had any trouble with Chez Scheme FFI before, it's extremely forgiving with whatever you throw at it, but I can't seem to get this function not to throw errors.

The goal is to simply virtually press and release the left windows key.

(load-shared-object "user32.dll")
(define-ftype win32-input-ftype
(struct (type unsigned-long)
(mi (union (dx long)
(dy long)
(mouseData unsigned-long)
(dwFlags unsigned-long)
(time unsigned-long)
(dwExtraInfo uptr)))
(ki (union (wVk unsigned-short)
(wScan unsigned-short)
(dwFlags unsigned-long)
(time unsigned-long)
(dwExtraInfo uptr)))
(hi (union (uMsg unsigned-long)
(wParamL unsigned-short)
(wParamH unsigned-short))))) 
;; Struct info from MSDN
;; dwExtraInfo is actually an (* unsigned-long), but creating a dummy ulong pointer set to 0
;; also had no effect. A nullable uptr is also interchangeable in working code for other ffi calls
(define-ftype input-array-ftype
(array 2 win32-input-ftype)) ;; win32-input-ftype/INPUT[2]
(define send-input-fp
(foreign-procedure "SendInput"
(unsigned-int
(* input-array-ftype)
int)
unsigned-int)) 
;; Define signature for SendInput from MSDN
(define input-array
(make-ftype-pointer input-array-ftype
(foreign-alloc (ftype-sizeof input-array-ftype)))) 
;; Allocate the array with the structs and create a pointer to it
(ftype-set! input-array-ftype
(0 type) input-array 1) ;; input_array[0].type = 1;
(ftype-set! input-array-ftype
(0 ki wVk) input-array #x5B) ;; input_array[0].ki.wVk = 0x5B;
(ftype-set! input-array-ftype
(0 ki wScan) input-array 0) ;; input_array[0].ki.wScan = 0;
(ftype-set! input-array-ftype
(0 ki dwFlags) input-array 0) ;; input_array[0].ki.dwFlags = 0;
(ftype-set! input-array-ftype
(0 ki time) input-array 0) ;; input_array[0].ki.time = 0;
(ftype-set! input-array-ftype
(0 ki dwExtraInfo) input-array 0) ;; input-array[0].dwExtraInfo = NULL;
(ftype-set! input-array-ftype
(1 type) input-array 1) ;; input_array[1].type = 1
(ftype-set! input-array-ftype
(1 ki wVk) input-array #x5B) ;; input_array[1].ki.wVk = 0x5B;
(ftype-set! input-array-ftype
(1 ki wScan) input-array 0) ;; input_array[1].ki.wScan = 0;
(ftype-set! input-array-ftype
(1 ki dwFlags) input-array 2) ;; input_array[1].ki.dwFlags = 2;
(ftype-set! input-array-ftype
(1 ki time) input-array 0) ;; input_array[1].ki.time = 0;
(ftype-set! input-array-ftype
(1 ki dwExtraInfo) input-array 0) ;; input_array[1].ki.dwExtraInfo = NULL;
(display (send-input-fp 2 input-array
(ftype-sizeof win32-input-ftype)))
;; The return is 0 for all events failing and GetLastError is 87 invalid parameters.
;; Recursing through the structs show they're all allocated as expected and the ftype-sizeof
;; is in the expected area as well.

And here's the working C++ code that I'm trying to mimic:

void PressWindowsKey()
{
INPUT inputs[2] = {};
INPUT *input_ptr = inputs;
inputs[0].type = 1;
inputs[0].ki.wVk = 0x5B;
inputs[0].ki.wScan = 0;
inputs[0].ki.time = 0;
inputs[0].ki.dwFlags = 0;
inputs[0].ki.dwExtraInfo = NULL;
inputs[1].type = 1;
inputs[1].ki.wVk = 0x5B;
inputs[1].ki.wScan = 0;
inputs[1].ki.time = 0;
inputs[1].ki.dwFlags = 2;
inputs[1].ki.dwExtraInfo = NULL;
UINT uSent = SendInput(2, input_ptr, sizeof(INPUT));
}

Any help would be appreciated!
This is on stand-alone 32-bit/64-bit Chez Scheme 9.5.4 (I've tried both), but I'm attaching Racket to the tags since if I'm not mistaken the Chez hosted within has the same FFI.

答案1

得分: 1

以下是您要翻译的内容:

"The code almost works as is, but as mentioned in the Chez Scheme documentation, allocating arrays is conservative in the number of bytes is uses. SendInput is also very particular about arg 3 being the exact number of bytes.

By manually typing in 28 bytes for arg 3 of SendInput instead of using (ftype-sizeof), the program works.

Edit:
I got some strange behavior from the (unions as well. Switching the foreign type definition to:

(define-ftype win32-input-ftype
  (struct (type unsigned-long)
	  (ki (struct (wVk unsigned-short)
		      (wScan unsigned-short)
		      (dwFlags unsigned-long)
		      (time unsigned-long)
		      (dwExtraInfo uptr))))) 

fixed this problem. Good luck"

英文:

The code almost works as is, but as mentioned in the Chez Scheme documentation, allocating arrays is conservative in the number of bytes is uses. SendInput is also very particular about arg 3 being the exact number of bytes.

By manually typing in 28 bytes for arg 3 of SendInput instead of using (ftype-sizeof), the program works.

Edit:
I got some strange behavior from the (unions as well. Switching the foreign type definition to:

(define-ftype win32-input-ftype
(struct (type unsigned-long)
(ki (struct (wVk unsigned-short)
(wScan unsigned-short)
(dwFlags unsigned-long)
(time unsigned-long)
(dwExtraInfo uptr))))) 

fixed this problem. Good luck

huangapple
  • 本文由 发表于 2023年7月11日 07:38:32
  • 转载请务必保留本文链接:https://go.coder-hub.com/76657918.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定