How to pass arguments to SetWindowsHookEx's callback? (if even possible) - winapi

I'm using SetWindowsHookEx with WH_CALLWNDPROC to catch all WndProc messages - and it works fine.
I was wondering if there is a way to store a parameter somewhere where the callback function can read and use it.
I assume that because the callback function is inside the "other" process, there's no connection to the process calling the SetWindowsHookEx, so just storing a value in a static variable wont do any good..
For example:
void Hook(DWORD dwThread, int randomNumber)
{
MagicallyStore(randomNumber);
SetWindowsHookEx(WH_CALLWNDPROC, hookProc, GetModuleHandle(L"WNDProcHooks"), dwThread);
...
...
}
LRESULT CALLBACK hookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
int randomNumber = MagicallyRestore();
DoSomthing(randomNumber);
return CallNextHookEx(0, nCode, wParam, lParam);
}
I already thought about having the "MagicallyStore" function write the parameter to a file and reading it once in the "MagicallyRestore" function - but there must be a better way..
Thanks in advance :)

Related

Set WH_GETMESSAGE hook makes the system dead

I use SetWindowsHookEx to install a global GETMESSAGE hook in a dll like this:
SetWindowsHookEx(WH_GETMESSAGE,HookProc,hModule,0);
and the the hook procedure within the dll too.But when i called InstallHook(this function is exported from the DLL) to install the GETMESSAGE hook,booom, the system can not respon the mouse operation,the windows on the desktop can be close or move) ,here is my HookProc Code:
LRESULT CALLBACK HookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode < 0)
{
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
WCHAR szMsg[MAX_PATH] = { 0 };
PMSG pMsg = (PMSG)lParam;
wsprintf(szMsg, L"MSG_FROM:%08x,MSG_TYPE:%d", pMsg->hwnd,pMsg->message);
OutputDebugString(szMsg);
return CallNextHookEx(NULL,nCode, wParam, lParam);
}
I've read the MSDN for many times,it just said i must process the message if the ncode is HC_ACTION,but,i don't know how to process the message.I think there must be someone else has this problem too, so, hope somebody give some help, and tell me how you process this trouble.
Thanks a lot.

Encapsulate Win32 in a class - pass class pointer in CreateWindow

I viewed many tutorials and posts on this subject, and they all say I pass the class instance pointer (this) in my CreateWindowEx() function, and then store it in the window procedure function, when the WM_NCCREATE message is sent. I guess this is because WM_NCCREATE is supposedly the first message that gets sent to the window procedure since a window is created.
A few questions/notes:
From debugging I came to know that actually WM_GETMINMAXINFO is the first sent message, before WM_NCCREATE (at least on my machine). Does this mean I should listen for this message instead of WM_NCCREATE?
According to this popular article, the reason everyone calls SetWindowLongPtr() after the message WM_NCCREATE is received is because
If the value does not exist by the time WM_NCCREATE is called then,
by some mysterious Windows behavior that I still don't understand, the
value never gets inserted.
I tried to do exactly that (that is, call SetWindowLongPtr() after CreateWindowEx()). It turns out to be just fine. The application runs okay. Below is my code, please tell me if there's something wrong with this approach.
void GLWin32::CreateWindow(...)
{
...
_hwnd = CreateWindowEx(NULL, _wndclassex.lpszClassName, title.c_str(), WS_OVERLAPPEDWINDOW, x, y, width, height, NULL, NULL, _hinstance, NULL);
SetWindowLongPtr(_hwnd, GWL_USERDATA, reinterpret_cast<LONG_PTR>(this));
...
}
//static window procedure for all instances of this class
LRESULT CALLBACK GLWin32::_msgRouter(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
LONG l = GetWindowLongPtr(hwnd, GWLP_USERDATA);
GLWin32* thisPtr = reinterpret_cast<GLWin32*>(l);
if (thisPtr)
return thisPtr->_winProc(msg, wparam, lparam);
else
return DefWindowProc(hwnd, msg, wparam, lparam);
}
LRESULT GLWin32::_winProc(UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_CLOSE:
{
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(_hwnd, msg, wparam, lparam);
}
Why is my approach not used instead of the popular approach?
The problem with this approach is that if you want to use the instance when processing any of the window creation messages (including "ordinary" messages that are sent as part of the creation process), you won't have access to it.
Suppose you want to create a button when processing WM_CREATE (typical scenario) and you want to set the button text to some instance member value. You want something like:
LRESULT GLWin32::_winProc(UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_CREATE:
{
CreateWindow("BUTTON", this->buttonText, WS_VISIBLE | WS_CHILD,
10, 10, 50, 30, this->hwnd, NULL, this->hInstance, NULL);
return 0;
}
}
return DefWindowProc(_hwnd, msg, wparam, lparam);
}
Problem is, when WM_CREATE is processed (before CreateWindowEx returns), SetWindowLongPtr wasn't called yet and the instance pointer is missing, so _winProc isn't being called at all.

How to use DialogBox in Windows API

