I am looking into reworking an old CBT windows hook, and am slightly confused as to how it is currently working. The way it is setup is one dll handles the Windows hooking and its logic, while another program calls into that dll when the hook should be set. It looks like this:
LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
// this is the function the other program calls into
void InstallHook()
{
// hdll is this dll's address
SetWindowsHookEx(WH_CBT, HookProc, hDLL, 0);
}
Then we have our DllMain function. That dllmain function seems to get called whenever the hookProc function is invoked, and I do not understand this behavior. I've examined the fdwReason and it is getting called due to a dll process attach event.
How is this event being fired every time the HookProc is called? Since it is a global hook, I thought windows would load the dll and just persist it, calling the HookProc when the need arose. But from what I'm seeing, it acts like it is loaded back up anytime HookProc is called. Is this how it usually works, or could another part of the code base be causing this?
DLLs that implement global hooks get loaded into any process in the system that triggers the hook.
(This is precisely why global hooks must be implemented as DLLs - so they can be loaded into other processes).
Related
In order to hook a wndproc, I write a wndprochook and use SetWindowLong:
wndproc=(WNDPROC)GetWindowLong(hwnd_1,GWL_WNDPROC);
SetWindowLong(hwnd_1,GWL_WNDPROC,(LONG)wndprochook);
Now I have to do something in wndproc and at the end of the function, I call the original wndproc:
return wndproc(hwnd, uMsg, wParam, lParam);
It fails, but thank god I find CallWindowProc:
return CallWindowProc(wndproc, hwnd, uMsg, wParam, lParam);
Now it's working. So Question1: Why do we have to use CallWindowProc? What's missing when simply calling wndproc?
The hook is working good, but when I quit the program, it crashes. Of course, everything is done and the crash doesn't actually affect anything. But it's still bad to see a crash.
So Question2: What may happened here and how to fix it?
I'm sorry that I have no information about how the original program closes itself, since all that I do is just hooking the wndproc to capture some messages. So I'm just hoping someone experienced enough who have ever encountered similar situations before could help.
From the documentation of CallWindowProc:
“If this value is obtained by calling the GetWindowLong function with the nIndex parameter set to GWL_WNDPROC or DWL_DLGPROC, it is actually either the address of a window or dialog box procedure, or a special internal value meaningful only to CallWindowProc”
You can't call the “special internal value“ except by doing the same as CallWindowProc does, and the easiest way to do that is to call CalLWindowProc…
By the way, have a look at SetWindowSubclass, it may ease things for you.
Regarding Question 2:
From comments on another answer, it sounds like your subclass wndprochook is in a DLL that's injected into a process. If that's the case, then during exit, your DLL may be unloaded while there are still messages pending for the window. So the Window's class still points to your wndproc, but that code is unloaded, so it crashes.
The safest thing to do is probably to restore the original wndproc before you shut down. For example, when your subclass sees WM_DESTROY or perhaps WM_NCDESTROY, you essentially reverse the steps you did when you subclassed the window: restore the original wndproc field in the window class, before doing your CallWindowProc with that message. Your code will no longer be called, even if a few more messages trickle in for that window.
thx to Adrian McCarthy.
Private Function WndProc(ByVal hWnd As Long, ByVal MSG As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
Select Case MSG
Case WM_CUT, WM_PASTE, WM_CLEAR
WndProc= 1
Case WM_DESTROY, WM_NCDESTROY
Call UnHookRKey(hWnd)
Case Else
WndProc= CallWindowProc(lngPrevWndProc, hWnd, MSG, wParam, lParam)
End Select
End Function
For those of you who do not know what I am talking about:
http://www.teamviewer.com/images/presse/quickconnect_en.jpg
Teamviewer overlays that button on all windows to allow you to quickly share a window with someone else. I would like any ideas on implementing something similar -- if you have example code, even better (specifically, the button -- not the sharing). I am interested in C++ and QT... but I would be interested in good solutions in other languages/libraries if there are any.
Thanks.
To draw buttons or other stuff in foreign windows, you need to inject code into the foreign processes.
Check the SetWindowsHookEx method for that:
You most probably want to install a hook for WH_CALLWNDPROCRET and watch out for the WM_NCPAINT message. This would be the right place to draw your button.
However, I'm not really sure, if you can place a window within a Non-Client-Area, so in the worst case, you'd have to paint the button "manually".
Just call this from your main application (or from within a DLL)
SetWindowsHookEx(WH_CALLWNDPROCRET, myCallWndRetProc, hModule, 0);
Note that myCallWndRetProc must reside within a DLL and hModule is the Module-HANDLE for this DLL.
Your myCallWndRetProc could look like:
LRESULT CALLBACK myCallWndRetProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HT_ACTION) {
CWPRETSTRUCT* cwpret = (CWPRETSTRUCT*)lParam;
if (cwpret->message == WM_NCPAINT) {
// The non-client area has just been painted.
// Now it's your turn to draw your buttons or whatever you like
}
}
return CallNextHookEx(0, nCode, wParam, lParam);
}
When starting with your implementation, I'd suggest, you just create a simple dialog application and hook your own process only:
SetWindowsHookEx(WH_CALLWNDPROCRET, myCallWndRetProc, NULL, GetCurrentThreadId());
Installing a global hook injects the DLL into all processes, which makes debugging pretty hard, and your DLL may be write-protected while it's in use.
I am stuck with an application I am writing where I need to monitor for mouse clicks.
The clicks may happen anywhere on the screen and not inside the app window, and for each click I must pass a message (perform an action or something).
I looked around and read some suggestions like using
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
but I was unsuccessful.
Does anyone have an idea on how to implement what I need?
You need to set a mouse hook as described in MSDN.
Note that in your case the hook would need to be global. This means that you need to implement a handler function in a DLL, which will be loaded into all processes in the system which receive mouse message. Such DLL will communicate with your main application using some interprocess communication (IPC) mechanism like shared memory or via Windows messages posted (not sent) from the DLL to the main application.
You can use the source code from this CodeProject article as a guide.
Update: as per Chris' correction, I should note that above applies to "regular" mouse hook which is synchronous. Low-level hook doesn't need to be located in the DLL, but it has certain limitations which are described in the corresponding MSDN article.
well I don't really know if you solved your problem. I hope so.
But I was in the same trouble today and searching I found a way really easy to do it.
So here you are:
int keyPressed(int key){
return (GetAsyncKeyState(key) & 0x8000 != 0);
}
int main(){
while(1){
if(keyPressed(VK_LBUTTON)){
printf("%s\n","Click izquierdo");
}
if(keyPressed(VK_RBUTTON)){
printf("%s\n","Click Derecho");
}
}
return 0;
}
the key of this solution is the function GetAsyncKeyState(key), where key anyone of the codes that appears here https://msdn.microsoft.com/en-us/library/dd375731(VS.85).aspx
You could use SetWindowsHookEx
Here's a small sample:
#define _WIN32_WINNT 0x0500
#include <windows.h>
HHOOK MouseHook;
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam){
PKBDLLHOOKSTRUCT k = (PKBDLLHOOKSTRUCT)(lParam);
POINT p;
if(wParam == WM_RBUTTONDOWN)
{
// right button clicked
GetCursorPos(&p);
}
}
void StayAlive(){
while(_getch() != 27) { }
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nShowCmd){
FreeConsole();
MouseHook = SetWindowsHookEx(WH_MOUSE_LL,MouseHookProc,hInstance,0);
StayAlive();
UnhookWindowsHookEx(MouseHook);
return 0;
}
LRESULT CALLBACK WndProc(...), as it name suggests is a (specific) window (message) processor where you can analyze and respond to messages on the queue that were deferred by the system to your custom definition of the callback for further processing.
Since you want to detect and act on mouse clicks anywhere on the screen, as chris suggested in the comments, one way is to hook yourself into the system by calling SetWindowsHookEx() which is quite verbose in its very definition - it allows you to track stuff happening on the system and relay that information back to your application.
This is the syntax which you need to employ in order to get yourself
HHOOK WINAPI SetWindowsHookEx(
__in int idHook,
__in HOOKPROC lpfn,
__in HINSTANCE hMod,
__in DWORD dwThreadId
);
It takes in a specific hook id, which are basically little #defines which tell the function what kind of messages you wish to receive from all over the system, you pass it a callback just like the WndProc, but this time it's meant to process the incoming messages regarding across the system. hMod simply refers to the handle to the application or the DLL in which the just mentioned proc function callback is located in. The last one relates to threads currently running on the system, setting this to 0 or NULL retrieves messages for all existing threads.
Important:
Do note that Aurus' example call to the SetWindowsHookEx is process-specific which a fancy word relating it to an actual application, instead of a DLL which can be appended to multiple processes across the system ( a global one ) and return information to your application. It would be prudent to take the time and effort to investigate Eugene's recommended method instead of this forceful approach useful only for experiments. It's a bit "harder", but the reward is worthwhile.
Less work is not always better or preferable.
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.
I want to do some processing when a particular dialog is opened but I am not able to find any way to get notification when that dialog is opened.
Is there any way to get notification in application for opening of a particular windows dialog?
The only available information about the dialog is its title and its unique.
The general solution is to use windows hooks, filter to WH_CBT, filter to WM_CREATE, or something like that, get the window text and see if it is the one of your interest.
One more important point: in hook you should use SetWindowLongPtr() to set window process to your own function, that will actually receive WM_CREATE event. In all calls this function should call the original window procedure.
You can also use a CBT Hook to watch window creation messages. You'll have access to the CREATSTRUCT used to create the actual window, eg, the title and class name. You can prevent the window from being created in your hook, modify the size, etc.
EDIT: sorry didn't notice that you don't have the code yourself but only the title. So I think the other posts solution is what you need
The event handling in win32 applications is done via a so called windows procedure which is a callback function with the following signature:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
This callback gets called by windows every time there is a message for windows which are registered with this callback function. One of the first messages send to a new window is the WM_CREATE message.
If you are creating your windows "by hand" with win32 API, then there should be a static callback function like the one below where you can filter for the WM_CREATE message.
LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch( message )
{
case WM_CREATE:
// do what ever you want
return 0;
case default:
return DefWndProc( hwnd, message, wParam, lParam );
}
}
If you use MFC dialogs (CDialog) then you can overwrite the function CDialog::OnInitDialog().
OK, the way to do this is to use SetWindowsHookEx(WH_SYSMSGFILTER,...)
You'll be getting a lot more callbacks than you really need. and global hooks are a real drain on system performance (they can force the system to serialize things that would normally run independently)
be sure to read the Remarks, especially this part:
SetWindowsHookEx can be used to inject a DLL into another process. A 32-bit DLL cannot be injected into a 64-bit process, and a 64-bit DLL cannot be injected into a 32-bit process. If an application requires the use of hooks in other processes, it is required that a 32-bit application call SetWindowsHookEx to inject a 32-bit DLL into 32-bit processes, and a 64-bit application call SetWindowsHookEx to inject a 64-bit DLL into 64-bit processes. The 32-bit and 64-bit DLLs must have different names.
Your hook must live in a dll, and the dll will end up loaded into other process's address space, so you won't it won't have access to your procees's address space, you will have to set up some sort of interprocess communication between your hook and your app.
On the whole I'd say this sounds like a really bad idea.