Announcement

Collapse
No announcement yet.

Classless event processing SDK

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

  • Classless event processing SDK

    I can't do what I want with DDT so started with SDK (on Saturday). I don't like the structure that is forced on you by having to process events from each control via the class wndproc, so I forced all the events into a single function by superclassing each control type to use the same class wndproc, which seems to work as long as you CallWindowProc the correct original wndproc for the control's class. Also, redirected WM_COMMAND messages from the parent wndproc. The superclassing is borrowed from Semen Matusovski and modified as necessary.

    It's early days but so far I find adding events to this program structure very simple, maybe because I am not "steeped in Windows". SDKers, tell me where I went so wrong!

    Code:
    #COMPILE EXE
    #REGISTER NONE
    #DIM ALL
    #INCLUDE "Win32Api.Inc"
    '
    ' SDK attempt at doing event processing all in one place
    ' Chris Holbrook 14-jan-2008
    '--------------------------------------------------------------
    TYPE ourClassnProc                ' old WNDPROC and new classname
        ClassName      AS STRING * 64
        WindProc       AS DWORD
    END TYPE
    
    '
    %IDC_LAB1       = 1001
    %IDC_LB1        = 1002
    %IDC_BN1        = 1003
    %IDC_BN2        = 1004
    %IDC_CB1        = 1005
    %IDC_EDIT1      = 1006
    %OUR_WMCOMMAND  = 100
    '
    GLOBAL ghinst           AS DWORD ' global handle to current instance
    
    '------------------------------------------------------------------------------
    ' borrowed from Semen Matusovski
    FUNCTION CreateSuperClass(OldClassName AS STRING, NewClassName AS STRING, lpfnNewWndProc AS LONG, cbWndExtra AS LONG) AS LONG
        LOCAL wc AS WNDCLASSEX
        STATIC tClassProc AS ourClassnProc
        LOCAL sz AS ASCIZ * 64
    
        sz = NewClassName
        wc.cbSize = SIZEOF(wc)
        IF GetClassInfoEx(BYVAL 0&, BYVAL STRPTR(OldClassName), wc) THEN
            ' store new classname together with old class windproc for use in AllSuperProc
    
            tClassProc.Classname = NewClassName
            tClassProc.WindProc = wc.lpfnWndProc
            '
            CallWindowProc lpfnNewWndProc, 0, 0, BYREF tClassProc, wc.cbWndExtra
            wc.hInstance = GetModuleHandle(BYVAL 0&)
            wc.lpszClassName = STRPTR(NewClassName)
            wc.lpfnWndProc = lpfnNewWndProc
            wc.cbWndExtra = wc.cbWndExtra + cbWndExtra
            FUNCTION = RegisterClassEx(wc)
    
        END IF
    END FUNCTION
    '------------------------------------------------------------------
    CALLBACK FUNCTION AllSuperProc
        LOCAL l, levent, lcontrolid, lmsg AS DWORD
        LOCAL OldProc AS LONG, OffsetWndExtra AS LONG
        LOCAL sz AS ASCIZ * 64
        LOCAL pClassProc AS ourClassnProc PTR
        DIM tClass_Windprocs(0 TO 10 ) AS STATIC ourClassnProc ' 10 classes? should be enough!
        STATIC lstate AS LONG
    
        ' whenever CreateSuperClass is called, we need to add a classname and oldWNDPROC
        ' to the array
        IF CBHNDL = 0 THEN
            ' CreateSuperClass is talking to us
            pClassProc = CBWPARAM
            OffsetWndExtra = CBLPARAM
            ' add a classname and OldClassWndProc to array
            WHILE tClass_Windprocs(l).WindProc <> 0
                INCR l
            WEND
            tClass_Windprocs(l).Classname = @pClassProc.Classname
            tClass_Windprocs(l).WindProc  = @pClassProc.WindProc
            EXIT FUNCTION ' don't need to pass this message on
        END IF
    
        lmsg = CBMSG
        IF CBMSG = %WM_USER + %OUR_WMCOMMAND THEN
            sz="WM_COMMAND"
            lmsg = %WM_COMMAND  ' pretend that we got the WM_COMMAND message
        END IF
    
        lControlId = getDlgCtrlId(CBHNDL)
        levent = MAK(DWORD, lControlId, lMsg)
        sz = sz + " " + STR$(lControlId) + " &H" + HEX$(lmsg)
    
    '    uncomment this to see all msgs
    '    sendmessage( getdlgitem(getparent(CBHNDL), %idc_lb1), %LB_INSERTSTRING, 0, varptr(sz))
    
        '
        SELECT CASE levent
            CASE MAK(DWORD, %IDOK, %WM_COMMAND)         :       GOSUB IDOK_WM_COMMAND
            CASE MAK(DWORD,%IDC_LAB1, %WM_MOUSEMOVE)    :       GOSUB IDC_LAB1_WM_MOUSEMOVE
            CASE MAK(DWORD,%IDC_BN2, %WM_COMMAND)       :       GOSUB IDC_BN2_WM_COMMAND
            CASE MAK(DWORD, %IDC_BN2, %WM_LBUTTONDOWN)  :       GOSUB IDC_BN2_WM_LBUTTONDOWN
            CASE MAK(DWORD, %IDC_BN2, %WM_ENABLE)       :       GOSUB IDC_BN2_WM_ENABLE
            CASE MAK(DWORD, %IDC_EDIT1, %WM_VSCROLL)    :       GOSUB IDC_EDIT1_WM_VSCROLL
        END SELECT
        ' how to call the correct windowproc? i.e. for original class?
        getclassname ( CBHNDL, BYREF sz, SIZEOF(sz))
        l = 0
        WHILE tClass_Windprocs(l).WindProc <> 0
            IF INSTR(tClass_Windprocs(l).Classname, sz) = 1 THEN
                oldProc = tClass_Windprocs(l).Windproc
                FUNCTION = CallWindowProc(OldProc, CBHNDL, CBMSG, CBWPARAM, CBLPARAM)
                EXIT FUNCTION
            END IF
            INCR l
        WEND
        ? "can't find windproc for class " + sz + " msg id &H" + HEX$(CBMSG)
        EXIT FUNCTION
    
    '    using explicit label names!
    IDOK_WM_COMMAND:
        IF CBCTLMSG <> %BN_CLICKED THEN RETURN
        ' toggle state
        IF lstate = 0 THEN 'instr(sz, "ENABLE") = 0 then
            lstate = 1
            sz = "Click me to ENABLE Button"
            enableWindow (getdlgitem(getparent(CBHNDL),%IDC_BN2), %FALSE)
            sendmessage(getdlgitem(getparent(CBHNDL),%IDOK), %WM_SETTEXT, 0, BYREF sz)
        ELSE
            lstate = 0
            sz = "Click me to DISABLE Button"
            enableWindow (getdlgitem(getparent(CBHNDL),%IDC_BN2), %TRUE)
            sendmessage(getdlgitem(getparent(CBHNDL),%IDOK), %WM_SETTEXT, 0, BYREF sz)
        END IF
    
    
    IDC_LAB1_WM_MOUSEMOVE:
        sz = "you moved the mouse over the label!"
        sendmessage( getdlgitem(getparent(CBHNDL), %idc_lb1), %LB_INSERTSTRING, 0, VARPTR(sz))
        RETURN
    
    IDC_BN2_WM_COMMAND:
        IF CBCTLMSG <> %BN_CLICKED THEN RETURN
        BEEP
        sendmessage(getparent(CBHNDL), %wm_close, 0, 0)
        RETURN
    
    IDC_BN2_WM_LBUTTONDOWN:
        sz = "IDC_BN2 " + $TAB + "WM_LBUTTONDOWN"
        sendmessage( getdlgitem(getparent(CBHNDL), %idc_lb1), %LB_INSERTSTRING, 0, VARPTR(sz))
        RETURN
    
    IDC_EDIT1_WM_VSCROLL:
        sz = "you scrolled the edit box"
        sendmessage( getdlgitem(getparent(CBHNDL), %idc_lb1), %LB_INSERTSTRING, 0, VARPTR(sz))
        RETURN
    
    IDC_BN2_WM_ENABLE:
        sz = "IDC_BN2 " + $TAB + "WM_ENABLE"
        sendmessage( getdlgitem(getparent(CBHNDL), %idc_lb1), %LB_INSERTSTRING, 0, VARPTR(sz))
        RETURN
    
    END FUNCTION
    
    '-----------------------------------------------------------------------------------
    FUNCTION My_MainWndProc _
      ( _
      BYVAL hWnd    AS DWORD, _ ' window handle
      BYVAL uMsg    AS DWORD, _ ' type of message
      BYVAL wParam  AS DWORD, _ ' first message parameter
      BYVAL lParam  AS LONG _   ' second message parameter
      ) EXPORT AS LONG
    
      LOCAL hWndChild                       AS DWORD
      LOCAL sz                              AS ASCIZ * 64
      LOCAL i, lCid, lCtlNo                 AS LONG
      STATIC lstate AS LONG
    
        SELECT CASE uMsg
            CASE %WM_COMMAND
                lCid = LOWRD(wParam) ' control identifier
                sendmessage getdlgitem(hWnd, lCid), %WM_USER + %OUR_WMCOMMAND, wParam, lParam
    '
            CASE %WM_PAINT
               LOCAL hdc AS LONG
               LOCAL ps AS PAINTSTRUCT
               LOCAL r AS rect
    
               hdc = beginpaint ( hWnd, BYREF ps)
               GetclientRect ( hwnd, BYREF r)
               'drawtext( hdc, "HELLO MOTHER", -1, BYREF r, %DT_SINGLELINE OR %DT_CENTER OR %DT_VCENTER )
               endpaint (hwnd,BYREF ps)
               FUNCTION = 0
               EXIT FUNCTION
    
            CASE %WM_DESTROY
                PostQuitMessage 0
                EXIT FUNCTION
               '
            CASE %WM_CREATE
               DIALOG SET TEXT hwnd, "BLAH"
               ' Create a label control
               hWndChild = CreateWindowEx(%NULL, _
                         "OurStatic", _
                         "I'm label1!", _
                         %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %SS_CENTER _
                         OR %SS_CENTERIMAGE OR %SS_NOTIFY,_
                         5,40, 85, 30, _
                         hWnd, %IDC_LAB1, _
                         ghInst, BYVAL %NULL)
               INCR lCtlNo
               ' Create a superclassed button control
               hWndChild = CreateWindowEx(%NULL, _
                         "OurButton", _
                         "Goodnight!", _
                         %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_NOTIFY OR _
                         %BS_PUSHBUTTON OR %BS_TEXT OR %BS_CENTER OR %BS_VCENTER, _
                         5,  75, 190, 20, _
                         hWnd, %IDC_BN2, _
                         ghInst, BYVAL %NULL)
               ' Create a superclassed Edit control
               hWndChild = CreateWindowEx(%NULL, _
                         "OurEdit", _
                         "Edit box!", _
                         %WS_CHILD OR %WS_VISIBLE OR %WS_hscroll OR %WS_VSCROLL OR _
                         %WS_BORDER OR %ES_LEFT OR %ES_MULTILINE OR %ES_MULTILINE OR %ES_WANTRETURN, _
                         5,  120, 190, 100, _
                         hWnd, %IDC_EDIT1, _
                         ghInst, BYVAL %NULL)
               INCR lCtlNo
               ' Create a button control
               hWndChild =  CreateWindowEx(%NULL, _
                         "ourBUTTON", _
                         "Press me to DISABLE Button!", _
                         %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %BS_NOTIFY OR _
                         %BS_PUSHBUTTON OR %BS_TEXT OR %BS_CENTER OR %BS_VCENTER, _
                         5,  95, 190, 20, _
                         hWnd, %IDOK, _
                         ghInst, BYVAL %NULL)
               INCR lCtlNo
               ' create a checkbox control
               hWndChild = CreateWindowEx(%NULL, _
                         "Button", _
                         "I'm a checkbox!", _
                         %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP OR %SS_CENTER _
                         OR %SS_CENTERIMAGE OR %SS_NOTIFY OR %BS_CHECKBOX, _
                         5, 5, 135, 30, _
                         hWnd, %IDC_CB1, _
                         ghInst, BYVAL %NULL)
               INCR lCtlNo
               ' create a listbox control
               hWndchild = CreateWindowEx(%WS_EX_CLIENTEDGE OR %ws_ex_rightscrollbar, _
                         "Listbox", _
                         "", _
                         %WS_CHILD OR %WS_VISIBLE OR %WS_VSCROLL OR _
                         %WS_BORDER OR %WS_TABSTOP OR _
                         %LBS_HASSTRINGS OR %LBS_NOTIFY, _
                         200, 5, 285, 345, _
                         hWnd, %IDC_LB1, _                                       ' parent HWND, control ID
                         ghInst, BYVAL %NULL)
               FUNCTION = 0
               EXIT FUNCTION
      END SELECT
    
      FUNCTION = DefWindowProc(hWnd, uMsg, wParam, lParam)
    
    END FUNCTION
    '--------------------------------------------------------------------------
    FUNCTION WINMAIN _
        ( BYVAL hInstance     AS LONG, _        ' handle of current instance
          BYVAL hPrevInstance AS LONG, _        ' handle of previous instance(not used in Win32)
          BYVAL pszCmdLine    AS ASCIIZ PTR, _  ' address of command line
          BYVAL nCmdShow      AS LONG _         ' show state of window
        ) AS LONG
    
        LOCAL szClassName   AS ASCIIZ * 32       ' class name
        LOCAL tWCX          AS WNDCLASSEX               ' class information
        LOCAL tmsg          AS tagMsg                   ' message information
        LOCAL hWnd, i, lresult          AS DWORD
    
        ' Save the handle of the application instance
        ghInst = hInstance
    
        ' Register the Form1 window
        szClassName        = "MY_CLASS"
        tWCX.cbSize        = SIZEOF(tWCX)                               ' size of WNDCLASSEX structure
        tWCX.style         = %CS_DBLCLKS  OR %CS_HREDRAW OR %CS_VREDRAW     ' class styles
        tWCX.lpfnWndProc   = CODEPTR(My_MainWndProc)                        ' address of window procedure used by class
        tWCX.cbClsExtra    = 0                                          ' extra class bytes
        tWCX.cbWndExtra    = 0                                          ' extra window bytes
        tWCX.hInstance     = hInstance                                  ' instance of the EXE/DLL that is registering the window
        tWCX.hIcon         = LoadIcon(%NULL, BYVAL %IDI_APPLICATION)    ' handle of class icon
        tWCX.hCursor       = LoadCursor(%NULL, BYVAL %IDC_ARROW)        ' handle of class cursor
        tWCX.hbrBackground = getstockobject(%white_brush)               ' brush used to fill background of window's client area
        tWCX.lpszMenuName  = %NULL                                      ' resource identifier of the class menu
        tWCX.lpszClassName = VARPTR(szClassName)                        ' class name
        tWCX.hIconSm       = LoadIcon(%NULL, BYVAL %IDI_APPLICATION)    ' handle of small icon shown in caption/system Taskbar
        IF ISFALSE RegisterClassEx(tWCX) THEN
          FUNCTION = %FALSE
          EXIT FUNCTION
        END IF
        ' superclass the button, STATIC, Edit, ListBox and ListView classes
        IF ISFALSE(CreateSuperClass("STATIC", "OurStatic", CODEPTR(AllSuperProc), 4)) THEN
            EXIT FUNCTION
        END IF
        IF ISFALSE(CreateSuperClass("BUTTON", "OurButton", CODEPTR(AllSuperProc), 4)) THEN
            EXIT FUNCTION
        END IF
        IF ISFALSE(CreateSuperClass("EDIT", "OurEdit", CODEPTR(AllSuperProc), 4)) THEN
            EXIT FUNCTION
        END IF
        IF ISFALSE(CreateSuperClass("LISTBOX", "OurLB", CODEPTR(AllSuperProc), 4)) THEN
            EXIT FUNCTION
        END IF
    '    IF ISFALSE(CreateSuperClass("SysListView32_1", "OurLVt", CODEPTR(CB1_Handler), 4)) THEN
    '        EXIT FUNCTION
    '    END IF
         ' Create main window
        hWnd = CreateWindowEx(%WS_EX_WINDOWEDGE, _
                              szClassName, _
                              "MY CREATEWINDOWEX TEST", _
                              %WS_OVERLAPPED OR %WS_VISIBLE OR %WS_SYSMENU, _
                              50, 50, 500, 400, _
                              %NULL, %NULL, _                                           ' desktop, menu handle
                              ghInst, BYVAL %NULL)
        ' fail if window is not created
        IF ISFALSE hWnd THEN
          FUNCTION = %FALSE
          EXIT FUNCTION
        END IF
    
        ' Activate window
        ShowWindow hWnd, %SW_SHOW
        ' Paint client area
        UpdateWindow hWnd
    
        WHILE ISTRUE GetMessage(tmsg, BYVAL %NULL, 0, 0)
    
    '        if tmsg.message = %WM_COMMAND then beep
            IF ISFALSE IsDialogMessage(hWnd, tmsg) THEN
                TranslateMessage tmsg
                DispatchMessage tmsg
            END IF
        WEND
    
        FUNCTION = tmsg.wParam
    
    END FUNCTION
    Last edited by Chris Holbrook; 15 Jan 2008, 03:31 AM. Reason: fix WM_COMMAND processing

  • #2
    blank white window?

    I thought I'd run your code before looking at it Chris, but all I got was a blank white window. Is there supposed to be more?
    Fred
    "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

    Comment


    • #3
      One line of code is msising:

      After the WM_DESTROY message code (ends with exit function), the WM_CREATE is messing.

      It should be:

      Code:
             CASE %WM_DESTROY
                  PostQuitMessage 0
                  EXIT FUNCTION
              CASE %WM_CREATE
                 DIALOG SET TEXT hwnd, "BLAH"
      Chris Boss
      Computer Workshop
      Developer of "EZGUI"
      http://cwsof.com
      http://twitter.com/EZGUIProGuy

      Comment


      • #4
        Chris,

        What exactly are you trying to accomplish ?

        Are you trying to generate events for messages only available to the controls window procedure (ie. WM_LBUTTONUP) ?

        You can create your own event engine using DDT, bu subclassing controls and then sending user defined messages through the WM_COMMAND message (sent to parent dialog).

        For example, buttons controls use values of less than 10 for notification codes (WM_COMMAND), so you could use higher values of your own for custom event messages.

        In the subclass routine simply send the parent dialog your own WM_COMMAND message using a custom notification code (which is not within the range used by the control class). This event will then be sent to the callback function defined in the DDT code for the control. Even controls that don't normally generate WM_COMMAND messages, this can be done.

        You then have to have some way to get any extra data the event needs to pass. This could be done by have the subclass routine store the data in static variables within the subclass procedure and then provide a message that can be sent from within the event (WM_COMMAND event) to the control to retrieve any needed data. Global variables could also be used.
        Chris Boss
        Computer Workshop
        Developer of "EZGUI"
        http://cwsof.com
        http://twitter.com/EZGUIProGuy

        Comment


        • #5
          I don't like the structure that is forced on you by having to process events from each control via the class wndproc...
          In my opinion its a tremendously elegant and beautiful design.

          In Linux/Unix at the level of XLib you also have a main message loop in your program, but it processes messages from every window running on the system. If that sounds chaotic, it is!

          In Windows, your WndProc() will mostly only receive messages from windows of classes you've personally defined, or child windows on such a parent. A huge body of code exists within PowerBASIC and C and C++ where efforts have been made to modularize the window procedure to route messages to a particular message/event handler. The success of Visual Basic was largely based on the idea of just showing the programmer an event handler (without showing him/her all the messy underlying details) in which code could be placed. This forced a certain amount of modularization even on the most sloppy, poorly thought out code. This whole concept is the concept of message crackers, I suppose.

          If you wish to be an extreme minimalist in terms of the Window Procedure, just below is an example where the WndProc has been reduced to just 16 lines, even though the program processes seven messages. Using this particular design it wouldn't matter if 100 messages were processed and significant quantities of code were executed in each of those 100 event handlers, the WndProc would still only be 16 lines (the program uses function pointers to the message handlers).

          Code:
          'http://www.jose.it-berater.org/smfforum/index.php?PHPSESSID=d06a0af58c7d4f5c171d62bda4159cb0&board=20.0
          #Compile Exe   "fnPtrs3"
          #Dim           All
          #Include       "Win32api.inc"
          
          
          Type MessageHandler                  'This Type Associates a message with the
            wMessage As Long                   'address of the message handler which
            fnPtr    As Dword                  'handles it.  Messages are usually fairly
          End Type                             'low numbers, e.g., WM_PAINT is 15.
          
          Global MsgHdlr() As MessageHandler
          
          
          Type WndEventArgs               'Type for passing window procedure parameters.  Allows me
            wParam           As Long      'to shorten parameter list.  .NET does this all the time.
            lParam           As Long      'See, for example pea for PaintEventArgs in the OnPaint()
            hWnd             As Dword     'Message Handler.
          End Type
          
          
          Type tagInstanceData   'User Defined Type for persisting or storing message
            wWidth   As Word     'information across invocations of fnWndProc.  It is
            wHeight  As Word     'necessary to persist this data because such items of
            wX       As Word     'information as, for example, the window height and
            wY       As Word     'width would be lost after they were obtained in a
            xPos     As Word     'WM_SIZE message after that message handler was exited.
            yPos     As Word     'Then, when a WM_PAINT message was received and it was
            wCharHt  As Word     'desired to update the window with this newly acquired
            szText   As Asciiz*128  'information, it would be gone.
          End Type
          
          
          'Model procedure showing function signature of all message handlers.
          Declare Function fnPtr(wea As WndEventArgs) As Long
          
          
          Function fnWndProc_OnCreate(wea As WndEventArgs) As Long
            Local ptrInstanceData As tagInstanceData Ptr
            Local tm As TEXTMETRIC      'When the main program window is created
            Local hHeap As Dword        'HeapAlloc() is called and a memory request is
            Local hDC As Dword          'made for enough bytes to store a tagInstanceData
                                        'Type.  If HeapAlloc()returns a non-zero number
            hHeap=GetProcessHeap()      '(a valid address), a call to GetTextMetrics() is
            ptrInstanceData= _          'made to obtain the height of a character for text
            HeapAlloc _                 'spacing purposes.  Then a Call to SetWindowLong()
            ( _                         'stores the address of the memory acquired by
              hHeap, _                  'HeapAlloc() into the four cbWndExtra bytes of
              %HEAP_ZERO_MEMORY, _      'extra window storage in the Window Class
              SizeOf(tagInstanceData) _ 'structure requested when the "Form2B" Class was
            )                           'Registered in WinMain().
            If ptrInstanceData Then
               hDC=GetDC(wea.hWnd)
               Call GetTextMetrics(hDC,tm)
               Call ReleaseDC(wea.hWnd,hDC)
               @ptrInstanceData.wCharHt=tm.tmHeight
               Call SetWindowLong(wea.hWnd,0,ptrInstanceData)
               MsgBox("@ptrInstanceData.wCharHt=" & Trim$(Str$(@ptrInstanceData.wCharHt)))
            Else
               fnWndProc_OnCreate=-1
            End If
          
            fnWndProc_OnCreate=0
          End Function
          
          
          Function fnWndProc_OnMouseMove(wea As WndEventArgs) As Long  'If a WM_MOUSEMOVE
            Local ptrInstanceData As tagInstanceData Ptr   'message is received a pointer
                                                           'to a tagInstanceData Type is
            ptrInstanceData= _                             'declared.  This variable is
            GetWindowLong _                                'initialized with the address
            ( _                                            'stored in the cbWndExtra bytes.
              wea.hWnd, _                                  'The mouse coordinates are
              0 _                                          'extracted from the lParam
            )                                              'parameter and 'persisted'
            @ptrInstanceData.wX=LoWrd(wea.lParam)          'in the allocated memory using
            @ptrInstanceData.wY=HiWrd(wea.lParam)          'pointer indirection techniques.
            Call InvalidateRect _                          'Finally, an InvalidateRect()
            ( _                                            'Call is made.  This will force
              wea.hWnd, _                                  'a WM_PAINT message to be sent
              ByVal %NULL, _                               'to this Window Procedure in a
              %TRUE _                                      'completely separate WndProc()
            )                                              'Call or invocation.  At that
                                                           'point in the WM_PAINT handler
            fnWndProc_OnMouseMove=0                        'the mouse coordinates will be
          End Function                                     'extracted and displayed.
          
          
          Function fnWndProc_OnSize(wea As WndEventArgs) As Long  'The same pattern
            Local ptrInstanceData As tagInstanceData Ptr   'described just above for the
                                                           'WM_MOUSEMOVE message will be
            ptrInstanceData= _                             'repeated here in WM_SIZE logic
            GetWindowLong _                                'and, in all the other message
            ( _                                            'handlers.  The only thing that
              wea.hWnd, _                                  'will be different is the data
              0 _                                          'transferred in the wParam and
            )                                              'lParam variables, as that is
            @ptrInstanceData.wWidth=LoWrd(wea.lParam)      'dependent on the message
            @ptrInstanceData.wHeight=HiWrd(wea.lParam)     'itself.  The repeating pattern
            Call InvalidateRect(wea.hWnd,ByVal %NULL,%TRUE)'will be to obtain the pointer
                                                           'from the cbWndExtra bytes,
            fnWndProc_OnSize=0                             'store data there, then force
          End Function                                     'a paint msg. to display data.
          
          
          Function fnWndProc_OnChar(wea As WndEventArgs) As Long
            Local ptrInstanceData As tagInstanceData Ptr
          
            ptrInstanceData=GetWindowLong(wea.hWnd,0)
            @[email protected]+Chr$(wea.wParam)
            Call InvalidateRect(wea.hWnd,ByVal %NULL,%TRUE)
          
            fnWndProc_OnChar=0
          End Function
          
          
          Function fnWndProc_OnLButtonDown(wea As WndEventArgs) As Long
            Local ptrInstanceData As tagInstanceData Ptr
          
            ptrInstanceData=GetWindowLong(wea.hWnd,0)
            If wea.wParam=%MK_LBUTTON Then
               @ptrInstanceData.xPos=LoWrd(wea.lParam)
               @ptrInstanceData.yPos=HiWrd(wea.lParam)
               Call InvalidateRect(wea.hWnd,ByVal 0,%TRUE)
            End If
          
            fnWndProc_OnLButtonDown=0
          End Function
          
          
          Function fnWndProc_OnPaint(wea As WndEventArgs) As Long
            Local ptrInstanceData As tagInstanceData Ptr
            Local szLine As Asciiz*64
            Local ps As PAINTSTRUCT     'This procedure will be called right after
            Local hDC As Long           'window creation, and every time an
                                        'InvalidateRect() call is made when the mouse is
            hDC=BeginPaint(wea.hWnd,ps) 'moved over the window, the window is being
            ptrInstanceData=GetWindowLong(wea.hWnd,0)       'resized, a char key is
            szLine= _                                       'pressed, or a left mouse down
            "MouseX="+Trim$(Str$(@ptrInstanceData.wX)) & _  'is received.  Before the
            "  MouseY="+Trim$(Str$(@ptrInstanceData.wY))    'InvalidateRect() call is made
            TextOut(hDC,0,0,szLine,Len(szLine))             'the data from the specific
            szLine= _                                       'handler that is to be
            "@ptrInstanceData.wWidth="+ _                   'persisted across WndProc()
            Trim$(Str$(@ptrInstanceData.wWidth)) & _        'invocations will be stored in
            " @ptrInstanceData.wHeight=" + _                'the memory pointed to by the
            Trim$(Str$(@ptrInstanceData.wHeight))           'cbWndExtra bytes pointer.
            TextOut _                                       'That pointer will then be
            ( _                                             'retrieved here in WM_PAINT,
              hDC, _                                        'and the data in its totality
              0, _                                          'displayed to the window.  It
              16, _                                         'is one awesome machine.
              szLine, _
              Len(szLine) _
            )
            TextOut(hDC,0,32,@ptrInstanceData.szText,Len(@ptrInstanceData.szText))
            If @ptrInstanceData.xPos<>0 And @ptrInstanceData.yPos<>0 Then
               szLine= _
               "WM_LBUTTONDOWN At (" & Trim$(Str$(@ptrInstanceData.xPos)) & _
               "," & Trim$(Str$(@ptrInstanceData.yPos)) & ")"
               Call TextOut _
               ( _
                 hDC, _
                 @ptrInstanceData.xPos, _
                 @ptrInstanceData.yPos, _
                 szLine, _
                 Len(szLine) _
               )
               @ptrInstanceData.xPos=0 : @ptrInstanceData.yPos=0
            End If
            Call EndPaint(wea.hWnd,ps)
          
            fnWndProc_OnPaint=0
          End Function
          
          
          Function fnWndProc_OnDestroy(wea As WndEventArgs) As Long  'The most noteworthy
            Local ptrInstanceData As tagInstanceData Ptr   'event that must occur here is
            Local hHeap As Dword,blnFree As Dword          'that the memory allocated in
            Static iCtr As Long                            'WM_CREATE, a pointer to which
                                                           'is stored in the cbWndExtra
            hHeap=GetProcessHeap()                         'bytes, must be released or
            ptrInstanceData=GetWindowLong(wea.hWnd,0)      'freed.  HeapFree() is used for
            If ptrInstanceData Then                        'that purpose.  Note that since
               blnFree=HeapFree(hHeap,0,ptrInstanceData)   'two windows of class fnPtrs3
               MsgBox _                                    'were created in WinMain(), and
               ( _                                         'two separate memory allocations
                 "blnFree=" & _                            'were made for the two WM_CREATE
                 Trim$(Str$(IsTrue(blnFree))) _            'messages, two deallocations
               )                                           'will need to be done - one for
               MsgBox _                                    'each window's data.  A static
               ( _                                         'counter variable was stuck in
                 "Always Make Sure Memory Deallocates!  Memory Leaks Are Bad!" _
               )                                           'here so that when it gets
            End If                                         'incremented to %TRUE a
            If iCtr Then                                   'PostQuitMessage() will be
               Call PostQuitMessage(0)                     'called and a WM_QUIT msg put
            End If                                         'in the message quene so the
            Incr iCtr                                      'app can correctly terminate.
          
            fnWndProc_OnDestroy=0
          End Function
          
          
          Sub AttachMessageHandlers() 'Here is where the numeric value of a specific message that
            ReDim MsgHdlr(6) As MessageHandler  'is going to be handled in this program is associated
                                                'with the actual address of the message handler.
            MsgHdlr(0).wMessage=%WM_CREATE      : MsgHdlr(0).fnPtr=CodePtr(fnWndProc_OnCreate)
            MsgHdlr(1).wMessage=%WM_MOUSEMOVE   : MsgHdlr(1).fnPtr=CodePtr(fnWndProc_OnMouseMove)
            MsgHdlr(2).wMessage=%WM_SIZE        : MsgHdlr(2).fnPtr=CodePtr(fnWndProc_OnSize)
            MsgHdlr(3).wMessage=%WM_CHAR        : MsgHdlr(3).fnPtr=CodePtr(fnWndProc_OnChar)
            MsgHdlr(4).wMessage=%WM_LBUTTONDOWN : MsgHdlr(4).fnPtr=CodePtr(fnWndProc_OnLButtonDown)
            MsgHdlr(5).wMessage=%WM_PAINT       : MsgHdlr(5).fnPtr=CodePtr(fnWndProc_OnPaint)
            MsgHdlr(6).wMessage=%WM_DESTROY     : MsgHdlr(6).fnPtr=CodePtr(fnWndProc_OnDestroy)
          End Sub
          
          
          Function WndProc(ByVal hWnd As Long,ByVal wMsg As Long,ByVal wParam As Long,ByVal lParam As Long) As Long
            Local wea As WndEventArgs  'Every time a message is retrieved from the message
            Register iReturn As Long   'loop in WinMain() and ends up here, this For loop
            Register i As Long         'will cycle through all the messages it wants to
                                       'handle to see if it can make a match.  If it makes
            For i=0 To 6               'a match the message handler will be called through
              If wMsg=MsgHdlr(i).wMessage Then     'a UDT array of function pointers.
                 wea.hWnd=hWnd: wea.wParam=wParam: wea.lParam=lParam
                 Call Dword MsgHdlr(i).fnPtr Using fnPtr(wea) To iReturn
                 WndProc=iReturn
                 Exit Function
              End If
            Next i
          
            WndProc=DefWindowProc(hWnd,wMsg,wParam,lParam)
          End Function
          
          
          Function WinMain(ByVal hIns As Long,ByVal hPrevIns As Long,ByVal lpCmdLine As Asciiz Ptr,ByVal iShow As Long) As Long
            Local hWnd1 As Dword, hWnd2 As Dword
            Local szClassName As Asciiz*16
            Local wc As WndClassEx
            Local Msg As tagMsg
          
            Call AttachMessageHandlers()  'Attach User Defined Type array of messages and function pointers.
            szClassName="fnPtrs3"         'Note that in the WndClassEx Type the cbWndExtra bytes were set to four.
            wc.cbSize=SizeOf(wc)                               : wc.style=0
            wc.lpfnWndProc=CodePtr(WndProc)                    : wc.cbClsExtra=0
            wc.cbWndExtra=4                                    : wc.hInstance=hIns
            wc.hIcon=LoadIcon(%NULL,ByVal %IDI_APPLICATION)    : wc.hCursor=LoadCursor(%NULL,ByVal %IDC_ARROW)
            wc.hbrBackground=GetStockObject(%WHITE_BRUSH)      : wc.lpszMenuName=%NULL
            wc.lpszClassName=VarPtr(szClassName)               : wc.hIconSm=0
            Call RegisterClassEx(wc)
            hWnd1=CreateWindowEx(0,szClassName,"fnPtrs3",%WS_OVERLAPPEDWINDOW,200,100,425,360,%HWND_DESKTOP,0,hIns,ByVal 0)
            hWnd2=CreateWindowEx(0,szClassName,"fnPtrs3",%WS_OVERLAPPEDWINDOW,250,150,425,360,%HWND_DESKTOP,0,hIns,ByVal 0)
            Call ShowWindow(hWnd1,iShow)
            Call ShowWindow(hWnd2,iShow)
            While GetMessage(Msg,%NULL,0,0)
              Call TranslateMessage(Msg)
              Call DispatchMessage(Msg)
            Wend
          
            WinMain=msg.wParam
          End Function
          Hope this helps!
          Fred
          "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

          Comment


          • #6
            [QUOTE=Chris Boss;273475]What exactly are you trying to accomplish ?

            For the moment, just to handle all the events in one place. I could do something similar as you suggest with DDT, but for other reasons I want to use SDK style.

            Thanks for finding the missing WM_CREATE, it took me 5 minutes and then I read your post! Must give up late working.

            Comment


            • #7
              Fred, thanks for the pointer (in your code) to Jose Roca's forums. I will have to look more closely at them.

              Originally posted by Fred Harris View Post
              In my opinion its a tremendously elegant and beautiful design.
              I hope that one day I shall agree with you.

              Originally posted by Fred Harris View Post
              In Linux/Unix ... chaotic...
              I'm not a UNIX fanatic either!

              Your example was interesting, I shall study the heap stuff carefully as I need to do something like this. Semantics: "events" and "messages" seem to be interchangeable. What name do you give to the unique combination of a specific message in a specific control? What I want my event handler to do is be aware of the event and control and do processing for that combination if any has been defined. That should take just one lookup and one jump!

              Comment


              • #8
                OK I found the mistake. When receiving a WM_USER + 100 message ( a notification that the parent had received a WM_COMMAND message), the local copy of the message id was being set to the CBCTLMSG, should have been to WM_COMMAND. The CBCTLMSG (for example, BN_CLICKED) should be dug out by the event code, not the handler.

                Comment


                • #9
                  I tend to use 'event' and 'message' interchangebly, particularly in the context of 'event handler' or 'message handler'. When the OS detects something - some kind of input, that's of course an event, so it packages the associated information together in a 'message'. Now an event occurring in a GUI will usually be associated with a window handle, and of course that's one of the most important parameters and actually the first of the four to the WndProc. The other two parameters to the WndProc (other than the msg itself) are wParam and lParam. These usually carry a heavy load as they are usually parsed into their low and high words. So in essence, when an event occurs involving any of the 'simple' windows controls, i.e., buttons, textboxes, etc., there is the potential for six unique pieces of information being transferred...

                  1) hWnd
                  2) msg
                  3) Lowrd(wParam)
                  4) Hiwrd(wParam)
                  5) Lowrd(lParam)
                  6) Hiwrd(lParam)

                  Taking the specific example of a button control on a dialog/form/parent window, these parameters would look like this when the button is clicked...

                  1) hWnd - Parent Window Handle whose child is the button
                  2) WM_COMMAND message
                  3) Lowrd(wParam) - Control ID of the button, i.e., %IDC_BUTTON1
                  4) Hiwrd(wParam) - %BN_CLICKED Notification Code
                  5) lParam hWnd of Button

                  So a whole 'packet' of information comes through for each event.

                  Now the situation with more complex controls (such as the Windows Common Controls and custom controls) is such that even the six potential piecies of information as described above won't be enough. In these cases Microsoft created the NMHDR structure/Type to augment the data transfer mechanism, and messages from these types of controls usually contain a pointer to a NMHDR type in the lParam. This opens the possibility of transferring an almost unlimited quantity of information through the messaging mechanism.

                  What I typically do for WM_COMMAND messages in the Wnd_Proc is route them to a WM_COMMAND message handler like so...
                  Code:
                  Case %WM_COMMAND
                     WndProc=fnWndProc_OnCommand(...)
                     Exit Function
                  
                  Then have a OnCommand() handler like so...
                  
                  Function fnWndProc_OnCommand(...)
                    Select Case As Long Lowrd(wParam)
                      Case %IDC_BUTTON1   'button was probably clicked
                         Call cmdButton1_OnClick(...)
                      Case %IDC_COMBOBOX1
                         Call cboBuyers(...)    'something happened with combo box
                      ..
                      ..
                    End Select    
                  End Function
                  
                  finally routines to handle code that actually does something in response to user's actions...
                  
                  Sub cmdButton1_OnClick(...)
                    ''code that does something
                  End Sub
                  In this way your program keeps investigating the message in order to determine its eventual disposition in terms of what Non UI code needs to run.
                  Last edited by Fred Harris; 15 Jan 2008, 08:36 AM. Reason: Fix Inaccuracy - notification code
                  Fred
                  "fharris"+Chr$(64)+"evenlink"+Chr$(46)+"com"

                  Comment


                  • #10
                    You can create your own event engine using DDT, bu subclassing controls and then sending user defined messages through the WM_COMMAND message (sent to parent dialog).

                    Call me an old fuddy-duddy, but I simply cannot endorse this method.

                    If you need custom notification messages, use the methods provided: either defining messages in the WM_USER to 0x7FFF range, or using RegisterWindowMessage.

                    Playing with the notification codes for existing messages has got to be tinkering with fire. Besides, HIWRD(wparam) or "CBCTLMSG" is also used to identify the fact that WM_COMMAND originated from the control, a menu or accelerator.

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

                    Comment


                    • #11
                      This is the way I do it for projects, and have for years. (Well before DDT)

                      The code is all generated from an rc dialog.

                      James




                      Code:
                      '----------------------------------------------------------------------------
                      'The following UDT is used for encapsulation of message cracker arrays. 
                      'If you need any private data just add to the UDT.
                      '----------------------------------------------------------------------------
                      TYPE DLG_100_InfoType
                        MaxDlgMsgs           AS LONG
                        DlgMsgs              AS DWORD PTR
                        DlgProcs             AS DWORD PTR
                        MaxCtlMsgs           AS LONG
                        CtlMsgs              AS DWORD PTR
                        CtlProcs             AS DWORD PTR
                        MaxNotifyMsgs        AS LONG
                        NotifyCtlIds         AS DWORD PTR
                        NotifyProcs          AS DWORD PTR
                        ExitFlag             AS LONG
                        DlgId                AS LONG
                      
                      END TYPE
                      Allocate memory for the UDT


                      Code:
                        ghHeap = HeapCreate(%HEAP_NO_SERIALIZE,1024,0)
                        lpMem = HeapAlloc(ghHeap,%HEAP_NO_SERIALIZE OR %HEAP_ZERO_MEMORY,LEN(DLG_100_InfoType))
                        lpDataInfo = lpMem


                      Set Up the Message Crackers

                      Code:
                      '=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
                      'DLG_100
                      '=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=
                      @lpDataInfo.MaxDlgMsgs =  9 
                      @lpDataInfo.MaxCtlMsgs =  2 
                      @lpDataInfo.MaxNotifyMsgs =  0 
                      '---------------------------------------------------------------------------
                      MemOffset = HeapAlloc(ghHeap,%HEAP_NO_SERIALIZE OR %HEAP_ZERO_MEMORY,(@lpDataInfo.MaxDlgMsgs + _
                                                     @lpDataInfo.MaxCtlMsgs + _
                                                     @lpDataInfo.MaxNotifyMsgs)*8)
                      IF ISFALSE MemOffset THEN
                        MsgBox "Message Array memory allocation error"
                        FUNCTION = 0
                        EXIT FUNCTION
                      END IF
                      '---------------------------------------------------------------------------
                      IF @lpDataInfo.MaxDlgMsgs THEN
                         @lpDataInfo.DlgMsgs = MemOffset
                         MemOffset = MemOffset + (@lpDataInfo.MaxDlgMsgs * 4)
                         @lpDataInfo.DlgProcs = MemOffset
                         MemOffset = MemOffset + (@lpDataInfo.MaxDlgMsgs * 4)
                      END IF
                      IF @lpDataInfo.MaxCtlMsgs THEN
                         @lpDataInfo.CtlMsgs = MemOffset 
                         MemOffset = MemOffset + (@lpDataInfo.MaxCtlMsgs * 4)
                         @lpDataInfo.CtlProcs = MemOffset
                         MemOffset = MemOffset + (@lpDataInfo.MaxCtlMsgs * 4)
                      END IF
                      IF @lpDataInfo.MaxNotifyMsgs THEN
                         @lpDataInfo.NotifyCtlIds =  MemOffset
                         MemOffset = MemOffset + (@lpDataInfo.MaxNotifyMsgs * 4)
                         @lpDataInfo.NotifyProcs = MemOffset
                      END IF
                      '===========================================================================
                      '>> BEGIN DLG_MSGS
                      '===========================================================================
                        MsgIndex = 0
                      '---------------------------------------------------------------------------
                      '~%WM_INITDIALOG   (%WM_INITDIALOG IS ALWAYS FIRST)
                      '---------------------------------------------------------------------------
                        @[email protected][MsgIndex] = %WM_INITDIALOG
                        @[email protected][MsgIndex] = CODEPTR(DLG_100_OnWmInitDialog)
                        INCR MsgIndex
                      '---------------------------------------------------------------------------
                      '~%WM_COMMAND
                      '---------------------------------------------------------------------------
                        @[email protected][MsgIndex] = %WM_COMMAND
                        @[email protected][MsgIndex] = CODEPTR(Ctl_Event_Proc)
                        INCR MsgIndex
                      '---------------------------------------------------------------------------
                      '~%WM_CTLCOLORSTATIC
                      '---------------------------------------------------------------------------
                        @[email protected][MsgIndex] = %WM_CTLCOLORSTATIC
                        @[email protected][MsgIndex] = CODEPTR(WM_CTLCOLOR_Proc)
                        INCR MsgIndex
                      '---------------------------------------------------------------------------
                      '~%WM_CTLCOLORBTN
                      '---------------------------------------------------------------------------
                        @[email protected][MsgIndex] = %WM_CTLCOLORBTN
                        @[email protected][MsgIndex] = CODEPTR(WM_CTLCOLOR_Proc)
                        INCR MsgIndex
                      '---------------------------------------------------------------------------
                      '~%WM_CTLCOLOREDIT
                      '---------------------------------------------------------------------------
                        @[email protected][MsgIndex] = %WM_CTLCOLOREDIT
                        @[email protected][MsgIndex] = CODEPTR(WM_CTLCOLOR_Proc)
                        INCR MsgIndex
                      '---------------------------------------------------------------------------
                      '~%WM_CTLCOLORLISTBOX
                      '---------------------------------------------------------------------------
                        @[email protected][MsgIndex] = %WM_CTLCOLORLISTBOX
                        @[email protected][MsgIndex] = CODEPTR(WM_CTLCOLOR_Proc)
                        INCR MsgIndex
                      '---------------------------------------------------------------------------
                      '~%WM_CLOSE
                      '---------------------------------------------------------------------------
                        @[email protected][MsgIndex] = %WM_CLOSE
                        @[email protected][MsgIndex] = CODEPTR(DLG_100_OnWmClose)
                        INCR MsgIndex
                      '---------------------------------------------------------------------------
                      '~%WM_DESTROY
                      '---------------------------------------------------------------------------
                        @[email protected][MsgIndex] = %WM_DESTROY
                        @[email protected][MsgIndex] = CODEPTR(DLG_100_OnWmDestroy)
                        INCR MsgIndex
                      '---------------------------------------------------------------------------
                      '~%WM_DRAWITEM
                      '---------------------------------------------------------------------------
                        @[email protected][MsgIndex] = %WM_DRAWITEM
                        @[email protected][MsgIndex] = CODEPTR(DLG_100_OnWmDrawItem)
                        INCR MsgIndex
                      '---------------------------------------------------------------------------
                      '>> END DLG_MSGS
                      '===========================================================================
                      '>> BEGIN CTL_MSGS
                      '===========================================================================
                        MsgIndex = 0
                      '---------------------------------------------------------------------------
                      '~DLG_100_DLG_10_PB_OK_OnClick >> %BN_CLICKED <<
                      '---------------------------------------------------------------------------
                        @[email protected][MsgIndex] = MAKDWD(%DLG_100_DLG_10_PB_OK,%BN_CLICKED)
                        @[email protected][MsgIndex] = CODEPTR(DLG_100_DLG_10_PB_OK_OnClick)
                        INCR MsgIndex
                      '---------------------------------------------------------------------------
                      '~DLG_100_PB_CANCEL_OnClick >> %BN_CLICKED <<
                      '---------------------------------------------------------------------------
                        @[email protected][MsgIndex] = MAKDWD(%DLG_100_PB_CANCEL,%BN_CLICKED)
                        @[email protected][MsgIndex] = CODEPTR(DLG_100_PB_CANCEL_OnClick)
                        INCR MsgIndex
                      '---------------------------------------------------------------------------
                      '>> END CTL_MSGS
                      '===========================================================================
                      '>> BEGIN NOTIFY_MSGS
                      '===========================================================================
                        MsgIndex = 0
                      '---------------------------------------------------------------------------
                      '>> END NOTIFY_MSGS
                      '===========================================================================
                      '~EOM         End of Messages
                      '=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=

                      The Single Message Procedure for All Dialogs

                      Code:
                      '----------------------------------------------------------------------------
                      '~Dlg_Event_Proc            [Sub/Func Tag]
                      '----------------------------------------------------------------------------
                      FUNCTION _
                        Dlg_Event_Proc ( _
                          BYVAL hDlg			AS DWORD,_
                          BYVAL wMsg			AS DWORD,_
                          BYVAL wParam		AS DWORD,_
                          BYVAL lParam		AS LONG _ 
                        )  AS LONG
                      
                        DIM i				AS LONG, _
                            pEventInfo	AS EventInfoType PTR, _
                            dwTemp		AS DWORD
                        
                      
                        IF wMsg = %WM_INITDIALOG THEN
                          
                          #IF %DEF(%ADP_MACROS)
                            m_SetDataInfo(hDlg,lParam)      
                          #ELSE
                            SetWindowLong hDlg,%DWL_USER,lParam
                          #ENDIF  
                          
                          pEventInfo = lParam
                          dwTemp = @[email protected][0]
                        ELSE
                          #IF %DEF(%ADP_MACROS)
                            pEventInfo = m_GetDataInfo(hDlg)
                          #ELSE
                            pEventInfo = GetWindowLong(hDlg,%DWL_USER)
                          #ENDIF  
                          IF ISFALSE pEventInfo THEN
                            EXIT FUNCTION
                          END IF
                          DO
                            IF i > @pEventInfo.MaxDlgMsgs THEN
                              EXIT DO
                            END IF
                            IF @[email protected][i] = wMsg THEN
                              dwTemp = @[email protected][i]
                              EXIT DO
                            END IF
                            INCR i
                          LOOP
                        END IF
                        IF dwTemp THEN
                          CALL DWORD dwTemp _
                            USING DlgCallBackProc(hDlg,_
                                                  wMsg,_
                                                  wParam,_
                                                  lParam) TO i
                          FUNCTION = i
                          SetWindowLong hDlg, %DWL_MSGRESULT, i
                        END IF
                        END FUNCTION
                      '==============================================================================
                      And finally the actual procedures.

                      Code:
                      'Message Cracker Functions For DLG_100
                      '============================================================================
                      '>> Dialog Functions
                      '============================================================================
                      '============================================================================
                      '~DLG_100_OnWmInitDialog           [Sub/Func Tag]
                      '============================================================================
                      FUNCTION _ 
                        DLG_100_OnWmInitDialog ( _
                          BYVAL hDlg        AS DWORD,_
                          BYVAL wMsg        AS DWORD,_
                          BYVAL wParam      AS DWORD,_
                          BYVAL lParam      AS LONG _
                        ) AS LONG
                      
                        DIM lpDataInfo       AS DLG_100_InfoType PTR
                      
                        lpDataInfo = m_GetDataInfo(hDlg)
                      
                        Initialize_Controls hDlg
                      '---------------------------------------------------------------------------
                        CenterWindow hDlg
                       FUNCTION = 1
                      END FUNCTION
                      '============================================================================
                      '~DLG_100_OnWmDestroy          [Sub/Func Tag]
                      '============================================================================
                      FUNCTION _ 
                        DLG_100_OnWmDestroy ( _
                          BYVAL hDlg			AS DWORD,_
                          BYVAL wMsg			AS DWORD,_
                          BYVAL wParam		AS DWORD,_
                          BYVAL lParam		AS LONG _
                        ) AS LONG
                      
                        DIM lpDataInfo      AS DLG_100_InfoType PTR
                      
                        lpDataInfo = m_GetDataInfo(hDlg)
                        #IF %DEF(%DLG_100_USE_OD_BUTTONS)
                          EnumChildWindows hDlg,CODEPTR(ODButFreeMem2),0
                        #ENDIF
                      
                        #IF %DEF(%USE_SPREAD)
                          EnumChildWindows hDlg,CODEPTR(SS_UserDataFreeMem),0
                        #ENDIF
                        EnumChildWindows hDlg,CODEPTR(Control_FreeMem),0
                        PostQuitMessage 0
                       FUNCTION = 0
                      END FUNCTION
                      '============================================================================
                      '~DLG_100_OnWmClose            [Sub/Func Tag]
                      '============================================================================
                      FUNCTION _ 
                        DLG_100_OnWmClose ( _
                          BYVAL hDlg        AS DWORD,_
                          BYVAL wMsg        AS DWORD,_
                          BYVAL wParam      AS DWORD,_
                          BYVAL lParam      AS LONG _
                        ) AS LONG
                      
                        DestroyWindow hDlg
                        FUNCTION = 0
                      END FUNCTION
                      '============================================================================
                      '============================================================================
                      '~DLG_100_OnWmDrawItem            [Sub/Func Tag]
                      '============================================================================
                      FUNCTION _
                        DLG_100_OnWmDrawItem ( _
                          BYVAL hDlg		AS DWORD,_
                          BYVAL wMsg      AS DWORD,_
                          BYVAL wParam    AS DWORD,_
                          BYVAL lParam    AS DWORD _
                        ) AS DWORD
                      
                      #IF %DEF(%DLG_100_USE_OD_BUTTONS)
                      
                      
                        LOCAL lpODButInfo		AS ODBut_InfoType PTR ,_
                              di				AS DRAWITEMSTRUCT PTR,_
                              lpCtlInfo		AS ControlInfoType PTR, _
                              bm				AS BITMAP,_
                              hBitmap			AS DWORD,_
                              rFocus			AS RECT,_
                              DcRect          AS RECT,_
                              NoFocusFlag     AS INTEGER
                      
                        di = lParam
                      
                        lpCtlInfo = GetProp(@di.hWndItem,"CtlInfo")
                        lpODButInfo = @lpCtlInfo.dwx
                      
                        IF ISFALSE lpODButInfo THEN
                          EXIT FUNCTION
                        END IF
                        IF (@di.ItemState AND %ODS_SELECTED) THEN
                          hBitMap = @lpODButInfo.hBitmapDn
                          rFocus = @lpODButInfo.rFocusDn
                        ELSE
                          hBitmap = @lpODButInfo.hBitmapUp
                          rFocus = @lpODButInfo.rFocusUp
                        END IF
                        GetObject hBitmap,LEN(BITMAP),bm
                        DcRect.nRight = bm.bmWidth
                        DcRect.nBottom = bm.bmHeight
                      
                        IF (@di.ItemAction AND %ODA_DRAWENTIRE) OR _
                          (@di.ItemAction AND %ODA_SELECT) THEN
                          PaintBitmap @di.hDc,DcRect,hBitMap,DcRect,@lpODButInfo.hPal
                        END IF
                      
                        'Need some code for focus
                        IF ISFALSE @lpODButInfo.NoFocusFlag  THEN
                          IF (@di.ItemState AND %ODS_FOCUS) THEN
                            FrameRect @di.hDc,rFocus,GetStockObject(%DKGRAY_BRUSH)
                          END IF
                        END IF
                        FUNCTION = 1
                      #ENDIF
                      END FUNCTION
                      '============================================================================
                      '============================================================================
                      '>> Control Functions
                      '============================================================================
                      '~DLG_100_DLG_10_PB_OK_OnClick          [Sub/Func Tag]
                      '============================================================================
                      FUNCTION _ 
                        DLG_100_DLG_10_PB_OK_OnClick ( _
                          BYVAL hDlg      AS DWORD,_
                          BYVAL wMsg      AS DWORD,_
                          BYVAL wParam    AS DWORD,_
                          BYVAL lParam    AS LONG _
                        ) AS LONG
                      
                      '>> Unrem if needed
                      '  DIM lpDataInfo   AS DLG_100_InfoType PTR
                      
                      '  lpDataInfo = m_GetDataInfo(hDlg)
                      
                        '----> Your Code Here <----
                      
                      END FUNCTION
                      '============================================================================
                      '~DLG_100_PB_CANCEL_OnClick         [Sub/Func Tag]
                      '============================================================================
                      FUNCTION _ 
                        DLG_100_PB_CANCEL_OnClick ( _
                          BYVAL hDlg      AS DWORD,_
                          BYVAL wMsg      AS DWORD,_
                          BYVAL wParam    AS DWORD,_
                          BYVAL lParam    AS LONG _
                        ) AS LONG
                      
                      '>> Unrem if needed
                      '  DIM lpDataInfo   AS DLG_100_InfoType PTR
                      
                      '  lpDataInfo = m_GetDataInfo(hDlg)
                      
                        '----> Your Code Here <----
                      
                      END FUNCTION
                      '============================================================================

                      Comment


                      • #12
                        WM_COMMAND and WM_NOTIFY are the standard ways of sending events from controls to dialogs.

                        WM_COMMAND is easier to impliment, so I suggest this, but WM_NOTIFY offers more control and parameter passing.

                        When one is writing their own application you have control of how both messages are processed and as long as one uses notification codes not currently used by the operating system then the danger is minimal. Of course one needs to be aware that future operating systems may use those notification code values and that must be taken into consideration.

                        The suggestion I made was based on the fact that currently DDT only supports WM_COMMAND messages for passing events to a controls callback function. Using any other method, tends to lose all the benefits of DDT.

                        Of course Chris said he prefers the SDK routine, so in that case, setting up an event routine and providing a way for windows to get the functions address and to call it will work fine.

                        I like working with DDT (when not using my own GUI engine), since so many PB users work with it and solutions using DDT tend to benefit more people. Currently I am working on a DDT Designer which does use an Event engine (not using WM_COMMAND), but it is based on a different coding model than most DDT apps. I do see the advantage of building an easy to use event engine.
                        Chris Boss
                        Computer Workshop
                        Developer of "EZGUI"
                        http://cwsof.com
                        http://twitter.com/EZGUIProGuy

                        Comment

                        Working...
                        X