How to exclude a thread from global hook - c#

We are hooking TextOut(),ExtTextOut() and DrawText() methods GLOBALLY .
i.e.
hhook = SetWindowsHookEx(WH_CBT, function_address, module_handle, 0);
But we want to exclude our application (which we are using to install/uninstall hook) from being hooked. If the last argument to SetWindowsHookEx() is 0(zero) it will hook all the existing threads.How to check here if the current thread is "OurApplication.exe" and then exclude it from hooking or immediately unhook it.
Please provide help.

I don't think it's possible. You either hook to everything or to a specific thread.
Why don't you just filter out your application in whatever code yout have at function_address? Most, if not all, CBT hook callbacks provide window handle at either wParam or lParam argument. You can then get process id from that handle and compare it to your application pid.

Off the top of my head:
Pass the hook dll the PID of the process you want to ignore when you install the hook. Make sure that PID is stored in a shared section so all hook instances see the same value.
In your hook function, check to see if the current process PID matches the one passed in. If it does, don't do your hooky stuff, just pass to CallNextHookEx.
I don't like this because it adds to work done in the hook function, which is always bad. But it seems like it should work in principle.

Thank you experts for replying to our question. We found the way to do that.
Now we added the following block of code in the entry point of the injecting dll.And it is working fine.
BOOL APIENTRY DllMain(HINSTANCE hModule, DWORD dwReason, PVOID lpReserved)
{
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
IsDebuggerPresent();
// Exclude the "someapplication.exe" from hooking
GetModuleFileName( GetModuleHandle( NULL ),Work,sizeof(Work) );
PathStripPath(Work );
if ( _stricmp( Work, "someapplication.exe" ) != 0 )
{
InstallWindowHooks();
}
break;
case DLL_PROCESS_DETACH:
hWindowReceiver = NULL;
CleanUp();
break;
}
return TRUE;
}

Related

Keyboard input lost when using cross-process parent/child windows

