I am trying to send a message to a game (to automate text commands), the problem is that I can't figure out how to use the information from spy++ to write a C# sendmessage function.
I was able to use spy++ to get
00220540 S WM_SETCURSOR hwnd:0024052C nHittest:HTCLIENT wMouseMsg:WM_MOUSEMOVE
Could anyone provide a breakdown of what this means, and how to send the message to the game in c#?
EDIT:
I found out that I was looking at the wrong process. Instead of looking at the javaw.exe, I was looking at the actual game.
Here is the code for pressing t:
<00919> 0038062A WM_INPUT nInputCode:RIM_INPUT hRawInput:189E0973
<00920> 0024052 P WM_KEYUP nVirtKey:'T' cRepeat:1 ScanCode:14fExtended:0fAltDown:0fRepeat:1fUp:1
So lets start with the signature for SendMessage, from Pinvoke.net:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
It taks a window handle, hWnd, a message ID, Msg, and two generic parameters wParam and lParam which change meaing based on the message ID.
What spy++ is showing you is the parameters that were sent to SendMessage. As you can see it doesn't show you wParam and lParam, but hwnd, nHittest, and wMouseMsg. That's because Spy++ knows what the wParam and lParam parameters actually mean for a WM_SETCURSOR message and is decoding them for you.
So decoding each piece of the what Spy++ has sent:
00220540 - the window handle receiving the message - the hWnd parameter.
S - It means it was sent via
SendMessage() and not posted via
PostMessage(). See http://msdn.microsoft.com/en-us/library/aa265147(v=vs.60).aspx
WM_SETCURSOR - The message ID - the
Msg parameter.
hwnd:0024052C - handle of the Window
containing the cursor - the wParam
parameter.
nHittest:HTCLIENT - the hit test
code - the low word of the lParam
parameter.
wMouseMsg:WM_MOUSEMOVE - the mouse
message - the high word of the
lParam parameter.
The way you would go about sending the message to a window is:
enum WindowMessages {
WM_SETCURSOR = 0x0020,
WM_MOUSEMOVE = 0x0200,
....
}
enum HitTestCodes {
HTCLIENT = 1,
....
}
....
IntPtr hWnd = [get your window handle some how]
int lParam = ((int)WindowMessages.WM_MOUSEMOVE) << 16 + (int)HitTestCodes.HTCLIENT;
SendMessage(hWnd, (uint)WindowMessages.WM_SETCURSOR, hWnd, (IntPtr)lParam);
For understanding what other messages mean you can do a search on Msdn.com for the messsage in the Windows documentation.
So after answering all of that I don't think this will have anything to do with sending keys to the game you are trying to control. WM_SETCURSOR doesn't have anything to do with keyboard input.
Related
I have a virtual mouse driver and an actual mouse on my computer.
I'm using LowLevelMouseProc to capture events windows wide and I would like to not process events from the virtual mouse.
I cannot use RawInput as I need to process message of another process.
Is there any way to know which device has sent the message ?
Forcing the dwExtraInfo also on a real mouse device may help me if possible.
private IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
MSLLHOOKSTRUCT hookStruct;
if (nCode < 0)
{
return CallNextHookEx(_hookId, nCode, wParam, lParam);
}
hookStruct = (MSLLHOOKSTRUCT) Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
// I'd like to know from here which mouse has sent the message.
return CallNextHookEx(_hookId, nCode, wParam, lParam);
}
There is nothing exposed from the .NET Windows API to distinguish between different mice. There was a Microsoft SDK for multiple inputs at one time but it was dropped before Windows 10 so it likely doesn't work anymore.
rawinput-sharp shows how to do it but it uses raw input, as the name suggests, which I know you said you don't want to do. This limitation you have put on yourself has gotten you stuck. It's like saying "how do I see the screen with my eyes closed?"
Perhaps you could correlate the two events somehow to get the filter you are looking for. Or maybe you could filter out all events from the LowLevelMouseProc and pass the raw input from just one device into the LowLevelMouseProc.
There is a related discussion from the GameDev SE site.
I'm currently using SendKeys.SendWait(text); in C#
but SendKeys sending the key global and I have to activate my application and then send it. And another problem is when I type something in my keyboard (in another app) and the SendKeys function activates (in my app) mistakes happen.
So how can I send a message to my application regardless what application is active and what I type in my keyboard?
SendMessage() does what you want. You'll need to use it like:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
const UInt32 WM_CHAR = 0x0102;
const int VK_Q = 0x51; // taken from http://msdn.microsoft.com/en-us/library/dd375731(v=vs.85).aspx
SendMessage(handleToTheInputForm, WM_CHAR, VK_Q, 1);
You will need to get a handle on the other application's window so that you can bring it to focus and reliably send your keystrokes to it,
Have a look at this tutorial
http://www.codeproject.com/KB/cs/SendKeys.aspx
I need to automate a third party program, and the only course of action is to simulate a click on some buttons.
I do this by finding the HWND handle of the button with EnumChildWindows. When I've found the "window" (the button), I try to send BM_CLICK to it with SendMessageW. This works, my tests show that the button indeed think it was clicked.
The problem arise in my error handling. There is no feedback given by the BM_CLICK message, so I don't really know if it has been clicked. I thought I should be diligent and check for any error codes though with Marshal.GetLastWin32Error.
This returns ERROR_PROC_NOT_FOUND, which is not really what I would expect from a successful message handling.
I import SendMessageW as follows:
[DllImport("User32.dll",
CharSet = CharSet.Unicode,
CallingConvention = CallingConvention.Winapi,
SetLastError = true)]
public static extern IntPtr SendMessageW(
HandleRef hWnd,
UInt32 Msg,
UIntPtr wParam,
IntPtr lParam);
The code doing the call is:
User32.SendMessageW(
buttonHandle,
(uint)ButtonControlMessages.BM_CLICK, // value of BM_CLICK = 0x00F5.
UIntPtr.Zero,
IntPtr.Zero);
int error = Marshal.GetLastWin32Error();
if (error != ErrorCodes.ERROR_SUCCESS) // love the name of this error code.
throw new Win32Exception(error);
My tests are just using a simple Windows Forms with a button control attached. Thus, I can procure the handle through button.Handle. It gets clicked; could it be that this error is completely unrelated?
It sure would be nice to get rid of it though, I'd like some way to be sure that the call to SendMessageW at least didn't fail.
I'm on Windows 7 x86-32 with .NET 4.
The calling convention should be Stdcall, but since that is the default you can just drop it.
I think your SendMessage P/Invoke looks a bit odd but that's probably not the cause of the issue. In any case I would do it like this:
[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, UInt32 Msg, IntPtr wParam, IntPtr lParam);
I think what's happening here is that SendMessage() is working but isn't assigning the last error. The only thing that the documentation for SendMessage() mentions about errors is:
When a message is blocked by UIPI the last error, retrieved with GetLastError, is set to 5 (access denied).
The return value for SendMessage() is dependent on the message sent. In the case of BM_CLICK there is apparently no message sent. In other words you simply do not get any feedback.
According to my research, when I run C# executable which opens WinForm, within .NET, they don't offer the function to access those WinForm object from separate c# process (separate file I mean) but win32 API does.
Then I came across 3 functions from API.
FindWindow();
GetWindowLong();
CallWindowProc()
I need to call it from top down to the bottom but then I got stuck by CallWIndowProc() because
I can't figure what I should pass for last 3 arguments.
private static extern UIntPtr CallWindowProc(IntPtr a, IntPtr b, uint c, IntPtr d, IntPtr e);
c, d and e
According to the doc, it should be some sort of "message" which is int. But where can I get such value???
http://msdn.microsoft.com/en-us/library/ms633571(v=vs.85).aspx
Code:
[DllImportAttribute("User32.dll")]
private static extern IntPtr FindWindow(String ClassName, String WindowName);
[DllImportAttribute("User32.dll")]
private static extern long GetWindowLong(IntPtr a, int b);
[DllImportAttribute("User32.dll")]
private static extern UIntPtr CallWindowProc(IntPtr a, IntPtr b, uint c, IntPtr d, IntPtr e);
[STAThread]
static void Main(string[] args)
{
IntPtr lResult;
uint lMsg = 0;
IntPtr HWND = FindWindow("WindowsFormsApplication1.Form1", "Form1");
int GWL_WNDPROC = -4;
long WNDPROC = GetWindowLong(HWND, GWL_WNDPROC);
lResult = CallWindowProc(WNDPROC, HWND, lMsg, 0, 0);
}
Clarification
OK.. I should have made it clear.. my goal is to run following chunk of code against the WebForm being executed. (I'ts WatiN)
var t = new Thread(() =>
{
Settings.AutoStartDialogWatcher = false;
var ie = new IE(form1.webBrowser1.ActiveXInstance);
ie.GoTo("http://www.google.com");
ie.TextField(Find.ByClass("lst")).TypeText("this is awesome!!");
ie.Button(Find.ByName("btnG")).Click();
});
t.SetApartmentState(ApartmentState.STA);
t.Start();
What message you are trying to send to callWinProc?
Arguments are
nProc is a value returned previously by SubClassWindow() (Source Window).
hWnd is the handle to the window that was subclassed (target window).
nMsg is the message (one of the WM_* values defined in WINDOWS.CH, basically kind of event or message like click is one message). For complete system messages see http://msdn.microsoft.com/en-us/library/ms644927(v=vs.85).aspx#system_defined
wParam depends on nMsg. For click, it takes left or right click
lParam depends on nMsg. for click it takes the location as lparam
you can see wparam and lparam defination for each message.
It looks like you're trying to call the window proc of a window from a different thread/process. I'm assuming this because you're using FindWindow, and I can't see where you created the window. If that is what you are doing, CallWindowProc won't work because you cannot call a window proc from a thread other than the one that created the window. What you need is SendMessage, which accepts the same last four parameters (HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) - to interpret them you need to know what message you're sending.
I recommand to use the parameter names from the native methode just for clearness. You can get those pinvoke signatures from pinvoke.net so you don't have to do it on your own all the time. These messages are definded in header files and documented in the msdn. Its quiete hard to use the right message in the correct manner if you're new to win32 and/or C#.
If you want to intercept the windows messages of your form you need a windows message hook, but this doesn't work in .Net. You can also read this article which cover this topic.
Maybe you should try to find a complete different solution for your problem. Other IPC methodes etc.
EDIT: The CLR type of your form (WindowsFormsApplication1.Form1) is not the class name you have to put in FindWindow, FindWindow is an unmanaged api and isn't aware of the CLR typesystem. Try out Spy++ to investigate some windows on your PC.
I want repeat sent windows messages to my winforms application.
Now, I have class implementing "IMessageFilter" which saves the selected messages (WM _KEYDOWN, WM _LBUTTONDOWN, etc...) to the list.
On key "Pause/Break" I copy the list of messages, clear original list, and resend the messages.
In my test project is only one form with one menuitem, one tab and one richtextbox. The hWnd of controls are same during saving and repeating messages.
All works fine, but the sending messages has not efect :/.
Sample code:
[System.Runtime.InteropServices.DllImport( "user32" )]
public static extern int SendMessage( IntPtr hwnd, int msg, IntPtr wparam, IntPtr lparam );
// ... in some method ...
SendMessage( msg.HWnd, msg.Msg, msg.WParam, msg.LParam );
It looks too easy, but don't know where can be problem.
Do you still have the message filter applied? Would that not interfere with sending the messages? Other possibility could be that the message in question should not be sent, but posted. Or, you may have to send the message from the correct thread for the target window.