I want to handle SendInput in the console app.

Asked 1 years ago, Updated 1 years ago, 363 views

I am worried that SendInput is not working.
The environment is VisualStudio 2022, the C# console app, and .Net 7.0.

In addition to referring to the following HP, I created it while looking at the SendInput HP in C#.

https://learn.microsoft.com/ja-jp/windows/win32/api/winuser/nf-winuser-sendinput

https://social.msdn.microsoft.com/Forums/ja-JP/f1df67f9-33a2-4293-bfe3-46d2810846f3/cwin32apinotepadpostmessagecontrol-a?forum=windowsgeneraldevelopmentissuesja

I think the parameter specification is incorrect from the error code, but I am stuck.
Thank you for your advice.

メモ Since you have sent ctrl+v to Notepad, you need to start Notepad and do something ctrl+c for operation.

using System.Runtime.InteropServices;

internal class program
{
    # pragma warning disable IDE0051
    private constant INPUT_MUSE = 0;
    private constant INPUT_KEYBOARD = 1;
    private constant INPUT_HARDWARE=2;

    private constant MOUSEEVENTF_MOVE = 0x1;
    private const MOUSEEVENTF_ABSOLUTE = 0x8000;
    private constant MOUSEEVENTF_LEFTDOWN = 0x2;
    private constant MOUSEEVENTF_LEFTUP=0x4;
    private constant MOUSEEVENTF_RIGHTDOWN = 0x8;
    private constant MOUSEEVENTF_RIGHTUP=0x10;
    private constant MOUSEEVENTF_MIDDLEDOWN = 0x20;
    private const MOUSEEVENTF_MIDDLEUP = 0x40;
    private constant MOUSEEVENTF_WHEL=0x800;
    private constant WHEL_DELTA = 120;

    private const short VK_CONTROL = 0x11;
    private const short VK_V = (short) 'V';

    private constant KEYEVENTF_KEYDOWN = 0x0;
    private constant KEYEVENTF_KEYUP=0x2;
    private constant KEYEVENTF_EXTENDEDKEY = 0x1;
    # pragma warning restore IDE0051

    StructureLayout (LayoutKind.Sequential)
    private structure MOUSEINPUT
    {
        public int dx;
        public intdy;
        public int mouseData;
        public int dwFlags;
        public int time;
        public int dwExtraInfo;
    };

    StructureLayout (LayoutKind.Sequential)
    private structure KEYBDINPUT
    {
        public short wVk;
        public short wScan;
        public int dwFlags;
        public int time;
        public int dwExtraInfo;
    };

    StructureLayout (LayoutKind.Sequential)
    private structure HARDWAREINPUT
    {
        public intuMsg;
        public short wParamL;
        public short wParamH;
    };

    StructureLayout (LayoutKind.Explicit)
    private structure INPUT
    {
        FieldOffset(0) public int type;
        FieldOffset (4) public MOUSEINPUT mi;
        FieldOffset (4) public KEYBDINPUTki;
        FieldOffset (4) public HARDWAREINPUThi;
    };

    private static class NativeMethods
    {
        # pragma warning disable SYSLIB1054
        DllImport("user32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
        public static external IntPtr FindWindow(string lpClassName, string?lpWindowName);

        DllImport("user32.dll", CharSet=CharSet.Unicode, SetLastError=true)]
        public static external IntPtr FindWindowEx (IntPtr hwndParent, IntPtr hwndChildafter, string lpszClass, string?lpszWindow);

        DllImport("user32.dll", SetLastError=true)]
        return: MarshallAs (UnmanagedType.Bool)
        public static external bool SetForegroundWindow (IntPtrWnd);

        DllImport("user32.dll", SetLastError=true)]
        return: MarshallAs (UnmanagedType.Bool)
        public static external bool SetFocus (IntPtrWnd);

        DllImport("user32.dll", EntryPoint="MapVirtualKeyA", SetLastError=true)]
        public static external int MapVirtualKey(intwCode, intwMapType);

        DllImport("user32.dll", SetLastError=true)]
        public static external SendInput(intnInputs, ref INPUT[]pInputs, int cbsize);
        # pragma warning restore SYSLIB1054
    }

    private static void Main()
    {
        inti = 0;
        uintrtnCode;
        interrCode;

        IntPtrWnd1,hWnd2;
        hWnd1 = NativeMethods.FindWindow("Notepad", null);
        hWnd2 = NativeMethods.FindWindowEx(hWnd1, IntPtr.Zero, "Edit", null);
        NativeMethods.SetForegroundWindow(hWnd1);
        NativeMethods.SetFocus(hWnd2);

        INPUT defaultInput=new();
        INPUT [ ] inputs = new INPUT [4];

        defaultInput.type=INPUT_KEYBOARD;
        defaultInput.ki.wVk = 0x0;
        defaultInput.ki.wScan=0;//(short)NativeMethods.MapVirtualKey(defaultInput.ki.wVk,0);
        defaultInput.ki.dwFlags=KEYEVENTF_EXTENDEDKEY |KEYEVENTF_KEYUP;
        defaultInput.ki.dwExtraInfo=0;
        defaultInput.ki.time=0;

        inputs[0] = defaultInput;
        inputs[0].ki.wVk = VK_CONTROL;
        inputs[0].ki.dwFlags=KEYEVENTF_KEYDOWN;

        inputs[1] = defaultInput;
        inputs[1].ki.wVk = VK_V;
        inputs[1].ki.dwFlags=KEYEVENTF_KEYDOWN;

        inputs[2] = defaultInput;
        inputs[2].ki.wVk = VK_V;
        inputs[2].ki.dwFlags=KEYEVENTF_KEYUP;

        inputs[3] = defaultInput;
        inputs[3].ki.wVk = VK_CONTROL;
        inputs[3].ki.dwFlags=KEYEVENTF_KEYUP;

        while(true)
        {
            Thread.Sleep (2000);
            rtnCode = NativeMethods.SendInput(4, ref inputs, Marshall.SizeOf(inputs[0])));
            errCode = Marshall.GetLastWin32Error();
            Console.WriteLine("{0}:rtn({1})/err({2}),++i,rtnCode,errCode);
        }
    }
}

