Author Topic: WM_CLOSE vs WM_DESTROY  (Read 13328 times)

Don57

  • Guest
WM_CLOSE vs WM_DESTROY
« on: February 16, 2013, 04:29:14 AM »
I was reading the answers to RuiLoureiro post, by dedndave and qWord about using WM_DESTROY to close handles etc. I'm not sure if I've got it right. From what I gathered WM_DESTROY is used for cleanup and WM_CLOSE is used to close child windows. Don't child windows close automatically when the parent window is closed.

      .ELSEIF uMsg==WM_DESTROY
           
          INVOKE ReleaseDC, hGlobal_hWnd, hdc 
          INVOKE DeleteObject,hBrush1
          INVOKE HeapFree, hProcessHeap, 0, lp_HeapAlloc
          INVOKE DestroyWindow,hGlobal_hWnd
          INVOKE PostQuitMessage,NULL
          xor eax,eax
   

jj2007

  • Member
  • *****
  • Posts: 9635
  • Assembler is fun ;-)
    • MasmBasic
Re: WM_CLOSE vs WM_DESTROY
« Reply #1 on: February 16, 2013, 04:49:00 AM »
WM_CLOSE allows you to decline shutdown, e.g. with a MsgBox "are you really sure?"

RuiLoureiro

  • Member
  • ****
  • Posts: 819
Re: WM_CLOSE vs WM_DESTROY
« Reply #2 on: February 16, 2013, 04:54:21 AM »
I was reading the answers to RuiLoureiro post, by dedndave and qWord about using WM_DESTROY to close handles etc. I'm not sure if I've got it right. From what I gathered WM_DESTROY is used for cleanup and WM_CLOSE is used to close child windows. Don't child windows close automatically when the parent window is closed.

      .ELSEIF uMsg==WM_DESTROY
           
          INVOKE ReleaseDC, hGlobal_hWnd, hdc 
          INVOKE DeleteObject,hBrush1
          INVOKE HeapFree, hProcessHeap, 0, lp_HeapAlloc
          INVOKE DestroyWindow,hGlobal_hWnd
          INVOKE PostQuitMessage,NULL
          xor eax,eax
 
               Yes it is exactly what i understood: when we get  WM_DESTROY
               we
                     INVOKE ReleaseDC, hGlobal_hWnd, hdc 
                     INVOKE DeleteObject,hBrush1
                     ...
                     etc.
                and not when we get WM_CLOSE !
 :biggrin:   

meanwhile:   why you  use « INVOKE DestroyWindow,hGlobal_hWnd» AGAIN
                      when the MSG = WM_DESTROY ? Is it to destroy other windows ?
                     

MichaelW

  • Global Moderator
  • Member
  • *****
  • Posts: 1209
Re: WM_CLOSE vs WM_DESTROY
« Reply #3 on: February 16, 2013, 06:22:27 AM »
The WM_CLOSE notification is sent when the user attempts to close the window, typically by clicking the close button on the title bar or selecting the Close command on the window menu (typically accessed by clicking the application icon at the left end of the title bar). The default handling of WM_CLOSE, as carried out by the default window procedure, is to call the DestroyWindow function.

Well Microsoft, here’s another nice mess you’ve gotten us into.

dedndave

  • Member
  • *****
  • Posts: 8823
  • Still using Abacus 2.0
    • DednDave
Re: WM_CLOSE vs WM_DESTROY
« Reply #4 on: February 16, 2013, 06:56:34 AM »
when the user clicks on a close box, the window is sent WM_SYSCOMMAND with wParam = SC_CLOSE
the lower 4 bits of wParam are used internally by the OS, and may be any value
so, the SC_CLOSE command could actually be any of 16 values (0F060h to 0F06Fh)

normally, we do not intercept this message - it is allowed to fall through to DefWindowProc
the default processing that occurs is a resulting WM_CLOSE message being generated

if your WndProc function has no code to handle WM_CLOSE, it should fall through to DefWindowProc
the default processing includes DestroyWindow, which destroys a window and all its' children
if you handle WM_CLOSE, you can prevent the close by exiting WndProc with EAX = 0 (rather than DefWindowProc)
actually, the value in EAX may not be too critical   :P
the point is, no call to DestroyWindow is made unless you call it or exit via DefWindowProc

