Jump to content
Xtreme .Net Talk

Recommended Posts

Posted

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 :)

Currently Using: Visual Basic.Net 2005, .Net Framework 2.0
Posted

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

For questions about VS .net extensibility, please fire at me! :)

For readability, please use the [ CS][/CS ] tags

Posted

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.

Currently Using: Visual Basic.Net 2005, .Net Framework 2.0
Posted

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

Currently Using: Visual Basic.Net 2005, .Net Framework 2.0
Posted

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

Currently Using: Visual Basic.Net 2005, .Net Framework 2.0
Posted

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.

Currently Using: Visual Basic.Net 2005, .Net Framework 2.0
Posted
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.
Currently Using: Visual Basic.Net 2005, .Net Framework 2.0
  • 2 weeks later...
Posted

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

Currently Using: Visual Basic.Net 2005, .Net Framework 2.0
Posted

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

Posted (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 by NeuralJack
Currently Using: Visual Basic.Net 2005, .Net Framework 2.0
Posted (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 by progload
Posted

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

Currently Using: Visual Basic.Net 2005, .Net Framework 2.0
  • 2 months later...
  • 2 months later...
Posted
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

  • 1 year later...
Posted
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?

  • 1 year later...
Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...