Create child window in WM_CREATE, relevance of same thread? - c++

A typical pattern is to create a child window in the message callback (WndProc) at message WM_CREATE:
LRESULT APIENTRY WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
...
switch (message) {
case WM_CREATE:
....
hwndChild[i] = CreateWindow (szChildClass[i], NULL, WS_CHILDWINDOW | WS_BORDER ...
I perfectly understand this is a good opportunity, but is it a problem to do it any time later? One reason for doing so is that the child window is created within the same thread. But is there any other reason?
And how important is to create the child window in the same thread (as the parent)? As of " Can a child thread of parent GUI dialog thread create a child window? " this seems to be no general problem?

It's no problem to create your child window later, however, as you have mentioned, it should be created from the same thread.
For instance, you can create a child window inside a WM_COMMAND message handler (e.g. when a user clicks on a button) or as a response to WM_TIMER.
Creating a child window from another thread is a bad idea, as each thread has its own message queue. However, if you want another thread to initiate creating the window, you can work around it by sending a user-defined message to your window:
Define your message (e.g. #define WM_CREATEMYWINDOW WM_USER + 123)
From another thread post it to your window:
PostMessage(g_hWnd, WM_CREATEMYWINDOW, 0, 0);
In your window procedure create the child window:
if (message == WM_CREATEMYWINDOW)
hwndChild[i] = CreateWindow(...);

Related

Determine which window the message was sent (SetWindowsHookEx & WH_KEYBOARD)

I need to be able to determine which window the message is intended for, but I don’t understand how to do it correctly. In WH_MOUSE has a special structure (MOUSEHOOKSTRUCT) that stores the hwnd of the window, but where to get the hwnd in WH_KEYBOARD?
LRESULT CALLBACK messageHandler(int nCode, WPARAM wParam, LPARAM lParam)
{
// ???
}
DWORD WINAPI messageDispatcher(LPVOID thread)
{
hookHandle = SetWindowsHookEx(WH_KEYBOARD, messageHandler, GetModuleHandle(nullptr), *reinterpret_cast<DWORD*>(thread));
if (!hookHandle)
{
return GetLastError();
}
MSG message{};
while (GetMessage(&message, 0, 0, 0) > 0)
{
TranslateMessage(&message);
DispatchMessage(&message);
}
return 0;
}
In theory, I could use GetForegroundWindow, but it seems to me that this is a terrible option, because the window can receive a keyboard message from some other process (if another process sends a SendMessage to this window) and not the fact that the current window will be exactly the one for which the message was intended.
At the time a keyboard action is generated, the OS doesn't know yet which window will eventually receive the message. That is why the WH_KEYBOARD hook doesn't provide a target HWND, like a WH_MOUSE hook does (since a mouse message carries window-related coordinates).
When a keyboard message is being routed to a target, the message gets delivered to the window that currently has input focus.
Per About Keyboard Input:
The system posts keyboard messages to the message queue of the foreground thread that created the window with the keyboard focus. The keyboard focus is a temporary property of a window. The system shares the keyboard among all windows on the display by shifting the keyboard focus, at the user's direction, from one window to another. The window that has the keyboard focus receives (from the message queue of the thread that created it) all keyboard messages until the focus changes to a different window.
Since your hook runs inside of the message queue of the target thread, you can use GetFocus() to get the target HWND at that time:
Retrieves the handle to the window that has the keyboard focus, if the window is attached to the calling thread's message queue.
Otherwise, you can use a WH_CALLWNDPROC/RET hook instead, which gets called when the message is actually delivered to a window. However, you can't block messages with this hook (as you were asking about in your previous question).
I think what you might be looking for is a hook of type WH_JOURNALRECORD.
With this, the callback procedure that Windows will call in response to the various events that this hook intercepts is of type JournalRecordProc, and the lparam parameter passed to this function points to an EVENTMSG structure, which looks like this:
typedef struct tagEVENTMSG {
UINT message;
UINT paramL;
UINT paramH;
DWORD time;
HWND hwnd;
} EVENTMSG;
And there is your hwnd!

How could I handle a Window's Message?

I'm working on some CreateWindow things.
My work need I to insert a Button into one of an Application's Window, and when I click the button, my application can do something. That Application isn't my Application, so I think I need to do some "hook thing".
And I tried this:
HWND hwnd = FindWindowEx("className",NULL)
CreateWindowEx(...hwnd...)
Its worked. The Button successfully inserted into target application.
but when I try to handle that window's message
I failed.
This hwnd is belongs to my application hInstance, but my Application has its own message loop by CEF.
I tried SetWindowsHookEx,but its not working.
Whatever I do, it will not handled.
and if i use while(GetMessage (&messages, NULL, 0, 0)),it will block my application's thread
WNDCLASS xxx and RegisterClass(xxx)
or CreateWindow(className)
confused me.
I try to use LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) but the while() will block my application's thread
and in my application's wndProc, there is no WM_COMMAND message in.
HWND hwnd = FindWindowEx(0, 0, L"TCustomBaseForm" , NULL);
HWND hwndButton = CreateWindowEx(0L,_T("Button"), L"Btn", WS_CHILD|WS_VISIBLE| BS_PUSHBUTTON, 435, 45, 35, 45, hwnd, NULL, GetModuleHandle(0), 0);
DWORD dwProcId = 0;
DWORD dwThreadId = 0;
dwThreadId = GetWindowThreadProcessId(hwndButton, &dwProcId);
SetWindowsHookEx(WH_MOUSE, Hookproc, g_hInstance, dwProcId);
Until now, my "inserted button" never work.
So, is there any way to make this "inserted window" or button same as a MFC button that, when I click it, I can handle a message like WM_LBUTTONCLICK in my WndProc?
A button sends a WM_COMMAND message to its parent window when you click it.
There are at least two ways to deal with this without hooking:
Create the button as a child of a STATIC control (or a custom window) that you also create. You need to subclass the STATIC control to receive the message.
Subclass the button and catch the mouse up message and space/enter key-down messages.
Thank you all. I did it.
I create a Window that have a button. And I use SetParent(myWindowHwnd,myTargetWindowHwnd) and handle the button's click event in my window, it works.
No hook, no problems.
Thank you all very much.
And thanks for edit my question, for my poooooooooooor English.
I've learned a lot about Windows Hook.

C++: How to set a new wndProc for a console application?

If I have a console application with a handle to it set up like so;
HWND hWnd = GetConsoleWindow();
Then how do I set up a new wndProc for the window?
I tried using
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)conProc);
With conProc being defined as
LRESULT CALLBACK conProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_NCHITTEST:
return HTCAPTION;
}
return DefWindowProc(hWnd, msg, wParam, lParam );
}
But it doesn't work and says "Error code: 5 - Access is denied" on GetLastError()
I understand that it's pretty difficult to modify the console application like this, since it's a csrss.exe application and all, but I'd still like to try..
Thanks.
While the impression is that console window belongs to your process (like other window), it is in fact hosted by CSRSS system process and its WndProc is there. This makes you unable to subclass the window and provide your own WndProc living in your process.
Some related reading:
The process that is in charge of displaying the GUI windows in which consoles are presented is... CSRSS
SetWindowsHookEx with WH_KEYBOARD doesn't work for me, what do I wrong?
Subclassing XP Console Window
First of all SetWindowLong is superseded by SetWindowLongPtr, you should use that function.
Are you trying to change the WNDPROC of your own console window or another process?
From the MSDN docs :
GWL_WNDPROC
-4
Sets a new address for the window procedure.
You cannot change this attribute if the window does not belong to the same process as the calling thread.