the call to DestroyWindow actually removes the window from the screen
then, it sends the window a WM_DESTROY message
more specifically, it repeats this for the top window, then for each child window
this seems backwards, but notice that when WM_DESTROY code is executed, any child windows still exist

when a window receives a WM_DESTROY message, it has already been removed from the screen
as qWord mentioned in the other thread, this is the time to perform clean-up
some of the more important things are destroying any GDI object handles and freeing any allocated memory
notice that no more WM_PAINT messages will be received, so it is safe to destroy things like bitmap handles
you might think of WM_DESTROY as the "opposite" of WM_CREATE   :P

for the top-level (main) window, you should call PostQuitMessage to signal process termination
this actually places a message in the queue, signaling the message loop to terminate
the next time GetMessage is called in the message loop, it will return EAX = 0
this is generally used as an indicator to terminate the process


things are a little different when a user logs off or shuts down
you really don't have to worry about things like GDI handles, because they will all be destroyed
you may, however, want to write some last bit of data to a file or perhaps signal a device
you can even prevent the user log off or shut down, although it normally isn't considered courteous

WM_QUERYENDSESSION is sent to all applications to "ask permission" to end the session
WM_ENDSESSION is sent to applications, indicating that they are being terminated

the OS sends WM_QUERYENDSESSION to all top-level windows
again, we normally allow this to fall through to DefWindowProc
or - you can return TRUE to allow shut down to continue
if any application returns FALSE (0), shut down is aborted
however, applications that returned TRUE will still receive a WM_ENDSESSION message
the ShutdownBlockReasonCreate function should be used to prevent or delay shut down
if you have some brief code to execute, you don't need to call the function
you simply perform it before returning from WM_QUERYENDSESSION

as i mentioned, no need to DestroyWindow or PostQuitMessage or anything, really
the application will be terminated and all handles will be destroyed and any memory allocations will be freed

console applications have no message pump
but, they do receive notification in the way of control events
you can call SetConsoleCtrlHandler to set the address of a handler routine
the notifications are
CTRL_CLOSE_EVENT - the user is closing the console window
CTRL_LOGOFF_EVENT - the user is logging off
CTRL_SHUTDOWN_EVENT - the user is shutting down

RuiLoureiro

  • Member
  • ****
  • Posts: 819
Re: WM_CLOSE vs WM_DESTROY
« Reply #5 on: February 16, 2013, 07:15:43 AM »
Very well Dave  ;)

Meanwhile you could say something about PostQuitMessage. Why to put it ?
What to do with the parameter that we give in that message ?

dedndave

  • Member
  • *****
  • Posts: 8823
  • Still using Abacus 2.0
    • DednDave
Re: WM_CLOSE vs WM_DESTROY
« Reply #6 on: February 16, 2013, 07:25:16 AM »
you simply put an exit code (most of us generally return 0)
in DOS days, we used this code in batch files to indicate status (ERRORLEVEL batch commands)
that still works, too   :biggrin:
but, it can be retreived in other apps by calling GetExitCodeProcess
this might be done if your process creates a child process and wants a "return status"

you should avoid using a return value of STILL_ACTIVE (103h)
that value is used as an error value in GetExitCodeProcess to indicate that a process is still running

as i mentioned, when you call PostQuitMessage, a message is placed in the message queue
the exit code is placed in the wParam member of the MSG structure
it is good practice to pass the value when you call ExitProcess

Code: [Select]
    INVOKE  ExitProcess,msg.wParam

RuiLoureiro

  • Member
  • ****
  • Posts: 819
Re: WM_CLOSE vs WM_DESTROY
« Reply #7 on: February 16, 2013, 07:45:00 AM »
Dave,
     very well !
     
     Now, suppose we call   ProcX  (in line X) of our application.
     And our ProcX create show ... a window and enter into a msg loop.
     What happen ?

Don57

  • Guest
Re: WM_CLOSE vs WM_DESTROY
« Reply #8 on: February 16, 2013, 07:59:03 AM »
There is one part I am still in the dark about is the DefWindowProc written by the coder or is it part of the OS.



In my code at the bottom of my WndProc loop I have as a fall through

   .ELSE

                  INVOKE DefWindowProc,hWnd,uMsg,wParam,lParam      
                   ret

