Sending a keystroke to an application in C # (sendkeys, postmessage, sendmessage all don't work)

I am trying to do one of the following 1. Open the desired program and programmatically press key 2. find the open program window and press the key programmatically (or well)

I have tried numerous implementations of SendKeys.SendWait (), PostMessage () and SendMessage () unsuccessfully. Below are my code snippets

//included all these for attempts [DllImport("User32.dll")] static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("User32.dll")] static extern int SetForegroundWindow(IntPtr hWnd); [DllImport("User32.Dll", EntryPoint = "PostMessageA")] static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam); [DllImport("user32.dll")] static extern byte VkKeyScan(char ch); [DllImport("user32.dll", CharSet = CharSet.Auto)] static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam); 

Get window handle, variables used by sendmessage / postmessage / sendkeys

 IntPtr ptrOBS = proc.Handle;//this works properly, proc is instantiated properly //IntPtr ptrOBS = FindWindow(null, "Open Broadcaster Software v0.472b"); SetForegroundWindow(ptrOBS); const UInt32 WM_CHAR = 0x0102; const uint WM_KEYDOWN = 0x100; const int VK_R = 0x52; // taken from http://msdn.microsoft.com/en-us/library/dd375731(v=vs.85).aspx const int VK_S = 0x53; 

SendMessage Error:

 SendMessage(ptrOBS, WM_KEYDOWN, (IntPtr)VK_R, (IntPtr)1);//tried both WM_CHAR and WM_KEYDOWN 

PostMessage attempt:

 string message = "rs"; bool sent = PostMessage(ptrOBS, WM_KEYDOWN, VkKeyScan(message[0]), 0); 

Trying SendKeys:

 SendKeys.SendWait("{r}"); 

I tried SetFocus in the parent window (application) and child window (the button is started by pressing the im key and try to send):

 static void SetFocus(IntPtr hwndTarget, string childClassName) { // hwndTarget is the other app main window // ... IntPtr targetThreadID = GetWindowThreadProcessId(hwndTarget, IntPtr.Zero); //target thread id IntPtr myThreadID = GetCurrentThread(); // calling thread id, our thread id try { bool lRet = AttachThreadInput(myThreadID, targetThreadID, -1); // attach current thread id to target window // if it not already in the foreground... lRet = BringWindowToTop(hwndTarget); SetForegroundWindow(hwndTarget); // if you know the child win class name do something like this (enumerate windows using Win API again)... IntPtr hwndChild = (IntPtr)1183492;//(IntPtr)EnumAllWindows(hwndTarget, childClassName).FirstOrDefault(); if (hwndChild == IntPtr.Zero) { // or use keyboard etc. to focus, ie send keys/input... // SendInput (...); return; } // you can use also the edit control hwnd or some child window (of target) here SetFocus(hwndChild); // hwndTarget); SendKeys.SendWait("{r}"); } finally { SendKeys.SendWait("{r}"); bool lRet = AttachThreadInput(myThreadID, targetThreadID, 0); //detach from foreground window SendKeys.SendWait("{r}"); } } 

For NSGaga:

  string windowName = "Open Broadcaster Software v0.472b"; IntPtr outerPtr = FindWindow(null, windowName); IntPtr ptrOBS = (IntPtr)527814;//button that im trying to trigger keypress on SetForegroundWindow(outerPtr); SetForegroundWindow(ptrOBS); SetFocus(outerPtr, "OBSWindowClass");//SetFocus(ptrOBS, "Button"); const UInt32 WM_CHAR = 0x0102; const int VK_R = 0x52; // taken from http://msdn.microsoft.com/en-us/library/dd375731(v=vs.85).aspx const int VK_S = 0x53; //SetForegroundWindow(ptrOBS); System.Threading.Thread.Sleep(3000); SendKeys.SendWait("{r}"); SendMessage(outerPtr, WM_KEYDOWN, (IntPtr)VK_R, (IntPtr)1); PostMessage(outerPtr, WM_KEYDOWN, VkKeyScan('r'), 0); 
+4
source share
2 answers

There are many trials and errors to make them work. Here is some code that I published earlier, you can try (and there is additional information) ...

Pinvoke SetFocus for a specific control

First try adjusting the focus (using the mentioned mechanism), and then use SendKeys or SendInput .

Here is the detailed code for SendInput ...

How to send a string to another application, including Microsoft Word

+2
source

You cannot reliably use SendMessage and PostMessage to synthesize keyboard input . They are simply not designed for this. These messages ( WM_CHAR , WM_KEYDOWN , etc.) are notifications raised by lower-level subsystems when keyboard input, processing, and forwarding to the appropriate recipient. Sending or posting these messages is in itself like jokes.

SendKeys (like all other input synthesizer methods, including the SendInput function, which was explicitly designed to synthesize keyboard input and at least some implementation is what SendKeys actually uses under the hood) only works when in the window that you want to get keyboard input has focus. On Windows, only oriented (active) windows receive input events.

So, SendKeys is probably the way to go if you ever want to make it work (either this, or P / Invoking SendInput , and all the structures associated with it), but you need to respect the caveat that the recipient window should have focus. Otherwise, nothing will work.

It appears that from your sample code, you are trying to use the SetForegroundWindow function to satisfy this precondition. Unfortunately, you pass it an invalid value and do not perform any error checks that could warn you of this error. In particular, this code is incorrect:

 IntPtr ptrOBS = proc.Handle;//this works properly, proc is instantiated properly SetForegroundWindow(ptrOBS); // WRONG, ptrOBS is not a window handle 

Even if I'm sure that you correctly initialized ptrOBS , this makes it a valid process handle, which is completely different than a valid window handle. In addition to the obvious nominal differences, processes can have several windows, and only one window can have focus (that is, be β€œin the foreground”).

You will need to get a handle in a specific window before calling SetForegroundWindow , and if we know that a process can have multiple windows, it can be difficult. You need a reliable way to determine which window you want. Many people do this by hard-coding the window name as a string, which works fine until the target application is recompiled and this implementation detail does not change. The only bulletproof way I can think of is to get the user to click the target window and your code to get the handle to the window currently under the mouse pointer.

And, of course, all of this suggests that you notice the restrictions on using SetForegroundWindow , listed in the Remarks section of the associated SDK documentation.

+4
source

All Articles