Announcement

Collapse
No announcement yet.

Subclassing Controls

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

  • Subclassing Controls

    I'd appreciate some help with a subclassing query. I've got a very
    simple dialog with 20 edit boxes which I have subclassed in order
    to capture keyboard entries such as cursor down and return to
    move to the next edit control. I've done this with the following
    code:

    For N&=1 To 20
    Control Add TextBox, hDlg, N&, "", 150*DU#, (N&*17+3)*DU#, 25*8*DU#, 16*DU#
    Control Add Label, hDlg, N&+100, Str$(N&), 110*DU#, (N&*17+3)*DU#, 4*8*DU#, 16*DU#
    Control Handle hDlg, N& To TmpFldHandle&
    EditControlOrigProc = SetWindowLong(TmpFldHandle&,%GWL_WNDPROC,CodePtr(CursorControl))
    Next N&

    This works great and my Function CursorControl does the job perfectly.
    My problem is that I have added a listbox and tried to subclass that
    as follows:

    N&=21
    Control Add ListBox, hDlg, N&, Items(), 150*DU#, (N&*17+3)*DU#, 25*8*DU#, 40
    Control Handle hDlg, N& To TmpFldHandle&
    EditControlOrigProc = SetWindowLong(TmpFldHandle&,%GWL_WNDPROC,CodePtr(CursorControl))

    This crashes Windows nicely every time! Can anybody point out to
    me where I am going so hideously wrong. All the posts I have read
    on subclassing only deal with single controls on a dialog.

    Cheers, Nick



    ------------------

  • #2
    ' Based on ideas of Patrice Terrier & Lance Edmonds
    'This code is from Semen (modified slightly)
    Code:
    #COMPILE EXE
    #REGISTER NONE
    DEFLNG A-Z
    TYPE POINTAPI
      x AS LONG
      y AS LONG
    END TYPE
    TYPE tagMSG
      hwnd AS DWORD
      message AS DWORD
      wParam AS DWORD
      lParam AS DWORD
      time AS DWORD
      pt AS POINTAPI
    END TYPE
    
    DECLARE FUNCTION GetMessage LIB "USER32.DLL" ALIAS "GetMessageA" _
            (lpMsg AS tagMSG, BYVAL hwnd AS LONG, BYVAL wMsgFilterMin AS LONG,_
             BYVAL wMsgFilterMax AS LONG) AS LONG
    
    DECLARE FUNCTION SetWindowText LIB "USER32.DLL" ALIAS "SetWindowTextA" _
            (BYVAL hwnd AS LONG, lpString AS ASCIIZ) AS LONG
    
    DECLARE FUNCTION IsDialogMessage LIB "USER32.DLL" ALIAS "IsDialogMessageA" _
            (BYVAL hDlg AS LONG, lpMsg AS tagMSG) AS LONG
    
    DECLARE FUNCTION TranslateMessage LIB "USER32.DLL" ALIAS "TranslateMessage" _
            (lpMsg AS tagMSG) AS LONG
    
    DECLARE FUNCTION DispatchMessage LIB "USER32.DLL" ALIAS "DispatchMessageA" _
            (lpMsg AS tagMSG) AS LONG
    
    %WM_DESTROY       = &H2        'Window messages
    %WM_KEYDOWN       = &H100      'Window messages
    %WM_KEYUP         = &H101      'Window messages
    %WM_CHAR          = &H102      'Window messages
    %DS_CENTER        = &H0800&    'Dialog styles
    %WS_SYSMENU       = &H80000&   'Window styles
    %WS_TABSTOP       = &H10000&   'Window styles
    %CBS_DROPDOWNLIST = &H2&       'Combo Box sytles
    %NULL             = 0
    %FALSE            = 0
    
    GLOBAL Stop&
    GLOBAL Counter&
    
    CALLBACK FUNCTION hDlg_CB
       SELECT CASE CBMSG
          CASE %WM_DESTROY: STOP = 1
       END SELECT
    END FUNCTION
    
    FUNCTION PBMAIN()
       LOCAL Msg  AS tagMsg
       DIALOG NEW 0 ,"SubClass ?", 0, 0, 200, 100, %DS_CENTER OR %WS_SYSMENU TO hDlg
       CONTROL ADD LABEL,  hDlg, 101, "Label", 10, 5, 170, 12
       CONTROL ADD TEXTBOX,  hDlg, 201, "Edit control-1", 10, 25, 170, 12
       CONTROL ADD TEXTBOX,  hDlg, 202, "Edit control-2", 10, 45, 170, 12
       CONTROL ADD COMBOBOX, hDlg, 301,, 10, 65, 170, 100, %CBS_DROPDOWNLIST OR %WS_TABSTOP
       COMBOBOX ADD hDlg, 301, "Combo box": COMBOBOX SELECT hDlg, 301, 1
       DIALOG SHOW MODELESS hDlg CALL hDlg_CB
       WHILE GetMessage(Msg, %NULL, 0, 0)
          SELECT CASE Msg.message
             CASE %WM_KEYDOWN: SetWindowText hDlg, "WM_KEYDOWN / " + STR$(Counter&)
             CASE %WM_KEYUP  : SetWindowText hDlg, "WM_KEYUP / "   + STR$(Counter&)
             CASE %WM_CHAR   : SetWindowText hDlg, "WM_KEYCHAR / " + STR$(Counter&)
             CASE ELSE       : SetWindowText hDlg,  STR$(Counter&)
          END SELECT
          IF IsDialogMessage(hDlg, Msg) = %FALSE THEN  ' Don't touch Tab
             TranslateMessage Msg
             DispatchMessage Msg
          END IF
          INCR Counter&
          IF STOP <> 0 THEN EXIT DO
       LOOP
       MSGBOX "Times executed:" + STR$(Counter&)   
    END FUNCTION


    ------------------
    How long is an idea? Write it down.

    Comment


    • #3
      Nick;

      Your are getting a GPF because when you subclassed the listbox it is using the
      same callback as your edit controls, and the GPF is occuring because you are not
      passing the untrapped messages on to the origional proceedure for that
      class. One global "EditControlOrigProc" works for the 20 edit controls, because
      they are all derived from the same class. But as soon as you replaced with with the
      listbox origional proceedure, it fails, you see, no more origional proceedure for the
      20 edit controls!

      There are several ways to deal with it, but the two simple ways are...

      1. use two seperate callbacks, one for each control type
      2. use two globals, EditControlOrigProc and ListboxControlOrigProc and pass the appropiate one
      on to the default window handler. (use an ID to determine Listbox or Edit control)

      Anyway, hope this helps, got to run...

      Regards,
      Jules
      Best regards
      Jules
      www.rpmarchildon.com

      Comment


      • #4
        Jules, Thanks for that one, I'm up and running now

        Mike, Thanks for the post. I'd seen Semen's example elsewhere but
        not followed it as I'm using DDT with callbacks and found other
        examples of how to subclass the edit boxes in that scenario.
        Jules advice fitted in with how I had got the edit controls to
        work and i'd prefer to keep the code similar.

        One more question for one of you helpful coders! In searching the
        forum I've seen advice from the likes of Lance that I need to clean
        up the subclassing in the %WM_DESTROY message for the dialog. Whats
        the story there? Now that I have two subclassed controls do I need
        to release both?

        ------------------

        Comment


        • #5
          Yes... you reset the %GWL_WNDPROC CODEPTR() in the %WM_DESTROY handler in the control's subclass function. You need to do this for each subclassed control.

          If you subclass the dialog itself, you reset the CODEPTR() in the %WM_DESTROY handler in the dialog subclass function.

          In summary, if you subclass *anything*, you must unsubclass it during %WM_DESTROY in the aappropriate handler.


          ------------------
          Lance
          PowerBASIC Support
          mailto:[email protected][email protected]</A>
          Lance
          mailto:[email protected]

          Comment


          • #6
            Difficult to beleive that it's necessary to unsubclass in WM_DESTROY.
            a) new proc is static in memory during whole life of window.
            b) subclassing of one window doesn't effect other windows with the same class.
            Lance, can you give a link to MSDN or example with troubles ?



            ------------------
            E-MAIL: [email protected]

            Comment


            • #7
              We are dealing with instance-subclassing here, rather than superclassing.

              I believe the clean-up recommendations are documented in Rector/Newcomer... I'll check when I get back to the office.

              Regardless, it is "standard best practice" to clean up after yourself... a good strategy to avoid building "gotcha's" into your code. Classic example is GUI objects - the #1 source of memory leak problems in applications.

              If can you get into the habit of cleaning up properly, you will be doing yourself a favor in the long run.

              ------------------
              Lance
              PowerBASIC Support
              mailto:[email protected][email protected]</A>
              Lance
              mailto:[email protected]

              Comment

              Working...
              X