No announcement yet.

dll and subclassing

  • Filter
  • Time
  • Show
Clear All
new posts

  • dll and subclassing

    It's still early days for me with dlls.

    My objective is to create a window in the exe and create then subclass a child window on it in the dll. I have established that DDT cannot be used in this way, not for the subclassed control anyway.

    Whenever control is passed to the subclass proc, things start to go wrong, usually ending in a GPF. I've gone around it a couple of times without success - any suggestions?

    the dll code
    ' dll and subclass problem
    #compile dll
    #dim all
    #include ""
    global hCtlStatic as dword
    global hDlg as dword
    global OldProc as dword
    function SCProc ( hWnd as dword, byval wMsg as dword, byval wparam as dword, byval lparam as dword) export as long
        local s as string
        ? "SubClassProc"
        s = "replacement title" 'hex$(wmsg)
        sendmessage hDlg, %WM_SETTEXT, 0, strptr(s)
        function = callWindowProc(OldProc, hWnd, Wmsg, wParam, lParam)
        'function = defWindowProc(hWnd, Wmsg, wParam, lParam)
    end function
    function CrWnd alias "CrWnd" ( hd as dword, lCtlStatic as long) export as dword
        local hinst, dw as dword
        local l as long
        hCtlStatic = CreateWindowEx(0,"Static","", _
                  %ws_child or %ws_visible or %ws_tabstop or %ws_border, _
                  205, 5, 200, 150, _
                  hd, lCtlStatic, getmodulehandle(byval 0), byval %NULL)
        hDlg = hD
        ? "hWnd=" + str$(hCtlStatic) + str$(hd)
        ? "pre subclass"
        OldProc = SetWindowLong(hCtlStatic, %GWL_WNDPROC, codeptr(SCProc))
        ? "post subclass"
    end function
    the exe code
    ' DDT DLL problem
    ' Chris Holbrook 22-DEC-2008
    #compile exe
    #dim all
    #include "WIN32API.INC"
    %IDD_DIALOG1 = 101
    %IDC_Static      = 1002
    declare function CrWnd lib "dllscproblem.dll" alias "CrWnd" ( hd as dword, lctlStatic as long) as dword
    'declare function SCProc lib "dllscproblem.dll" alias "SCProc" ( hWnd as dword, byval wMsg as dword, byval wparam as dword, byval lparam as dword) as long
    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
        select case uMsg
            case %wm_destroy
                PostQuitMessage 0
                exit function
            case %wm_create
                CrWnd( hWnd, %IDC_Static)' Create a STATIC control
                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
        ' Register the Form1 window
        szClassName        = "MY_CLASS"
        tWCX.cbSize        = sizeof(tWCX)                               ' size of WNDCLASSEX structure         = %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
        ' Create main window
        hWnd = CreateWindowEx(%ws_ex_windowedge, _
                              szClassName, _
                              "One day...",_
                              %ws_overlapped or %ws_visible or %ws_sysmenu, _
                               100, 100, 200, 100, _
                              %NULL, %NULL, hInstance, byval %NULL)
        ' fail if window is not created
        if isfalse hWnd then
          function = %FALSE
          exit function
        end if
        ' Activate window
        ShowWindow hWnd, %sw_show
        UpdateWindow hWnd
        while istrue GetMessage(tmsg, byval %NULL, 0, 0)
            if isfalse IsDialogMessage(hWnd, tmsg) then
                TranslateMessage tmsg
                DispatchMessage tmsg
            end if
    end function

  • #2
    I am not sure what you are trying to accomplish, but at first glance you have a problem in your subclassing routine.

    Be very careful of executing code outside of a Select case structure for the MSG parameter. For example you call:

    sendmessage hDlg, %WM_SETTEXT, 0, strptr(s)

    and it is not within a standard message processing select case structure.


       CASE %WM_LBUTTONUP   ' some message to be processed
       CASE ELSE

    in the subclass routine and it is not in a standard Select case structure for messages. Actually you don't have such a structure.

    What happens is that the code that is not in such a structure, gets executed for "every single message" the window processes and there can be many. Especially when the mouse moves over a control, there can be hundreds of messages generated within a few seconds.

    By calling sendmessage the way you do to set text for the parent window, this could happen many, many times very quickly.

    While the API docs don't discuss this as far as I know, this can create what I would call an "overload" for Windows.

    I don't know if this is the cause of your problem, but it surely is not a good practice.
    Chris Boss
    Computer Workshop
    Developer of "EZGUI"


    • #3
      Thanks Chris - yes, I debugged the select statement out of existence. Replacing it with the code below doesn't change the outward signs much.

          select case wMsg
              case %wm_lbuttonup   ' some message to be processed
                  s = "replace title"
                  sendmessage hDlg, %WM_SETTEXT, 0, strptr(s)
              case else
          end select


      • #4
        Found the problem!


        hWnd as dword


        BYVAL hWnd as dword

        in the subclass procedures parameter list.

        Forgetting the BYVAL in any of the parameters will definitely cause a crash.
        Chris Boss
        Computer Workshop
        Developer of "EZGUI"


        • #5
          Chris, thanks a thousand!


          • #6
            AMAZING how just 1 lil word can speak TONS!!!!!

            Especially "BYVAL" and "BYREF" and how it is used in a language, or if omitted (what is substituted in its place)

            Sometimes this is the cause in the ole
            1. Works great
            2. Suddenly fails
            3. WHAT???? just happened????
            4. Somethings wrong.....what changed?
            5. Nothing changed (that I can find)....sooooo "WHATTTT CHANGED!!!!"
            6. Nothing
            7. Nothing
            8. Nothing
            9. Oppps missed a word, and a "Bug" has been there all the while and just now crept up
            Engineer's Motto: If it aint broke take it apart and fix it

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

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

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