Win32中的SendInput密钥& Win64机器

时间:2011-01-04 16:53:05

标签: c# marshalling win64 sendinput

我使用webservices在xp 32bits下使用sendInput()来推送当前聚焦窗口的F5。现在在Vista win64下,我无法获得此结果。有些文章指出使用4位或8位的uint问题,但这并不能解决使用差异编译和FieldOffset(4)或(8)的vista下的问题。其他人说使用此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);

}

2 个答案:

答案 0 :(得分:3)

我在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;
} 

这是一个有点kludgy的部分。使用哪种结构取决于应用程序运行的体系结构。您可以编译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。

答案 1 :(得分:-1)