Announcement

Collapse
No announcement yet.

GetMessage TranslateMessage Again

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • GetMessage TranslateMessage Again

    In the past I asked about why my MessagePump was not working for a Dialog/Window (or rather would work as long as the mouse was over the window) but would stop looping until there was a message to be gotten.

    The rough answer was that I was mixing DDT and SDK commands, but since then I still have the same problem. Below is an example of each for comparison

    DDT Modal ---> Works as advertised
    Code:
    #COMPILE EXE
    #DIM ALL
    
    '------------------------------------------------------------------------------
    '   ** Includes **
    '------------------------------------------------------------------------------
    #IF NOT %DEF(%WINAPI)
        #INCLUDE "WIN32API.INC"
    #ENDIF
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Constants **
    '------------------------------------------------------------------------------
    %IDD_DIALOG1 = 101
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Declarations **
    '------------------------------------------------------------------------------
    DECLARE CALLBACK FUNCTION ShowDIALOG1Proc()
    DECLARE FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Main Application Entry Point **
    '------------------------------------------------------------------------------
    FUNCTION PBMAIN()
        ShowDIALOG1 %HWND_DESKTOP
    END FUNCTION
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** CallBacks **
    '------------------------------------------------------------------------------
    CALLBACK FUNCTION ShowDIALOG1Proc()
    
        SELECT CASE AS LONG CBMSG
            CASE %WM_INITDIALOG
                ' Initialization handler
    
            CASE %WM_NCACTIVATE
                STATIC hWndSaveFocus AS DWORD
                IF ISFALSE CBWPARAM THEN
                    ' Save control focus
                    hWndSaveFocus = GetFocus()
                ELSEIF hWndSaveFocus THEN
                    ' Restore control focus
                    SetFocus(hWndSaveFocus)
                    hWndSaveFocus = 0
                END IF
    
            CASE %WM_COMMAND
                ' Process control notifications
                SELECT CASE AS LONG CBCTL
    
                END SELECT
        END SELECT
    END FUNCTION
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Dialogs **
    '------------------------------------------------------------------------------
    FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
        LOCAL lRslt AS LONG
        LOCAL hDlg  AS DWORD
        DIALOG NEW hParent, "Dialog1", 70, 70, 201, 121, %WS_POPUP OR %WS_BORDER _
            OR %WS_DLGFRAME OR %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
            %WS_MINIMIZEBOX OR %WS_MAXIMIZEBOX OR %WS_CLIPSIBLINGS OR _
            %WS_VISIBLE OR %DS_MODALFRAME OR %DS_3DLOOK OR %DS_NOFAILCREATE OR _
            %DS_SETFONT, %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR _
            %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
        DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt                            '<--- Works as advertised
        FUNCTION = lRslt
    END FUNCTION
    '------------------------------------------------------------------------------
    DDT Modeless ---> Works as advertised
    Code:
    #COMPILE EXE
    #DIM ALL
    
    '------------------------------------------------------------------------------
    '   ** Includes **
    '------------------------------------------------------------------------------
    #IF NOT %DEF(%WINAPI)
        #INCLUDE "WIN32API.INC"
    #ENDIF
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Constants **
    '------------------------------------------------------------------------------
    %IDD_DIALOG1 = 101
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Declarations **
    '------------------------------------------------------------------------------
    DECLARE CALLBACK FUNCTION ShowDIALOG1Proc()
    DECLARE FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Main Application Entry Point **
    '------------------------------------------------------------------------------
    FUNCTION PBMAIN()
        ShowDIALOG1 %HWND_DESKTOP
    END FUNCTION
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** CallBacks **
    '------------------------------------------------------------------------------
    CALLBACK FUNCTION ShowDIALOG1Proc()
    
        SELECT CASE AS LONG CBMSG
            CASE %WM_INITDIALOG
                ' Initialization handler
    
            CASE %WM_NCACTIVATE
                STATIC hWndSaveFocus AS DWORD
                IF ISFALSE CBWPARAM THEN
                    ' Save control focus
                    hWndSaveFocus = GetFocus()
                ELSEIF hWndSaveFocus THEN
                    ' Restore control focus
                    SetFocus(hWndSaveFocus)
                    hWndSaveFocus = 0
                END IF
    
            CASE %WM_COMMAND
                ' Process control notifications
                SELECT CASE AS LONG CBCTL
    
                END SELECT
        END SELECT
    END FUNCTION
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Dialogs **
    '------------------------------------------------------------------------------
    FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
        LOCAL lRslt AS LONG
        LOCAL hDlg  AS DWORD
        LOCAL MessagePumping AS LONG
        DIALOG NEW hParent, "Dialog1", 70, 70, 201, 121, %WS_POPUP OR %WS_BORDER _
            OR %WS_DLGFRAME OR %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
            %WS_MINIMIZEBOX OR %WS_MAXIMIZEBOX OR %WS_CLIPSIBLINGS OR _
            %WS_VISIBLE OR %DS_MODALFRAME OR %DS_3DLOOK OR %DS_NOFAILCREATE OR _
            %DS_SETFONT, %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR _
            %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
        DIALOG SHOW MODELESS hDlg, CALL ShowDIALOG1Proc TO lRslt
        DO                                                                     '<--- Works as advertised
             DIALOG DOEVENTS 0 TO MessagePumping
        LOOP WHILE MessagePumping
        FUNCTION = lRslt
    END FUNCTION
    '------------------------------------------------------------------------------
    Sdk -------> Stops Looping until there is a Message to be gotten.
    Code:
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    ' Declares
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    #COMPILE EXE
    #INCLUDE "WIN32API.INC"
    '----------------------------------------------------------------------
    DECLARE FUNCTION WndProc (BYVAL hWnd AS LONG, BYVAL wMsg AS LONG, _
                              BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
    DECLARE FUNCTION MessagePump() AS LONG
    
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    ' Program entrance
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    FUNCTION WINMAIN (BYVAL hInst AS LONG, BYVAL hPrevInstance AS LONG, _
                      BYVAL lpszCmdLine AS ASCIIZ PTR, BYVAL nCmdShow AS LONG) AS LONG
      LOCAL hDlg AS LONG, hCtl AS LONG, hFont AS LONG, _
            wc AS WndClassEx, szClassName AS ASCIIZ * 80
    
      hFont = GetStockObject(%ANSI_VAR_FONT)
    
      szClassName      = "MyClassName"
      wc.cbSize        = SIZEOF(wc)
      wc.style         = %CS_HREDRAW OR %CS_VREDRAW
      wc.lpfnWndProc   = CODEPTR(WndProc)
      wc.cbClsExtra    = 0
      wc.cbWndExtra    = 0
      wc.hInstance     = hInst
      wc.hIcon         = LoadIcon  (%NULL, BYVAL %IDI_APPLICATION)
      wc.hCursor       = LoadCursor(%NULL, BYVAL %IDC_ARROW)
      wc.hbrBackground = %COLOR_3DFACE + 1
      wc.lpszMenuName  = %NULL
      wc.lpszClassName = VARPTR(szClassName)
      wc.hIconSm       = LoadIcon  (%NULL, BYVAL %IDI_APPLICATION)
      CALL RegisterClassEx (wc)
    
      hDlg = CreateWindowEx(%WS_EX_DLGMODALFRAME OR %WS_EX_CONTROLPARENT OR %WS_EX_WINDOWEDGE, "MyClassName", "Dialog1", _
                  %WS_POPUP OR %WS_VISIBLE OR %WS_CLIPSIBLINGS OR %WS_CAPTION OR _
                  %WS_SYSMENU OR %WS_THICKFRAME OR %WS_MINIMIZEBOX OR %WS_MAXIMIZEBOX OR _
                  %DS_3DLOOK OR %DS_NOFAILCREATE OR %DS_SETFONT OR _
                  %DS_MODALFRAME, _
                  (GetSystemMetrics(%SM_CXSCREEN) - 318) / 2, _
                  (GetSystemMetrics(%SM_CYSCREEN) - 233) / 2, _
                   318, 233, 0, 0, GetModuleHandle(""), BYVAL %NULL)
    
      ShowWindow hDlg, nCmdShow
      UpdateWindow hDlg
    
    
      FUNCTION = MessagePump
    END FUNCTION
    
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    ' Main Window procedure
    '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
    FUNCTION WndProc (BYVAL hWnd AS LONG, BYVAL wMsg AS LONG, _
                      BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
    
      SELECT CASE wMsg
         CASE %WM_CREATE
            'A good place to initiate things, declare variables,
            'create controls and read/set settings from a file, etc.
            '-------------------------------------------------------
    
         CASE %WM_COMMAND
            'Messages from controls and menu items are handled here.
            '-------------------------------------------------------
            SELECT CASE LOWRD(wParam)
               CASE %IDCANCEL
                  IF HIWRD(wParam) = %BN_CLICKED THEN
                     SendMessage hWnd, %WM_DESTROY, wParam, lParam
                     FUNCTION = 0 : EXIT FUNCTION
                  END IF
    
            END SELECT
    
         CASE %WM_CTLCOLORDLG
            SetBkColor wParam, GetSysColor(%COLOR_WINDOW)
            FUNCTION = GetStockObject(%NULL_BRUSH)
            EXIT FUNCTION
    
         CASE %WM_CTLCOLORBTN, %WM_CTLCOLOREDIT, %WM_CTLCOLORLISTBOX, %WM_CTLCOLORSTATIC
            ' wParam is handle of control's display context (hDC)
            ' lParam is handle of control
            ' Example on how to set colors to a specific control:
            '-----------------------------------------------------
            'IF lParam = GetDlgItem(hWnd, CtlId) THEN
            '   SetBkColor wParam, GetSysColor(%COLOR_INFOBK)
            '   SetTextColor wParam, GetSysColor(%COLOR_INFOTEXT)
            '   FUNCTION = GetSysColorBrush(%COLOR_INFOBK)
            '   EXIT FUNCTION
            'END IF
            '-----------------------------------------------------
    
         CASE %WM_DESTROY
            ' is sent when program ends - a good place to delete any created objects and
            ' store settings in file for next run, etc. Must send PostQuitMessage to end
            ' properly in SDK-style dialogs. The PostQuitMessage function sends a WM_QUIT
            ' message to the program's (thread's) message queue, and then WM_QUIT causes
            ' the GetMessage function to return zero in WINMAIN's message loop.
            '----------------------------------------------------------------------------
            PostQuitMessage 0
            FUNCTION = 0 : EXIT FUNCTION
    
         CASE %WM_SIZE
            IF wParam <> %SIZE_MINIMIZED THEN
               ' LOWRD(lParam) = width of dialog's client area
               ' HIWRD(lParam) = height of dialog's client area
               ' Example that resizes a control to dialog's client area:
               '------------------------------------------------------
               'LOCAL pt AS POINTAPI, rc AS RECT
               'GetWindowRect GetDlgItem(hWnd, CtlId), rc   'get control's position on screen
               'pt.x = rc.nLeft : pt.y = rc.nTop            'need left and top pos
               'ScreenToClient hWnd, pt                     'convert coordinates to client area
               'MoveWindow GetDlgItem(hWnd, CtlId), pt.x, pt.y, _
               '           LOWRD(lParam) - pt.x, HIWRD(lParam) - pt.y, %TRUE
            END IF
    
      END SELECT
    
      FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)
    END FUNCTION
    
    FUNCTION MessagePump() AS LONG
         LOCAL Msg AS tagMsg
         LOCAL PerformanceFrequency AS QUAD
         STATIC LastTime AS QUAD
         WHILE GetMessage(Msg, %NULL, 0, 0)<>0
              TranslateMessage Msg
              DispatchMessage Msg
              QueryPerformanceFrequency PerformanceFrequency
    #DEBUG PRINT "Hwnd = " + TRIM$(STR$(Msg.hwnd)) + SPACE$(5) _
              + "Message = " + TRIM$(STR$(Msg.message)) + SPACE$(5) _
              + "Wparam = " + TRIM$(STR$(Msg.wParam)) + SPACE$(5) _
              + "Lparam = " + TRIM$(STR$(Msg.lParam)) + SPACE$(5) _
              + "Time = " + FORMAT$(((1/(PerformanceFrequency) * (Msg.time - LastTime)) * 1000), "0.000000") + " MilliSeconds" + SPACE$(5) _
              + "X = " + TRIM$(STR$(Msg.pt.x)) + SPACE$(5) _
              + "Y = " + TRIM$(STR$(Msg.pt.y))
              LastTime = Msg.time
         WEND                                                        '<--- Why do I stop looping until the window gets a mouse or keyboard message????
         FUNCTION = Msg.wParam
    END FUNCTION
    Run each in debugger under "Animate" and do not move the mouse or touch the keyboard and you will see the loop stop looping.
    Engineer's Motto: If it aint broke take it apart and fix it

    "If at 1st you don't succeed... call it version 1.0"

    "Half of Programming is coding"....."The other 90% is DEBUGGING"

    "Document my code????" .... "WHYYY??? do you think they call it CODE? "

  • #2
    Stops Looping until there is a Message to be gotten.
    ...
    Run each in debugger under "Animate" and do not move the mouse or touch the keyboard and you will see the loop stop looping
    Correct; GetMessage does not return until there is a message. As documented.

    So what's the problem?
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]
    http://www.talsystems.com

    Comment


    • #3
      The difference is between GetMessage and PeekMessage. GetMessage waits until a message is available. PeekMessage returns immediately, even if no message is pending.

      Your SDK message loop is using GetMessage.

      Likely DDT's doevents is using PeekMessage so the DDT form of the message loop runs continuously. This is why it provides a parameter to define a SLEEP interval, otherwise the loop would hog CPU time.
      Chris Boss
      Computer Workshop
      Developer of "EZGUI"
      http://cwsof.com
      http://twitter.com/EZGUIProGuy

      Comment


      • #4
        Correct; GetMessage does not return until there is a message. As documented.

        So what's the problem?
        Did you even try testing the fully compilable example before answering?

        The debugger stops at the "WEND" line until I either mouse-over or keyboard or something. Now if it had stopped at the GetMessage then I would have been looking at what the docs clearly states that it does not return until it has a Message.

        In my example it does not even check, it just stops at WEND

        In my much bigger program, this is becoming a problem because the code stops execution, and I have to tell the user to "wiggle the mouse" (not very professional in my mind, this is not some old TV set that you smack on the side to make it work)
        Engineer's Motto: If it aint broke take it apart and fix it

        "If at 1st you don't succeed... call it version 1.0"

        "Half of Programming is coding"....."The other 90% is DEBUGGING"

        "Document my code????" .... "WHYYY??? do you think they call it CODE? "

        Comment


        • #5
          If the debugger highlights the last line actually executed and completed, then that would be correct. WEND would be executed and the next line to be executed would be the WHILE which also has the function GetMessage called in it, so that line is what is actually being executed.

          I don't use the PB debugger so I can't comment on how it works, but your code is actually waiting for the GetMessage to return.
          Chris Boss
          Computer Workshop
          Developer of "EZGUI"
          http://cwsof.com
          http://twitter.com/EZGUIProGuy

          Comment


          • #6
            I threw in a break on the line before WEND to see if its the last line or the line about to be executed. It turns out its the line about to be executed.

            I was watching my debug output and noticed this when the code stops at the WEND
            Code:
            Hwnd = 202724     Message = 49393     Wparam = 0     Lparam = 0     Time = 0.000000 MilliSeconds     X = 352     Y = 94
            Hwnd = 202724     Message = 49393     Wparam = 0     Lparam = 0     Time = 1.676191 MilliSeconds     X = 352     Y = 94
            Hwnd = 0    Message = 49387     Wparam = 1     Lparam = 0     Time = 4.055264 MilliSeconds     X = 1279     Y = 854
            Hwnd = 202596     Message = 275     Wparam = 1     Lparam = 0     Time = 8.210820 MilliSeconds     X = 354     Y = 92
            Ok I can account for 202724 because it is my Hwnd, I think I can account for Hwnd = 0 to be a message for any window that may be listening via (RegisterWindowMessages I think???)
            Where the heck 202596 came from and what its link to the loop not looping to check for a message? I have no clue. (Could be Koinky-Dink, but I doubt it)
            Engineer's Motto: If it aint broke take it apart and fix it

            "If at 1st you don't succeed... call it version 1.0"

            "Half of Programming is coding"....."The other 90% is DEBUGGING"

            "Document my code????" .... "WHYYY??? do you think they call it CODE? "

            Comment


            • #7
              GetMessage():
              hWnd
              [in] Handle to the window whose messages are to be retrieved. The window must belong to the calling thread. The NULL value has a special meaning:
              NULL
              GetMessage retrieves messages for any window that belongs to the calling thread and thread messages posted to the calling thread using the PostThreadMessage function.
              You are asking for all messages on your thread's queue. You can limit your the messages you get to only messages for the 'window of interest' by specifying that 'window of interest'

              If you get a mystery hwnd, you can ask about it:

              GetCLassName
              getWindowText
              GetParent (or better, GetWindow for %GW_OWNER)

              Windows does a lot of stuff by creating windows you never see.

              FWIW, message 275d (0x0113) = %WM_TIMER.
              Michael Mattias
              Tal Systems (retired)
              Port Washington WI USA
              [email protected]
              http://www.talsystems.com

              Comment


              • #8
                FWIW, message 275d (0x0113) = %WM_TIMER.
                I kinda figured that too when I started looking at the message instead of the Hwnd. So I grabbed my handy-dandy calculator and a copy of WIN32API.inc and did a search for every occurrence of 275 and found nothing that instinctively made me wonder if that was the message.
                So I punched in 275 (Decimal) and clicked the Hex, and it showed 113 so again I searched, and sure enough %WM_TIMER = 113 so now I have to look at how %WM_TIMER message works. (At the moment I would not know cause I DESPISE programs that use a timer to look for an event, I would rather wait for the event and then check what it was than waste time looking for something that may never come)

                Anyways more :coffee: and reading to go and see if I can figure this out?:confused2:
                Engineer's Motto: If it aint broke take it apart and fix it

                "If at 1st you don't succeed... call it version 1.0"

                "Half of Programming is coding"....."The other 90% is DEBUGGING"

                "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                Comment


                • #9
                  (At the moment I would not know cause I DESPISE programs that use a timer to look for an event, I would rather wait for the event and then check what it was than waste time looking for something that may never come)
                  Don't disparge the use of the timer, Cliff. Timers have their use.

                  However, I can only reinforce what you are saying about using a timer to check for something which may never happen.... it's generally a waste of computer resources and using the CORRECT synchronization object - one which is signalled only when the 'event of interest' actually happens - will result in superior (yes that IS subjective) code.

                  (At least a timer is not as bad as looping on a test of a GLOBAL variable)
                  Michael Mattias
                  Tal Systems (retired)
                  Port Washington WI USA
                  [email protected]
                  http://www.talsystems.com

                  Comment


                  • #10
                    Don't disparge the use of the timer, Cliff. Timers have their use.
                    Agreed MCM, but outside of "Every couple of X cycles" (seconds, minutes hours or some given unit) check if "SOMETHING" (whatever "SOMETHING" may be) then Timer has a bad rep for being mis-used as a sort of "Poor-Mans" message-pump of sorts.)

                    Depending on the application, it could be beneficial (but HIGHLY detrimental years later if used outside the original intent)
                    Engineer's Motto: If it aint broke take it apart and fix it

                    "If at 1st you don't succeed... call it version 1.0"

                    "Half of Programming is coding"....."The other 90% is DEBUGGING"

                    "Document my code????" .... "WHYYY??? do you think they call it CODE? "

                    Comment


                    • #11
                      Using timers for other purposes is probably just a natural extension of Ye Olde Aphorism, "To the man who has only a hammer every problem looks like a nail."

                      The solution is obvious: Get some more tools!
                      Michael Mattias
                      Tal Systems (retired)
                      Port Washington WI USA
                      [email protected]
                      http://www.talsystems.com

                      Comment

                      Working...
                      X