Announcement

Collapse
No announcement yet.

Subclassing

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

  • Subclassing

    I think I have it, can anyone tell me if this looks good, er, correct

    It works, it does exactly what i want it to do, allow hex input only basically (A-F,a-f, 0-9)
    Code:
    In WM_INITDIALOG of DialogProc
             ' Subclass the edit control
             Control Handle CbHndl, %IDTEXT1 To hEdit&
             gOldSubClassProc = SetWindowLong(hEdit&, %GWL_WNDPROC, CodePtr(SubClassProc))
    
    
    '-------------------------------------------------------------------------------
    Function SubClassProc(ByVal hWnd&, ByVal wMsg&, ByVal wParam&, ByVal lParam&) As Long
    Local NewChar As Asciiz * 2
    Local Y       As Long
    Local zText   As Asciiz * 13
    Local yMsg    As Long
    ' Process our messages in this subclass procedure
    Select Case wMsg&
        Case %WM_KEYDOWN
        Case %WM_KEYUP
        Case %WM_CHAR
             yMsg = LoWrd(wParam&) 'Actual ascii value of keystroke coming in
             If yMsg <> 8 And Len(St) = 12 Then Exit Function 'We don't want a MAC address longer than 12
             Select Case yMsg
                      Case 8 'BackSpace
                      Case 48 To 57 '0-9
                         St = St + Chr$(yMsg)
                      Case 65 To 70 'A-F
                         St = St + Chr$(yMsg)
                      Case 97 To 102 'a-f
                         St = St + UCase$(Chr$(yMsg))
                      Case Else
                           Exit Function
              End Select
    End Select
    ' Pass the message on to the original window procedure... the DDT engine!
    Function = CallWindowProc(gOldSubClassProc, hWnd&, wMsg&, wParam&, lParam&)
    End Function
    -------------
    Scott Turchin


    Scott Turchin
    MCSE, MCP+I
    http://www.tngbbs.com
    ----------------------
    True Karate-do is this: that in daily life, one's mind and body be trained and developed in a spirit of humility; and that in critical times, one be devoted utterly to the cause of justice. -Gichin Funakoshi

  • #2
    If you don't need the textbox for anything else, you could also set it to
    automatically convert all input to upper case letters with the following:
    (can e.g. be set when the text box is created)

    Code:
    CALL SetWindowLong(hEdit&, %GWL_STYLE, GetWindowLong(hEdit&, %GWL_STYLE) _
                                                           OR %ES_UPPERCASE)
    (or %ES_LOWERCASE for lower case letters only)

    Comment


    • #3
      A couple of points:

      1. Dont forget to remove your subclass procedure (restore the original DlgProc address) which is usually performed in the WM_DESTROY handler.

      2. There is not enough of your code to be sure, but it looks like you are building your string with "ST", but depending on how the user edits the label as it is typed (ie, it's possible to insert into the string using the mouse to change the insert point), but your "ST" string will be incorrectly built. IOW, it is better to capture the actual edit control text during %EN_CHANGE, that way your retrieved string is certain to be correct.

      3. If the keystroke is unwanted, it may be better to pass a NULL in the LOWRD() of WPARAM rather than totally discarding the %WM_CHAR event (which you currently do by skiping the CallWindowProc() function).


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

      Comment


      • #4
        I put the OR %ES_UPPERCASE in when I built the textbox, but I see your point! THat is what i want!!


        OK Yes, St is global and is the main string for doing the MAC address swap:

        I've got this in WM_DESTROY:

        ' Important! Remove the subclassing
        SetWindowLong hEdit&, %GWL_WNDPROC, gOldSubClassProc


        And Lance your Point #3 is exactly what I would prefer to do, you were right, if I paste a "T" into the textbox it takes it...good point!!


        So here's what I got so far (Disregard the experimenting with the font etc)


        Code:
        '------------------------------------------------------------------------------
        
        Function WinMain (ByVal hInstance     As Long, _
                          ByVal hPrevInstance As Long, _
                          lpCmdLine           As Asciiz Ptr, _
                          ByVal iCmdShow      As Long) As Long
        
        Local szClassName As Asciiz * 80
        Local wndclass          As WndClassEx
        
          CCS            = "Computer Creations Software"
          Mine           = "Bit-Swap!"
          hInst          = hInstance
          szClassName    = "BITSWAP"
          Ver            = "v2.00"
          Copyrite       = "Copyright © 1999-2000"
          %HK            = %HKEY_LOCAL_MACHINE
          URL            = "http://www.tngbbs.com/ccs"
          hInst = hInstance
          wndclass.cbSize        = SizeOf(WndClass)
          wndclass.style         = %CS_HREDRAW Or %CS_VREDRAW
          wndclass.lpfnWndProc   = CodePtr( DialogProc )
          wndclass.cbClsExtra    = 0
          wndclass.cbWndExtra    = 0
          wndclass.hInstance     = hInstance
          wndclass.hIcon         = LoadIcon( hInstance, "BITSWAP" )
          wndclass.hCursor       = LoadCursor( %NULL, ByVal %IDC_ARROW )
          wndclass.hbrBackground = GetStockObject( %HOLLOW_BRUSH )
          wndclass.lpszMenuName  = %NULL
          wndclass.lpszClassName = VarPtr( szClassName )
          wndclass.hIconSm       = LoadIcon( hInstance, ByVal %IDI_APPLICATION )
          RegisterClassEx wndclass
          InitCommonControls
          InitUrlCtrl
        
        Dialog New 0, Mine,,, 185,75, %WS_MINIMIZEBOX Or %WS_CAPTION Or %WS_SYSMENU Or %WS_EX_LEFT To hDlg
        hIcon = LoadIcon(hInst, ByVal %PROGRAM)
        hMenu = LoadMenu(hInst, "MAINMENU")
        Control Add Label,hDlg, %IDLABEL1,"Enter a 12 digit MAC address:", 5,1,100,10
        Control Add TextBox,hDlg, %IDTEXT1,"",5,10,100,10, %ES_RIGHT Or %WS_TABSTOP Or %ES_UPPERCASE,%WS_EX_CLIENTEDGE
        Control Add Label,hDlg, %IDLABEL2,"Swapped MAC address:", 5,20,100,10
        Control Add TextBox,hDlg, %IDTEXT2,"",5,30,100,10, %ES_RIGHT Or %WS_TABSTOP Or %ES_UPPERCASE,%WS_EX_CLIENTEDGE
        Control Add Button, hDLg, %IDSWAP,"&Swap",120,10,45,14, %BS_DEFAULT
        Control Add Button, hDLg, %IDCOPY,"&Copy to Clpbrd",120,30,60,14 Call ClipBoard
        hStatus = CreateStatusWindow(%WS_CHILD Or %WS_CLIPSIBLINGS Or %WS_DLGFRAME Or %WS_VISIBLE _
                                         Or %SBS_SIZEGRIP,"", hDlg, 200)
        Dialog Send hDlg, %WM_SETICON, %ICON_BIG, hIcon
        Menu Attach hMenu, hDlg
        Dialog Show Modal hDlg Call DialogProc To Result
        End Function  ' WinMain
        
        CallBack Function DialogProc() As Long
        Local wMsg            As Long
        Local wParam          As Long
        Local lParam          As Long
        Static zText           As Asciiz * 255
        Local HlpMsg          As String
        Local NewChar         As String
        Local Tmp             As String
        Static x              As Long
        Static Y              As Long
        
        Local Lb              As LOGBRUSH
        Local lf              As LOGFONT
        Static hBrushBlue      As Long
        Static hBrushDialog    As Long
        Static hDC      As Long
        Static tRect    As RECT
        Static LpPaint  As PaintStruct
        Static hBrush   As Long
        Static hFont    As Long
        Static sz       As Sizel
        
        wMsg = CbMsg
        lParam = CbLparam
        wparam = CbWparam
        
          Select Case wMsg
        
            Case %WM_CREATE
        '         hBrush   = CreateSolidBrush(GetSysColor(%COLOR_3DFACE))
        
            Case %WM_INITDIALOG
                 zText = Mine + " " + Ver
                 SendMessage hStatus, %WM_SETTEXT, 0, VarPtr(zText)
                 Control Disable hDlg, %IDSWAP
                 hFont = MakeFont("Courier New", 10)
                 GetObject hFont, SizeOf(lf), ByVal VarPtr(lf)
                 hFont = CreateFontIndirect(lf)
                 'Make the text bold font or normal
                 lf.lfWeight = %FW_NORMAL
                 Lb.lbStyle  = %BLACK_BRUSH
                 Control Send CbHndl, %IDTEXT1, %WM_SETFONT,hFont, 1
                 Control Send CbHndl, %IDTEXT2, %WM_SETFONT,hFont, 1
        
                 ' Subclass the edit control
                 Control Handle CbHndl, %IDTEXT1 To hEdit&
                 gOldSubClassProc = SetWindowLong(hEdit&, %GWL_WNDPROC, CodePtr(SubClassProc))
        
            Case %WM_SETFONT
            Case %WM_PAINT
            Case %WM_ERASEBKGND
            Case %WM_NOTIFY
            Case %WM_SETFOCUS
                 zText = Mine + " " + Ver
                 SendMessage hStatus, %WM_SETTEXT, 0, VarPtr(zText)
        
            Case %WM_MENUSELECT
              LoadString hInst, wParam, zText, SizeOf(zText)
              SendMessage hStatus, %WM_SETTEXT, 1, VarPtr(zText)
        
            Case %WM_SIZE
             SendMessage hStatus, wMsg, wParam, lParam
        
            Case %WM_COMMAND
              Select Case LoWrd(wParam)
                Case %IDTEXT1
                  Select Case CbCtlMsg
                           Case %EN_UPDATE  'Before painted to window
                               Control Get Text hDlg, %IDTEXT1 To St
                               If Len(St) = 12 Then
                                  Control Enable hDlg, %IDSWAP
                               Else
                                  Control Disable hDlg, %IDSWAP
                               End If
                  End Select
        
                Case %IDSWAP  'Swap button
                  Tmp = St
                  Control Set Text hDlg, %IDTEXT2, SwapAddress(Tmp) '%ES_UPPERCASE makes it all upper case when creating
                  Function = 0
                  Exit Function
        
                Case %IDM_EXIT
                  Dialog End hDlg,1
                  Function = 0
                  Exit Function
        
        
                Case %IDM_HELP
                     HlpMsg = Mine + " " + Ver + $CRLF
                     HlpMsg = HlpMsg + "Used to convert a 12 digit LAA or MAC address to/from ethernet/Token-Ring" + $CRLF
                     HlpMsg = HlpMsg + "ie 400000000001 Swaps to 020000000080"
                     MsgBox HlpMsg,%MB_ICONINFORMATION,CCS
                     Function = 0
                     Exit Function
                Case %IDM_ABOUT
                     Result = CCSShellAbout(hDlg, _
                                     Mine,_
                                     Ver,_
                                     CCS,_
                                     Copyrite,_
                                     URL,_
                                     LoadIcon(hInst,ByVal %PROGRAM))
                  Function = 0
                  Exit Function
        
              End Select
        
            Case %WM_DESTROY
              KillTimer hDlg, %IDTIMER1
              ' Important! Remove the subclassing
              SetWindowLong hEdit&, %GWL_WNDPROC, gOldSubClassProc
              PostQuitMessage 0
              Function = 0
              Exit Function
        
          End Select
          '* Default processing for other messages.
        
        End Function
        
        '-------------------------------------------------------------------------------
        Function SubClassProc(ByVal hWnd&, ByVal wMsg&, ByVal wParam&, ByVal lParam&) As Long
        Local NewChar As Asciiz * 2
        Local Y       As Long
        Local zText   As Asciiz * 13
        Local yMsg    As Long
        ' Process our messages in this subclass procedure
        Select Case wMsg&
            Case %WM_KEYDOWN
            Case %WM_KEYUP
            Case %WM_CHAR
                 yMsg = LoWrd(wParam&) 'Actual ascii value of keystroke coming in
                 If yMsg <> 8 And Len(St) = 12 Then Exit Function 'We don't want a MAC address longer than 12
                 Select Case yMsg
                          Case 8 'BackSpace
                          Case 48 To 57 '0-9
                             St = St + Chr$(yMsg)
                          Case 65 To 70 'A-F
                             St = St + Chr$(yMsg)
                          Case 97 To 102 'a-f
                             St = St + UCase$(Chr$(yMsg))
                          Case Else
                             exit function  
                  End Select
        
        End Select
        ' Pass the message on to the original window procedure... the DDT engine!
        Function = CallWindowProc(gOldSubClassProc, hWnd&, wMsg&, wParam&, lParam&)
        End Function
        '-------------------------------------------------------------------------------

        -------------
        Scott Turchin


        Scott Turchin
        MCSE, MCP+I
        http://www.tngbbs.com
        ----------------------
        True Karate-do is this: that in daily life, one's mind and body be trained and developed in a spirit of humility; and that in critical times, one be devoted utterly to the cause of justice. -Gichin Funakoshi

        Comment


        • #5
          There is not enough of your code to compile it, but there are a few resource leaks... brushes & fonts created in the callback and not destroyed at %WM_DESTROY.

          Also, you are still building "ST" in the subclass function, and also updating "ST" when %EN_UPDATE occurs... these are contradictory.

          Also, your %WM_COMMAND handlers are not testing the reason before reacting... remember our previous discussions on %BN_CLICKED ?



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

          Comment


          • #6
            I *DO* like your efficiency Lance!


            OK That part hopefully has been cleared up and the functions are still working.
            Basically St is global, it needs to be 12 characters, mac addresses are 12 characters, so I disable the swap button before it is and if it is longer than 12, makes life that much easier for the person entering the address to make sure they enter it correctly..so if User hits backspace(8), I have to manually adjust St back one digit, which is OK with me...

            But, while this is working, and I like it, I still am not doing it 100% correctly, I'm not nullifying out the keystroke if i don't like what the user typed (Wow, talk about censorship!)....


            Code:
            '------------------------------------------------------------------------------
            CallBack Function DialogProc() As Long
            Local wMsg            As Long
            Local wParam          As Long
            Local lParam          As Long
            Static zText           As Asciiz * 255
            Local HlpMsg          As String
            Local Tmp             As String
            Static x              As Long
            Static Y              As Long
            
            Local Lb              As LOGBRUSH
            Local lf              As LOGFONT
            Static hFont1    As Long
            Static hFont2    As Long
            
            wMsg = CbMsg
            lParam = CbLparam
            wparam = CbWparam
            
              Select Case wMsg
            
                Case %WM_CREATE
            
                Case %WM_INITDIALOG
                     zText = Mine + " " + Ver
                     SendMessage hStatus, %WM_SETTEXT, 0, VarPtr(zText)
            
                     Control Disable hDlg, %IDSWAP 'Disable swap button until 12 chars are entered
                     'happy font
                     hFont1 = MakeFont("Courier New", 10)
                     hFont1 = MakeFont("Courier New", 10)
                     GetObject hFont1, SizeOf(lf), ByVal VarPtr(lf)
                     GetObject hFont2, SizeOf(lf), ByVal VarPtr(lf)
                     hFont1 = CreateFontIndirect(lf)
                     hFont2 = CreateFontIndirect(lf)
            
                     'Make the text bold font or normal
                     lf.lfWeight = %FW_NORMAL
                     Lb.lbStyle  = %BLACK_BRUSH
                     Control Send CbHndl, %IDTEXT1, %WM_SETFONT,hFont1, 1
                     Control Send CbHndl, %IDTEXT2, %WM_SETFONT,hFont2, 1
            
                     ' Subclass the edit control
                     Control Handle CbHndl, %IDTEXT1 To hEdit&
                     gOldSubClassProc = SetWindowLong(hEdit&, %GWL_WNDPROC, CodePtr(SubClassProc))
            
            
                Case %WM_DESTROY
                  KillTimer hDlg, %IDTIMER1
                  DeleteObject hFont1
                  DeleteObject hFont2
                  ' Important! Remove the subclassing
                  SetWindowLong hEdit&, %GWL_WNDPROC, gOldSubClassProc
                  PostQuitMessage 0
                  Function = 0
                  Exit Function
            
                Case %WM_SETFOCUS
                     zText = Mine + " " + Ver
                     SendMessage hStatus, %WM_SETTEXT, 0, VarPtr(zText)
            
                Case %WM_MENUSELECT
                  LoadString hInst, wParam, zText, SizeOf(zText)
                  SendMessage hStatus, %WM_SETTEXT, 1, VarPtr(zText)
            
                Case %WM_SIZE
                 SendMessage hStatus, wMsg, wParam, lParam
            
                Case %WM_COMMAND
                  Select Case LoWrd(wParam)
            
                    Case %IDSWAP  'Swap button
                             Select Case CbCtlMsg
                                 Case %BN_CLICKED
                                      Tmp = St
                                      Control Set Text hDlg, %IDTEXT2, SwapAddress(Tmp) '%ES_UPPERCASE makes it all upper case when creating
                                      Function = 0
                                      Exit Function
                            End Select
                            
                    Case %IDM_EXIT
                             Select Case CbCtlMsg
                                 Case %BN_CLICKED
                                      Dialog End hDlg,1
                             End Select
            
                    Case %IDM_HELP
                         HlpMsg = Mine + " " + Ver + $CRLF
                         HlpMsg = HlpMsg + "Used to convert a 12 digit LAA or MAC address to/from ethernet/Token-Ring" + $CRLF
                         HlpMsg = HlpMsg + "ie 400000000001 Swaps to 020000000080"
                         MsgBox HlpMsg,%MB_ICONINFORMATION,CCS
                         Function = 0
                         Exit Function
                    Case %IDM_ABOUT
                         Result = CCSShellAbout(hDlg, _
                                         Mine,_
                                         Ver,_
                                         CCS,_
                                         Copyrite,_
                                         URL,_
                                         LoadIcon(hInst,ByVal %PROGRAM))
                      Function = 0
                      Exit Function
            
                  End Select
            
            
              End Select
            End Function
            
            '-------------------------------------------------------------------------------
            Function SubClassProc(ByVal hWnd&, ByVal wMsg&, ByVal wParam&, ByVal lParam&) As Long
            Local NewChar As Asciiz * 2
            Local Y       As Long
            Local zText   As Asciiz * 13
            Local yMsg    As Long
            ' Process our messages in this subclass procedure
            Select Case wMsg&
                Case %WM_KEYUP
                Case %WM_KEYDOWN
                Case %WM_CHAR
                     yMsg = LoWrd(wParam&) 'Actual ascii value of keystroke coming in
                     Select Case yMsg
                              Case 8 'BackSpace
                                 If Len(St) > 1 Then St = Left$(St,Len(St)-1)
                              Case 48 To 57 '0-9
                                 St = St + Chr$(yMsg)
                              Case 65 To 70 'A-F
                                 St = St + Chr$(yMsg)
                              Case 97 To 102 'a-f
                                 St = St + UCase$(Chr$(yMsg))
                              Case Else
                                Function = %NULL
                                Exit Function
                      End Select
                     If Len(St) = 12  Then
                        Control Enable hDlg, %IDSWAP
                     Else
                        Control Disable hDlg, %IDSWAP
                     End If
            
            End Select
            ' Pass the message on to the original window procedure... the DDT engine!
            Function = CallWindowProc(gOldSubClassProc, hWnd&, wMsg&, wParam&, lParam&)
            End Function
            '-------------------------------------------------------------------------------

            -------------
            Scott Turchin




            [This message has been edited by Scott Turchin (edited January 24, 2000).]
            Scott Turchin
            MCSE, MCP+I
            http://www.tngbbs.com
            ----------------------
            True Karate-do is this: that in daily life, one's mind and body be trained and developed in a spirit of humility; and that in critical times, one be devoted utterly to the cause of justice. -Gichin Funakoshi

            Comment


            • #7
              I just found another issue with my code, under NT 4.0 SP3 the cursor starts at the left, while set as %ES_RIGHT, but under NT 4.0 SP5 + it does not, nor on Win98, BUT in addition, my method if keeping the string St behind the scenes is not working because my tester started dumping code in the middle of the value already in the textbox and it let him and gave some pretty sporatic results (Delete key is not checked..)


              So, how does one nullify the keystroke before it gets painted to screen, my method is weak and not going to work without patching it constantly...(Yuck)....

              Thanks,

              Scott

              -------------
              Scott Turchin


              Scott Turchin
              MCSE, MCP+I
              http://www.tngbbs.com
              ----------------------
              True Karate-do is this: that in daily life, one's mind and body be trained and developed in a spirit of humility; and that in critical times, one be devoted utterly to the cause of justice. -Gichin Funakoshi

              Comment


              • #8
                I would try this: In the subclass procedure, if the keystroke code is not acceptable then set WPARAM to zero before letting the default class handler process the %WM_CHAR message.

                I did not check for this in your code, but to ensure the MAC address entry is limited to 12 characters, you can set the maximum character limit for the textbox accordingly- see the %EM_SETTEXTLIMIT message.

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

                Comment


                • #9
                  Almost cofused me there

                  Had to look that one up, it wasn't showing, so the names are reversed...
                  OK, so in my WM_INITDIALOG I send this but it doesn't seem to have an effect...

                  SendMessage GetDlgItem(hDlg,%IDTEXT1),%EM_SETLIMITTEXT,0, 12


                  Then in the subclass I set wParam& to %null but I'm still getting characters that don't belong....it's a good start though ...


                  Scott

                  -------------
                  Scott Turchin


                  Scott Turchin
                  MCSE, MCP+I
                  http://www.tngbbs.com
                  ----------------------
                  True Karate-do is this: that in daily life, one's mind and body be trained and developed in a spirit of humility; and that in critical times, one be devoted utterly to the cause of justice. -Gichin Funakoshi

                  Comment


                  • #10
                    Oops! I was working from memory... I should have double-checked the message equate name before posting... sorry!

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

                    Comment


                    • #11
                      I believe you should have:

                      SendMessage GetDlgItem(hDlg,%IDTEXT1),%EM_SETLIMITTEXT,12, 0

                      Regards, Ian
                      :) IRC :)

                      Comment


                      • #12
                        Yup, that's what I got, and that worked Now I don't have to worry about them typing over 12 characters, rather nice

                        Thanks all, this has been a success! the application is freeware if anyone is interested, http://www.tngbbs.com/ccs and click on freeware..


                        Scott

                        -------------
                        Scott Turchin


                        Scott Turchin
                        MCSE, MCP+I
                        http://www.tngbbs.com
                        ----------------------
                        True Karate-do is this: that in daily life, one's mind and body be trained and developed in a spirit of humility; and that in critical times, one be devoted utterly to the cause of justice. -Gichin Funakoshi

                        Comment

                        Working...
                        X