1

我在 xp 32bits 下使用 sendInput() 使用 web 服务来推送当前焦点窗口的 F​​5。现在在 Vista win64 下我不能得到这个结果。一些文章指出使用 4 位或 8 位的 uint 问题,但这并不能解决 vista 下使用差分编译和 FieldOffset(4) 或 (8) 的问题。其他人则谈到使用此 SendInput() 方法的 Vista 屏幕和窗口之间不再有交互。有人可以指出在win32和win64机器上推动F5的解决方案。谢谢。

uint intReturn = 0;
NativeWIN32.INPUT structInput;
structInput = new NativeWIN32.INPUT();
structInput.type = (uint)1;
structInput.ki.wScan = 0;
structInput.ki.time = 0;
structInput.ki.dwFlags = 0;
structInput.ki.dwExtraInfo = IntPtr.Zero; 

// Key down the actual key-code 
structInput.ki.wVk = (ushort)NativeWIN32.VK.F5;
//vk; 
intReturn = NativeWIN32.SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));
// Key up the actual key-code 
structInput.ki.dwFlags = NativeWIN32.KEYEVENTF_KEYUP;
structInput.ki.wVk = (ushort)NativeWIN32.VK.F5;
//vk; 
intReturn = NativeWIN32.SendInput((uint)1, ref structInput, Marshal.SizeOf(structInput));



public class NativeWIN32
{ 
    public const ushort KEYEVENTF_KEYUP = 0x0002; 
    public enum VK : ushort 
    {  
        F5                   = 0x74,  
    } 

    public struct KEYBDINPUT 
    {  
        public ushort wVk;  
        public ushort wScan;  
        public uint dwFlags;  
        public long time;  
        public uint dwExtraInfo; 
    }; 
    [StructLayout(LayoutKind.Explicit,Size=28)]  
    public struct INPUT 
    {  
        [FieldOffset(0)] 
        public uint type;
        #if x86 
    //32bit 
    [FieldOffset(4)] 
        #else
        //64bit 
        [FieldOffset(8)]
        #endif
        public KEYBDINPUT ki; 
    };

    [DllImport("user32.dll")] 
    public static extern uint SendInput(uint nInputs, ref INPUT pInputs, int cbSize);

}

4

2 回答 2

4

我在 XP 上遇到了 32/64 的问题,这就是我想出的解决方案。我不是 pInvoke 专家,所以可能会有更优雅的解决方案。

根本原因似乎是两种架构之间的字长不同。这会导致一些复杂数据从外部调用中使用的数据结构中解析出来。我必须为 64 位和 32 位声明两组独立的结构和外部调用。

internal static class SendInputExternalCalls
{
    // This SendInput call uses the 32bit input structure.
    [DllImport("user32.dll", SetLastError = true, EntryPoint = "SendInput")]
    public static extern UInt32 SendInput(
        UInt32 numInputs,
        [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)]
        SEND_INPUT_FOR_32_BIT[] sendInputsFor,
        Int32 cbSize);

    // This SendInput call uses the 64bit input structure.
    [DllImport("user32.dll", SetLastError = true, EntryPoint = "SendInput")]
    public static extern UInt32 SendInput(
        UInt32 numInputs,
        [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] 
        SEND_INPUT_FOR_64_BIT[] sendInputsFor,
        Int32 cbSize);
}

// This is the basic structure for 32 bit input.  SendInput allows for other input   
// types, but I was only concerned with keyboard input, so I harcoded my strucs that way.
[StructLayout(LayoutKind.Explicit, Pack = 1)]
internal struct SEND_INPUT_FOR_32_BIT
{
    [FieldOffset(0)]
    public uint InputType;  
    [FieldOffset(4)]
    public KEYBOARD_INPUT_FOR_32_BIT KeyboardInputStruct; 
}

// Here is the structure for keyboard input.  The key code, scan code, and flags
// are what's important.  The other variables are place holders so that the structure
// maintains the correct size when compared to the other possible input structure types.  
[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct KEYBOARD_INPUT_FOR_32_BIT
{
    public ushort VirtualKeyCode;
    public ushort ScanCode;
    public uint Flags;
    public uint Time;
    public uint ExtraInfo;
    public uint Padding1;
    public uint Padding2;
}

// Here's the corresponding 64 bit structure.  Notice that the field offset are larger. 
[StructLayout(LayoutKind.Explicit, Pack = 1)]
internal struct SEND_INPUT_FOR_64_BIT
{
    [FieldOffset(0)]
    public uint InputType;
    [FieldOffset(8)]
    public KEYBOARD_INPUT_FOR_64_BIT KeyboardInputStruct;
}

// Here's the keyboard 64 bit structure.  Notice that the field offset are again larger.
[StructLayout(LayoutKind.Explicit, Pack = 1)]
internal struct KEYBOARD_INPUT_FOR_64_BIT
{
    [FieldOffset(0)]
    public ushort VirtualKeyCode;
    [FieldOffset(2)]
    public ushort ScanCode;
    [FieldOffset(4)]
    public uint Flags;
    [FieldOffset(12)]
    public uint Time;
    [FieldOffset(20)]
    public uint Padding1;
    [FieldOffset(28)]
    public uint Padding2;
} 

这是稍微笨拙的部分。使用哪种结构取决于应用程序运行的架构。您可以针对 32 位或 64 位目标进行编译,但您仍然可以在 64 位 Windows 上运行 32 位编译的应用程序。如果您希望您的 32 位编译应用程序在 64 位机器上使用 SendInput,您必须确定在运行时使用哪个结构。我通过在调用发送输入的公共方法时检查字长来做到这一点。

    public static void SendInput( ushort charUnicode )
    {
        // In 32 bit the IntPtr should be 4; it's 8 in 64 bit.
        if (Marshal.SizeOf(new IntPtr()) == 8)
        {
            SendInput64(charUnicode);
        }
        else
        {
            SendInput32(charUnicode);
        }
    }

我没有在 Vista 中尝试过,但它适用于 32/64 Windows XP 和 32/64 Windows 7。

于 2012-04-30T18:23:56.943 回答
-1

将您的项目编译为 32 位将解决此问题。请参考:http ://social.msdn.microsoft.com/Forums/en-SG/Vsexpressvb/thread/69e5529e-372b-4d70-bb94-556507a2358e

于 2011-08-18T06:57:51.723 回答