Announcement

Collapse
No announcement yet.

Window Get ID problem

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

  • Window Get ID problem

    In the app below, Window Get ID will not return the Control ID of a label unless I include the %ss_notify as a style for the label.

    But Help says that %ss_notify will allow a label to receive %STN_CLICKED and %STN_DBLCLK notification messages. It doesn't say anything about needing %ss_notify for Window Get ID to work.

    Does anyone know more about this? What else does %ss_notify enable, or disable (by its absence)?

    And BTW, GetDlgCtrlID has the same result as Window Get ID - both require %ss_notify for the return value to be the control ID.

    Code:
    #Compile Exe
    #Dim All
    #Include "Win32api.inc"
    
    Global hDlg As Dword
    
    Function PBMain()
        Dialog New Pixels, 0, "My Dialog",,, 100,100, %WS_OverlappedWindow , To hDlg
        Dialog Set Icon hDlg, "face"
        Control Add TextBox, hDlg, 551, "Button",  10, 10, 50, 50
        Control Add Label, hDlg, 200, "Button",  70, 10, 10, 60, ' %ss_notify
        Control Set Color hDlg, 200, %White, %White
        Dialog Show Modal hdlg Call DlgProc()
    End Function
    
    ' Dialog Callback Function ===============================================================
    
    CallBack Function DlgProc() As Long
        'Console message list
        Static iMsgCount&
        CPrint Str$(iMsgCount&)+ " " + WinMsg(Cb.Msg)
        Incr iMsgCount&
    
        'Respond to messagess
        Static iCount&
        Dim Style As Long, iReturn As Long, hTemp As Dword, temp$
        Select Case Cb.Msg
            Case %WM_SetCursor
                Incr iCount
                Window Get Id Cb.WParam To iReturn
                'print:   control id + handle of window under mouse + dialog handle
                CPrint "SetCursor: " & Str$(iReturn) & " " & Str$(Cb.WParam) &  " " & Str$(hDlg)
                Select Case iReturn
                    Case 200
                        CPrint Str$(iCount) + " H-setcursor"
                End Select
        End Select
    End Function
    
    Sub CPrint (SOut As String)    'Semen Matusovski's CPrint code:
        Static hConsole As Long, cWritten As Long
        If hConsole = 0 Then AllocConsole: hConsole = GetStdHandle(-11&)
        WriteConsole hConsole, ByCopy sOut + $CrLf, Len(sOut) + 2, cWritten, ByVal 0&
    End Sub
    Last edited by Gary Beene; 6 Mar 2009, 02:02 PM.

  • #2
    >GetStdHandle(-11&)

    GetStdHandle (%STD_OUTPUT_HANDLE) is a little easier to understand, isn't it?

    Well, perhaps not this afternoon, but six months from now you will look at this code and be wondering what the heck "-11&" means....
    Michael Mattias
    Tal Systems (retired)
    Port Washington WI USA
    [email protected]
    http://www.talsystems.com

    Comment


    • #3
      What SS_NOTIFY does or does not do is immaterial to your question.

      It's what WINDOW GET ID does or does not do.

      However, if you are not over a control when WM_SETCURSOR notification message is sent, unless you added a Window ID yourself (in sample code you didn't) you should get back zero.

      (Add ID: SetWindowLong hWnd, %GWL_ID, idvalue)
      Last edited by Michael Mattias; 6 Mar 2009, 02:12 PM.
      Michael Mattias
      Tal Systems (retired)
      Port Washington WI USA
      [email protected]
      http://www.talsystems.com

      Comment


      • #4
        Michael,

        Yes, and on my website examples I use the named constants. It's always a better way to go for production or long-lived code.

        Today, I just had the -11 code handy and used it.


        On the question of Window Get ID vs %ss_notify:

        Since GetDlgCtrlID and Window Get ID both give the same result - won't work without %ss_notify - I had not focussed on Window Get ID as the culprit.

        In WINDOW, Help says "The WINDOW statement may be used with any type of window in your program, including a Control or Dialog", which didn't leave much room to wonder if it should work.

        Did you mean to hint that I missed something in the Help on WINDOW?

        It would seem that whatever is the problem with my code, it's affecting two windows functions, not a problem with just one.

        Comment


        • #5
          Mouse 101:

          The label control (when not using the SS_NOTIFY style) is considered a non-user input control. The label control is actually of the STATIC window class (which also includes the PB Graphic control, Image Control, Icon control).

          When a window class is Static like this, Windows treats the control as if it does not exist as far as the mouse is concerned. The mouse is viewed as moving over the parent dialog, rather than the control.

          This means the WM_SETCURSOR message is being generated for the Dialog and not the control.

          Basically Windows treats the Label control like it does not exists to the mouse, so WM_SETCURSOR and other mouse related messages won't be generated for the Label.

          This is why WINDOW GET ID returns zero (the dialog has no ID).

          Here is some code which demonstrates this. It even subclasses the label controls to see if they get WM_SETCURSOR (this message is a forwarded message, where the control forwards it to the parent to let it set the cursor first).

          Code:
          #COMPILE EXE
          #DIM ALL
          #INCLUDE "Win32api.inc"
          GLOBAL hDlg AS DWORD
          GLOBAL StaticWndProc AS DWORD
          FUNCTION PBMAIN()
              DIALOG NEW PIXELS, 0, "My Dialog",,, 300,100, %WS_OVERLAPPEDWINDOW , TO hDlg
              DIALOG SET ICON hDlg, "face"
              CONTROL ADD TEXTBOX, hDlg, 551, "Button",  10, 10, 50, 50
              CONTROL ADD LABEL, hDlg, 200, "",  70, 10, 70, 60  ', %WS_CHILD or %WS_VISIBLE or %ss_notify
              CONTROL SET COLOR hDlg, 200, %BLACK, %WHITE
              CONTROL ADD LABEL, hDlg, 300, "SS_NOTIFY",  160, 10, 70, 60 , %WS_CHILD OR %WS_VISIBLE OR %SS_NOTIFY
              CONTROL SET COLOR hDlg, 300, %BLACK, %WHITE
              LOCAL hCtrl&
              CONTROL HANDLE hDlg, 200 TO hCtrl&
              StaticWndProc=SetWindowLong(hCtrl&, %GWL_WNDPROC, CODEPTR(SubClassProc))
              CONTROL HANDLE hDlg, 300 TO hCtrl&
              StaticWndProc=SetWindowLong(hCtrl&, %GWL_WNDPROC, CODEPTR(SubClassProc))
              DIALOG SHOW MODAL hdlg CALL DlgProc()
          END FUNCTION
          ' Dialog Callback Function ===============================================================
          CALLBACK FUNCTION DlgProc() AS LONG
              'Console message list
              SELECT CASE CB.MSG
                  CASE %WM_SetCursor
                      LOCAL iReturn AS LONG
                      WINDOW GET ID CB.WPARAM TO iReturn
                      IF CB.WPARAM=CB.HNDL THEN
                           DIALOG SET TEXT hDlg, "Mouse Over Dialog"
                      ELSE
                           IF iReturn=551 THEN DIALOG SET TEXT hDlg, "Mouse Over TextBox"
                      END IF
              END SELECT
          END FUNCTION
          FUNCTION SubClassProc(BYVAL hWnd&, BYVAL Msg&, BYVAL wParam&, BYVAL lParam&) AS LONG
               SELECT CASE Msg&
                    CASE %WM_SETCURSOR
                         DIALOG SET TEXT hDlg, "Mouse Over Label"
                    CASE ELSE
               END SELECT
               FUNCTION=CallWindowProc(StaticWndProc, hWnd&, Msg&, wParam&, lParam&)
          END FUNCTION
          Last edited by Chris Boss; 6 Mar 2009, 02:41 PM.
          Chris Boss
          Computer Workshop
          Developer of "EZGUI"
          http://cwsof.com
          http://twitter.com/EZGUIProGuy

          Comment


          • #6
            Gary,

            It would be better for your CPrint() function to also have the wParam and lParam values in the output, - then you may have spotted the problem immediately.
            I use similar code to CPrint() in my apps and tend to output function name and all parameters (plus any additional data), it's great for debugging with "real time" info.
            kgpsoftware.com | Slam DBMS | PrpT Control | Other Downloads | Contact Me

            Comment


            • #7
              Kev,

              Yes, it's a good idea. I was actually doing that in my "real" test code. I just cut the code down so I wouldn't feel like I was posting a book. I could see the results, I just couldn't find any documentation that led to me expect those results!

              Chris,
              Thanks for the information. What you told me is one of the reasons I curse windows almost daily - information that comes piece meal - usually from the hands of someone helping out, rather than from any documentation. It would seem to me that the action of a static control (label) with %ss_notify would have gotten more lines of documentation than what MSDN wrote:

              "Sends the parent window STN_CLICKED, STN_DBLCLK, STN_DISABLE, and STN_ENABLE notification messages when the user clicks or double-clicks the control."
              Michael,
              And yes, %ss_notify is just a value. It's what the controls do with the value that is the mystery to solve.

              Having gone back and read the static control and mouse sections as MSDN, I still didn't see anything that would have forewarned me of this specific problem.

              I know I can't expect documentation to tell me everything I need to know, but exact response of each and every common control seems like a reasonable expectation.

              Especially now that the world has been programming with messages for a very long time, I'm always surprised that "gotchas" (or got me's, to be exact) are all over the documentation. Every time I have to ask a question on the forum, that I think MS should have documented, it irks me. It takes my time and your time - which is probably replicated by thousands? of programmer every day!

              Comment


              • #8
                You are missing my point, Gary.

                The point is, the documentation for WINDOW GET ID says it will return something. It is not qualified as to when you may call it or with what kind of control handle is required, in fact the doc says...
                Remarks
                The WINDOW statement may be used with any type of window in your program, including a Control or Dialog...
                If you are passing a valid window or control handle to WINDOW GET ID and you are NOT getting back the ID of that control, then either WINDOW GET ID is broken or the documentation is in error. Pick one.

                MCM
                Michael Mattias
                Tal Systems (retired)
                Port Washington WI USA
                [email protected]
                http://www.talsystems.com

                Comment


                • #9
                  When a window class is Static like this, Windows treats the control as if it does not exist as
                  far as the mouse is concerned. The mouse is viewed as moving over the parent dialog, rather than
                  the control.
                  Chris, your post really does not explain what is going on here.

                  The behaviour of a control is largely determined by how its window procedure is coded and to a lesser
                  extent its class styles. The return values of certain window management and creation messages also
                  play a key role. This means that a control does not have to belong to the Static class to exhibit the
                  behaviour Gary is seeing.

                  The key to all of this is the WM_NCHITTEST and WM_SETCURSOR messages.

                  The WM_SETCURSOR message is one of those messages in Windows(OS) that bubbles up the window hierarchy.

                  The values returned by DefWindowProc or the values a programmer chooses to return when the
                  WM_NCHITTEST message is received determines how a window behaves in response to mouse actions.
                  A return value of HTTRANSPARENT makes the window invisible to mouse actions. HTCLIENT means the mouse
                  is over the client area of the window and that it will process mouse actions.

                  First, let us look at what happens when the mouse is moved over a label that has the SS_NOTIFY style.
                  Note: in this and the second case, the mouse is not captured.

                  Note: Window procedure in the diagrams refers to the actual window procedure that is registered for
                  the class(Static aka label and dialog), not the obfuscation added by the dialog engine and DDT.

                  To understand the diagrams, read them as the following example for the first one:

                  The operating system(OS) sends the WM_NCHITTEST message to the window procedure for the label.
                  The window procedure then returns a value of HTTRANSPARENT.

                  Case 1: label(SS_NOTIFY)

                  The operating system sends the WM_NCHITTEST message to the label.
                  Code:
                                OS                 
                                |                  
                               \|/                 
                          WM_NCHITTEST(message)  
                                |
                          Label Window procedure
                                | 
                          HTTRANSPARENT(return value)
                  The OS then sends the message to the underlying window, the parent dialog, in this case.

                  Code:
                                OS                   
                                |                    
                               \|/                   
                          WM_NCHITTEST(message)    
                                |
                          Dialog Window procedure
                                | 
                          HTCLIENT(return code)
                  The OS then sends WM_SETCURSOR message to the dialog.

                  Code:
                                  OS                      
                                  |                       
                                 \|/                      
                            WM_SETCURSOR(message)       
                                  |
                           Dialog Window procedure
                                  |
                              FALSE(return value)  
                                  | 
                            DefWindowProc  <--- sets the cursor the registered 
                                                class cursor(IDC_ARROW)
                  Case 2: label(~SS_NOTIFY)

                  The following simplified diagram shows what happens when the mouse is moved over a
                  label that does not have the SS_NOTIFY style.

                  The operating system sends the WM_NCHITTEST message to the label.
                  Code:
                                OS                 
                                |                  
                               \|/                 
                          WM_NCHITTEST(message)  
                                |
                          Label Window procedure
                                | 
                          HTCLIENT(return code)
                  The OS then sends WM_SETCURSOR message to the label.

                  Code:
                                      OS                      
                                      |                       
                                     \|/                      
                                WM_SETCURSOR(message)
                                      |
                               Label Window procedure
                                      |
                                FALSE(return value)  
                                      | 
                                 DefWindowProc  <--- before processing the message, 
                                      |              DefWindowProc passes it to the
                                      |              parent(the dialog) of the label.
                                     \|/                                                                                                                                             
                               WM_SETCURSOR(message)
                                      |
                              Dialog Window procedure   
                                      |
                     _________________|_________________________
                    |                                           |
                    |                                           |
                  FALSE(return value)                         TRUE(return value)
                      |                                         |
                  DefWindowProc <---+                     DefWindowProc <---+ 
                                    |                                       |
                  sets the cursor the registered         does no further processing. This means that
                  class cursor for labels(IDC_ARROW)     a call to the SetCursor functions will set
                                                         the shape of the cursor over the label.

                  Please note, it is a coincidence that the registered class cursors for the dialog
                  class(#32770) and the static class are both the same(IDC_ARROW).


                  By the way, I started working on the post I promised on messages, but had to put it on hold
                  because Phoenix3.0 is taking up all my time.
                  Last edited by Dominic Mitchell; 6 Mar 2009, 07:06 PM.
                  Dominic Mitchell
                  Phoenix Visual Designer
                  http://www.phnxthunder.com

                  Comment


                  • #10
                    Thanks Dominic,

                    I forgot about the WM_NCHITTEST message!

                    If WM_NCHITTEST returns back %HTTRANSPARENT then Windows will treat the window like it does not exist (transparent) and all mouse (and cursor) messages get passed through to the window (or dialog) behind it.

                    The Static control is obviously returning %HTTRANSPARENT when the %SS_NOTIFY style is not used.

                    One could override this, simply by returning something else in WM_NCHITTEST in the subclass routine.

                    To demonstrate this, I redid the example I posted and I processed the %WM_NCHITTEST message. The code reverses the behavior of the Label control. The one without %SS_NOTIFY will generate the WM_SETCURSOR message and the one with %SS_NOTIFY will not.

                    Code:
                    #COMPILE EXE
                    #DIM ALL
                    #INCLUDE "Win32api.inc"
                    GLOBAL hDlg AS DWORD
                    GLOBAL StaticWndProc AS DWORD
                    GLOBAL hLabel1 AS LONG, hLabel2 AS LONG
                    FUNCTION PBMAIN()
                        DIALOG NEW PIXELS, 0, "My Dialog",,, 300,100, %WS_OVERLAPPEDWINDOW , TO hDlg
                        DIALOG SET ICON hDlg, "face"
                        CONTROL ADD TEXTBOX, hDlg, 551, "Button",  10, 10, 50, 50
                        CONTROL ADD LABEL, hDlg, 200, "",  70, 10, 70, 60  ', %WS_CHILD or %WS_VISIBLE or %ss_notify
                        CONTROL SET COLOR hDlg, 200, %BLACK, %WHITE
                        CONTROL HANDLE hDlg, 200 TO hLabel1
                        CONTROL ADD LABEL, hDlg, 300, "SS_NOTIFY",  160, 10, 70, 60 , %WS_CHILD OR %WS_VISIBLE OR %SS_NOTIFY
                        CONTROL HANDLE hDlg, 300 TO hLabel2
                        CONTROL SET COLOR hDlg, 300, %BLACK, %WHITE
                        LOCAL hCtrl&
                        CONTROL HANDLE hDlg, 200 TO hCtrl&
                        StaticWndProc=SetWindowLong(hCtrl&, %GWL_WNDPROC, CODEPTR(SubClassProc))
                        CONTROL HANDLE hDlg, 300 TO hCtrl&
                        StaticWndProc=SetWindowLong(hCtrl&, %GWL_WNDPROC, CODEPTR(SubClassProc))
                        DIALOG SHOW MODAL hdlg CALL DlgProc()
                    END FUNCTION
                    ' Dialog Callback Function ===============================================================
                    CALLBACK FUNCTION DlgProc() AS LONG
                        'Console message list
                        SELECT CASE CB.MSG
                            CASE %WM_SetCursor
                                LOCAL iReturn AS LONG
                                WINDOW GET ID CB.WPARAM TO iReturn
                                IF CB.WPARAM=CB.HNDL THEN
                                     DIALOG SET TEXT hDlg, "Mouse Over Dialog"
                                ELSE
                                     IF iReturn=551 THEN DIALOG SET TEXT hDlg, "Mouse Over TextBox"
                                END IF
                        END SELECT
                    END FUNCTION
                    FUNCTION SubClassProc(BYVAL hWnd&, BYVAL Msg&, BYVAL wParam&, BYVAL lParam&) AS LONG
                         SELECT CASE Msg&
                              CASE %WM_NCHITTEST
                                   IF hWnd&=hlabel2 THEN
                                        FUNCTION=%HTTRANSPARENT
                                   ELSE
                                        FUNCTION=%HTNOWHERE
                                   END IF
                                   EXIT FUNCTION
                              CASE %WM_SETCURSOR
                                   DIALOG SET TEXT hDlg, "Mouse Over Label"
                              CASE ELSE
                         END SELECT
                         FUNCTION=CallWindowProc(StaticWndProc, hWnd&, Msg&, wParam&, lParam&)
                    END FUNCTION
                    Chris Boss
                    Computer Workshop
                    Developer of "EZGUI"
                    http://cwsof.com
                    http://twitter.com/EZGUIProGuy

                    Comment


                    • #11
                      Code:
                      ' add a DECLARE of convenience, subject to limitations below: 
                      DECLARE FUNCTION ChildWindowFromPointAPI LIB "USER32.DLL" ALIAS "ChildWindowFromPoint" _
                              (BYVAL hwndParent AS DWORD, BYVAL pt AS POINTAPI) AS DWORD
                      ....
                      
                        LOCAL Pt AS POINTAPI, hCtrl AS LONG, ctrlId AS LONG 
                      
                        CASE  %WM_SETCURSOR (or whenever) 
                           GetCursorPos     pt 
                           ScreenToClient   CBHNDL, pt 
                           hCtrl          = ChildWindowfromPointApi (CBHNDL, pt) ' See notes
                           IF ISTRUE hCtrl THEN 
                               IF hCtrl = CBHNDL THEN 
                                  ' cursor is within screen boundaries, but not over a control 
                               ELSE
                                    CtrlId = GetDlgCtrlId (hCtrl)     ' control ID 
                               END IF 
                           ELSE 
                              cursor is not within the boundaries of screen 'CBHNDL'
                              which can occur if the mouse has been captured and dragged off. 
                           END IF
                      Use of this DECLARE requires PBCC 4+ or PB/WIN 8+ (support for multiple procedures with shared ALIAS).

                      If older compiler - or you just feel like it - you can use this declare (included in Win32API.INC) and this call:
                      Code:
                       
                      DECLARE FUNCTION ChildWindowFromPoint LIB "USER32.DLL" ALIAS "ChildWindowFromPoint" _ 
                              (BYVAL hwndParent AS DWORD, BYVAL x AS LONG, BYVAL y AS LONG) AS DWORD
                      
                           .......
                      
                          hCtrl = ChildWindowFromPoint (CBHNDL, pt.x, pt.y)
                      Use ChildWindowFromPointEx() function to ignore disabled and/or invisible and/or transparent child controls.

                      MCM
                      Michael Mattias
                      Tal Systems (retired)
                      Port Washington WI USA
                      [email protected]
                      http://www.talsystems.com

                      Comment

                      Working...
                      X