It seems to work fine I just assumed it was a windows call

dedndave

  • Member
  • *****
  • Posts: 8823
  • Still using Abacus 2.0
    • DednDave
Re: WM_CLOSE vs WM_DESTROY
« Reply #9 on: February 16, 2013, 07:59:14 AM »
Rui,
i am not sure i understand what you are asking
but, a single message loop handles messages for all windows of a process

now, if you are refering to creating a process....
that process continues to run, even if the process that created it is terminated

dedndave

  • Member
  • *****
  • Posts: 8823
  • Still using Abacus 2.0
    • DednDave
Re: WM_CLOSE vs WM_DESTROY
« Reply #10 on: February 16, 2013, 08:04:00 AM »
Don,
yes - DefWindowProc is a system call
it provides default processing for all messages that aren't handled by your WndProc
to describe exactly what it does would be difficult, as its' behaviour varies from message to message
you would want to look up the specific message and see what it says about default processing

for certain messages and in some cases, i may want to execute some code, then exit via DefWindowProc
or - even execute DefWindowProc, then execute some special code (rare)

notice, that if you allow DefWindowProc, it returns a value in EAX that should be returned by your WndProc

for dialog boxes using a private class, DefDlgProc should be used
for dialog boxes using a system class, you generally return 0

RuiLoureiro

  • Member
  • ****
  • Posts: 819
Re: WM_CLOSE vs WM_DESTROY
« Reply #11 on: February 16, 2013, 08:07:50 AM »
There is one part I am still in the dark about is the DefWindowProc written by the coder or is it part of the OS.



In my code at the bottom of my WndProc loop I have as a fall through

   .ELSE

                  INVOKE DefWindowProc,hWnd,uMsg,wParam,lParam      
                   ret

It seems to work fine I just assumed it was a windows call
                     It is an API from OS to process messagens we dont process.
It looks fine.

RuiLoureiro

  • Member
  • ****
  • Posts: 819
Re: WM_CLOSE vs WM_DESTROY
« Reply #12 on: February 16, 2013, 08:14:54 AM »
Rui,
i am not sure i understand what you are asking
but, a single message loop handles messages for all windows of a process

now, if you are refering to creating a process....
that process continues to run, even if the process that created it is terminated
              Well suppose we create our main window which has his own message loop.
Now when we click one button we call ProcX that creates another window of another class and then it enters into a second msg loop. This second loop is not the first. What happen ? Are you saying all the messages are posted into the first window ?

dedndave

  • Member
  • *****
  • Posts: 8823
  • Still using Abacus 2.0
    • DednDave
Re: WM_CLOSE vs WM_DESTROY
« Reply #13 on: February 16, 2013, 08:15:25 AM »
here is a "template" WndProc
notice that it does not handle WM_CLOSE
and that it is for the main window, as it does handle WM_DESTROY by calling PostQuitMessage

this is my preference - there are other methods
but, it allows the code for each message to control the return value differently
and, the value returned in EAX from DefWindowProc is passed to the RET
Code: [Select]
WndProc PROC    hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM

    mov     eax,uMsg
    .if eax==WM_CREATE

        ;create code

        xor     eax,eax          ;return 0

    .elseif eax==WM_DESTROY
        INVOKE  PostQuitMessage,NULL
        xor     eax,eax          ;return 0

    .else
        INVOKE  DefWindowProc,hWnd,uMsg,wParam,lParam

    .endif
    ret

WndProc ENDP

dedndave

  • Member
  • *****
  • Posts: 8823
  • Still using Abacus 2.0
    • DednDave
Re: WM_CLOSE vs WM_DESTROY
« Reply #14 on: February 16, 2013, 08:17:53 AM »
              Well suppose we create our main window which has his own message loop.
Now when we click one button we call ProcX that creates another window of another class and then it enters into a second msg loop. This second loop is not the first. What happen ? Are you saying all the messages are posted into the first window ?

a single message loop handles all messages for all windows in that thread
you can create any number of windows in a thread, and the messages are all dispatched by 1 loop

however, if you create another thread, with its' own window(s) and own loop, those are seperate

EDIT: corrected "process" to "thread" per qWord