Dot-Net

SendInput 和 64 位

  • December 16, 2021

下面是我用來通過 SendInput API 模擬按鍵的一些程式碼的摘錄。如果我將應用程序設置為針對 x86 CPU 進行編譯,這可以正常工作,但不適用於 x64 CPU 編譯。

我猜這與 x64 使用雙倍大小指針這一事實有關,但我試圖將其更改為此[FieldOffset(4)][FieldOffset(8)]沒有奏效。

這可能與它正在導入 32 位版本的 user32.dll 的事實有關嗎?

   #region SendInput API

   [DllImport("user32.dll", EntryPoint = "SendInput", SetLastError = true)]
   static extern uint SendInput(uint nInputs, INPUT[] pInputs, int cbSize);

   [DllImport("user32.dll", EntryPoint = "GetMessageExtraInfo", SetLastError = true)]
   static extern IntPtr GetMessageExtraInfo();

   private enum KeyEvent
   {
       KeyUp = 0x0002,
       KeyDown = 0x0000,
       ExtendedKey = 0x0001
   }

   private struct KEYBDINPUT
   {
       public ushort wVk;
       public ushort wScan;
       public uint dwFlags;
       public long time;
       public uint dwExtraInfo;
   };

   [StructLayout(LayoutKind.Explicit, Size = 28)]
   private struct INPUT
   {
       [FieldOffset(0)]
       public uint type;
       [FieldOffset(4)]
       public KEYBDINPUT ki;
   };

   #endregion

   public void sendKey(KeyCode Key)
   {
       INPUT[] InputList = new INPUT[2];

       INPUT keyInput = new INPUT();
       keyInput.type = 1;

       keyInput.ki.wScan = 0;
       keyInput.ki.time = 0;
       keyInput.ki.dwFlags = (int)KeyEvent.KeyDown;
       keyInput.ki.dwExtraInfo = (uint)GetMessageExtraInfo();
       keyInput.ki.wVk = (ushort)Key;

       InputList[0] = keyInput;

       keyInput.ki.dwFlags = (int)KeyEvent.KeyUp;

       InputList[1] = keyInput;

       SendInput((uint)2, InputList, Marshal.SizeOf(InputList[0]));
   }

除了 SLaks 發現的錯誤之外,您剩下的問題是大小INPUT不正確。這意味著SendInput失敗,因為它接收到一個類型的參數INPUT[]。您無法指定大小,StructLayout(LayoutKind.Explicit, Size = 28)因為您需要同時處理 x86 和 x64 的程式碼。

這一切都源於您僅將KEYBRDINPUT結構包含在INPUT. MOUSEINPUT結構大於KEYBRDINPUT導致問題的原因。

最好的解決方案是正確定義 INPUT 結構,包括聯合部分。這樣做(來自pinvoke.net的聲明)。

[StructLayout(LayoutKind.Sequential)]
struct MOUSEINPUT
{
   public int dx;
   public int dy;
   public uint mouseData;
   public uint dwFlags;
   public uint time;
   public IntPtr dwExtraInfo;
}

[StructLayout(LayoutKind.Sequential)]
struct KEYBDINPUT 
{
    public ushort wVk;
    public ushort wScan;
    public uint dwFlags;
    public uint time;
    public IntPtr dwExtraInfo;
}

[StructLayout(LayoutKind.Sequential)]
struct HARDWAREINPUT
{
    public int uMsg;
    public short wParamL;
    public short wParamH;
}

[StructLayout(LayoutKind.Explicit)]
struct MouseKeybdHardwareInputUnion
{
   [FieldOffset(0)]
   public MOUSEINPUT mi;

   [FieldOffset(0)]
   public KEYBDINPUT ki;

   [FieldOffset(0)]
   public HARDWAREINPUT hi;
}

[StructLayout(LayoutKind.Sequential)]
struct INPUT
{
   public uint type;
   public MouseKeybdHardwareInputUnion mkhi;
}

引用自:https://stackoverflow.com/questions/6830651