News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

PopUp Window

Started by RuiLoureiro, August 27, 2008, 09:10:52 PM

Previous topic - Next topic

RuiLoureiro

jj2007,
          Thanks
         
«When your child window receives a WM_MOVE or WM_SIZE message,
you can tell Windows to simply ignore it:

CASE WM_SIZE
   return 0 »
   
CASE WM_MOVE
   return 0 

This was exactly what i did ( in Chil10 ).
But as it didnt work i had doubts.

If i dont pass this messages to DefWindowProc, and process it

CASE WM_SIZE
   return 0
CASE WM_MOVE
   return 0  »

the window moves ( when we put the mouse on the title bar, take it with
left button and move ).

I dont know if subclassing works or not. My doubt is this: if i registered
WndProcW as a Child window procedure and that Child window is not a system
class window (it should not be processed by internal default procedures)
- it is not a control - why to create an intermediate procedure -
SubClassProc, for example - to process WM_MOVE & WM_SIZE if i can process
it directly in WndProcW ?
----------------------------------------------------------------------------------------------------------------
WndProcW proc hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
SWITCH uMsg
    CASE WM_SIZE
             return 0

     CASE WM_MOVE
            return 0
;..............................
      CASE WM_PAINT
            invoke   PasMsgPr, hWnd, _pPasMsg
            return 0       
      CASE WM_CLOSE
            invoke   DestroyWindow,  hWnd
            return 0
      CASE WM_DESTROY
     
            return 0
     ENDSW

         invoke  DefWindowProc, hWnd, uMsg, wParam, lParam
         ret
WndProcW endp


Rui

jj2007

Quote from: RuiLoureiro on September 01, 2008, 06:25:16 PM
why to create an intermediate procedure -
SubClassProc, for example - to process WM_MOVE & WM_SIZE if i can process
it directly in WndProcW ?

Because those messages are for your main window, not for the children. Test it with a Debug window...
Subclassing is not that difficult, and an essential technique in Windows.

MichaelW

Rui,

I did not add a title bar to the popup window because to me a title bar implies a movable window. You could add another static control to the window and use it to display a title. You could control the color of the title by handling the WM_CTLCOLORSTATIC message in the popup window procedure. Because there would be more than one static control, you would need to check the control handle in lParam to ensure that you were setting the color of the correct control.

Also, you could make the CreatePopup procedure size the window and static controls to fit the message, similar to the way a Message Box sizes itself. To determine the on-screen size of the message string see GetTextExtentPoint32.


eschew obfuscation

RuiLoureiro

MichaelW,
           If you didnt do an example with a title bar, hummm, i guess it doesnt seem to be
           an easy task. May be jj can help me. Or you
           Many thanks to you, MichaelW !

JJ2007,
           I have some doubts, jj. Let me put it in this way:

           1. About this question:
              «why to create an intermediate procedure - SubClassProc, for example -
                 to process WM_MOVE & WM_SIZE if i can process it directly in WndProcW ?»
               ( WndProcW is the Child window procedure)

               
              You gave this answer:
              Because those messages are for your main window, not for the children.

              Ok, it may be for the main window. Then
              «why i need to create an intermediate procedure - SubClassMain, for example -
               to process WM_MOVE & WM_SIZE if i can process it directly in WndProc ?».
               ( WndProc is the main window procedure that i registered. It is not
               a system class procedure. )

          2. The documentation about WM_MOVE & WM_SIZE says this:

           ** The WM_MOVE message is sent after a window has been moved;
           ** The WM_SIZE message is sent to a window after its size has changed; 

             If they are sent AFTER it has been moved/changed what can we do in
             that time ? ISTBO that the child window is already in another position
             when we receive that message.

             If i process it in WndProc (in Child10), the window moves just as before.

         3. About Subclassing:
            «Subclassing is not that difficult, and an essential technique in Windows»

             It seems that i understood it. When we have a system procedure X that process
             messages in a way that we dont want, we give the address of another procedure Y
             in such a way that the system calls the procedure Y first. In this way, in Y
             we can process the messages that we dont want to pass to X. The messages that
             we dont want to process in Y we pass to X. It is made with SetWindowsLong, etc.

             Now, let me know where i am wrong.

             Many thanks to you, JJ
             
ISTBO = It seems to be obvious
Rui

PBrennick

