I've got a relatively simple Window class. I've created a window, associated my this, etc etc. Now later, I've thrown an exception to indicate a problem. When I call MessageBox to pop up the error, the program crashes, because it's attempting to call my Window Proc. Now, I mean, admittedly, I failed SRP here and just writing a brief self-owning HWND class will solve this problem, as the window wasn't cleaned up properly. However, I'm really mystified as to why it's trying to process Window messages in my MessageBox call- the owner parameter is nullptr. Any suggestions?
Edit: If I call DestroyWindow appropriately, then now the message box just doesn't show up, although the app doesn't crash. It only works if I manually remove this from the window, so that if the proc were called it would forward to DefWindowProc, and then DestroyWindow. I mean, I thought that if you called MessageBox without an owner, then it would just work, regardless of what you had done to other windows in the system.
What is happening here is that there are still messages for the dud window in the queue when you show the message box. The message box runs a modal window message pump and dispatches the troublesome messages. Remember that all windows created from the same thread share a single message queue.
I have no idea how to fix your problem but that's what's going on.
By the way, passing a null owner isn't a great idea as it will result in your message box not being minimised when your main app is minimised, for example.
Related
I have created a modeless dialog as a main window, but the window procedure isn't being sent WM_INITDIALOG messages.
Here's what I've done.
Created a dialog template using Visual Studio's resource editor, and
set its class name to a custom class.
Used WNDCLASSEX to register the class, window procedure, as well as
some icons and brush etc.
Used CreateDialog() with the last two parameters set to NULL, (Parent
window, and window procedure).
Created the message loop using IsDialogMessage(), TranslateMessage()
and DispatchMessage();
Returned DefDlgProc() in the window procedure as the default if no
messages were processed.
I can't think of anything else significant. Everything works well except for not receiving WM_INITDIALOG messages.
I've done it this way so the app minimises to the task bar, and I can have a menu if needed.
So my first question is, Have I done anything stupid?
Secondly, should I expect to receive WM_INITDIALOG messages using this system?
And if not, what is a good way to initialise say a combobox with strings.
(I've looked at things like WM_ACTIVATE, WM_ACTIVATEAPP etc, but nothing seems appropriate.
And the combobox isn't created yet at WM_CREATE.)
Thanks in advance.
I realised the answer shortly after posting.
As mentioned in the comments above, it's a window procedure, not a dialog procedure, so I shouldn't have been trying to initialize child windows within the procedure.
So I initialized them outside the procedure, after creating the dialog box and before the message loop.
All the dialog features are working as expected, but it's a main window that can have a menu and minimizes to the taskbar.
I'm using and improving on an open source MFC work-alike library called FFC. Sometimes the library associates the wrong window handle to a dialog object, which means the C++ object can't be found later when the correct handle is looked up. In particular, this is happening when the application opens its root window, which is a dialog that it opens with a call to DoModal.
In its DoModal function, the FFC library uses a... "surprising" way to attach the handle to the dialog object. It stashes the "this" pointer in a global variable and hooks a function to be called on all window messages before calling the DialogBox function. This hook function it registered in term assumes the handle from the first message it receives is the handle for the window in the global variable, and attaches that handle to it.
Sometimes, this works. Often - and I don't know if it's because of intrusive things done by the McAfee scanner on my work computer, or because my program starts from a console window, or something else - many unrelated messages will be captured before a message actually meant for the modal dialog comes through.
At first I thought it was because FFC wasn't making sure the message it looks for is "WM_CREATE". I added this check, but it didn't fix the problem. Turns out one or more of the spurious messages are also WM_CREATE messages! Before it gets the one for the real dialog, the first WM_CREATE it receives is a handle for a window with blank window text and rectangle 0,0-0,0.
So is this really the correct or canonical way to get the handle for a modal dialog? It seems unreliable. (Note that because the dialog is modal, you can't use the return value from CreateWindowEx because the DialogBox function doesn't return until the modal dialog is closed.) Is this really how MFC does it? Is there a better way? Could I associate some data with the dialog or look for data that should be associated with it to make sure I have the right window handle? (For instance checking the template parameter passed to the dialog box call, if I can get that back from the handle somehow.)
I am sure this is published in books, but MFC sets a windows hook (WH_CBT) and then looks for the HCBT_CREATEWND code in the hook to marry the C++ object to the HWND.
I have a thread that send update messages to a window, I use ::SendMessage() and ::PostMessage() APIs.
I go in and out of multiple dialogs and register the dialog that I am currently in with the thread via the window handle (m_hWnd). If I exit all the way out, the main application window doesn't handle these messages. For that reason I don't register that window. At this point the thread will have the handle of an older window which now doesn't exist.
Is it okay if it sends messages to that non-existent window? I am assuming it should not do any harm but wanted to double check.
No, it is not ok to post a message to a deleted window.
There is no guarantee noone will set up shop at that address just after the previous tennant is gone.
If you use a NULL window handle, you'll post a thread message to the current threads message queue. SendMessage as far as I could google shoul be a no-op.
Might be harmless enough.
Now, we get tricky:
Under specific cicumstances it does not matter, pre-supposing well-behaved applications.
A message like WM_NULL should not make anything happen.
A window-message you globally registered in your application using RegisterWindowMessage, if you can guarantee none of your applications windows created in the meantime will choke on it.
I have to deal with a nasty MS Windows application that quits doing its job as soon as it loses focus. My question is, how can I trick this application somehow to believe that it is still in focus, although it really is not?
My thoughts are:
Is it possible to suppress the corresponding "WM" message from just this application?
Can I send a fake message to this window that it acts like it is in focus?
Sending the WM_ACTIVATE message works for some apps:
SendMessage(hWnd, WM_ACTIVATE, WA_CLICKACTIVE, hWnd);
Leaving the last parameter as NULL might work too.
It might be a simple question, but I don't know where to start the search for the answer. How do I create two individual windows interface in one application using native winapi? Do I put two CreateWindow() functions using same HINSTANCE? What if I want a login screen windows and the content page such that login screen comes first, and after I press the button, the login screen is destroyed, and the content page appears. How do I do such trick?
I was thinking of using DestroyWindow and then CreateWindow inside the button click message. However, this would mean the main while loop (for translate/dispatch msg) in WinMain will exit its loop and cause the whole program to exit. Another way is to pre-create it in WinMain, but how would I notify the WinMain if the button was clicked and enter the second loop instead of exiting the program?
You're over-thinking it. To create two windows, call CreateWindow twice. It's just that simple.
Calling DestroyWindow does not cause your program to exit its message pump. Calling PostQuitMessage is what does that. So don't do that.
When the button is clicked, destroy the one window and create the other. There are no tricks. The message pump delivers messages to all windows (unless you're doing it wrong by explicitly requesting messages for one window, but you shouldn't do that).