Close callback or WM_CLOSE from a HWND reference

I'm calling the HtmlHelpA winapi method to display the .chm of my app. This method returns a HWND immediatelly, and the help window is shown as a separate window.
Along with the window, I set a timer for this hwnd. My problem is that I need to know when this window gets closed to kill the timer.
My first approach was trying to register the WndProc callback, but I couldn't do that because I'm not creating the window, I only have a reference to the hwnd.
Then I tried with a hook (SetWindowsHookEx) but the HOOKPROC won't bring the HWND as a parameter to the callback. Besides, I need to know the thread for this hwnd.
Is there any way to register a callback when a HWND gets closed or having a WndProc to wait for the WM_CLOSE message?
If required you can register a new window procedure for an existing window. Check out the documentation on SetWindowLongPtr().
Invoking it like this:
SetWindowLongPtr(hwnd, GWLP_WNDPROC, &MyCustomHelpWindowProc);
Just remember that window subclassing is very delicate. You might want to store the old window procedure somewhere and invoke that rather than DefWindowProc() for messages you are not interested in.
You want to subclass the help window. Subclassing gives you a chance to spy on all the messages going to the window proc. You do whatever additional work you need when you see a message of interest, and then pass the message on to the original window procedure for normal processing.
LRESULT CALLBACK MyWndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);
WNDPROC fnOldProc = reinterpret_cast<WNDPROC>(::SetWindowLongPtr(hwndHelp, GWLP_WNDPROC, &MyWndProc));
LRESULT CALLBACK MyWndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
if (msg == WM_CLOSE) {
// Kill your timer here.
}
return CallWindowProc(fnOldProc, hwnd, msg, wp, lp);
}

Window Wrapper Class C++ (G++)

I am attempting to learn about creating windows in c++, I have looked at an article about creating a wrapper class but I don't really understand it. So far I know that you can't have a class method WndProc (I dont know why) but honestly, that is all. Can somebody give an explanation, also explaining the reinterpret_cast? Here is the article.
LRESULT CALLBACK Window::MsgRouter(HWND hwnd, UINT message,
WPARAM wparam, LPARAM lparam)
{
Window *wnd = 0;
if(message == WM_NCCREATE)
{
// retrieve Window instance from window creation data and associate
wnd = reinterpret_cast<Window *>((LPCREATESTRUCT)lparam)->lpCreateParams;
::SetWindowLong(hwnd, GWL_USERDATA, reinterpret_cast<long>(wnd));
// save window handle
wnd->SetHWND(hwnd);
}
else
// retrieve associated Window instance
wnd = reinterpret_cast<Window *>(::GetWindowLong(hwnd, GWL_USERDATA));
// call the windows message handler
wnd->WndProc(message, wparam, lparam);
}
Thanks in advance, ell.
The MsgRouter() procedure acts as a proxy between the Windows message handling system to the Window instance associated with a HWND. It routes Windows messages to C++ objects.
A pointer to the Window instance is passed to the MsgRouter() procedure via the last parameter of the CreateWindow() function. When you first create a HWND via CreateWindow() (or CreateWindowEx()), some messages are sent - one of them being WM_NCCREATE. When the procedure receives a WM_NCCREATE message, the LPARAM parameter contains a pointer to a CREATESTRUCT which contains the arguments that was passed into the CreateWindow() function. The procedure retrieves the Window instance pointer from the CREATESTRUCT and saves it in the HWND by setting it as an attribute of the HWND (GWL_USERDATA via SetWindowLong()).
Now that the pointer has been saved, the window procedure can from now on retrieve a pointer to the original Window instance from a HWND via GetWindowLong() when it receives a message. Finally, the window procedure calls WndProc() on the retrieved Window pointer, passing in the exact message and parameters, so the Window instance can handle the message.