I'm getting in trouble by hooking window messages. I need to detect window text (caption) changes, so I intercept the WM_SETTEXT message for the interesting windows (I do so because at window creation the window caption is not specified).
Reading the documentation of the WM_SETTEXT documentation, the lParam parameter specify a pointer to the string representing the window text.
The message is forwarded to a .NET application using SendMessage. What I do in the .NET application is:
private static bool ProcessMessage(ref Message msg) {
...
string s = Marshal.PtrToStringAuto(msg.LParam) *
}
where ProcessMessage is the routine handling messages of the .NET form.
What I always get is an empty string, which is not the expected result. I tried other Marshal.PtrToString* methods, but no one has worked.
What am I doing wrong in the conversion of a IntPtr to String?
(*)Note that I cannot debug this code, since it would block the entire system, since all windows messages are intercepted.
LParam is a string pointer, and your code is correct, assuming that it is executed in the same process where WM_SETTEXT message was sent. In another process, this pointer is invalid, and result of using this pointer is undefined.
It is probably a pointer to a pointer of chars.
So read the IntPtr, the read the value in IntPtr which is also IntPtr, then use that as you did.
Maybe it works, maybe it doesn't :p
Related
I want to simulate input in games with SendKeys, but I have a hard time.
If I use it with i.e. the letter T, while the cursor in Minecraft is in a textbox (in the main menu), it works, the letter T is written in the textbox.
But with {ESC} it doesn't work. Nothing happens. If I press it manually, it backs to the previous menu. (as it should)
With some applications ESC works:
It works with Discord, Sourcetree, Slack, Chrome, CS2D,
but for some reason it doesn't work with Minecraft, Spelunky, Half-Life.
All of the applications mentioned above were in windowed mode.
Another issue:
If I send 2 to Minecraft while in a text field, it works correctly, 2 is written.
But if I send it while I'm playing, there is no effect. (The character should switch to Item Slot #2)
Same with " " (whitespace). In text fields it works, but the character won't jump in the game.
Code:
[DllImport("USER32.DLL", CharSet = CharSet.Unicode)]
public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
public Form1()
{
InitializeComponent();
IntPtr minecraftHandle = FindWindow("GLFW30", "Minecraft* 1.15.2");
if (minecraftHandle == IntPtr.Zero)
{
MessageBox.Show("Minecraft is not running.");
return;
}
SetForegroundWindow(minecraftHandle);
SendKeys.SendWait("{ESC}");
}
I tried it without focus switching: by assigning the SendKey calls to a hotkey, so the target application can be in focus when the SendKeys are called.
The results are the same :\
Do not use SendKeys.Send to messaging between processes working on different runtimes
SendKeys.Send method is from System.Windows.Forms namespace.
This means it is not a Windows Input simulator, but just a little helper for Windows Forms applications. There is no guarantee this method work with another process on different (not .NET) runtime system.
Despite the fact that SendKeys.Send method uses native Windows API, it send key pressing message only of fixed period of time, so game frame handling may not have time to catch this message to manage it. So you may need for separate commands to send message about key down and key up events.
Do not use SendKeys API for messaging with another processes, especially with games.
Also, games can use protection system to rid of automatic bots that can blocks any messages from operation system programming input
So, what you can use?
First, you can try to use PostMessage of user32.dll system library:
const uint WM_KEYDOWN = 0x0100;
const uint WM_KEYUP = 0x0101;
[DllImport("user32.dll")]
static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
// hWnd - Window handler (can be getted by using GetForegroundWindow/FindWindow methods)
// msg - Key up/down message (WM_KEYUP / WM_KEYDOWN)
// wParam - Virual key code you need to pass to the window
// lParam - Additional parameter for set up key message behaviour.
All virtual key codes can be found on microsoft docs website:
https://learn.microsoft.com/en-us/windows/win32/inputdev/virtual-key-codes
Don't forget that you need to wait some time before key releasing. This is needed because games cache inputs between frames, and frame has fixed time to catch input. Just write some delay between key down and up messages.
Also you can set up key message behaviour by lParam. See WM_KEYDOWN and WM_KEYUP parameters. Special thing about WM_KEYDOWN message is if you pressing key on real keyboard long time, operation system repeating WM_KEYDOWN message accordingly. Repeating count can be setted up through lParam. Use it if window you messaging does not react on single keydown message.
PostMessage is low-level system command that can be used for messaging between processes. This command has a low probability to be blocked by protection system (but not zero) and high probability to be received by the game/process you working with. Also it provides opportunity to separate key up and key down messages.
What if PostMessage didn't work?
Try to use hardware scan code instead of virtual key code. Detailed explanation how you can do that described in this answer.
If protection system is really good and PostMessage is blocking even if you use hardware scan code, one thing you can try is to use another keyboard input driver or write it yourself. That driver must replace default system keyboard driver. And you can message it to interact with game. This is the 100% guarantee way to interact with other process through keyboard. But if you use public custom keyboard drivers, there is some probability that protection system blocks it. So you need to write your own driver to message between processes.
I'm developing a small Windows Service in C# that needs to do interop with Win32 API at some point. I'm getting the following exception which does not make sense to me:
System.ComponentModel.Win32Exception: The operation completed successfully
Right after the last line in this C# snippet:
var sessionId = Kernel32.WTSGetActiveConsoleSessionId();
var userTokenPtr = new IntPtr();
if (!WtsApi32.WTSQueryUserToken(sessionId, out userTokenPtr))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
Here's how I'm declaring WTSQueryUserToken in WtsApi32:
[DllImport("Wtsapi32.dll", EntryPoint="WTSQueryUserToken")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool WTSQueryUserToken
(
[In, MarshalAs(UnmanagedType.U8)] ulong sessionId,
[Out] out IntPtr phToken
);
Some facts:
This works perfectly on 64bit Win7, but fails on a 32bit Win7.
There's no way the 10,000 handle limit has been reached when this is executed, it's the first Win32 call in a very small windows service.
I think there might be some underlying Win32 error but some bug overwrote the errorcode with a 0, thus giving me the "success" error message, but I don't know how to confirm or even diagnose this.
When I catch the exception, sessionId is 1 and userTokenPtr is 0. However, GetLastError returns 0 so I have no idea what happened.
Nearly all of the answers I found to this problem had to do with improper disposal of user controls. Since this is a Windows service, this is not the case.
I'm guessing there must be something wrong with my WTSQueryUserToken declaration, since it only fails on 32bit Windows, which leads me to think it's a marshaling problem. However, I still can't see what it might be.
Your sessionId parameter us defined as a c# ulong - an unsigned 64-bit integer, whereas the actual function export is expecting a Win32 ulong - an unsigned 32-bit integer.
c# ulong data type
Win32 data types
im trying to do something on an app, that I know its name etc...(so I'm alredy casting findwindow and stuff)
For ex. I want to notify user when that window tries to gain focus.
I have mess around with wndproc yet I seem to not get it at all.
for ex. here is a code I found on stackoverflow and failed even executing it
public IntPtr WndProc(int hwnd, int msg, IntPtr wParam, IntPtr lParam)
{
if (msg == WM_NCACTIVATE)
{
SystemSounds.Beep.Play();
SystemSounds.Beep.Play();
SystemSounds.Beep.Play();
SystemSounds.Beep.Play();
SystemSounds.Beep.Play();
}
return IntPtr.Zero;
}
now the thing I dont understand is, there is int msg that I think stands for message. arent wndproc is the one that supposed to get it ? what is the point of giving it to wndproc ?
Second, executing this function. What do I do, check for message every 100 ms or are there event-type thing for it ?
Im really confused here and I'd appreciate little help here.
I'm afraid I don't entirely understand what you're asking here.
That WndProc function definition that you've found is not what it would look like in C#. Instead, you would override the WndProc member function of the Control class. All window messages are routed through this function. You would only override it if you wanted to process a message in an unusual way, to do something that the .NET Framework isn't already doing for you.
For example, for a Form, you would override WndProc like this:
public class MyForm : Form
{
// other code
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case WM_NCACTIVATE:
{
SystemSounds.Beep.Play();
break;
}
base.WndProc(ref m); // proceed with default processing
}
}
}
Notice that the .NET Framework wraps all of the message information up into a Message structure, rather than passing 4 raw parameters to the function like the Win32 API does.
there is int msg that I think stands for message. arent wndproc is the one that supposed to get it ? what is the point of giving it to wndproc ?
The Message.Msg member corresponds to the int msg parameter in your function definition. This is the identifier of the window message that is to be processed. These are all defined inside of the Windows header files, and they generally begin with WM_. You can find the documentation for these messages on MSDN, which will tell you what they mean and when they are received. For example, the WM_NCACTIVATE message is sent to a window when its non-client area is being activated or inactivated.
The WndProc function is going to be called each time any message is received. The way you determine which message was received, and therefore which one you should be processing, is by switching on the value of the Message.Msg member (or, in your original example, the msg parameter).
Second, executing this function. What do I do, check for message every 100 ms or are there event-type thing for it ?
You don't have to check for anything. WndProc is a function, just like any other function, including those that you write yourself, which means that it only gets called when it should execute.
It is not itself an event, although the default processing inside of the WndProc function is what is responsible for raising the events you're familiar with in response to certain messages that it receives.
im trying to do something on an app, that I know its name etc...(so I'm alredy casting findwindow and stuff) For ex. I want to notify user when that window tries to gain focus.
I'm not exactly sure what this means, but you should look into the WM_ACTIVATEAPP message. This message is sent to a window whenever it is being activated and whenever it is being deactivated. In response to that message, you could choose to do whatever you like, including playing a sound. As the linked documentation indicates, the wParam parameter (found in the Message.WParam member) tells you whether your window is being activated or deactivated.
This is pretty much as advanced as it gets. It's extremely rare that you need to override the WndProc method when you're programming in WinForms. By doing so, you can do nearly anything, but there's almost always a better, simpler way to do things.
I'm attempting to pass messages between two applications - one of them is a plugin, and the other is a standalone configuration utility. When my plugin detects an event, I want to send a message to my utility and prompt the user to reconfigure.
The code I'm using is as follows:
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SendMessage(IntPtr hwnd, uint Msg, IntPtr wParam, IntPtr lParam);
private const int MESSAGE_UNAUTH = 0x401;
[... misc logic here, function def, etc]
Process[] processes = Process.GetProcessesByName("MyConfigurationApplication");
if (processes.Length > 0)
{
foreach (Process p in processes)
{
SendMessage(p.MainWindowHandle, MESSAGE_UNAUTH, IntPtr.Zero, IntPtr.Zero);
}
}
And then in my receiving process, I have the following code (I also defined MESSAGE_UNAUTH in this class):
protected override void WndProc(ref Message message)
{
if (message.Msg == MESSAGE_UNAUTH)
{
MessageBox.Show("Message received");
}
base.WndProc(ref message);
}
Things I have already verified with the debugger:
The message is getting sent. All the code in the Sender, including the SendMessage call, is executing.
The message is not getting received (obviously).
The WndProc() function is not getting called at all when the message is sent. It is, however, getting called a whole bunch of times when the configuration utility is launched (I'm assuming this is Windows' behavior).
I've gone through enough online tutorials to need eyedrops, and as far as I know, everything here is syntax-correct and "proper," but for some reason, between when I send the message and when the receiver's WndProc() should be called, black magic is happening.
Any ideas would be greatly appreciated.
Update: Using Marshal.GetLastWin32Error(), I am getting an error #1400, which appears to correspond to an invalid window handle. However, I don't see why that would be the case, since the process was found and we entered the for each loop successfully. The one caveat I can think of is that my configuration utility is presented as a taskbar icon, and doesn't necessarily have a visible window at all times - would this prevent p.MainWindowHandle from being valid? If so, how can I work around this to pass a message to the process instead of the window?
Update: Process.MainWindowHandle is 0, so it looks like that is indeed the problem - when the form in my configuration utility is not visible, no valid window handler is returned, even though my utility icon is visible in the notification bar. Is there any way I can send a message to the process, or even to the taskbar icon?
You can try to enumerate all windows associated with the process. See How to enumerate all windows belonging to a particular process using .NET?
Depending on the .NET framework you are using, this will help resolve your issues.
There was a bug in the old .NET frameworks (2.0 I think) where calling to Process.MainWindowHandle when the process starts up returns 0. Any subsequent call will also result in a 0. This is due to caching the main window handle, which should have been fixed in .NET 3.0 and later.
You might also try giving full trust to your WndProc which might help. Something like:
[System.Security.Permissions.PermissionSet( System.Security.Permissions.SecurityAction.Demand, Name="FullTrust")]
protected override void WndProc(ref Message m)
{
//...
}
On a side note, if you can change your implementation then I strongly suggest you go for better inter process communication means such as sockets, TCPChannel (which I think is replaced by WCF), named pipes...
The message might not be sent, it might be blocked. See here: When a message is blocked by UIPI the last error, retrieved with GetLastError, is set to 5 (access denied).
Use Windows Registermessage in bothe sender and receiver end will resolve the problem
Problem was that the process I was sending the message to only existed as a tooltip icon and not as an active, open window. Turns out the windows message functionality is designed for window-to-window messages, not process-to-process messages.
Solution was aforementioned kludgy system of file IO handlers.
I am running some automation in a C# program (.Net 4.0). There is an issue with a modal dialog where I want to click the message away and continue testing. I have tried a few options (SendKey and using Win32 to send a click event with code modified from here: http://msdn.microsoft.com/en-us/magazine/gg309183.aspx. Neither of these have proved to be reliable enough to be considered effective.
My next approach will be to try calling the EndDialog() function from my C# program and simply sending the enumeration/return code to the message box.
EndDialog(HWND hDlg, INT_PTR nResult) is the call where hDlg is the handle to the message box being closed and nResult is the result of the dialog.
Where I am running into an issue is how to send the desired result. An example would be that the return code IDCANCEL has a value of 2. How exactly do I send this value? What variables or constants would I need to declare? I'm just looking for how to get the proper pointer declared to send the desired result to the function.
Further information on these result values can be found here http://msdn.microsoft.com/en-us/library/windows/desktop/ms645505(v=VS.85).aspx
just invoke PostMessage. Here is a sample in c/c++:
::PostMessage(hWnd, WM_COMMAND, MAKEWPARAM(IDCANCEL,BN_CLICKED), 0);