If a window is closed (like with sending WM_CLOSE), are the destructors of objects called?
I followed my source code with a break point in that situation, but the compiler doesn't seem to pass through my destructor.
Is the program closed without calling any destructors?
Normally, not, unless your WindowProc makes it so.
The Window class (e.g. CWnd in ;FC and CWindow in ATL) are distinct entities from the OS' concept of a window (I'll denote as HWND). They have different lifetimes, but they can be "coupled" together using the WNDPROC.
IIRC, MFC will delete CView-derived classes, but not most of the CWindow-derived. Also, ATL's CWindow, by itself won't be destroyed, as it is by default only a one-way attachment (i.e. attaching a CWindow to a HWND usually doesn't subclass the window).
Most of the time, calling the destructor is by another mechanism:
CDialog foo;
foo.DoModal();
When the dialog is closed, the scope where foo is declared will be exited and foos destructor will be called.
Similary, closing the main window will cause the application to exit, tearign down instances on that way.
I'm not too sure I understand, but let's say you've got a window setup with a typical WndProc and you're pumping messages with something akin to:
while (GetMessage(&msg, hwnd, 0, 0) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
When the window finishes (processes WM_DESTROY, after WM_CLOSE posts is handled and called DestroyWindow), this loop will end, and you'll continue normal execution.
In other words, the window isn't anything too special, but while it's up you're pretty much stuck in this loop. You get the same cleanup as always.
It depends on what the program does after the windows is closed. If it exits normally (by returning control from main()) - then yes, the destructors will get called, but only of stack-allocated and global objects. If it calls TerminateProcess() they will definitely not get called.
The objects in Windows (windows, dialogs, controls etc) are separate and distinct from the C++ objects in your program which wrap them. A window or dialog being closed will not delete a C++ object in your program which happens to be associated with it by way of an m_Hwnd member variable.
To put it in MFC terms, think of it this way - if closing a dialog destroyed the CDialog object associated with it, how could you then retrieve the CDialog DDX data associated with the (small d) dialog's controls?
Related
On MSDN website, I found following:
Calling SetWindowLongPtr with the GWLP_WNDPROC index creates a
subclass of the window class used to create the window. An application
can subclass a system class, but should not subclass a window class
created by another process. The SetWindowLongPtr function creates the
window subclass by changing the window procedure associated with a
particular window class, causing the system to call the new window
procedure instead of the previous one. An application must pass any
messages not processed by the new window procedure to the previous
window procedure by calling CallWindowProc. This allows the
application to create a chain of window procedures.
Does this mean, that every time I call SetWindowLongPtr with GWLP_WNDPROC, new subclass will be created, or is Windows smart enough to create subclass only once if same procedure is passed multiple times as parameter?
The term "subclass" is conceptual in the winapi. It was originally designed back in 1983 to target the C language. Which does not have any support for classes of course.
1983 was an important year in software development, that's when objected-oriented programming started to take flight. That's when Bjarne Stroustrup renamed his "C with Classes" to C++. And when Xerox released their Smalltalk-80 implementation to anybody who wanted a copy. Given Smalltalk's focus on message passing, it is likely to have been a strong inspiration to the Windows designers.
So while the winapi could not be purely objected-oriented, it certainly got a whiff of the technique. RegisterClass() function is most obvious, acts like a base class that gives any window "object" created from that class the same behavior. The window procedure specified with WNDCLASS.lpfnWndProc acts like a virtual method that can be overridden.
So a "subclass" of the class registered with RegisterClass() merely overrides the lpfnWndProc function. You do that with SetWindowLongPtr(), you have to bring the new function yourself. You do have to call the "base" function like you would commonly do when you override a virtual function in a C++ program.
Not the only way to do it. The SubWindowSubclass() function is a helper function to get it right. The DefSubclassProc() function helps you call the "base class". Recommended.
I have seen some examples on the internet where buttons were created under WM_CREATE and I have done some projects where creating "some" buttons such as Start/Stop buttons or Text Fields had to be created under MainWindow and not under WM_CREATE.
Is there any reason for chosing/difference/benefit of the choice of one over other when we can chose between these two?
I don't know anything about the Win32Gui library in particular, but I've used plenty of Win32 wrapper libraries and even written one myself.
Handling the WM_CREATE message (which is sent to a window after it is created) is the typical way of creating dynamic child windows such as button controls. This would be the same regardless of whether you're working directly with the Win32 API or using a wrapper library. The only difference might be how that wrapper library expects you to handle the message. For example, in MFC, you would override a member function of the window class called OnWmCreate.
But you really can create child windows anywhere in the code. You aren't forced to do it in response to WM_CREATE. You could do it in response to WM_KEYDOWN if you wanted. The only requirement is that you must have already created the parent window (because you must pass a valid handle to the parent window when creating the child window).
It sounds to me like the MainWindow you're talking about is the constructor method for your MainWindow class (a C++ object that models a Win32 window). Depending on the design of the framework, this may or may not be a valid place to create child windows. It depends on that above-stated requirement: whether the underlying Win32 window represented by the C++ object has already been created and whether you have a valid handle to it available inside of the constructor body.
Some frameworks implement a two-phase style of construction for window objects. What I mean by that is that the class constructor creates an instance of a C++ object, and then you need to call a second member function (e.g. Create) to create the Win32 window represented by the C++ object. In cases like this, you cannot create child windows inside of the parent window's constructor because the parent window has not yet been created and you do not have a valid handle to use when creating the children.
Other frameworks might require that you specify all of the necessary parameters to create the underlying Win32 window when creating your C++ object, and then the constructor will take care of creating both the C++ object and the underlying Win32 window (e.g. by calling the CreateWindow function). If the creation of either fails, an exception will be thrown. Otherwise, you can be sure that you have access to a valid window handle inside the body of your derived class's constructor.
However, even if this single-phase approach to construction describes the design of your wrapper library, I would still suggest creating child windows in response to the WM_CREATE message, rather than in the constructor. But that's just a personal preference and a matter of individual style.
Different people have different ideas about how much work should be done inside of a constructor. My personal litmus test is that, after the constructor has run, you should have a valid, fully usable object on which any member functions can be called. I don't much care for two-phase construction, because I don't like the interface complexity that introduces of requiring the consumer to not only create the object, but also call a Create or Init method. I don't consider child windows to be an integral part of the parent, though, so I say that their creation belongs elsewhere than in the parent's constructor.
I cannot understand why you say
I have done some projects where creating "some" buttons such as Start/Stop buttons or Text Fields had to be created under MainWindow and not under WM_CREATE.
There is no reason why you would have to create child windows in the constructor and you would be unable or it would not work to do so in response to the WM_CREATE message.
I have a legacy code. The code works like this: after an Event1 has happened it creates an window object ( inherited from CWindowImpl class ) in the heap. After an Event2 has happened it applies changes made in the window, closes it by calling DestroyWindow() and frees the memory in the heap by calling delete.
This code is buggy because it deletes the window object before all the messages for this window are processed. How to know for sure when it's safe to call delete for the window object?
The only solution i found out is to override OnFinalMessage and call delete this there. I don't like it because it must be guaranteed that the object is created in the heap only. Are there better ideas?
Thank you.
Having done DestroyWindow, you have the handle of the window destroyed, so it is safe to use delete on the window class pointer. No late messages can arrive at that point.
OnFinalMessage comes from inner WTL's handler for WM_NCDESTROY message.
Why the constructor of my derived CWinApp should be invoked before main function starts?
Why can't it be something like:
int WinMain()
{
CMainFrame* pMainFrame = new CMainFrame;
// etc ...
}
I'm looking for the technical reason that forces this behavior.
Edit:
To make clearer - If I'm using win32 API without MFC the main window is created inside WinMain so what is the difference?
Basically, that's because the MFC designers decided to provide the application entry point (WinMain(), not main()) in the library itself, so users would not have to write one.
The application's initialization and termination logic is then relocated to the InitInstance()and ExitInstance() methods of the instance of a user-provided CWinApp-derived singleton. This instance has to exist before WinMain() runs, because it calls the aforementioned methods (and Run() to enter the message loop) and uses it to store state (like the nCmdShow argument it receives).
Defining the CWinApp-derived instance in the global scope is an easy way to ensure it does exist by the time WinMain() runs.
This article has additional details on what happens under the hood when an MFC application starts.
According to msdn, when I get a CWnd* with CWnd::FromHandle,
The pointer may be temporary and should not be stored for later use.
What is meant by "later use" is not clear to me. Is it only the scope of the current method?
As far as I know, there is no GC in Win32!
MFC maintains a number of handle maps, from HWND to CWnd, HDC to CDC etc, which are stored in the thread state. Each handle map contains a permanent map and temporary map - permanent entries are added when you call a method such as CWnd::Create or CDC::Attach, while temporary entries are created when you call FromHandle on a handle that doesn't have a permanent entry.
Temporary entries are cleaned up during idle processing (in CWinApp::OnIdle), so they can only safely be used while processing the current message. As soon as you return to the message loop, or enter another modal loop (e.g. by calling DoModal) then they may be deleted.
FromHandle is basically used for getting a transient reference to an already existing window object. MFC stores these references in an internal structure called a temporary handle map (a handle map is a map of Windows HWNDs to MFC CWnd objects used by MFC to make Win32 calls to manipulate the actual Windows window the MFC object corresponds to). In order to avoid the number of objects in this structure from growing beyond all bounds, items are deleted from the handle map during MFC's idle loop processing.
As you may have guessed, there is also a permanent handle map that won't have this automatic clean up behavior. If you need to get a CWnd object that doesn't put its HWND reference in the temporary handle map you can call FromHandlePermanent().
-Ron
Based on the same MSDN description, I would assume that this means that if no CWnd is attached to the hWnd provided as an object, it will create a temporary CWnd which probably gets destroyed once something goes out of scope, or a destructor elsewhere is called, or a CWnd is explicitly created for the hWnd in question. So if you already have a CWnd created, you should be OK, otherwise you will probably need to be very careful with storing the pointer you receive.
Typically they only want you to use this handle with in the scope of your function. And not to store it as a class field where you reference it through out the life of your object.