winapi - FindWindow vs HCBT_CREATEWND - winapi

I need to find HWND for the context menu. I create a context menu as in this tutorial but without submenus.
I can use FindWindow function this way:
HWND hWndMenu = FindWindow(TEXT("#32768"), NULL);
I can also use the WH_CBT hook. Here is the hook procedure:
LRESULT CALLBACK HookProc(int code, WPARAM wParam, LPARAM lParam)
{
if (code == HCBT_CREATEWND)
{
HWND hwnd = (HWND)wParam;
WCHAR name[1024] = { 0 };
GetClassName(hwnd, name, sizeof(name));
if (wcscmp(name, L"#32768"))
{
HWND hwndMenu = FindWindow(TEXT("#32768"), NULL);
std::cout << "HCBT_CREATEWND hwnd: " << hwnd << std::endl;
std::cout << "FindWindow hwnd: " << hwndMenu << std::endl;
}
}
return code < 0 ? CallNextHookEx(myHook, code, wParam, lParam) : 0;
}
When I open context menu I get two different hwnd's. I don't understand why. Could you explain it ?

At the time the WH_CBT hook is called, the menu window is still in progress of being created but is not yet available to FindWindow(). So, you end up finding another unrelated menu window that exists elsewhere. That is why you are seeing different HWNDs.

Related

Windows API Mousehook , Capture rightmousebutton + Ctrl (WM_RBUTTONDOWN + MK_CONTROL) clicked togather

