SendMessage or SendInput API on .NET

NeuralJack

Well-known member
Joined
Jul 28, 2005
Messages
138
Hey yall, 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 its 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 thats all fine and dandy.

With some research I think that either the SendMessage or SendInput API should do what im looking for. The problem is all of the documentation i see on these APIs have their examples set in VB6 or earlier and I cant see them used in .NET at all - and im pretty sure that they are used differently in .NET. I tried to use them as they did in VB6 with no luck, and ive 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 im 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 :)
 
Try this one to activate the old APIs in your program:
Note: This is C#, may need a lil changing to work in VB .net, but only very minor

C#:
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 ;)
 

Attachments

Thanks a lot, but im mainly a novice programmer and am only good at VB.net. The syntax for C# is totally different from where im standing. Ive 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.
 
try
Code:
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
 
Thanks. My problem now is that im not very familar with UIntPtr and IntPtr variable types. There seem to be no easy conversion menthods for them, especially with UIntPtr. I cant 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)



PlausiblyDamp said:
try
Code:
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
 
Ok im also wondering if the Sendmessage handle has to be a control handle or can it just be a Window handle?

if its a control handle ill have to use FindWindowEx

if it can be a window handle then FindWindow shoudl work fine
 
OK ive been able to use SendMessage with the WM_CHAR command. But Id 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.

Heres 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 im 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 im using:
Private Const WM_KEYDOWN = &H100
Private Const WM_KEYUP = &H101
Public Const WM_CHAR = &H102

Any help would be immensely appreciated.
 
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 ive gotten sendmessage to work with other commands though.
 
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 apis there is no warning if you are using it wrong unfortunately.

thanks for the reply
 
Ill 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
 
Ok thanks, Im sending it to no particular control. Im 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, Id 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 Id really like to use the WM_KEYDOWN, WM_UP rather than the WM_CHAR because id 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 im sure it would be simple to add a delay between that too.

So, all id 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. Heres 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.




progload said:
Ill 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
 
Last edited by a moderator:
Jbob,

Ok, now I got it.. thanks..

You wont be able, in windows 2000/XP to send it directly using SendMessage as the message must be Translated, youll 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:

Code:
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/d...eference/keyboardinputmessages/wm_keydown.asp

and

http://msdn.microsoft.com/library/d...ndmessagequeuesfunctions/translatemessage.asp

Hope this Helps you out, and If I can help you with anything else let me know.

progload

[Edited for missing functions]

Code:
    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
 
Last edited by a moderator:
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
 
JBob said:
Ok im also wondering if the Sendmessage handle has to be a control handle or can it just be a Window handle?

if its a control handle ill 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:
Code:
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)   <--  Doesnt work
        SendMessage(controlHandle, WM_CHAR, Keys.C, 0)  <--  Works
    End Sub

End Class
 
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.

Code:
        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 dont 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 isnt it? Am I wrong there or something?
 
Thanks for your class. It was extremely helpful. Couldnt find this listed anywhere on the interwebs.
 
Back
Top