I have been tasked with trying to monitor activity in all GUI programs spawned from an initial program and killing them when they become inactive for a set period of time. This cannot be system activity as we must close the programs even if the user is just using another program for a while (not spawned by the initial program). The application spawning processes is a .Net program and that will not change. I was able to use SetWindowsHookEx to set low level hooks (WH_KEYBOARD_LL and WH_MOUSE_LL) from .Net but was unsure of how to associate the messages with the processes I've started (Using System.Diagnostics.Process.) I could hook events from the application doing the hooking, but it would always fail when I tried to hook to a specific thread for a spawned program.
The closest I was able to come was by creating a C++ dll that calls SetWindowsHookEx on behalf of the .Net program. Using this method I am able to hook into the first thread of a spawned notepad.exe, but the callback function is never called. If I specify a thread id of 0 the callback is called when there is activity in the original application so I know the SetWindowsHookEx works in that case.
I don't fully understand hooking yet, but from what I have read this will not work because the dll callback function address will be meaningless to the hooked process. Is that the issue I am running into? If so, is there a way around this or can somebody please suggest an alternative to determining if a spawned process is actively being used?
.Net (C#) code:
private const int WH_MOUSE = 14;
[DllImport("TestHook.dll", EntryPoint="InitializeHook", SetLastError=true, CharSet=CharSet.Unicode, ExactSpelling=true, CallingConvention=CallingConvention.StdCall)]
private static extern bool InitializeHook(uint hookType, int threadID);
private void HookEm() {
//...
System.Diagnostics.Process testProcess = System.Diagnostics.Process.Start("notepad");
if(!InitializeHook(WH_MOUSE, testProcess.Threads[0].Id)) // The notepad.exe thread I know hooks
MessageBox.Show("Boom!");
//...
}
C++ dll:
HHOOK hookValue;
bool InitializeHook(UINT hookID, int threadID) {
//... Determining which callback to use
hookValue = SetWindowsHookEx(hookID, (HOOKPROC)MouseHookCallback, _dllInstance, threadID);
//...
return hookValue != NULL
}
static LRESULT CALLBACK MouseHookCallback(int code, WPARAM wparam, LPARAM lparam) {
//From what I can see, this is never touched when hooking a thread on an outside process
}
All of this is currently being done on a 32 bit Windows XP computer. I do understand that a separate 64 bit dll would be needed to work with 64 bit applications spawned.
For anyone who encounters a similar issue, our final solution was to check the foreground window on an interval using GetWindowThreadProcessId(GetForegroundWindow(), ref foregroundWindowProcessId) and keeping a map of our spawned process ids. Each time this timer fires we set a boolean value to check in the function that calls CallNextHookEx since it has to be efficient/fast or windows will unhook us. We then use the boolean value above and the system hooks from SetWindowsHookEx to determine if the user is active in our application. No C++ dll was needed for this solution.
Related
I'm pretty new to the Hook-Stuff and I'm trying to learn how to work with it. When I learn new stuff I usually copy Code from the Internet and see if it works - if yes i go into detail and search everything up. So with all Codes I tried I have the same issue. They stop working at the GetMessage() function. I'm working with Visual Studio - I debugged it and when it reaches the function it just does nothing but stays on it.
I tried it with several Codes - for example this one:
HMODULE lib = LoadLibrary("C:\\Users\\A\\Desktop\\Dll1.dll");
if (lib) {
HOOKPROC procedure = (HOOKPROC)GetProcAddress(lib, "_procedure#12");
if (procedure)
hook = SetWindowsHookEx(WH_CALLWNDPROC, procedure, lib, 0);
else
printf("Can't find function in dll!\n");
}
else
printf("Can't find dll!\n");
if (hook)
printf("Hook installed properly!\n\n");
MSG message;
while (GetMessage(&message, NULL, 0, 0))
{
TranslateMessage(&message);
DispatchMessage(&message);
}
FreeLibrary(lib);
UnhookWindowsHookEx(hook);
It prints "Hook installed properly!" and does nothing! The code is from http://www.rohitab.com/discuss/topic/41238-global-hooks-to-intercept-windows-messages/
Unlike a mouse/keyboard hook, a window procedure hook runs in the context of a hooked thread that calls a window procedure. It does not delegate back to the thread that installed the hook, like you are expecting. That is why a window procedure hook must exist in a DLL when hooking other processes - the DLL gets injected into the address space of a hooked process, and then the hook is called by any hooked thread before/after it passes a message to a window procedure.
Your program that is installing the hook has no windows of its own, so no messages are being received. That is why GetMessage() blocks your app indefinitely. You would need to add a UI to your app, or have your hook manually post/send its own message back to your app using (Post|Send)Message() or PostThreadMessage(), in order to unblock GetMessage().
Your program is not going to receive messages unless it creates windows, hooks are delivered as part of the hooked program's message loop (that is why the hook function needs to be in a DLL for this situation).
The message queue is specific to the thread that created the window, posted messages are always going to be received on the thread that created the window, that is simply the way Windows operates.
I need to monitor the display state of any application window in Windows7. I am trying to find out if any application window (based on the process id) is in minimized/maximized/normal state.
I am using JNA 4.2.1, Java 8 update72 on Windows 7 Enterprise.
Any pointers will be very helpful. Thanks in advance to all.
A sample code I tried is given below.
import com.sun.jna.platform.win32.User32;
import com.sun.jna.platform.win32.WinUser.HOOKPROC;
import com.sun.jna.platform.win32.WinUser.MSG;
public class Main{
public static void main(String[] args) {
HOOKPROC proc = new HOOKPROC() {
public User32.LRESULT callWndRetProc(int nCode, User32.WPARAM wParam, User32.LPARAM lParam) {
System.out.println("Recieved window event");
return User32.INSTANCE.CallNextHookEx(null, nCode, wParam, lParam);
}
};
User32.INSTANCE.SetWindowsHookEx(12, proc, null, 0);
}
}
Not easily done. From MSDN:
If the dwThreadId parameter is zero or specifies the identifier of a
thread created by a different process, the lpfn parameter must point
to a hook procedure in a DLL. Otherwise, lpfn can point to a hook
procedure in the code associated with the current process.
JNA dynamically generates small bits of code that call back into Java and it uses these to provide native function pointers for Java-based functions. However, this code assumes that you already have a JVM up and running, and because they are dynamically generated, they do not live in a DLL.
The callback function to SetWindowsHookEx must be DLL-resident if not in the same thread as the target window. In order to work with a JVM, that DLL-resident callback function would have to be responsible for launching the JVM if not already running. JNA has some support for DLL-resident callbacks, but unfortunately does not implement any of the JVM launching support you'd need to make it actually work.
I have C++ library (Win32 Console) where I have implemented an asynchronous function using a timer. The asynchronous method returns device information.
I have created a separate thread, "Timer Thread", to create a hidden window and then I call SetTimer() and then the implemented message loop.
When the timer expires, it enables a callback.
When I use the library in a console application, it is working fine.
In an MFC application I am doing a post message to update the user interface when the callback triggers. The post message is not working.
If I remove the message loop in the library, it is working fine in the MFC application.
I came to conclusion that:
I guess the problem is due to two message loops, one MFC (main thread) and the TimerThread message loop. So when the callback is called and the subsequent PostMessage results in the TimerThread message loop and not reported in the MFC (main thread) message loop.
If I remove the TimerThread message loop then it works fine in the MFC application, but it fails to work in the console application.
How do I overcome this problem?
class IDeviceEnumerationCallback
{
public:
virtual void onDeviceDiscovered(DeviceInfo* pDeviceInfo,unsigned short nNoOfDevice) = 0;
};
class IDeviceDiscovery
{
public:
virtual int InitialiseDiscovery(IDeviceEnumerationCallback*) = 0;
virtual void UnInitialiseDiscovery() = 0;
virtual int EnumerateDevice() = 0;
};
class CDeviceDiscovery:IDeviceDiscovery
{
//Implementation
}
In the MFC/console application I am implementing IDeviceEnumerationCallback to get a callback.
I am using Bonjour API to enumerate the device and all the methods in Bonjour API are callbacks.
I am wating for some time interval to enumerate a device using Bonjour API and then say after 400 ms I am calling a callback to return the result. In the MFC application when the callback is called, I am doing a PostMessage() to update the user interface.
Earlier I tried without Windows message pump. I had a SetTimer function, and it is working with the MFC application, but for the console application, the callback never gets called, so I implemented a message pump here. Now it is not working for MFC application.
First, there's no reason to do what you did: creating a separate threads, then creating a window in it, set the window timer, run the message loop, respond to the WM_TIMER message and invoke the callback.
If you create "your own" thread - you don't actually need all this. You could just implement a simple loop with either Sleep (or WaitForXXXX if you want an abort option), and invoke your callback.
Usually one creates a hidden window with a timer to avoid creating an additional thread. That is, within a thread that operates GUI (and hence - runs the message loop) you create a window, and it will be served by the message loop. Actually this is would you could do in your MFC app.
However, as you said, you want a generic code for both MFC and console apps.
In MFC application I am doing post message to update UI when the
callback triggers.the post message is Not wokring.
What exactly do you mean by "diung post message"? The message should be posted either to a specific window, or to the thread. In the first case it's dispatched to the window procedure, and in the second case the message loop implementation is responsible for handling the message.
If you post your message to a specific window - how do you get its handle (HWND)? Is it your app's main window (AfxGetMainWnd)? What does your thread start working, after the MFC has created the main window, or earlier?
I ask all those question because you seem to be a newbie (no offences), and those are typical mistakes.
The problem is that you should not be creating a hidden window and using SetTimer instead you should be using the MFC worker thread functionality for background work.
//You create a thread like so.
// you need a CMyObject only if you need to pass any information
//to the thread function.
CMyObject *pNewObject = new CMyObject;
AfxBeginThread(MyThreadProc, pNewObject);
//This function will be run in separate thread
UINT MyThreadProc( LPVOID pParam )
{
//The parameter that was passed to this function
CMyObject* pObject = (CMyObject*)pParam;
while( 1 )
{
//add your code to do stuff.
Sleep(5000); //or whatever your SetTimer interval was
}
return 0; // thread completed successfully
}
I installed a global mouse hook function like this:
mouseEventHook = ::SetWindowsHookEx( WH_MOUSE_LL, mouseEventHookFn, thisModule, 0 );
The hook function looks like this:
RESULT CALLBACK mouseEventHookFn( int code, WPARAM wParam, LPARAM lParam )
{
if ( code == HC_ACTION ) {
PMSLLHOOKSTRUCT mi = (PMSLLHOOKSTRUCT)lParam;
// .. do interesting stuff ..
}
return ::CallNextHookEx( mouseEventHook, code, wParam, lParam );
}
Now, my problem is that I cannot control how long the 'do interesting stuff' part takes exactly. In particular, it might take longer than the LowLevelHooksTimeout defined in the Windows registry. This means that, at least on Windows XP, the system no longer delivers mouse events to my hook function. I'd like to avoid this, but at the same time I need the 'do interesting stuff' part to happen before the target GUI receives the event.
I attempted to solve this by doing the 'interesting stuff' work in a separate thread so that the mouseEventHookFn above can post a message to the worker thread and then do a return 1; immediately (which ends the hook function but avoids that the event is handed to the GUI). The idea was that the worker thread, when finished, performs the CallNextHookEx call itself.
However, this causes a crash inside of CallNextHookEx (in fact, the crash occurs inside an internal function called PhkNextValid. I assume it's not safe to call CallNextHookEx from outside a hook function, is this true?
If so, does anybody else know how I can run code (which needs to interact with the GUI thread of an application) before the GUI receives the event and avoid that my hook function blocks too long?
assume it's not safe to call CallNextHookEx from outside a hook function, is this true?
I believe this is true.
Since there is a finite number of operations that you can receive through your low-level mouse hook, you could just put them onto a queue to be re-posted to the receiving window once your long-running operation has finished. If you put your long-running on another thread, you'll not 'lock up' the UI, but merely 'eat' or 'defer' the user actions. Return 1 to prevent other hooks happening. Use a boolean flag to signify whether you're collecting events (because your long-running operation has to run yet) or re-posting them (and thus shouldn't hook them).
There aren't likely to be (m)any other low-level hooks in the system that you're cancelling, but you should test this mechanism thoroughly in your situation. I have used it only to block operations before (kill right-mouse-click) rather than defer them.
No fix, you'll have to make your code faster. These hooks are potentially very detrimental to the user interface responsiveness, Windows makes sure that a misbehaving one gets put in the cellar. Even if the timeout were configurable, it would never be documented. That would defeat the purpose of having a timeout in the first place.
Why are you using a mouse event hook? are you hooking the mouse generally or just for a specific window? If it is for a specific window then you need to - instead of using a hook - actually subclass the target window.
This is normally a 2 stage process - hooks always need to be in dll's as the hook needs to be executed in the context of the process (and thread) thats actually handling the message.
So you start by writing a hook dll that, when sent a message, calls SetWindowLong on an HWND to replace the GWL_WINDOWPROC with your new window proc.
In your WindowProc you can take as long as you want to handle messages.
I want to set global hook that tracks which application is active.
In my main program I am doing the foloowing :
HMODULE mod=::GetModuleHandle(L"HookProcDll");
HHOOK rslt=(WH_CALLWNDPROCRET,MyCallWndRetProc,mod,0);
The hook procedure which is called MyCallWndRetProc exists in separate dll called HookProcDll.dll. The hook procedure is watching for WM_ACTIVATE message.
The thing is that the code stucks in the line where I am setting the hook, i.e in the line where I am calling ::SetWindowsHookEx. And then Windows gets unresponsive, my task bar disappears and I am left with empty desktop. Then I must reset the computer.
What am doing wrong, why Windows get unresponsive ? and
Do I need to inject HookProcDll.dll in every process in order to set the global hook, and how can I do that ?
This almost definitely sounds like a crashing bug in MyCallWndRetProc. You specify your hook DLL to get loaded in every process with a window and it crashes when MyCallWndRetProc gets called after a window message. Since it gets called after every window message in every process, it'll eventually take down every process displaying UI in the user session. You can't even launch new apps since your hook proc will be immediately loaded into them.
Including the code to MyCallWndRetProc, and perhaps your DllMain as well, should give us some insight into what is happening.
This is the code for my hook procedure, and it is stored in HookProcDll.dll :
#include "HookProcDll.h"
LRESULT CALLBACK MyCallWndRetProc(
__in int nCode,
__in WPARAM wParam, /* whether the msg is sent by the current process */
__in LPARAM lParam /* pointer to CWPRETSTRUCT , which specifies details about the message */
)
{
if(nCode >=0)
{
CWPRETSTRUCT* retStruct=(CWPRETSTRUCT*)lParam;
if(retStruct->message == WM_ACTIVATE)
{
}
}
return ::CallNextHookEx(0,nCode,wParam,lParam);
}
My HookProcDll.dll has no explicit DllMain function .The HookProcDll.dll is made with visual studio dll project so I guess it includes standrad implementation for DllMain.