Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SendInput fails on 64bit [duplicate]

Possible Duplicate:
SendInput and 64bits

I'm using SendInput from .NET code (PInvoke).
code used to work fine on 32bit OS, but now on WIN7 SendInput returns 0, and last error is set to 57 (ERROR_INVALID_PARAMETER).
I cannot compile my code as x86 as I am loaded into a 64bit host. Also, I tried various solutions regarding structure sizes and field offsets, none worked.
These are my PInvoke imports and types:

[StructLayout(LayoutKind.Sequential)]
struct KEYBOARD_INPUT
{
    public uint type;
    public ushort vk;
    public ushort scanCode;
    public uint flags;
    public uint time;
    public uint extrainfo;
    public uint padding1;
    public uint padding2;
}

[DllImport("User32.dll", SetLastError=true)]
private static extern uint SendInput(
    uint numberOfInputs, 
   [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] KEYBOARD_INPUT[] input,
   int structSize);

and code usage is:

uint result = SendInput(
       (uint)inputs.Count, 
       inputs.ToArray(), 
       Marshal.SizeOf(inputs[0]));

where inputs array contains 1 KEYBOARD_INPUT struct.
this yields in result = 0, and when I check last error I get that last error is set to 57 (ERROR_INVALID_PARAMETER, The parameter is incorrect).

Is there a way to make this work under 64bit host in WIN7 64bit OS? this works in XP...

thanks

like image 453
Oren Avatar asked Jan 22 '12 17:01

Oren


1 Answers

Try using the following definitions (courtesy of pinvoke.net):

const int INPUT_MOUSE = 0;
const int INPUT_KEYBOARD = 1;
const int INPUT_HARDWARE = 2;
const uint KEYEVENTF_EXTENDEDKEY = 0x0001;
const uint KEYEVENTF_KEYUP = 0x0002;
const uint KEYEVENTF_UNICODE = 0x0004;
const uint KEYEVENTF_SCANCODE = 0x0008;

struct INPUT
{
    public int type;
    public InputUnion u;
}

[StructLayout(LayoutKind.Explicit)]
struct InputUnion
{
    [FieldOffset(0)]
    public MOUSEINPUT mi;
    [FieldOffset(0)]
    public KEYBDINPUT ki;
    [FieldOffset(0)]
    public HARDWAREINPUT hi;
}

[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
{
    /*Virtual Key code.  Must be from 1-254.  If the dwFlags member specifies KEYEVENTF_UNICODE, wVk must be 0.*/
    public ushort wVk;
    /*A hardware scan code for the key. If dwFlags specifies KEYEVENTF_UNICODE, wScan specifies a Unicode character which is to be sent to the foreground application.*/
    public ushort wScan;
    /*Specifies various aspects of a keystroke.  See the KEYEVENTF_ constants for more information.*/
    public uint dwFlags;
    /*The time stamp for the event, in milliseconds. If this parameter is zero, the system will provide its own time stamp.*/
    public uint time;
    /*An additional value associated with the keystroke. Use the GetMessageExtraInfo function to obtain this information.*/
    public IntPtr dwExtraInfo;
}

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

[DllImport("user32.dll")]
static extern IntPtr GetMessageExtraInfo();

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

Then, in your client code, use:

INPUT[] inputs = new INPUT[]
{
    new INPUT
    {
        type = INPUT_KEYBOARD,
        u = new InputUnion
        {
            ki = new KEYBDINPUT
            {
                wVk = key,
                wScan = 0,
                dwFlags = 0,
                dwExtraInfo = GetMessageExtraInfo(),
            }
        }
    }
};

SendInput((uint)inputs.Length, inputs, Marshal.SizeOf(typeof(INPUT)));
like image 134
Douglas Avatar answered Nov 15 '22 07:11

Douglas