Rui,
Look at GetWindowPlacement and SetWindowPlacement. You would use tthe first API to mionitor and the second one to restore if the window is moved.

I ike you too.
--Paul
The GeneSys Project is available from:
The Repository or My crappy website

MichaelW

#35
I modified my code to produce a single fixed-size, fixed-position popup window, with a title bar but without a close button. The popup window position is fixed within the client area of the main window, but since it is a child of the main window, it will move with the main window.

Edit: Provided a way to close the popup window.


; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    include \masm32\include\masm32rt.inc
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    .data
      hInst   dd          0
      hWnd    dd          0
      hwndPop dd          0
      _X      dd          0
      _Y      dd          0
      rc      RECT <>
      wcx     WNDCLASSEX  <>
      msg     MSG         <>
    .code
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
CreatePopup proc hParent:DWORD, pszTitle:DWORD, pszMessage:DWORD

    LOCAL hwnd:DWORD
    LOCAL hdc:DWORD
    LOCAL _x:DWORD, _y:DWORD
    LOCAL sz:_SIZE

    invoke GetDC, NULL
    mov hdc, eax

    mov edx, len(pszMessage)
    invoke GetTextExtentPoint32, hdc, pszMessage, edx, ADDR sz

    mov wcx.style,         CS_BYTEALIGNWINDOW
    mov wcx.lpfnWndProc,   OFFSET PopupProc
    mov wcx.cbClsExtra,    NULL
    mov wcx.cbWndExtra,    NULL
    m2m wcx.hInstance,     hInst
    mov wcx.hbrBackground, rv(GetStockObject, LTGRAY_BRUSH)
    mov wcx.lpszMenuName,  NULL
    mov wcx.lpszClassName, chr$("popup_class")
    mov wcx.hIcon,         rv(LoadIcon, NULL, IDI_APPLICATION)
    mov wcx.hCursor,       rv(LoadCursor, NULL, IDC_ARROW)
    mov wcx.hIconSm,       0

    invoke RegisterClassEx, ADDR wcx

    ;------------------------------------------------
    ; This code sizes the window to fit the message.
    ;------------------------------------------------

    invoke GetSystemMetrics, SM_CXFIXEDFRAME
    add eax, eax
    mov ecx, sz.x
    add ecx, 20
    add ecx, eax
    mov _x, ecx

    invoke GetSystemMetrics, SM_CYSIZE
    push eax
    invoke GetSystemMetrics, SM_CXFIXEDFRAME
    add eax, eax
    pop ecx
    add eax, ecx
    add eax, sz.y
    add eax, 8
    mov _y, eax

    invoke CreateWindowEx, NULL,
                           chr$("popup_class"),
                           pszTitle,
                           WS_VISIBLE or WS_CHILD or \
                           WS_BORDER or WS_CAPTION,
                           0, 0, _x, _y,
                           hParent, NULL,
                           hInst, NULL
    mov hwnd, eax

    invoke CreateWindowEx, 0,
                           chr$("STATIC"), pszMessage,
                           WS_CHILD or WS_VISIBLE or SS_LEFT,
                           10, 3, sz.x, sz.y, hwnd, 101,
                           hInst, NULL

    invoke ShowWindow, hwnd, SW_SHOWNORMAL
    invoke UpdateWindow, hwnd

    return hwnd

CreatePopup endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
PopupProc proc hwnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
    SWITCH uMsg

      CASE WM_MOVING

        invoke GetWindowRect, hwnd, ADDR rc

        mov edx, lParam
        mov eax, rc.left
        mov [edx].RECT.left, eax
        mov eax, rc.top
        mov [edx].RECT.top, eax
        mov eax, rc.right
        mov [edx].RECT.right, eax
        mov eax, rc.bottom
        mov [edx].RECT.bottom, eax

        return TRUE

      CASE WM_CLOSE

        invoke DestroyWindow, hwnd
        ret

      CASE WM_DESTROY

        invoke DestroyWindow, hwnd
        ret

    ENDSW

    invoke DefWindowProc, hwnd, uMsg, wParam, lParam

    ret
