none
SendInput()

    Question

  • I wrote a program in C# (.Net 2) with VS2005 using P / I (http://msdn2.microsoft.com/en-us/library/ms646310.aspx) to move the mouse and click. Under WinXp the app works fine. No problems.

    But when I start the program under Windows Vista x64 (Final) the mouse movement and clicking does not work. SendInput does not return any error. So it seems to be an Vista Issue.

    Some ideas how to get this running under Vista?


    Thursday, January 25, 2007 10:14 PM

Answers

All replies

  • What is the return value of the function?
    Friday, January 26, 2007 12:43 AM
  • "The number of events that it successfully inserted into the keyboard or mouse input stream."

    And my function correctly returns this.
    Friday, January 26, 2007 1:17 PM
  • Are you trying to send input from a normal process to the window of an elevated process?  Or are both sender and target running at the same level?
    Friday, January 26, 2007 3:09 PM
  • They are on the same level (user process). As I said even elevating the process doesn't help.I even tried to move the cursor relative inside the app. I doesn't work though SendInput() still returns that the event was successful. Amazing that I get an win32 error 1400 just after simulating a click though the SendInput() function doesn't indicate an error.Maybe someone can reproduce the error or find the a mistake in my class. I post it here. Maybe someone can help me:

    using System;
    using System.Collections.Generic;
    using System.Text;
    using System.Runtime.InteropServices;
    using System.Windows.Forms;


    namespace AutoSetto
    {
        public class Win32Input
        {
            [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 InputType
            {
                INPUT_MOUSE = 0,
                INPUT_KEYBOARD = 1,
                INPUT_HARDWARE = 2,
            }

            [Flags()]
            private enum MOUSEEVENTF
            {
                MOVE =        0x0001,  // mouse move
                LEFTDOWN =    0x0002,  // left button down
                LEFTUP =      0x0004,  // left button up
                RIGHTDOWN =   0x0008,  // right button down
                RIGHTUP =     0x0010,  // right button up
                MIDDLEDOWN =  0x0020,  // middle button down
                MIDDLEUP =    0x0040,  // middle button up
                XDOWN =       0x0080,  // x button down
                XUP =         0x0100,  // x button down
                WHEEL =       0x0800,  // wheel button rolled
                VIRTUALDESK = 0x4000,  // map to entire virtual desktop
                ABSOLUTE =    0x8000,  // absolute move
            }

            [Flags()]
            private enum KEYEVENTF
            {
                EXTENDEDKEY = 0x0001,
                KEYUP =       0x0002,
                UNICODE =     0x0004,
                SCANCODE =    0x0008,
            }

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

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

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

            [StructLayout(LayoutKind.Explicit)]
            private struct INPUT
            {
                [FieldOffset(0)]
                public int type;
                [FieldOffset(4)]
                public MOUSEINPUT mi;
                [FieldOffset(4)]
                public KEYBDINPUT ki;
                [FieldOffset(4)]
                public HARDWAREINPUT hi;
            }
            /// <summary>
            /// This function moves the cursor to a specific point at the screen.
            /// </summary>
            /// <param name="x">X coordinate of the posotion as pixel</param>
            /// <param name="y">Y coordinate of the posotion as pixel</param>
            /// <returns>Returns 0 if there was an error otherwise 1.</returns>
            public static uint Move(int x, int y)
            {
                // Bildschirm Auflösung
                float ScreenWidth = Screen.PrimaryScreen.Bounds.Width;
                float ScreenHeight = Screen.PrimaryScreen.Bounds.Height;

                INPUT input_move = new INPUT();
                input_move.mi.dx = (int)Math.Round(x * (65535 / ScreenWidth), 0);
                input_move.mi.dy = (int)Math.Round(y * (65535 / ScreenHeight), 0);
                input_move.mi.mouseData = 0;
                input_move.mi.dwFlags = (int)(MOUSEEVENTF.MOVE | MOUSEEVENTF.ABSOLUTE);

                INPUT[] input = {input_move};
                return SendInput(1, input, Marshal.SizeOf(input_move));
            }

            /// <summary>
            /// This function simulates a simple mouseclick at the current cursor position.
            /// </summary>
            /// <returns>All right if it is 2. All below indicates an error.</returns>
            public static uint Click()
            {
                INPUT input_down = new INPUT();
                input_down.mi.dx = 0;
                input_down.mi.dy = 0;
                input_down.mi.mouseData = 0;
                input_down.mi.dwFlags = (int)MOUSEEVENTF.LEFTDOWN;

                INPUT input_up = input_down;
                input_up.mi.dwFlags = (int)MOUSEEVENTF.LEFTUP;

                INPUT[] input = {input_down, input_up};
                return SendInput(2, input, Marshal.SizeOf(input_down));
            }
        }
    }



    • Proposed as answer by truekold Wednesday, June 17, 2009 6:10 AM
    Friday, January 26, 2007 5:25 PM
  • There are some know issues around this type of behavior.

    See the "UIPI (GUI Portion of User Account Control)" portion of the following link:

    "For compatibility reasons, SendMessage and other APIs will return success even if the API was blocked because of privilege issues."

    http://msdn2.microsoft.com/en-us/library/aa480152.aspx

     

    Monday, February 05, 2007 9:52 PM
  • I have struggled with this all day as well.  Here is what I just found on another forum and it works perfectly.   The problem that I was having is this:

    1. SendInput worked great on XP sp2 x86.
    2. SendInput would NOT work on Vista x64 ( my development box is this for this very reason).
    3. SendInput would work when I booted into Vista x86.

    The problem is your field offsets in the INPUT struct. they should be 8 instead of 4... due to x64 pointers being 8 bytes instead of 4 bytes.

    [StructLayout(LayoutKind.Explicit)]
            private struct INPUT
            {
                [FieldOffset(0)]
                public int type;
                [FieldOffset(8)]
                public MOUSEINPUT mi;
                [FieldOffset(8)]
                public KEYBDINPUT ki;
                [FieldOffset(8)]
                public HARDWAREINPUT hi;
            }


    The dumbest question is how to implement this so that we can compile for "any cpu" but have the correct field offsets for the cpu... ie. if i have a INPUT struct and my .net dll is loaded on an x64 machine, the offset should reflect that.

    Beuller?


    Friday, February 22, 2008 11:24 PM
  •  

    Change the struct such that [FieldOffset(8)] reads as [FieldOffset(sizeof(int))] ?
    • Proposed as answer by truekold Wednesday, June 17, 2009 6:10 AM
    Wednesday, March 19, 2008 5:08 PM
  • It would have to be [FieldOffset(sizeof(IntPtr)]  and this causes the following compile error:

    Error    1    'System.IntPtr' does not have a predefined size, therefore sizeof can only be used in an unsafe context (consider using System.Runtime.InteropServices.Marshal.SizeOf)    U:\Visual Studio 2005\Projects\RemoteControlMouseAndKeyboard\RemoteControlMouseAndKeyboard\Form1.cs    802    22    RemoteControlMouseAndKeyboard


    I think the answer is actually declaring two INPUT structures (INPUT/INPUT64) with the correct respective outputs, declaring an SENDINPUTOBJECT class that has a getINPUT and getINPUT64, two P/Invoke declarations for SendInput one that takes an INPUT, the other takes an INPUT64, and finally a method "SendInput()"  that checks the size of IntPtr, gets the appropriate INPUT  and calls SendInput with that object.

    I'm writing this all up with code samples and I'll post a link when I'm done.
    Wednesday, March 19, 2008 5:54 PM
  • I used GetNativeSystemInfo from http://www.koders.com/csharp/fid495E7D0ED07BA35F5F0CE0EEFE87D7375BF1CF55.aspx
    to get the Platform Type. This worked perfectly. This also useful if you are running you .
    Net configuration in 32bit mode only.

    Ie with C:\WINDOWS\Microsoft.NET\Framework64\v2.0.50727\Ldr64.exe setwow .

    From

    Code Needed:
    private enum Platform
            {
                X86,
                X64,
                Unknown
            }
    
            internal const ushort PROCESSOR_ARCHITECTURE_INTEL = 0;
            internal const ushort PROCESSOR_ARCHITECTURE_IA64 = 6;
            internal const ushort PROCESSOR_ARCHITECTURE_AMD64 = 9;
            internal const ushort PROCESSOR_ARCHITECTURE_UNKNOWN = 0xFFFF;
    
            [StructLayout(LayoutKind.Sequential)]
            internal struct SYSTEM_INFO
            {
                public ushort wProcessorArchitecture;
                public ushort wReserved;
                public uint dwPageSize;
                public IntPtr lpMinimumApplicationAddress;
                public IntPtr lpMaximumApplicationAddress;
                public UIntPtr dwActiveProcessorMask;
                public uint dwNumberOfProcessors;
                public uint dwProcessorType;
                public uint dwAllocationGranularity;
                public ushort wProcessorLevel;
                public ushort wProcessorRevision;
            };
    
            [DllImport("kernel32.dll")]
            internal static extern void GetNativeSystemInfo(ref SYSTEM_INFO lpSystemInfo);        
            
            private static Platform GetPlatform()
            {
                SYSTEM_INFO sysInfo = new SYSTEM_INFO();
                GetNativeSystemInfo(ref sysInfo);
    
                switch (sysInfo.wProcessorArchitecture)
                {
                    case PROCESSOR_ARCHITECTURE_AMD64:
                        return Platform.X64;
    
                    case PROCESSOR_ARCHITECTURE_INTEL:
                        return Platform.X86;
    
                    default:
                        return Platform.Unknown;
                }
            }

    Wednesday, April 15, 2009 8:29 PM
  • Actually I take that back it turns out it really matters what .NET thinks it is running as ( 32bit or 64bit ). When you make the SendInput calls on a 64 bit machine that has Ldr64 set to setWow then the way .NET behaves is strictly 32bit, including Platform Invoke calls. This was a huge stumbling point for me. 

     

    So if you want to know absolute .dll and file locations that are specific to 64 bit machines (ProgramFiles (x86)) use GetNativeSystemInfo call. Otherwise just check the size of the IntPtr (4 == 32bit) (8 == 64 bit). That way you can get both .Nets behavior and the operating systems true type.

     

     

    I could not find this documented anywhere. So there it is.


    Thursday, April 16, 2009 5:29 PM