I am investigating a bug that results in key-presses being 'lost' when users are providing rapid keyboard input to our application. It seems to happen randomly. If a user writes e.g. "I am writing this text fast on my keyboard" the actual text that ends up in the application's text box looks something like "Ia wrting thistext fstn mykeybrd."
We have managed to find out that the issue seems to be related to how we integrate the text-input component into our main application. Our main app is a .NET Framework 4.8 WinForms process. The text-input component is running as a .NET 4.8 WPF app in a separate process. The WinForms app is responsible for launching the WPF process, passing the window handle of its own main window as an argument to the new process. Once launched, the WPF process uses the provided window handle to reparent itself as a child window of the WinForms app. This is done using Win32 API calls through P/Invoke.
private void Reparent() {
ChangeStyle(this.myHandle);
Win32.SetParent(this.myHandle, this.hostHandle);
}
private static void ChangeStyle(IntPtr myHandle) {
const int GWL_STYLE = -16;
const uint WS_POPUP = 0x80000000;
const uint WS_CHILD = 0x40000000;
uint style = Win32.GetWindowLong(myHandle, GWL_STYLE);
style |= WS_CHILD;
style &= ~WS_POPUP;
Win32.SetWindowLong(myHandle, GWL_STYLE, style);
}
According to MSDN this seems to be legal.
For compatibility reasons, SetParent does not modify the WS_CHILD or WS_POPUP window styles of the window whose parent is being changed. Therefore, if hWndNewParent is NULL, you should also clear the WS_CHILD bit and set the WS_POPUP style after calling SetParent. Conversely, if hWndNewParent is not NULL and the window was previously a child of the desktop, you should clear the WS_POPUP style and set the WS_CHILD style before calling SetParent.
We understand that this is a bit erm... 'unorthodox', but the design has been like this for a long time without any other issues.
Interestingly, removing the code that sets the WS_CHILD flag fixes the lost keys problem, but causes a bunch of other issues instead.
According to Raymond Chen
Creating a cross-thread parent/child or owner/owned window relationship implicitly attaches the input queues of the threads which those windows belong to...
We interpret this like AttachThreadInput is called 'under the hood', but do not fully understand what causes keypresses to be lost. Is it some sort of thread-safety issue? A race condition?
By using the AttachThreadInput function, a thread can share its input states (such as keyboard states and the current focus window) with another thread. Keyboard and mouse events received by both threads are processed in the order they were received until the threads are detached by calling AttachThreadInput a second time and specifying FALSE for the fAttach parameter.
We have used Spy++ to monitor the Windows messages that gets sent to the WPF process and it seems that when you type slowly, WM_KEYDOWN is sent together with WM_CHAR. When the input is lost, we still receive the WM_KEYDOWN messages, but no WM_CHAR. This led us to start investigating the .NET framework source. Among other things, we found the following code in HwndSource.cs
switch ((WindowMessage)msgdata.msg.message)
{
case WindowMessage.WM_SYSKEYDOWN:
case WindowMessage.WM_KEYDOWN:
// MITIGATION: HANDLED_KEYDOWN_STILL_GENERATES_CHARS
// In case a nested message pump is used before we return
// from processing this message, we disable processing the
// next WM_CHAR message because if the code pumps messages
// it should really mark the message as handled.
_eatCharMessages = true;
DispatcherOperation restoreCharMessages = Dispatcher.BeginInvoke(DispatcherPriority.Normal, new DispatcherOperationCallback(RestoreCharMessages), null);
// Force the Dispatcher to post a new message to service any
// pending operations, so that the operation we just posted
// is guaranteed to get dispatched after any pending WM_CHAR
// messages are dispatched.
Dispatcher.CriticalRequestProcessing(true);
The variable named _eatCharMessages could perhaps be related, although debugging this code using dnSpy has not made us any wiser.
We're looking for a Win32-wizard to shed some more light on this. Anything that can point us in the right direction would be greatly appreciated. We need to figure out the root cause of the problem in order to decide how to fix it.

The definitive code that prevents a c# console app from exiting [until custom cleanup code has completed]

Can we work together to come up with something that works for control-c, control-break, log off, window X button pressed, etc?
Here is what I have so far:
class Program
{
private static ConsoleEventHandlerDelegate consoleHandler;
delegate bool ConsoleEventHandlerDelegate(CtrlTypes eventCode);
static void Main(string[] args)
{
consoleHandler = new ConsoleEventHandlerDelegate(ConsoleCtrlCheck);
SetConsoleCtrlHandler(consoleHandler, true);
System.Diagnostics.Process.GetCurrentProcess().Exited
+= delegate(object sender, EventArgs e)
{
GeneralManager.Stop();
};
Console.CancelKeyPress += delegate(object sender,
ConsoleCancelEventArgs e)
{
e.Cancel = false;
GeneralManager.Stop();
};
GeneralManager.Start();
}
private static bool ConsoleCtrlCheck(CtrlTypes ctrlType)
{
switch (ctrlType)
{
case CtrlTypes.CTRL_C_EVENT:
Console.WriteLine("CTRL+C received!");
GeneralManager.Stop();
break;
case CtrlTypes.CTRL_BREAK_EVENT:
isclosing = true;
Console.WriteLine("CTRL+BREAK received!");
GeneralManager.Stop();
break;
case CtrlTypes.CTRL_CLOSE_EVENT:
Console.WriteLine("Program being closed!");
GeneralManager.Stop();
break;
case CtrlTypes.CTRL_LOGOFF_EVENT:
case CtrlTypes.CTRL_SHUTDOWN_EVENT:
Console.WriteLine("User is logging off!");
GeneralManager.Stop();
break;
}
return true;
}
#region unmanaged
[DllImport("kernel32.dll")]
static extern bool SetConsoleCtrlHandler(ConsoleEventHandlerDelegate
handlerProc, bool add);
public delegate bool HandlerRoutine(CtrlTypes CtrlType);
public enum CtrlTypes
{
CTRL_C_EVENT = 0,
CTRL_BREAK_EVENT,
CTRL_CLOSE_EVENT,
CTRL_LOGOFF_EVENT = 5,
CTRL_SHUTDOWN_EVENT
}
#endregion
}
Two problems:
In the Managed Control-Break handler, if we set e.Cancel = true it fails with an exception for .Net4. This is noted in the MSDN article with no work-around: http://msdn.microsoft.com/en-us/library/system.consolecanceleventargs.cancel.aspx
I don't know how to cancel the close in the ConsoleCtrlCheck. I get a second or two to do some cleanup, but I'd rather cancel and make sure it all gets done properly.
UPDATE:
Thanks for the replies. Upvoted both. Will wait to see if anyone can come up with a reply that directly solves what I asked for, otherwise will accept one of the "use NT services" answers.
I need to wait for pending user requests to complete, disconnect them cleanly, run a few queries on the database to reflect the change(s) in state and so forth. It's a TCP server.
Then don't run it as a Console or any other kind of Client app.
Just run it as a Windows (NT) Service and the only events you'll have to worry about are Power loss and a stop signal.
Use a UPS and make sure you can close in a reasonable timespan.
I have not tried to do this kind of thing with a console app, but you may do better with a Windows Forms (or WCF app). They will give you a FormClosing event which is cancellable. Alternately, use a Windows Service if you are writing a network service, it provides an interface to cleanly stop your application.
If you are really keen on a console app, perhaps a try {} finally {} clause around all your code or something more exotic like a critical finaliser may allow you to run clean up code. But this is really not the right tool for the job.
And there are cases which you cannot prevent you app being closed, eg: power failure, or Task Manager kill command (and if an app didn't close via the X, Task Manager is the first tool I'd reach for).
So, code your service application such that all client requests are logged to a transaction log (like SQL server does). If you are unexpectedly interrupted (by whatever circumstance) anything which has happened up until that point is in the log. When your service next starts, replay that log.
One of your things to log will be "I was shutdown cleanly at time T". If you restart and don't find that item at the end of your log, you know something went wrong, and you can take whatever action is required.
If you need to know what your service is doing, use one of the many logging frameworks to pipe events to a second app, which just displays activity.
I spent couple hours looking at this and as I don't have time now to build a working code; as while it's probably short, getting it right would take a while. I'll just give you link to the various stuff that's needed to get this done:
http://pastebin.com/EzX3ezrf
Summarizing the lessons from the code in the paste:
Need a message pump to handle some/all of WM_QUERYENDSESSION, WM_ENDSESSION, CTRL_SHUTDOWN_EVENT (in c# SystemEvents.SessionEnding may cover some/all of these)
Easiest way to get a message pump is to make it a hidden form/window app, but I recall it's possible to build as a console app and add a message pump also. I didn't include that code in the paste though.
"If an application must block a potential system shutdown, it can call the ShutdownBlockReasonCreate function"
As AllocConsole is used to create the console, you need to use SetConsoleCtrlHandler and use ExitThread(1) in the handler. This is a "hack" that kills off the thread that would close the console otherwise. It's used in FarManager. see interf.cpp for example
You need to also initialize and clean up the console when using AllocConsole.
Pressing CTRL+C is reported to mess up the input. I'm not sure if FarManager is handling this scenario. There's some code in the CTRL_BREAK_EVENT handler in interf.cpp that I'm not sure what it does.
FarManager also handles WM_POWERBROADCAST, probably to do with suspending
If all that isn't enough (should be), you can also add the console into another process and IPC your messages to it like shown here. Why does closing a console that was started with AllocConsole cause my whole application to exit? Can I change this behavior?
RMTool can be used to simulate logoff/shutdown messages for testing: http://download.microsoft.com/download/d/2/5/d2522ce4-a441-459d-8302-be8f3321823c/LogoToolsv1.0.msi
MSDN has some C# code also at microsoft.win32.systemevents.sessionending.aspx
and microsoft.win32.systemevents.aspx (hidden form example)
The mischel.com/pubs/consoledotnet/consoledotnet.zip has a sample winTest project with AllocConsole being used and some of the events handled.

CallWndProc hook not receiving all messages

I am making a little tool like Displayfusion and I need some Hooks to receive messages when Windows move/activate/etc , however I'm stuck..
I am using this project for the CallWndProc hook:
http://www.codeproject.com/KB/system/WilsonSystemGlobalHooks.aspx
For pretty much all windows it works great(x86 and x64), however on some windows it seems to can't inject the hook DLL. Currently I am having problems with adobe reader X. No messages are being received from that window. I think it has something to do with the sandbox? Can somebody give me a push in the right direction?
The initialization code for the hook:
bool InitializeCallWndProcHook(int threadID, HWND destination)
{
if (g_appInstance == NULL)
return false;
if (GetProp(GetDesktopWindow(), "WILSON_HOOK_HWND_CALLWNDPROC") != NULL)
SendNotifyMessage((HWND)GetProp(GetDesktopWindow(), "WILSON_HOOK_HWND_CALLWNDPROC"), RegisterWindowMessage("WILSON_HOOK_CALLWNDPROC_REPLACED"), 0, 0);
SetProp(GetDesktopWindow(), "WILSON_HOOK_HWND_CALLWNDPROC", destination);
hookCallWndProc = SetWindowsHookEx(WH_CALLWNDPROC, (HOOKPROC)CallWndProcHookCallback, g_appInstance, threadID);
return hookCallWndProc != NULL;
}
Hmm, try if Spy++ can catch the messages. If it can, then obviously it's not a problem with security measures. It Spy++ can't however, then it's pretty much impossible.
See if this works: Use both WH_CALLWNDPROC and WH_GETMESSAGE hooks, since apparently, the former only catches sent message, and the latter only catches posted messages.
I have a similar Problem in my application. Visit the following link:
Strange behaviour of windows hooks
My guess ist that an application interrupts the filter function chain by not calling the CallNextHookEx method. Note that is this only possible when you are using WH_CBT hooks.

Is there a reliable way to activate / set focus to a window using C#?

I'm trying to find a reliable way to activate / set focus to a window of an external application using C#. Currently I'm attempting to achieve this using the following Windows API calls:
SetActiveWindow(handle);
SwitchToThisWindow(handle, true);
Previously I also had ShowWindow(handle, SW_SHOWMAXIMIZED); executing before the other 2, but removed it because it was causing strange behavior.
The problem I'm having with my current implementation is that occasionally the focus will not be set correctly. The window will become visible but the top part of it will still appear grayed out as if it wasn't in focus.
Is there a way to reliably do this which works 100% of the time, or is the inconsistent behavior a side-effect I can't escape? Please let me know if you have any suggestions or implementations that always work.
You need to use AttachThreadInput
Windows created in different threads typically process input independently of each other. That is, they have their own input states (focus, active, capture windows, key state, queue status, and so on), and they are not synchronized with the input processing of other threads. By using the AttachThreadInput function, a thread can attach its input processing to another thread. This also allows threads to share their input states, so they can call the SetFocus function to set the keyboard focus to a window of a different thread. This also allows threads to get key-state information. These capabilities are not generally possible.
I am not sure of the ramifications of using this API from (presumably) Windows Forms. That said, I've used it in C++ to get this effect. Code would be something like as follows:
DWORD currentThreadId = GetCurrentThreadId();
DWORD otherThreadId = GetWindowThreadProcessId(targetHwnd, NULL);
if( otherThreadId == 0 ) return 1;
if( otherThreadId != currentThreadId )
{
AttachThreadInput(currentThreadId, otherThreadId, TRUE);
}
SetActiveWindow(targetHwnd);
if( otherThreadId != currentThreadId )
{
AttachThreadInput(currentThreadId, otherThreadId, FALSE);
}
targetHwnd being the HWND of the window you want to set focus to. I assume you can work out the P/Invoke signature(s) since you're already using native APIs.
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool SetForegroundWindow(IntPtr hWnd);
This one worked for me
If it's all internal in your application then you can get the parent window or that window, and in this way activate it (vb sorry):
Public Class Form1 : Inherits Form
Protected Overrides Sub OnLoad(e As EventArgs)
Dim form2 As New Form2
form2.Show()
End Sub
End Class
Class Form2 : Inherits Form
Protected Overrides Sub OnLoad(e As EventArgs)
MyBase.OnLoad(e)
Me.Owner.Activate()
End Sub
End Class
hwnd_WhoRecvFocus.ShowWindow( SW_MINIMIZE )
hwnd_WhoRecvFocus.ShowWindow( SW_RESTORE )

Equivalent of PreviewKeyDown of C# needed for native C++/MFC

I used a ActiveXControl in a C# Forms application and had the possibility to implement a PreviewKeyDown event handler for that ActiveXControl. That was needed to specify that, e.g. the [ALT] key, is an input key.
For some reasons or other I have to reimplement the application in native C++/MFC and don't know how to specify that this [ALT] key is an input key and to be handled by the ActiveXControl.
You could use SetTimer to generate a WM_TIMER event 20 times a second or so
SetTimer( NULL, kMyTimer, 50, MyTimerCallback );
Then implement a function as follows.
void CALLBACK MyTimerCallback( HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime )
{
static short lastLeftAltPress = 0;
short thisLeftAltPress = GetAsyncKeyState( VK_LMENU );
if ( thisLeftAltPress != 0 && lastLeftAltPress == 0 )
{
CallAltHandlingCode();
}
thisLeftAltPress = lastLestAltPress;
// Handling code for other keys goes here.
}
This will then poll the keyboard every 50ms to find out if the left alt key has just been pressed and then call your handling code. If you want to fire the handler when its released then you would use the following if statement
if ( thisLeftAltPress == 0 && lastLeftAltPress != 0 )
or if you just want to see if it is down then you do
if ( thisLeftAltPress != 0 )
The docs for GetAsyncKeyState do state that you can check whether the lowest bit is set to see if the key has just been pressed but it does also point out that this may fail in unexpected ways in multi-threaded environments. The above scheme should always work.
thanks for all your recommendations.
For my case I finally found some way how to make it work. So far what I have learnt the situation is that a PreviewKeyDown event is triggered before the KeyDown message is sent.
I implemented PreTranslateMessage in the dialog which hosts the ActiveX control and called ::SendMessage(WM_KEYDOWN...) with the handle of the ActiveX control, using pMsg for the arguments.
Cheers,
Ilmari
I think that you can use the GetAsyncKeyState Win32 function (http://msdn.microsoft.com/en-us/library/ms646293%28VS.85%29.aspx) to get the state of all the keys in the system, VK_MENU (http://msdn.microsoft.com/en-us/library/dd375731%28v=vs.85%29.aspx) is the key you should monitor for the [Alt] key.
Haven't tried this, but MSDN doesn't say that you won't get a WM_KEYDOWN for the ALT key -- any other key pressed while ALT is down generates a WM_SYSKEYDOWN, but that doesn't say that you can't handle ALT via WM_KEYDOWN.

Categories

Resources