PopupProc endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
WindowProc proc hwnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
    SWITCH uMsg
      CASE WM_KEYDOWN
        SWITCH wParam
          CASE VK_F2
            .IF rv(IsWindow, hwndPop) == 0
              invoke CreatePopup, hwnd, chr$("Title"), chr$("Test message")
              mov hwndPop, eax
            .ENDIF
          CASE VK_F3
            invoke DestroyWindow, hwndPop
        ENDSW
      CASE WM_CLOSE
        invoke PostQuitMessage, NULL
      CASE WM_DESTROY
        invoke DestroyWindow, hwnd
    ENDSW
    invoke DefWindowProc, hwnd, uMsg, wParam, lParam
    ret
WindowProc endp
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
start:
; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««
    mov hInst, rv(GetModuleHandle, NULL)
    mov wcx.cbSize,        sizeof WNDCLASSEX
    mov wcx.style,         CS_HREDRAW or CS_VREDRAW \
                              or CS_BYTEALIGNWINDOW
    mov wcx.lpfnWndProc,   OFFSET WindowProc
    mov wcx.cbClsExtra,    NULL
    mov wcx.cbWndExtra,    NULL
    m2m wcx.hInstance,     hInst
    mov wcx.hbrBackground, rv(GetStockObject, WHITE_BRUSH)
    mov wcx.lpszMenuName,  NULL
    mov wcx.lpszClassName, chr$("test_class")
    mov wcx.hIcon,         rv(LoadIcon, NULL, IDI_APPLICATION)
    mov wcx.hCursor,       rv(LoadCursor, NULL, IDC_ARROW)
    mov wcx.hIconSm,       0

    invoke RegisterClassEx, ADDR wcx

    W = 400
    H = 300
    invoke GetSystemMetrics, SM_CXSCREEN
    shr eax, 1
    sub eax, W / 2
    mov _X, eax
    invoke GetSystemMetrics, SM_CYSCREEN
    shr eax, 1
    sub eax, H / 2
    mov _Y, eax

    invoke CreateWindowEx,  WS_EX_OVERLAPPEDWINDOW,
                            chr$("test_class"),
                            chr$("Test"),
                            WS_OVERLAPPED or WS_SYSMENU,
                            _X, _Y, W, H,
                            NULL, NULL,
                            hInst, NULL
    mov hWnd, eax
    invoke ShowWindow, hWnd, SW_SHOWNORMAL
    invoke UpdateWindow, hWnd
  msgLoop:
    invoke GetMessage, ADDR msg, NULL, 0, 0
    .IF eax != 0
      invoke TranslateMessage, ADDR msg
      invoke DispatchMessage, ADDR msg
      jmp   msgLoop
    .ENDIF
    exit msg.wParam

; «««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««««

end start

eschew obfuscation

RuiLoureiro

Paul,
           Thank you ! It seems i found one solution yesterday        

MichaelW,
           Today it is late. Tomorrow i will post something to you.
           I am studying your example.
           «single fixed-size, fixed-position popup window, with a title bar»
                is what i want.

           
           Many thanks to you
Rui

RuiLoureiro

MichaelW,
            First of all, many thanks for your work. You got the solution.

            I was reading a lot of stuff about message processing.
            I found WM_WINDOWPOSCHANGING in
           
            Platform SDK -> User Interface Services -> Windows User Interface -> Windowing ->
                Windows -> Windows Overviews -> Window Features
                ...
                Window Size and Position -> ... Size and Position Functions


«The system sends the WM_WINDOWPOSCHANGING message to a window whose size, position,
position in the z-order, or show state is about to change. This message includes a pointer
to a WINDOWPOS .... By setting the members of WINDOWPOS, an application can affect
the window's new size, position, and appearance.»


            If we set the flags member of WINDOWPOS to SWP_NOMOVE   
            it Retains the current position  and ignores the x and y parameters.

            It seems i found the solution. But it has problems !

            It is about this problems i want to ask you to you see why they happen, please.

            I attached Child12.zip (asm & exe) & Child13.zip (asm & exe).
            See WndProcW procedure (this is the child processor).

            In Child13 i used what you used (but not the STATIC)
            In Child12 i used WM_WINDOWPOSCHANGING.

            Try this:
                      . run Child12.exe and choose Child -> Open Child msg1
                      . click on client area
                      . took the window with the mouse and move
                      . click on title bar (press and release).
                        It closes the window (this is the question)

            What is happening ? Have you an idea. I would like to know besause
            i am trying to study this questions. The system sends CLOSE ?

            Thanks !

            EDIT: i saw your edit: F3