initially i was able to print something when i pressed only right mouse button using
if (wParam == WM_RBUTTONDOWN)but now , i want the same effect, i want to print something when right mouse button + Ctrl key is pressed. how can i acheive that ?
i have tried this
LRESULT CALLBACK MainWindow::mouseProc(int Code, WPARAM wParam, LPARAM lParam)
{
auto& ms = *(const MSLLHOOKSTRUCT*)lParam;
MSLLHOOKSTRUCT* pMouseStruct = (MSLLHOOKSTRUCT*)lParam;
if (pMouseStruct != nullptr)
{
if (wParam == WM_RBUTTONDOWN & MK_CONTROL) // Here, i added MK_CONTROL but it doesn't work
{
qDebug() << "Print something when Right mouse button and Ctrl button is pressed togather";
}
}
return CallNextHookEx(NULL, Code, wParam, lParam);
}
UPDATE
when i want to try the case where only Ctrl is pressed and it should print something, it still doesn't work
LRESULT CALLBACK MainWindow::mouseProc(int Code, WPARAM wParam, LPARAM lParam)
{
auto& ms = *(const MSLLHOOKSTRUCT*)lParam;
MSLLHOOKSTRUCT* pMouseStruct = (MSLLHOOKSTRUCT*)lParam;
if (pMouseStruct != nullptr)
{
if (wParam == MK_CONTROL) // Here, i added only MK_CONTROL but it doesn't work
{
qDebug() << "Print something when Ctrl button is pressed ";
}
}
return CallNextHookEx(NULL, Code, wParam, lParam);
}
what am i missing here ?
First of all, if you want to capture the right button + ctrl, you can check the state of the Ctrl key (whether it is pressed) when WM_RBUTTONDOWN is detected.
LRESULT CALLBACK mouseProc(int Code, WPARAM wParam, LPARAM lParam)
{
auto& ms = *(const MSLLHOOKSTRUCT*)lParam;
MSLLHOOKSTRUCT* pMouseStruct = (MSLLHOOKSTRUCT*)lParam;
if (pMouseStruct != nullptr)
{
if (wParam == WM_RBUTTONDOWN && (GetAsyncKeyState(VK_LCONTROL)&0x8000)) //Left CONTROL key as example
{
std::cout << "ctrl + rbutton";
}
}
return CallNextHookEx(NULL, Code, wParam, lParam);
}
If you want to use a keyboard hook to hook only "Ctrl":
LRESULT CALLBACK keyboardProc(int Code, WPARAM wParam, LPARAM lParam)
{
KBDLLHOOKSTRUCT* pKeyboardStruct = (KBDLLHOOKSTRUCT*)lParam;
if (pKeyboardStruct != nullptr)
{
if (pKeyboardStruct->vkCode == VK_LCONTROL)
{
if(wParam == WM_KEYDOWN)
std::cout << " -ctrl- ";
}
}
return CallNextHookEx(NULL, Code, wParam, lParam);
}
void main(void)
{
HHOOK hmouse = SetWindowsHookEx(WH_MOUSE_LL, mouseProc, hInstance, 0);
HHOOK hkeyboard = SetWindowsHookEx(WH_KEYBOARD_LL, keyboardProc, hInstance, 0);
MSG msg;
while (GetMessage(&msg, 0, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
UnhookWindowsHookEx(hmouse);
UnhookWindowsHookEx(hkeyboard);
return;
};

SetWindowsHookEx to monitor Windows open and close

I took this example code from here that hooks a function to intercept keyboard events, and it works:
#include <Windows.h>
// variable to store the HANDLE to the hook. Don't declare it anywhere else then globally
// or you will get problems since every function uses this variable.
HHOOK _hook;
// This struct contains the data received by the hook callback. As you see in the callback function
// it contains the thing you will need: vkCode = virtual key code.
KBDLLHOOKSTRUCT kbdStruct;
// This is the callback function. Consider it the event that is raised when, in this case,
// a key is pressed.
LRESULT __stdcall HookCallback(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode >= 0)
{
// the action is valid: HC_ACTION.
if (wParam == WM_KEYDOWN)
{
// lParam is the pointer to the struct containing the data needed, so cast and assign it to kdbStruct.
kbdStruct = *((KBDLLHOOKSTRUCT*)lParam);
// a key (non-system) is pressed.
if (kbdStruct.vkCode == VK_F1)
{
// F1 is pressed!
MessageBox(NULL, "F1 is pressed!", "key pressed", MB_ICONINFORMATION);
}
}
}
// call the next hook in the hook chain. This is nessecary or your hook chain will break and the hook stops
return CallNextHookEx(_hook, nCode, wParam, lParam);
}
void SetHook()
{
// Set the hook and set it to use the callback function above
// WH_KEYBOARD_LL means it will set a low level keyboard hook. More information about it at MSDN.
// The last 2 parameters are NULL, 0 because the callback function is in the same thread and window as the
// function that sets and releases the hook. If you create a hack you will not need the callback function
// in another place then your own code file anyway. Read more about it at MSDN.
if (!(_hook = SetWindowsHookEx(WH_KEYBOARD_LL, HookCallback, NULL, 0)))
{
MessageBox(NULL, "Failed to install hook!", "Error", MB_ICONERROR);
}
}
void ReleaseHook()
{
UnhookWindowsHookEx(_hook);
}
void main()
{
// Set the hook
SetHook();
// Don't mind this, it is a meaningless loop to keep a console application running.
// I used this to test the keyboard hook functionality. If you want to test it, keep it in ;)
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
}
}
I am trying to make the similar code works for WH_GETMESSAGE to intercept WH_CREATE and WH_DESTROY messages, but it didn't work:
#include "stdafx.h"
#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <psapi.h>
#include <iostream>
HHOOK _hook;
LRESULT CALLBACK GetMsgProc(_In_ int nCode, _In_ WPARAM wParam, _In_ LPARAM lParam)
{
std::cout << "Enter hook\n";
if (nCode >= 0)
{
// the action is valid: HC_ACTION.
std::cout << "HC_ACtION\n";
if (wParam != PM_REMOVE) return NULL;
MSG m = *((MSG*)lParam);
std::cout << "Message received\n";
TCHAR Buffer[MAX_PATH];
if (GetModuleFileNameEx(m.hwnd, 0, Buffer, MAX_PATH))
{
// At this point, buffer contains the full path to the executable
MessageBox(NULL, Buffer, L"key pressed", MB_ICONINFORMATION);
}
else
{
// You better call GetLastError() here
}
//CloseHandle(Hand);
}
// call the next hook in the hook chain. This is nessecary or your hook chain will break and the hook stops
return CallNextHookEx(_hook, nCode, wParam, lParam);
}
void SetHook()
{
if (!(_hook = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, NULL, 0)))
{
MessageBox(NULL, L"Failed to install hook!", L"Error", MB_ICONERROR);
}
}
void ReleaseHook()
{
UnhookWindowsHookEx(_hook);
}
void main()
{
// Set the hook
SetHook();
// Don't mind this, it is a meaningless loop to keep a console application running.
// I used this to test the keyboard hook functionality. If you want to test it, keep it in ;)
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
}
}
MSDN specifies to use the function GetMsgProc with a predefined signature, but I don't see it does anything.

Can't click on controls/menu when detach MDI child out of MDI client area

