Window Wrapper Class C++ (G++) - c++

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.

Related

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.

how to create window in an application that started as console one?

I know the way window is created when the app is windowed one from the start, that is you call
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
int WinMain(HINSTANCE hInst,HINSTANCE,LPSTR,int nCmdShow);
But what to do if I want to get user an option to display a console application output when it ends. That is display its data in more readable form in ad-hoc created window instead of text-only mode that console permits.
In console app I have a function that watches for user key press, and when my program ends it shows message: press D to display result in a window instead of console, and in code:
if (virtual_key == 0x44) {
HWND myWindow = myCreateWindFunc(/* data */);
}
That is I need to pack all the code for creating window into one function an then just call function on it with the data to fill it's controlls.
A console application can create child windows or dialog boxes using any related WinAPI function (MessageBox, DialogBox etc).
The only caveat is that the create function may require the handle of the console window. To obtain it, you could use the example here How To Obtain a Console Window Handle

Create child window in WM_CREATE, relevance of same thread?

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(...);

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);
}

The difference between the handle received in the WNDPROC window callback procedure vs the one returned by CreateWindow?

So i was wondering if there is any difference between the handle returned when creating the window using CreateWindow/CreateWindowEx, and the one that is passed as a parameter to the WNDPROC window callback procedure for the concerned window. The context for this question is that I need to use certain API functions that require a handle to the window, so I thought that instead of passing the handle received by the window callback procedures, I could just save a copy of the handle returned by CreateWindow once, and then use it for successive operations, in case both handles are the same.
Regards,
Devjeet
Be careful here, the window procedure is used by multiple instances of a window. The callback is determined by the value of WNDCLASSEX.lpfnWndProc so any CreateWindow/Ex() call that uses the same window class name uses the same callback. If you are doing this to map the callback to a class instance method then you first have to go through a thunk that maps the callback's hwnd argument to a class instance. Making a special case for WM_CREATE of course.
Yes they are the same, that's the whole point of having an HWND. Every window has only one HWND that identifies it within the system and remains valid until DestroyWindow is called with it. It is returned by CreateWindow(EX) and sent in with every message so you can use that as a unique identifier for your window, even if you create several windows of the same class.
But note that some messages are sent to the window procedure even before the CreateFunction returns, so if you use a global variable to hold your HWND:
HWND globalHwnd = NULL;
int main()
{
//...
globalHwnd = CreateWindow(...);
}
LRESULT WndProc(HWND hWnd, ...)
{
assert(hWnd == globalHwnd); //fail!
}
The assertion will fail because several messages such as WM_CREATE are sent before CreateWindow returns, so the global variable is not yet assigned.