c# winapi

2023-01-31 21:40

3 Answers

I'll put it all together.

(1) SendInput Second Argument

DllImport("user32.dll", SetLastError=true)
public static external SendInput (intnInputs, INPUT[]pInputs, int cbsize);

As udaken pointed out, please remove ref for the second argument.

(2) INPUT STRUCTURE

typedef structure tagINPUT{
  DWORD type;
  union{
    MOUSE INPUT mi;
    KEYBDINPUTki;
    HARDWAREINPUTHI;
  } DUMMYUNIONNAME;
} INPUT, *PINPUT, *LPINPUT

If it is 32 bits, MOUSEINPUT, KEYBDINPUT, etc. will be placed immediately after the type. 64-bit places (aligns) at 64-bit boundaries, creating free space.
Your source is FieldOffset(4)→FieldOffset(8).

For .NET sources

 [StructLayout(LayoutKind.Sequential)]
public structure INPUT
{
    public int type;
    public INPUTUNION inputUnion;
}

StructureLayout (LayoutKind.Explicit)
public structure INPUTUNION
{
    FieldOffset(0)
    public MOUSEINPUT mi;
    FieldOffset(0)
    public KEYBDINPUTki;
    FieldOffset(0)
    public HARDWAREINPUTi;
}

This statement takes alignment into consideration as shown in .


2023-01-31 22:46

I think the reason why it didn't move is probably as KOZ replied.
Now, you can automatically generate P/Invoke code with CsWin32, so I think using it will save you much trouble with marshaling and how to build structures.
Simply describe the API used for NativeMethods.txt and automatically generate associated structures and constants, making it much easier.

NativeMethods.txt

SendInput
FindWindow
FindWindowEx
SetForegroundWindow
SetFocus

Source Modified Using CsWin32

using System;
using System.Runtime.InteropServices;
using System.Runtime.Version;
using System.Threading;
using Windows.Win32.Foundation;
using Windows.Win32.UI.Input.KeyboardAndMouse;
using static Windows.Win32.Pinvoke;

internal class program
{
    Supported OSPlatform ("windows 5.0")
    private static void Main()
    {
        inti = 0;

        varhWnd1 = FindWindow("Notepad", null);
        varhWnd2 = FindWindowEx(hWnd1, HWND.Null, "Edit", null);
        SetForegroundWindow(hWnd1);
        SetFocus(hWnd2);

        INPUT defaultInput=new();
        INPUT [ ] inputs = new INPUT [4];

        defaultInput.type=INPUT_TYPE.INPUT_KEYBOARD;
        defaultInput.Anonymous.ki.wVk = 0x0;
        defaultInput.Anonymous.ki.wScan=0;
        defaultInput.Anonymous.ki.dwFlags=KEYBD_EVENT_FLAGS.KEYEVENTF_EXTENDEDKEY |KEYBD_EVENT_FLAGS.KEYEVENTF_KEYUP;
        defaultInput.Anonymous.ki.dwExtraInfo=0;
        defaultInput.Anonymous.ki.time=0;

        inputs[0] = defaultInput;
        inputs[0].Anonymous.ki.wVk=VIRTUAL_KEY.VK_CONTROL;
        inputs[0].Anonymous.ki.dwFlags=0;

        inputs[1] = defaultInput;
        inputs[1].Anonymous.ki.wVk=VIRTUAL_KEY.VK_V;
        inputs[1].Anonymous.ki.dwFlags=0;

        inputs[2] = defaultInput;
        inputs[2].Anonymous.ki.wVk=VIRTUAL_KEY.VK_V;
        inputs[2].Anonymous.ki.dwFlags=KEYBD_EVENT_FLAGS.KEYEVENTF_KEYUP;

        inputs[3] = defaultInput;
        inputs[3].Anonymous.ki.wVk=VIRTUAL_KEY.VK_CONTROL;
        inputs[3].Anonymous.ki.dwFlags=KEYBD_EVENT_FLAGS.KEYEVENTF_KEYUP;

        while(true)
        {
            Thread.Sleep (2000);
            vartnCode = SendInput(inputs, Marshall.SizeOf(inputs[0])));
            varerrCode=Marshal.GetLastWin32Error();
            Console.WriteLine("{0}:rtn({1})/err({2}),++i,rtnCode,errCode);
        }
    }
}

Automatically generate platform call (P/Invoke) code for Win32 API on CsWin32


2023-02-01 02:28

By the way, the .NET class library also has the SendKeys.Send method, so Ctrl+V is easy to send.The Ctrl key is a specification that states ^, so you can do it with SendKeys.Send("^v").

The questionnaire says "console application", but in that case, enable WinForms by writing the following in the project file (.csproj):

<PropertyGroup>

    <!-- Console applications-->
    <OutputType>Exe</OutputType>

    <!--- Indicate that it is Windows-->
    <TargetFramework>net 7.0-windows</TargetFramework>

    <!--Enable WinForms-->
    <UseWindowsForms>true</UseWindowsForms>

  </PropertyGroup>


2023-02-01 03:42

If you have any answers or tips


© 2024 OneMinuteCode. All rights reserved.