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.
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 sent a WM_ACTIVE message using postmessage api to some programs.
When a program is deactivated, sending a message does not actually activate the window, but the program thinks it is active. ( It actually succeeded. )
However, I think it is very inefficient to send postmessage regularly.
If I want to check the WM_ACTIVE value of the program and it is inactivated, I try to send a WM_ACTIVE message again using the POSTMESSAGE API to confuse the program itself with being active, but I can't think of a way. Although there is an idea that hooking would be easy to use, C# did not support other types of global hooking except for the keyboard and mouse.
Can anyone come up with any other ideas? please help me.
To check if a process is focused you should use GetForegroundWindow to get the focused window handle and then use GetWindowThreadProcessId to get the process from that window handle:
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
static extern uint GetWindowThreadProcessId(int hWnd, out int ProcessId);
IntPtr focusedWindow = GetForegroundWindow(); //get the focused window
int focusedProcessID = 0;
GetWindowThreadProcessID(focusedWindow, out focusedProcessID); //get it's process id
Process focusedProcess = Process.GetProcessById(focusedProcessID);//get the focused process
Console.WriteLine("Current Focused Process:" + focusedProcess.ProcessName);
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 wanna send key stroke to a program even if it is running in background. But I can do this only for NOTEPAD like this,
[DllImport("user32.dll")]
protected static extern byte VkKeyScan(char ch);
[DllImport("user32.dll", SetLastError = true)]
protected static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("User32.Dll", EntryPoint = "PostMessageA")]
protected static extern bool PostMessage(IntPtr hWnd, uint msg, int wParam, int lParam);
char Key = // key value to send
IntPtr hWnd = FindWindowEx(_handle, IntPtr.Zero, "edit", null); // _handle is the windows handle of the program (here its notepad)
PostMessage(hWnd, WM_KEYDOWN, VkKeyScan(Key), 0);
But for all other applications I can't send keystrokes if its in background. Since I don't know the lpszClass of that program (I think this is the userControl name of the typing area in that program. For NotePad it is "edit". I found this surfing internet).
For all other applications what I'm doing is, get the application to foreground, then send the key, then again get my program foreground. I need my program to be run as foreground always.
[DllImport("USER32.DLL")]
public static extern bool SetForegroundWindow(IntPtr hWnd);
SetForegroundWindow(_handle); // _handle is the windows handle of the program
System.Threading.Thread.Sleep(50); // Waiting few milliseconds till application coming to foreground.
wsh.SendKeys(Key.ToString(), ref wait); // wsh is WshShellClass wsh= new WshShellClass();
SetForegroundWindow(_mainHandle); // _mainHandle is the windows handle of my application
But this way is not working. some keys getting missed and the program foreground->background->foregound->background...... like its dancing...
How to send keys to other applications if its running in background.
or are there any way/source to find the lpszClass of a program ?
Sorry if I have missed any required information. this is a large application. I have posted only required parts here. If someone needs any additional information, pls ask.
I think you'll need to have the background program install a low-level keyboard hook via the win32 function SetWindowsHookEx().
Here's the MSDN documentation for SetWindowsHookEX()
http://msdn.microsoft.com/en-us/library/ms644990(v=vs.85).aspx
And here's the KB article on how to do it from C#
http://support.microsoft.com/kb/318804
This article goes into some detail, too: http://www.codeguru.com/columns/vb/article.php/c4829
I expect your app will get caught by various spyware/anti-virus software as a keyboard logger, though.
Good luck.
You may be able to figure out the lpszClass of the program using an inspection tool such as WinSpy++. It gives you a crosshair that you can drag and position over the desired control. This was able to easily provide me with the "edit" class name for notepad.
If things aren't working, click the "More>>" button in the lower right of WinSpy++, then click the "Locate" button to view the control hierarchy; you may need to post the WM_KEYDOWN message to one of the parent or child controls instead.