Rui


[attachment deleted by admin]

MichaelW

#38
I'm not sure yet why the window disappears, but WM_CLOSE is not being called. One thing I do see that could be a problem is that you are responding to a WM_PAINT message, but you are not doing the normal processing for WM_PAINT, where you start with BeginPaint and end with EndPaint.

Edit:

The problem appears to be somewhere in WndProcW. If I substitute the code from child13, then the problem goes away. When experimenting with API code it's generally best to keep your code as small and simple as possible. Large, complex code can hide problems that would be easy to see in small, simple code. This is one of the reasons why I use SWITCH CASE in window procedures.

eschew obfuscation

RuiLoureiro

MichaelW,
          Many thanks for your answers.
          I hadnt time to come here until now.
         
          The window disappears because the system Hide it, no ? I think. But how and why ?
          I converted that code to switch/case and i made WndProcZ.
          Now we can experiment with WndProcW or WndProcZ (see "mov wc.lpfnWndProc, ?").
          If we use WndProcW we can use PasMsgPr or PrPasMsg.
          PrPasMsg uses BeginPaint, and WndProcZ uses it also.
          I am experimenting SetTimer too ( comment it, put ; )
          All this is in child15.zip below.
          The window procedures where the messages are processed
                i call it processors (if they process than processor)
.

          One word to jj2007: Thanks for your help.

Rui


[attachment deleted by admin]

MichaelW

The problem is just a small logical error in your code, in a non-obvious detail.

WndProcZ            proc    hWnd:DWORD, iMsg:DWORD, wParam:DWORD, lParam:DWORD

                    SWITCH iMsg
                    CASE WM_WINDOWPOSCHANGING

                    cmp     _fnomove, 1
                    je      short @F

                    mov     _fnomove, 1
                    jmp     _eWndProcZ
                   
@@:                     mov     edx, lParam         ; pointer to WINDOWPOS struc

                        ;-------------------------------------------
                        ; Set SWP_NOMOVE flags bit WITHOUT changing
                        ; the value of the other bits.
                        ;-------------------------------------------

                        or [edx].WINDOWPOS.flags, SWP_NOMOVE
                       
                        ;mov     [edx].WINDOWPOS.flags, SWP_NOMOVE


I didn't test this, but I think the direct problem is with clearing the SWP_SHOWWINDOW bit.

And in case it's not clear what I mean when I refer to the flags bits, like many flags in API programming the flags member is "bitmapped". If you check the values of the SWP_ constants, you will see that each one is a power of 2, so each constant is the value of a single bit.
eschew obfuscation

RuiLoureiro

#41
MichaelW,
          Once more, many thanks for your Help.
          I passed the problem to you because i dont know this details and
          you have much experience about this type of problems and you could help me.
          To me it is not obvious but i think it is to you.
          In fact, it solves the problem and we dont need _fnomove flag.


          My problem was this: «...like many flags in API programming
                                   the flags member is "bitmapped"»

          And if it is "bitmapped" we should use OR not mov.

          Did i do some other errors, MichaelW. Please, see Child16.
          rsrc file is somewhere above.
          I removed SetTimer, but see it also.
         
          And thank you MichaelW  :U

          EDIT: i updated Child16
Rui


[attachment deleted by admin]

MichaelW

The only problem I see so far is:

In WndProc, the WM_CLOSE handler would normally call the DestroyWindow function and pass it the handle of the window, and the WM_DESTROY handler would normally call the PostQuitMessage function.
eschew obfuscation

RuiLoureiro

Hi MichaelW,
             Thank you for your answer.
             
             I saw this today and i corrected my file Child16.
             I searched MSDN for WM_CLOSE, WM_DESTROY and WM_COMMAND this afternoon.
             About WM_CLOSE they say
             «If an application processes this message, it should return zero.
                   If we pass it to DefWindowProc it calls DestroyWindow by default.»

             DestroyWindow sends WM_DESTROY.

             I updated Child16, but this time i used SetTimer. Am i using it
             correctly ? What to do to cancel it before the timeout value? KillTimer, no ?
Rui

MichaelW

Because the system calls the timer procedure, it must have a specific set of parameters, as shown here.

As far as I know the only two ways to cancel a running timer are to destroy the timer with the KillTimer function, or replace the timer with the SetTimer function.
eschew obfuscation