Whole sample project can be found here: Sample project
Normal MDI child:
MDI child is detached out of MDI client area:
Problem is after MDI child is detached, I am not able to click on menu/controls anymore.
I think one approach is to subclass winproc of MDI app, and then catching the messages and redirect them (like this one). But I dont know where to begin.
Any idea/ other approaches are welcome!
The code I used to detach MDI child:
HWND MDIHwnd = pMainFrame->m_hWndMDIClient;
HWND mdiChildHwnd = GetWindow(MDIHwnd, GW_CHILD);
unsigned int style = GetWindowLongPtr(mdiChildHwnd, GWL_STYLE);
style = (style & (~WS_CHILD) | WS_POPUP);
SetWindowLongPtr(mdiChildHwnd, GWL_STYLE, style);
WaitForInputIdle(mdiChildHwnd, INFINITE);
SetParent(mdiChildHwnd, NULL);
WaitForInputIdle(mdiChildHwnd, INFINITE);
SetWindowLongPtr(mdiChildHwnd, GWLP_HWNDPARENT, (long)MDIHwnd);
Some experts here said that it's impossible and I found out the solution.
Lesson learnt: when someone said it's impossible which mean that's only impossible to them not you.
Whole sample project can be found here: Sample Project Answer
#Experts: if you are really an good expert then be helpful and objective rather than trying to telling people that you are an expert and you know things that other people don't know. Moreover, giving out some advice that's not really helping and being subjective are really frustrating to people who asking.
For reference
For the record: I don't care about the downvote, what I care is someone willing to help and knowledge that I get.
WndProc Code:
LRESULT CALLBACK MDIAppWndProc(
HWND hwnd, // handle to window
UINT uMsg, // message identifier
WPARAM wParam, // first message parameter
LPARAM lParam) // second message parameter
{
WNDPROC wpOrigMDIAppWndProc = (WNDPROC)GetWindowLongPtr(hwnd, GWL_USERDATA);
if (wpOrigMDIAppWndProc == NULL)
{
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
switch (uMsg)
{
case WM_ACTIVATE:
case WM_SETFOCUS:
return 0;
case WM_CLOSE:
SetWindowLong(hwnd, GWL_WNDPROC, (LONG)wpOrigMDIAppWndProc);
PostMessage(hwnd, WM_CLOSE, 0, 0);
return 0;
default:
return CallWindowProc(wpOrigMDIAppWndProc, hwnd, uMsg, wParam, lParam);
}
return 0;
}
Detaching code:
HWND MDIHwnd = pMainFrame->m_hWndMDIClient;
HWND mdiChildHwnd = GetWindow(MDIHwnd, GW_CHILD);
unsigned int style = GetWindowLongPtr(mdiChildHwnd, GWL_STYLE);
style = (style & (~WS_CHILD) | WS_POPUP);
SetWindowLongPtr(mdiChildHwnd, GWL_STYLE, style);
WaitForInputIdle(mdiChildHwnd, INFINITE);
SetParent(mdiChildHwnd, NULL);
WaitForInputIdle(mdiChildHwnd, INFINITE);
SetWindowLongPtr(mdiChildHwnd, GWLP_HWNDPARENT, (long)MDIHwnd);
HWND MDIAppHwnd = GetAncestor(MDIHwnd, GA_ROOT);
WNDPROC wpOrigMDIAppWndProc = (WNDPROC)SetWindowLong(MDIAppHwnd, GWL_WNDPROC, (LONG)MDIAppWndProc);
SetWindowLongPtr(MDIAppHwnd, GWL_USERDATA, (LONG)wpOrigMDIAppWndProc);

Windows hook gets called only once

Good afternoon. I'm writing a global mouse hook. Everything seems to work just fine except that the hook is called only for the first mouse event.
Some code:
// Dll defined function
extern "C" Q_DECL_EXPORT LRESULT MouseProc(int code, WPARAM wParam, LPARAM lParam)
{
qDebug() << "MouseProc";
return TRUE;
}
// Application code
...
hLib = LoadLibrary(TEXT("ServerHook.dll"));
HOOKPROC hookAddr = (HOOKPROC)GetProcAddress(hLib, "MouseProc");
if (!hookAddr) {
qDebug() << "Invalid hook proc " << GetLastError();
}
if ((WinInputHook::hookHandle = SetWindowsHookEx(
WH_MOUSE, hookAddr, hLib, 0))
== NULL) {
qDebug() << "Invalid hook handle " << GetLastError();
}
...
The hooking you'r installing (WH_KEYBOARD) "installs a hook procedure that monitors keystroke messages" and not the mouse

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