I'm learning windows api for some weeks, now I got a problem, my code is like this
LRESULT CALLBACK MainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
switch(message){
case(...)
DialogBox(hInstance,MAKEINTRESOURCE(IDD_MYDIALOG),hwnd,(DLGPROC)MyDialogProc);
return 0;
}
bool MyDialogProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam){
switch (message){
...
}
return false;
}
I don't know what else should I do before I use DialogBox where should I place EndDialog(). IDD_MYDIALOG is a resource file created by myself. I don't understand what is hInstance and how to get it, I think I just need a simple example, than I can know how use DialogBox. Thank you for helping!

Why SetWindowsHookEx not works in the CLI(which codes in main() instead dllmain,etc.)?

#include <stdio.h>
#include <windows.h>
LRESULT CALLBACK KeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) {
printf("Keyboard event, nCode = %d, wParam = %d, lParam = 0x%.8X\n", nCode, wParam, lParam);
return (LRESULT)NULL;
}
void main() {
HHOOK HookHandle = SetWindowsHookEx(WH_KEYBOARD, (HOOKPROC)KeyboardProc, (HINSTANCE) NULL, GetCurrentThreadId());
printf("Hook handle = 0x%.8X\n", HookHandle);
MSG message;
while (GetMessage(&message,NULL,0,0)) {
TranslateMessage(&message);
DispatchMessage(&message);
}
UnhookWindowsHookEx(HookHandle);
}
Expected it outputs something like "keyboard event...", but it does not work, it always keep silent whatever I type.
The compile options is simple: gcc -o test.exe test.c
Most (if not all) of these hooks have to be injected into the target application(s), so they must be implemented in a DLL.
From the documentation of the KeyboardProc callback function:
The system calls this function
whenever an application calls the
GetMessage or PeekMessage function and
there is a keyboard message (WM_KEYUP
or WM_KEYDOWN) to be processed.
Console applications don't use the message queue to handle input, so your hook will never be called.
You could try using a low-level keyboard hook (WH_KEYBOARD_LL). Even though that's a global hook, you don't need to use a DLL: as mentioned in the Remarks section of the documentation, the hook code is not injected in other processes. The problem with this approach of course is that you'll get notifications for all key events in the system (not just the ones in your program).

WM_MOUSEHOVER in a global hook

I have implemented custom tooltips for a couple of controls in my application (MFC) but I would like to make it general for all the controls.
Right now I am calling TrackMouseEvent in WM_MOUSEMOVE and then catching WM_MOUSEHOVER (both in the overwritten function WindowProc of the control). But this way I have to duplicate code for every control. So my intention was to set a global hook for mouse events and there ask the control for the message to display in the tooltip.
The problem is that I am not able to catch WM_MOUSEHOVER in a global hook. This is the code:
hMouseHook = SetWindowsHookEx( WH_MOUSE,
CallWndMouseProc,
NULL,
AfxGetThread()->m_nThreadID);
hMainHook = SetWindowsHookEx( WH_CALLWNDPROC,
CallWndProc,
NULL,
AfxGetThread()->m_nThreadID);
LRESULT CALLBACK CallWndMouseProc( int nCode,
WPARAM wParam,
LPARAM lParam )
{
if(nCode == HC_ACTION)
{
MOUSEHOOKSTRUCT* pwp = (MOUSEHOOKSTRUCT*)lParam;
TRACE( _T("message: %x hwnd: %x x: %d y: %d\n"),
wParam,
pwp->hwnd,
pwp->pt.x,
pwp->pt.y);
TRACKMOUSEEVENT eventTrack;
eventTrack.cbSize = sizeof(TRACKMOUSEEVENT);
eventTrack.dwFlags = TME_HOVER;
eventTrack.dwHoverTime = HOVER_DEFAULT;
eventTrack.hwndTrack = pwp->hwnd;
_TrackMouseEvent(&eventTrack);
if(wParam == WM_MOUSEHOVER)
{
AfxMessageBox(_T("CallWndMouseProc: WM_MOUSEHOVER"));
}
}
// let the messages through to the next hook
return CallNextHookEx( hMouseHook,
nCode,
wParam,
lParam);
}
LRESULT CALLBACK CallWndProc( int nCode,
WPARAM wParam,
LPARAM lParam )
{
if(nCode == HC_ACTION)
{
CWPSTRUCT *pData = (CWPSTRUCT*)lParam;
if(pData->message == WM_MOUSEHOVER)
{
AfxMessageBox(_T("CallWndProc: WM_MOUSEHOVER"));
}
}
// let the messages through to the next hook
return CallNextHookEx( hMainHook,
nCode,
wParam,
lParam);
}
Both hooks are being call for the rest of messages and I am sure WM_MOUSEHOVER is being sent because it's capture in the WindowProc function. For instance this is the WindowProc function for a custom CListBox:
LRESULT CMyListBox::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
if(message == WM_MOUSEHOVER)
{
AfxMessageBox(_T("WindowProc: WM_MOUSEHOVER"));
}
return CListBox::WindowProc(message, wParam, lParam);
}
Ok. So what I am missing? It's just not possible to capture this message in a global hook? Is there other way to make this without having to put the same code in every single control?
Thanks.
Javier
WM_MOUSEHOVER is posted to the thread's message queue, so you won't see it with WH_CALLWNDPROC (that's for sent messages). WH_MOUSE does get posted messages, so I find it a little strange that you aren't seeing it... Perhaps the hook only gets low level mouse input messages? Try a WH_GETMESSAGE hook.

Resources