NeuralJack Posted July 28, 2005 Posted July 28, 2005 Hey y'all, this is my first post. I came here because it seems like great forums with active knowledgable people. I usually find my answers to all my VB.Net questions through hours or days or weeks of searching the internet, and I usually find my answer. But this question has been plaguing me for over a month so it's time to bite the bullet. What I need to do is sendkeys to a non-active window. The SendKeys and keybd_event commands only seem to send it to the windows environment in general, so it sends the key to the active window. Is there a way to send it to a non-active window? I already have code that successfully gets me the window handler, so that's all fine and dandy. With some research I think that either the SendMessage or SendInput API should do what i'm looking for. The problem is all of the documentation i see on these API's have their examples set in VB6 or earlier and I can't see them used in .NET at all - and i'm pretty sure that they are used differently in .NET. I tried to use them as they did in VB6 with no luck, and i've tried many other variations to .Net-ify it and nothing worked. Can someone just throw me a few lines of ultra simple code that would show me how to do what i'm looking for? Remember I have the window Handle already, I just need to send it a key (lets say a "w") WITHOUT first making it the top window or activating that window. So, no SetForgroundWindow API please :) Quote Currently Using: Visual Basic.Net 2005, .Net Framework 2.0
Himo Posted July 28, 2005 Posted July 28, 2005 Try this one to activate the old API's in your program: Note: This is C#, may need a lil' changing to work in VB .net, but only very minor using System.Runtime.InteropServices; [DllImport("USER32.DLL", EntryPoint="PostMessageW", SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)] public static extern bool PostMessage(int hwnd, int Msg, int wParam, int lParam); [DllImport("USER32.DLL", EntryPoint="SendMessageW", SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)] public static extern bool SendMessage(int hwnd, int Msg, int wParam, int lParam); And a nice library with all the message constants is attached ;)Messages.zip Quote For questions about VS .net extensibility, please fire at me! :) For readability, please use the [ CS][/CS ] tags
NeuralJack Posted July 29, 2005 Author Posted July 29, 2005 Thanks a lot, but i'm mainly a novice programmer and am only good at VB.net. The syntax for C# is totally different from where i'm standing. I've tried to change things form C# before into VB and have had to deal with things like C# calling variable types different names than VB, etc. I know nothing of C# hehe. Here is how i am currently defining SendMessage: Public Declare Function SendMessage Lib "user32" Alias "SendMessageA" _ (ByVal hwnd As IntPtr, _ ByVal wMsg As Integer, _ ByVal wParam As Integer, _ ByVal lParam As Long) As Integer Private Const WM_KEYDOWN = &H100 Private Const WM_KEYUP = &H101 To get the window handler I use FindWindow API, and it goes into the variable hwnd Then to simulate a "B" Keystroke this is what i have: SendMessage(hwnd, WM_KEYDOWN, Keys.B, 0) SendMessage(hwnd, WM_KEYUP, Keys.B, 1) I am sure the error lies in either the declaration or the useage of SendMessage. I know the correct handle is being retrieved becuase it works just fine in the Flashwindow or SetForegroundWindow API. Quote Currently Using: Visual Basic.Net 2005, .Net Framework 2.0
Administrators PlausiblyDamp Posted July 29, 2005 Administrators Posted July 29, 2005 try Declare Function SendMessage Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As UIntPtr, ByVal lParam As IntPtr) As IntPtr for your declaration Quote Posting Guidelines FAQ Post Formatting Intellectuals solve problems; geniuses prevent them. -- Albert Einstein
NeuralJack Posted July 29, 2005 Author Posted July 29, 2005 Thanks. My problem now is that i'm not very familar with UIntPtr and IntPtr variable types. There seem to be no easy conversion menthods for them, especially with UIntPtr. I can't seem to convert a simple integer into a UIntPtr or IntPtr and in the end Keys.B and "0" are integers. so this no longer works SendMessage(hwnd, WM_KEYUP, Keys.B, 0) try Declare Function SendMessage Lib "user32.dll" (ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As UIntPtr, ByVal lParam As IntPtr) As IntPtr for your declaration Quote Currently Using: Visual Basic.Net 2005, .Net Framework 2.0
NeuralJack Posted July 29, 2005 Author Posted July 29, 2005 Ok i'm also wondering if the Sendmessage handle has to be a control handle or can it just be a Window handle? if it's a control handle i'll have to use FindWindowEx if it can be a window handle then FindWindow shoudl work fine Quote Currently Using: Visual Basic.Net 2005, .Net Framework 2.0
NeuralJack Posted July 29, 2005 Author Posted July 29, 2005 OK i've been able to use SendMessage with the WM_CHAR command. But I'd really like to use the WM_KEYDOWN and WM_KEYUP commands to simulate the up and down nature of keyboard buttons. This is so that I can put a delay between the Down and Up nature of the simulated keystroke. All the while sending this to a non-active non-focused window. Here's how i am able to send the Character: Declaration: Private Declare Ansi Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As String) As Integer Usage: SendMessage(x, WM_CHAR, Keys.B, 0) ;--- THIS WORKS x is the handle of the control using FindWindowEx So what i'm saying is that SendMessage(x, WM_KEYDOWN, Keys.B, 0) SendMessage(x, WM_KEYUP, Keys.B, 0) ;--- DOESNT WORK just doesnt seem to work or simulate a keystroke Here are the constants i'm using: Private Const WM_KEYDOWN = &H100 Private Const WM_KEYUP = &H101 Public Const WM_CHAR = &H102 Any help would be immensely appreciated. Quote Currently Using: Visual Basic.Net 2005, .Net Framework 2.0
NeuralJack Posted August 3, 2005 Author Posted August 3, 2005 So no one else is able to send a simulated keystroke using sendmessage to a window, with WM_KEYDOWN , WM_KEYUP either? I still havent been able to solve this. As stated i've gotten sendmessage to work with other commands though. Quote Currently Using: Visual Basic.Net 2005, .Net Framework 2.0
NeuralJack Posted August 18, 2005 Author Posted August 18, 2005 Bump Still need help, if anyone can figure it out. Quote Currently Using: Visual Basic.Net 2005, .Net Framework 2.0
Administrators PlausiblyDamp Posted August 18, 2005 Administrators Posted August 18, 2005 Does either the key down or key up commands work or do both fail / just get ignored? Quote Posting Guidelines FAQ Post Formatting Intellectuals solve problems; geniuses prevent them. -- Albert Einstein
NeuralJack Posted August 20, 2005 Author Posted August 20, 2005 From what i can tell both are ignored. I am not sure if you can really use a keyup w/out a keydown first. with these api's there is no warning if you are using it wrong unfortunately. thanks for the reply Quote Currently Using: Visual Basic.Net 2005, .Net Framework 2.0
progload Posted August 20, 2005 Posted August 20, 2005 I'll give a try at helping you out, but... "sending this to a non-active non-focused window" Is Not enough information. What are you trying to send the keys to on this "Window" a list box, a textbox, a menu, a button, or what? And what will be the outcome of sending the keys? Thanks, progload Quote
NeuralJack Posted August 22, 2005 Author Posted August 22, 2005 (edited) Ok thanks, I'm sending it to no particular control. I'm using it to play around with a game, but these Keyup, keydowns (in conjunction with Sendmessage) wont even work in Notepad. It would be ideal if it could send the Keyup/keydown to the window/program itself and not a particular control. I have tried to make it work on Notepad, by sending it to the control on there that has the text in it (sorry i forgot the name of that control), but that didnt work. If, indeed, the sendmessage API with Keydown/keyup does require a control to send it to then even that information would be useful. If you can get it to work in Notepad, I'd love to see that example. To be more clear I have this: Things I have gotten to work in Notepad and the Game ---------------------------------------------------- - keybd_event with KEYEVENTF_KEYUP, WITHOUT using Sendmessage API (so Notepad must be top window) - SendMessage(handle, WM_CHAR, Keys.B, 0) Things I cant get to work in Notepad nor the Game ---------------------------------------------------- -Keyup/Keydown WITH Sendmessage API (ideally the window wouldnot need to be active and topmost here) And I'd really like to use the WM_KEYDOWN, WM_UP rather than the WM_CHAR because i'd like to occasionally use a delay between the KEYDOWN AND THE KEYUP. What that delay does is allow me to move a certain distance in game by pressing the forward key for the delay time. This delay works fine w/out the sendmessage API and if i could get the sendmessage API to work with WM_KEYDOWN and WM_UP then i'm sure it would be simple to add a delay between that too. So, all i'd like is an example of using WM_KEYDOWN, WM_UP in the SendMessage API into the Notepad program. Just write a 'w' into the programs textbox if you can without making it active/topmost, that would help me a lot. If you could do it w/out choosing the control (and just choosing the window) to send it to, that would be great, but it is not necessary. Note, It may be possible to just use the KeyUp command in Sendmessage w/out keydown, I am not sure. Here's how i code for a simulated keystroke W/out Sendmessage API, Which means It only goes to the topmost window: keybd_event(Key, 0, 0, 0) 'press Sleep(Delay) keybd_event(Key, 0, KEYEVENTF_KEYUP, 0) 'release I hope this is more clear. Thanks for the help. I'll give a try at helping you out, but... "sending this to a non-active non-focused window" Is Not enough information. What are you trying to send the keys to on this "Window" a list box, a textbox, a menu, a button, or what? And what will be the outcome of sending the keys? Thanks, progload Edited August 22, 2005 by NeuralJack Quote Currently Using: Visual Basic.Net 2005, .Net Framework 2.0
progload Posted August 23, 2005 Posted August 23, 2005 (edited) Jbob, Ok, now I got it.. thanks.. You won't be able, in windows 2000/XP to send it directly using SendMessage as the message must be Translated, you'll need to use TranslateMessage instead. The MSDN WM_KEYDOWN documentation states(see crefs below for reference): "Windows 2000/XP: Applications must pass wParam to TranslateMessage without altering it at all." so I passed wParam off to TranslateMessage and It works just fine like this: Declare Function TranslateMessage Lib "user32.dll" (ByRef lpMsg As MSG) As Integer Public Structure MSG Public hwnd As Integer Public message As Integer Public wParam As Integer Public lParam As Integer Public time As Integer Public pt As Integer End Structure Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim hwnd As Integer = FindWindow(vbNullString, "Untitled - NotePad") '/// assuming you have notepad open. Dim x As Integer = FindWindowEx(hwnd, 0, "Edit", vbNullString) Dim myMsg As MSG = New MSG If Not x = 0 Then myMsg.hwnd = x myMsg.message = WM_KEYDOWN myMsg.wParam = Keys.B myMsg.lParam = 0 Dim ret As Integer ret = TranslateMessage(myMsg) Debug.WriteLine("TranslateMessage " & ret.ToString) End If End Sub I believe you can code it anyway you like from here and put your "sleep" code in and it should work just fine, it is here. cref: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardinput/keyboardinputreference/keyboardinputmessages/wm_keydown.asp and http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/windowing/messagesandmessagequeues/messagesandmessagequeuesreference/messagesandmessagequeuesfunctions/translatemessage.asp Hope this Helps you out, and If I can help you with anything else let me know. progload [Edited for missing functions] Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Integer Private Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As Integer, ByVal hWnd2 As Integer, ByVal lpsz1 As String, ByVal lpsz2 As String) As Integer Edited August 23, 2005 by progload Quote
NeuralJack Posted August 23, 2005 Author Posted August 23, 2005 This works great!! Thanks a ton for taking the time to help out Progload! I know this sort of stuff can take some time. -JBob Quote Currently Using: Visual Basic.Net 2005, .Net Framework 2.0
scriptor Posted November 1, 2005 Posted November 1, 2005 Thanks! Extreme thanks, progload! I've been looking forever for the answer to this question! :D Quote
Console Posted January 20, 2006 Posted January 20, 2006 Ok i'm also wondering if the Sendmessage handle has to be a control handle or can it just be a Window handle? if it's a control handle i'll have to use FindWindowEx if it can be a window handle then FindWindow should work fine I would very much like an answer to this question. It looks as though it should work with a windows handle, however it seems to only work when I supply a control handle. Anyone able to provide a definitive answer to this? Thanks For reference, the code in question: Public Class Form1 Private Declare Function FindWindow Lib "user32.dll" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Integer Private Declare Function FindWindowEx Lib "user32.dll" Alias "FindWindowExA" (ByVal hWnd1 As Integer, ByVal hWnd2 As Integer, ByVal lpsz1 As String, ByVal lpsz2 As String) As Integer Private Declare Ansi Function SendMessage Lib "user32.dll" Alias "SendMessageA" (ByVal hwnd As Integer, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As String) As Integer Private Const WM_CHAR = &H102 Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim windowHandle As Integer = FindWindow(vbNullString, "Untitled - NotePad") '/// assuming you have notepad open. Dim controlHandle As Integer = FindWindowEx(windowHandle, 0, "Edit", vbNullString) SendMessage(windowHandle, WM_CHAR, Keys.B, 0) '<-- Doesn't work SendMessage(controlHandle, WM_CHAR, Keys.C, 0) '<-- Works End Sub End Class Quote
hongen1990 Posted February 21, 2007 Posted February 21, 2007 This works great!! Thanks a ton for taking the time to help out Progload! I know this sort of stuff can take some time. -JBob Hi there, I decided to hijack this thread since my problem resolve on the same "Low-level" format and it is stimulation of keyboard keys. I figured out a way to send ctrl+v and other commands anyway. '22 is ctrl+v as derived from ascii table GOOGLE "ascii table" 'ret = SendMessage(editHwnd, WM_CHAR, 22, vbNull) Debug.WriteLine("Char " & ret.ToString) But now the question is, how the heaven can I hold down a stimulated key, in low level also. I tried using WM_KEYDOWN and WM_KEYUP, but they don't seem to work fine. I mean, as long as I send WM_KEYDOWN it is supposed to hold a key down until I send WM_KEYUP isn't it? Am I wrong there or something? Quote
paigew Posted October 2, 2008 Posted October 2, 2008 Thanks for your class. It was extremely helpful. Couldn't find this listed anywhere on the interwebs. Quote
Recommended Posts