SendInput Keys in Win32 & Win64 machines
I have used sendInput() under xp 32bits using webservices to push F5 of current focused windows. Now under Vista win64 i can´t obtain this result. Some articles point uint problems using 4bits or 8bits but this is not fixing the problem under vista with differential compilation and FieldOffset(4)or(8). Others speak about no more interaction beetween Vista screen and the window using this SendInput() method. Can someone point the solution to push F5 in win32 and win64 machines. Thanks.
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);
}
I ran into this problem with 32/64 on XP and this is the solution I came up with. I'm not a pInvoke expert, so there may be a more elegant solution.
The root cause seems to be that word size is different between the two architectures. This throws off where some of the complex data gets parsed out of the data structures used in the external call. I had to declare two separate sets of structures and external calls for 64 bit and 32 bit.
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;
}
Here comes the slightly kludgy part. Which structure to use is determined by the architecture the app runs on. You can compile for a 32 or 64 bit target, but you can still run a 32 bit compiled app on 64 bit Windows. If you want your 32 bit compiled app to use SendInput on a 64 bit machine you have to figure out which struct to use at run time. I did this by checking the word size when my public method to send input was called.
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);
}
}
I haven't tried this in Vista, but it works in 32/64 Windows XP and 32/64 Windows 7.
Compile your project for 32 bit would fix this. Please refer to : http://social.msdn.microsoft.com/Forums/en-SG/Vsexpressvb/thread/69e5529e-372b-4d70-bb94-556507a2358e
精彩评论