Announcement

Collapse
No announcement yet.

Subclass dialog from DLL

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

  • Subclass dialog from DLL


    I don't understand what I'm doing wrong. I want to reach all events from dialog1(main), I have tried this with a SUBCLASS of dialog1 to be able to capture this in a child dialog Can anyone point out what I'm doing wrong? Tank's in advance
    Code:
    [FONT=Helvetica]#COMPILE EXE[/FONT]  #DIM ALL
    
    #INCLUDE "WIN32API.INC"
    
    %IDD_DIALOG1 =  101
    %IDC_BUTTON1 = 1001
    
    DECLARE FUNCTION startdll LIB "MyDll.dll" ALIAS "initdll" (BYVAL xx AS LONG) AS LONG
    
    FUNCTION PBMAIN()  '   ** Main Application Entry Point **
        ShowDIALOG1 %HWND_DESKTOP
    END FUNCTION
    '------------------------------------------------------------------------------
    CALLBACK FUNCTION ShowDIALOG1Proc() '   ** CallBacks **
        LOCAL lblTEXT AS ASCIIZ * 20
    
        SELECT CASE AS LONG CBMSG
    
            CASE %WM_COMMAND
                SELECT CASE AS LONG CBCTL
                    CASE %IDC_BUTTON1
                     startdll( GetActiveWindow() )  ' Send active hWnd
                END SELECT
        END SELECT
    END FUNCTION
    '------------------------------------------------------------------------------
    FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG   '   ** Dialogs **
        LOCAL lRslt AS LONG
        LOCAL hDlg  AS DWORD
        DIALOG NEW hParent, "Dialog1", 70, 70, 201, 121, _
              %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
              %WS_MINIMIZEBOX OR %WS_MAXIMIZEBOX TO hDlg
        CONTROL ADD BUTTON, hDlg, %IDC_BUTTON1, "Start MyDll", 5, 10, 70, 20
        DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
        FUNCTION = lRslt
    END FUNCTION


    Code:
    #COMPILE DLL
    #DIM ALL
    #INCLUDE "Win32API.inc"
    
    %IDC_Button = 500
    %IDC_Button1= 501
    
    GLOBAL hWndMain AS DWORD
    GLOBAL hWndInst AS DWORD
    
    '-------------------------------------------------------------------------------
    ' Main DLL entry point called by Windows...
    '
    FUNCTION LIBMAIN (BYVAL hInstance   AS LONG, _
                      BYVAL fwdReason   AS LONG, _
                      BYVAL lpvReserved AS LONG) AS LONG
    
        SELECT CASE fwdReason
            CASE %DLL_PROCESS_ATTACH
                'Indicates that the DLL is being loaded by another process (a DLL
                'or EXE is loading the DLL).  DLLs can use this opportunity to
                'initialize any instance or global data, such as arrays.
    
                FUNCTION = 1   'success!
                'FUNCTION = 0   'failure!  This will prevent the EXE from running.
    
            CASE %DLL_PROCESS_DETACH
                'Indicates that the DLL is being unloaded or detached from the
                'calling application.  DLLs can take this opportunity to clean
                'up all resources for all threads attached and known to the DLL.
    
                FUNCTION = 1   'success!
                'FUNCTION = 0   'failure!
    
            CASE %DLL_THREAD_ATTACH
                'Indicates that the DLL is being loaded by a new thread in the
                'calling application.  DLLs can use this opportunity to
                'initialize any thread local storage (TLS).
    
                FUNCTION = 1   'success!
                'FUNCTION = 0   'failure!
    
            CASE %DLL_THREAD_DETACH
                'Indicates that the thread is exiting cleanly.  If the DLL has
                'allocated any thread local storage, it should be released.
    
                FUNCTION = 1   'success!
                'FUNCTION = 0   'failure!
        END SELECT
    END FUNCTION
    
    FUNCTION initdll ALIAS "initdll"(BYVAL hInst AS LONG ) EXPORT AS LONG
        LOCAL hwnd  AS DWORD
        LOCAL lpCmdLine AS ASCIIZ PTR
    
        hWndInst = hInst
        hwnd = GetParent(hwnd)
        WINMAIN hwnd, 0, lpCmdLine, %SW_SHOW
    END FUNCTION
    
    FUNCTION WINMAIN (BYVAL hInst AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpCmdLine AS ASCIIZ PTR, BYVAL iCmdShow AS LONG) AS LONG
       'arguments to WinMain are provided by Windows - not defined by the programmer
       'hInst             current instance of the application
       'hPrevInstance    previous instance (not used - returns %Null in Win32)
       'lpCmdLine        pointer to command line (whatever the user types in after MyApp.EXE). A null terminated string.
       'iCmdShow         used the first time ShowWindow is called to display the application main window
       LOCAL Msg         AS tagMsg
       LOCAL W           AS WndClassEx
       LOCAL szAppName  AS ASCIIZ * 80
       LOCAL hWndButton AS DWORD
       LOCAL hAccel     AS DWORD
       LOCAL WndStyle   AS LONG
       LOCAL WndStyleX  AS LONG
       LOCAL hWnd,hInstance AS DWORD
    
       'register window class
       szAppName = "SDK"
       W.cbSize        = SIZEOF(W)
       W.Style         = %CS_HREDRAW OR %CS_VREDRAW   '%WS_OverlappedWindow Or %WS_HScroll Or %WS_VScroll  '
       W.lpfnWndProc   = CODEPTR(WndProc)
       W.cbClsExtra    = 0
       W.cbWndExtra    = 0
       W.hInstance     = hInst
       W.hIcon         = %null 'LoadIcon(hInst, "logo")
       W.hCursor       = LoadCursor(%NULL, BYVAL %IDC_ARROW)
       W.hbrBackground = %Color_BtnFace+1
       W.lpszMenuName  = %NULL
       W.lpszClassName = VARPTR(szAppName)
       W.hIconSm       = LoadIcon(hInst, BYVAL %IDI_APPLICATION)   'why not %NULL
       RegisterClassEx W
    
       'create window of that class
       WndStyle  = %WS_OVERLAPPEDWINDOW
       WndStyleX = %WS_EX_LEFT
       hWndMain  = CreateWindowEX( _
          WndStyleX,  _    'dwStyle        extended style of window
          szAppName,  _    'lpClassName    pointer to a null-terminated string (any registered name, including predefined system class names).
          "Child dialog",      _    'lpWindowName   pointer to a null-terminated String (placed in title bar, text of the control, icon name or #identifier)
          WndStyle,   _    'dwStyle        style of window
          500,        _    'x              initial horizontal position (upper left screen, except for child is relative to parent window's client area)
          400,        _    'y              initial vertical position  (upper left screen, except for child is relative to parent window's client area)
          300,        _    'nWidth         width in device units
          300,        _    'nHeight        height in device units
          %Null,      _    'hWndParent     handle to parent window (optional for a pop-up window)
          %Null,      _    'hMenu          handle to a menu
          hInst,      _    'handle to instance of the module to be associated with the window
          BYVAL %Null _    'pointer to CREATESTRUCT structure pointed to by the lParam param of the WM_CREATE message.
          )
    
       'create window of existing class "Button"
       WndStyle  = %WS_TABSTOP OR %WS_VISIBLE OR %WS_CHILD OR %BS_DEFPUSHBUTTON
       hInstance = GetWindowLong(hWndMain, %GWL_HINSTANCE)
        hWnd= CreateWindow( "Button", "Send to Parent",  WndStyle, 10, 10, 110, 25, hWndMain, %IDC_Button , hInstance, BYVAL %Null )
        hWnd= CreateWindow( "Button", "Get Parent size", WndStyle, 10, 40, 160, 25, hWndMain, %IDC_Button1, hInstance, BYVAL %Null )
    
    
       ShowWindow hWndMain, iCmdShow   'controls how window is to be shown. 1st must use iCmdShow
       UpdateWindow hWndMain           'sends the window it's first WM_Create to display the window on the screen
    
       'message pump - calls WndProc whenever an application-specific message is received
       'WndProc can process the message, or pass it on to a the default window procedure that is built into Windows.
       WHILE GetMessage(Msg, %NULL, 0, 0) > 0
          IF ISFALSE TranslateAccelerator (hWndMain, hAccel, Msg) THEN
             IF ISFALSE ISDialogMessage (hWndMain, Msg) THEN
                TranslateMessage Msg
                DispatchMessage  Msg
             END IF
          END IF
       WEND
    END FUNCTION
    
    FUNCTION WndProc (BYVAL hWnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) EXPORT AS LONG
       LOCAL hDC AS DWORD, pPaint AS PAINTSTRUCT, tRect  AS RECT
       LOCAL pnmhdr AS NMHDR PTR
       LOCAL oldProc AS DWORD
       LOCAL lblTEXT AS ASCIIZ * 20
       LOCAL DialogID AS LONG
    
    
       SELECT CASE wMsg
    
           CASE %WM_INITDIALOG
               ' Subclass
               DialogID = getdlgctrlid ( hWndInst )
               oldProc = SetWindowLong( DialogID, %GWL_WNDPROC, CODEPTR(SubClassProc))
    
               'SetTimer hWnd, 1001, 500, 0
               'SendMessage hwnd,%WM_TIMER, 1001, 0
    
           CASE %WM_DESTROY
              SetWindowLong DialogID, %GWL_WNDPROC, oldProc
              PostQuitMessage 0
              EXIT FUNCTION
    
    
           CASE %WM_COMMAND 'control notifications
    
                 SELECT CASE LO(WORD,wParam)
                    CASE %IDC_Button
                       SELECT CASE HI(WORD,wParam)
                          CASE %BN_CLICKED
                             lblTEXT = "From child " & TIME$  ' Send message to Parent
                             setWindowText( hWndInst, lblTEXT )
                          END SELECT
                    CASE %IDC_Button1             ' Get size from Parent
                       SELECT CASE HI(WORD,wParam)
                          CASE %BN_CLICKED
                              GetClientRect hWndInst, tRect ' get size from parent client
                              lblTEXT= STR$(trect.left) & "|" & STR$(trect.top) & "|" & _
                              STR$(trect.right-trect.left) & "|" & STR$(trect.bottom-trect.top)
                              setWindowText( hWndInst, lblTEXT )
                        END SELECT
                 END SELECT
    
           CASE %WM_SIZE            'after its size has changed on local dialog
                lblTEXT= "local size "& STR$(LOWORD(lParam)) & "|" & STR$(HIWORD(lParam))   'STR$(wParam)
                setWindowText( hWnd, lblTEXT )
    
           CASE %WM_ERASEBKGND
              hDC = wParam
              DrawGradient hDC
              FUNCTION = 1 : EXIT FUNCTION
           CASE %WM_PAINT           'set when request is made to paint a portion of an application's window.
              hDC = BeginPaint(hWnd, pPaint)
              GetClientRect hWnd, tRect
              SetBkMode hDC, %TRANSPARENT
              SetTextColor hDC, %WHITE
              DrawText hDC, "Child", -1, tRect, %DT_SINGLELINE OR %DT_CENTER OR %DT_VCENTER
              EndPaint hWnd, pPaint
              FUNCTION = 1 : EXIT FUNCTION
    
        CASE %WM_TIMER
         ' SELECT CASE WPARAM
         '   CASE 1001
                lblTEXT= "Timer " & TIME$   & STR$(LOWORD(lParam)) & "|" & STR$(HIWORD(lParam))   'STR$(wParam)
                setWindowText( hWnd, lblTEXT )
            '  IF hWndInst > 0 THEN
              '   GetClientRect hWndInst, tRect
                 'SendMessage(hWnd, %WM_SIZE, wparam, lParam)
               '   movewindow( hwnd, trect.left, trect.top, trect.right-trect.left, trect.bottom-trect.top, -1 )
    
             ' end if
         '   end select
    
       END SELECT
       FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)   'if not handled above, pass to Windows default message handler.
    END FUNCTION
    
    '======================== SUBCLASS ============================================
    FUNCTION SubClassProc(BYVAL hWnd AS DWORD, BYVAL wMsg AS DWORD, _
                          BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG
    
      LOCAL lRes, oldProc AS DWORD
      LOCAL lblTEXT AS ASCIIZ * 20
      '------------------------------------------------------------------
      SELECT CASE AS LONG wMsg
    
       CASE %WM_COMMAND
           ' SELECT CASE LO(WORD,wParam)
    
                  lblTEXT= STR$(wParam)
                  setWindowText( hWnd, lblTEXT )
           ' end select
    
       CASE %WM_SIZE   'after its size has changed.
             lblTEXT= "SIZE of PARENT " 'STR$(wParam)
             setWindowText( hWnd, lblTEXT )
    
      END SELECT
    
      FUNCTION = CallWindowProc(oldProc, hWnd, wMsg, wParam, lParam)
    END FUNCTION
    '------------------------------------------------------------------
    SUB DrawGradient (BYVAL hDC AS DWORD)
       LOCAL rectFill AS RECT, rectClient AS RECT, fStep AS SINGLE, hBrush AS DWORD, lOnBand AS LONG
       GetClientRect WindowFromDC(hDC), rectClient
       fStep = rectClient.nbottom / 200
       FOR lOnBand = 0 TO 199
          SetRect rectFill, 0, lOnBand * fStep, rectClient.nright + 1, (lOnBand + 1) * fStep
          hBrush = CreateSolidBrush(RGB(0, 0, 255 - lOnBand))
          Fillrect hDC, rectFill, hBrush
          DeleteObject hBrush
       NEXT
    END SUB
    Last edited by janne sikstrom; 24 Oct 2017, 02:49 AM.

  • #2
    I want to reach all events from dialog1
    All you have to do is intercept wMSG of the dialog proc (CB.MSG if using DDT ) ====>

    Code:
    {CALLBACK} FUNCTION DlgProc ( {BYVAL hwnd as LONG, BYVAL wMsg AS LONG, BYVAL wParam AS LONG, BYVAL lParam AS LONG}) AS LONG
    
          Show (don't try  MSGBOX, there are too many.. maybe a STDOUT or equivalent (see:[URL="http://www.powerbasic.com/support/pbforums/showthread.php?t=25007"]Simple STDOUT for PB/DLL and PB/Win 2-13-04[/URL]
    
    O,  with PB/Win  10+ you might want to use a TXT window.
    
           STDOUT or TXT or whatever  (value of wMSG  or CB.MSG)
    ANY and ALL user events generate a message to the owning window which may be intercepted in the window procedure..

    I have no clue what you are trying to accomplish with that DLL and the functions within it. (And I'm pretty good at figuring out stuff like this).

    MCM

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

    Comment


    • #3
      Thank's MCM,


      I am aware of the relationship between mother and child.

      But I wont to do the opposite, get all events from mother to child. Like I do when I press button i mine child dialog(DLL), I read the size of main dialog.

      I don't know if their is any difference that it is an DLL?


      The reason is that the main dialog can not create certain controls, that I would like.

      I have to do this child dialog DLL i PowerBasic that I access through a DLL from the other program. The other program can not even send messages (hWnd, msg, wparam, lparam)


      The first thing I struggled with was the size and it did not work. I also want to check the main dialog if it is minimized / closed etc. I've missed something obviously.




      Comment


      • #4
        But I wont to do the opposite, get all events from mother to child. Like I do when I press button i mine child dialog(DLL), I read the size of main dialog.
        I'm not sure I understand, but if you mean you want to get messages received by an owned window back to its owning wiindow, you may intercept the message in the window procedure of the owned window (may require subclassing if this is a child window) and send or post to its owner using GetWindow (hWnd, %GW_OWNER) as the target. E.G., if you want the size of an owner window you can do something like this in the widow procedure for the owned window...

        Code:
        LOCAL RC as RECT
        GetWindowRect  GetWindow(hOwnedWindow, %GWOWNER), RC
        To go the other way, there's no reason you can't intercept events in the owner window and SEND or POST that message to an owned window.

        The reason [for all the stuff in the DLL] is that the main dialog can not create certain controls, that I would like.
        I must be missing something because I know of no such limitation. See the "CONTROL ADD "classname" ...." statement; you may use this to add any control to a DDT-managed dialog; and of course there is no limitation on class when adding a control to an SDK-created and managed control with CreateWindowEx() or via a dialog template in a program resource.

        If you are trying to communicate with a non-cooperating program (= one that is NOT your program) then all bets are off.


        RE DLLs: DDT has some limitations: all statements creating and managing a DDT dialog must be in the same code module, but that may be an EXE or DLL. There are no special code module restrictions for SDK-style window management procedure calls.

        MCM
        Last edited by Michael Mattias; 24 Oct 2017, 11:08 AM.
        Michael Mattias
        Tal Systems (retired)
        Port Washington WI USA
        [email protected]
        http://www.talsystems.com

        Comment


        • #5
          Thanks again MCM,
          You're right that it's not my program. However, the EXE program in Item # 1 simulates this program.

          In the DLL program from Item # 1, I have a button "Get Parent Size" where I download the size from the EXE file. So it works.
          I then try with subclass (SubClassProc) to be able to know all the actions/events, but it does not work.

          So I can read from the main dialog but not through the subclass? Perhaps the subclass at the dialog level does not work as textbox, buttons, etc.?

          Comment


          • #6
            Janne,

            Do you want to monitor notifications from a third party application - eg. capture a button press on a window in another app?


            Rgds, Dave

            Comment


            • #7
              Uncooperative interception of Windows messages to 3rd party program?

              Spyware???????????
              Dale

              Comment


              • #8
                Hello Dave,
                Thank's for asking, but I have similar programs "API Monitor" from www.rohitab.com Have tried this but my problem lies in the subclass of the entire dialog1.
                Don't know if the problem is because it's a DLL?
                Appreciate if you can you give me a tip in the right direction?

                Comment


                • #9
                  If you really want all window messages in a third party executable, you might want to get a thread ID for that process (start that program with CreateProcess(), that gives you a threadid directly, although that's not the only way to get the thread ID) , then set a Windows hook of type WH_CALLWNDPROC (or WH_CALLWNDPROCRET) for that thread with SetWindowsHookEx.

                  Don't know if the problem is because it's a DLL?
                  As as I said before, DLL/EXE is immaterial except if the dialog is PowerBASIC DDT-managed. (Or other specialty window management).

                  That is the extent of my participation in one of these "I want to communicate with a non-cooperating application" scenarios.

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

                  Comment


                  • #10
                    Hi Janne,

                    I think there is a problem with this code.
                    Code:
                           CASE %WM_INITDIALOG
                               ' Subclass
                               DialogID = getdlgctrlid ( hWndInst )
                               oldProc = SetWindowLong( DialogID, %GWL_WNDPROC, CODEPTR(SubClassProc))
                    Added later: As this is an SDK style Window Proc you won't get %WM_INITDIALOG ~ try %WM_CREATE instead

                    The first parameter for SetWindowLong should be a Window Handle.
                    Fixing that may help your test code to work but in the long run I think you will find that you cannot Subclass a window that does not belong to the same process as the calling thread.
                    (Hence my earlier question regarding your target being a Third Party App).

                    Depending upon the specifics your best solution could be using a hook..

                    Later again: FWIW here is a version of your test code that 'Works'
                    Code:
                    #COMPILE Exe
                    #DIM ALL
                    
                    #INCLUDE "WIN32API.INC"
                    
                    %IDD_DIALOG1 =  101
                    %IDC_BUTTON1 = 1001
                    
                    DECLARE FUNCTION startdll LIB "MyDll.dll" ALIAS "initdll" (BYVAL xx AS LONG) AS LONG
                    
                    FUNCTION PBMAIN()  '   ** Main Application Entry Point **
                        ShowDIALOG1 %HWND_DESKTOP
                    END FUNCTION
                    '------------------------------------------------------------------------------
                    CALLBACK FUNCTION ShowDIALOG1Proc() '   ** CallBacks **
                        LOCAL lblTEXT AS ASCIIZ * 20
                        Local lRes As Dword
                    
                        SELECT CASE AS LONG CBMSG
                    
                            CASE %WM_COMMAND
                                SELECT CASE AS LONG CBCTL
                                    CASE %IDC_BUTTON1
                                      Dialog Set Text Cb.Hndl, Hex$(GetActiveWindow)        ' test
                                     lRes = startdll( GetActiveWindow() )  ' Send active hWnd      ' should be Dialog1..
                     '                  If lRes Then Control Disable Cb.Hndl, %IDC_BUTTON1
                                END SELECT
                        END SELECT
                    END FUNCTION
                    '------------------------------------------------------------------------------
                    FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG   '   ** Dialogs **
                        LOCAL lRslt AS LONG
                        LOCAL hDlg  AS DWORD
                        DIALOG NEW Pixels, hParent, "Dialog1", 70, 70, 301, 221, _
                              %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
                              %WS_MINIMIZEBOX OR %WS_MAXIMIZEBOX TO hDlg
                        CONTROL ADD BUTTON, hDlg, %IDC_BUTTON1, "Start MyDll", 5, 10, 70, 20
                        DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
                        FUNCTION = lRslt
                    END FUNCTION
                    Code:
                    #COMPILE DLL
                    #DIM ALL
                    #INCLUDE "Win32API.inc"
                    
                    %IDC_Button = 500
                    %IDC_Button1= 501
                    
                    GLOBAL hWndMain   AS DWORD
                    GLOBAL ghWndInst  AS DWORD
                    Global gOldProc   As Dword
                    '-------------------------------------------------------------------------------
                    ' Main DLL entry point called by Windows...
                    '
                    FUNCTION LIBMAIN (BYVAL hInstance   AS LONG, _
                                      BYVAL fwdReason   AS LONG, _
                                      BYVAL lpvReserved AS LONG) AS LONG
                    
                        SELECT CASE fwdReason
                            CASE %DLL_PROCESS_ATTACH
                                'Indicates that the DLL is being loaded by another process (a DLL
                                'or EXE is loading the DLL).  DLLs can use this opportunity to
                                'initialize any instance or global data, such as arrays.
                    
                                FUNCTION = 1   'success!
                                'FUNCTION = 0   'failure!  This will prevent the EXE from running.
                    
                            CASE %DLL_PROCESS_DETACH
                                'Indicates that the DLL is being unloaded or detached from the
                                'calling application.  DLLs can take this opportunity to clean
                                'up all resources for all threads attached and known to the DLL.
                    
                                FUNCTION = 1   'success!
                                'FUNCTION = 0   'failure!
                    
                            CASE %DLL_THREAD_ATTACH
                                'Indicates that the DLL is being loaded by a new thread in the
                                'calling application.  DLLs can use this opportunity to
                                'initialize any thread local storage (TLS).
                    
                                FUNCTION = 1   'success!
                                'FUNCTION = 0   'failure!
                    
                            CASE %DLL_THREAD_DETACH
                                'Indicates that the thread is exiting cleanly.  If the DLL has
                                'allocated any thread local storage, it should be released.
                    
                                FUNCTION = 1   'success!
                                'FUNCTION = 0   'failure!
                        END SELECT
                    END FUNCTION
                    
                    FUNCTION initdll ALIAS "initdll"(BYVAL hInst AS LONG ) EXPORT AS LONG
                        LOCAL hwnd  AS DWORD
                        LOCAL lpCmdLine AS ASCIIZ PTR
                    
                        ghWndInst = hInst                           ' Global handle to Dialog1 (Target?)
                        hwnd = GetParent(hwnd)                      ' ??
                        WINMAIN hwnd, 0, lpCmdLine, %SW_SHOW
                       Function = ghWndInst
                    END FUNCTION
                    
                    FUNCTION WINMAIN (BYVAL hInst AS DWORD, BYVAL hPrevInstance AS DWORD, BYVAL lpCmdLine AS ASCIIZ PTR, BYVAL iCmdShow AS LONG) AS LONG
                       'arguments to WinMain are provided by Windows - not defined by the programmer
                       'hInst             current instance of the application
                       'hPrevInstance    previous instance (not used - returns %Null in Win32)
                       'lpCmdLine        pointer to command line (whatever the user types in after MyApp.EXE). A null terminated string.
                       'iCmdShow         used the first time ShowWindow is called to display the application main window
                       LOCAL Msg         AS tagMsg
                       LOCAL W           AS WndClassEx
                       LOCAL szAppName  AS ASCIIZ * 80
                       LOCAL hWndButton AS DWORD
                       LOCAL hAccel     AS DWORD
                       LOCAL WndStyle   AS LONG
                       LOCAL WndStyleX  AS LONG
                       LOCAL hWnd,hInstance AS DWORD
                    
                       'register window class
                       szAppName = "SDK"
                       W.cbSize        = SIZEOF(W)
                       W.Style         = %CS_HREDRAW OR %CS_VREDRAW   '%WS_OverlappedWindow Or %WS_HScroll Or %WS_VScroll  '
                       W.lpfnWndProc   = CODEPTR(WndProc)
                       W.cbClsExtra    = 0
                       W.cbWndExtra    = 0
                       W.hInstance     = hInst
                       W.hIcon         = %null 'LoadIcon(hInst, "logo")
                       W.hCursor       = LoadCursor(%NULL, BYVAL %IDC_ARROW)
                       W.hbrBackground = %Color_BtnFace+1
                       W.lpszMenuName  = %NULL
                       W.lpszClassName = VARPTR(szAppName)
                       W.hIconSm       = LoadIcon(hInst, BYVAL %IDI_APPLICATION)   'why not %NULL
                       RegisterClassEx W
                    
                       'create window of that class
                       WndStyle  = %WS_OVERLAPPEDWINDOW
                       WndStyleX = %WS_EX_LEFT
                       hWndMain  = CreateWindowEX( _
                          WndStyleX,  _    'dwStyle        extended style of window
                          szAppName,  _    'lpClassName    pointer to a null-terminated string (any registered name, including predefined system class names).
                          "Child dialog",      _    'lpWindowName   pointer to a null-terminated String (placed in title bar, text of the control, icon name or #identifier)
                          WndStyle,   _    'dwStyle        style of window
                          500,        _    'x              initial horizontal position (upper left screen, except for child is relative to parent window's client area)
                          400,        _    'y              initial vertical position  (upper left screen, except for child is relative to parent window's client area)
                          300,        _    'nWidth         width in device units
                          300,        _    'nHeight        height in device units
                          %Null,      _    'hWndParent     handle to parent window (optional for a pop-up window)
                          %Null,      _    'hMenu          handle to a menu
                          hInst,      _    'handle to instance of the module to be associated with the window
                          BYVAL %Null _    'pointer to CREATESTRUCT structure pointed to by the lParam param of the WM_CREATE message.
                          )
                    
                       'create window of existing class "Button"
                       WndStyle  = %WS_TABSTOP OR %WS_VISIBLE OR %WS_CHILD OR %BS_DEFPUSHBUTTON
                       hInstance = GetWindowLong(hWndMain, %GWL_HINSTANCE)
                        hWnd= CreateWindow( "Button", "Send to Parent",  WndStyle, 10, 10, 110, 25, hWndMain, %IDC_Button , hInstance, BYVAL %Null )
                        hWnd= CreateWindow( "Button", "Get Parent size", WndStyle, 10, 40, 160, 25, hWndMain, %IDC_Button1, hInstance, BYVAL %Null )
                    
                    
                       ShowWindow hWndMain, iCmdShow   'controls how window is to be shown. 1st must use iCmdShow
                       UpdateWindow hWndMain           'sends the window it's first WM_Create to display the window on the screen
                    
                       'message pump - calls WndProc whenever an application-specific message is received
                       'WndProc can process the message, or pass it on to a the default window procedure that is built into Windows.
                       WHILE GetMessage(Msg, %NULL, 0, 0) > 0
                          IF ISFALSE TranslateAccelerator (hWndMain, hAccel, Msg) THEN
                             IF ISFALSE ISDialogMessage (hWndMain, Msg) THEN
                                TranslateMessage Msg
                                DispatchMessage  Msg
                             END IF
                          END IF
                       WEND
                    END FUNCTION
                    
                    FUNCTION WndProc (BYVAL hWnd AS DWORD, BYVAL wMsg AS DWORD, BYVAL wParam AS DWORD, BYVAL lParam AS LONG) EXPORT AS LONG
                       LOCAL hDC AS DWORD, pPaint AS PAINTSTRUCT, tRect  AS RECT
                       LOCAL pnmhdr AS NMHDR PTR
                       LOCAL oldProc AS DWORD
                       LOCAL lblTEXT AS ASCIIZ * 20
                       LOCAL DialogID AS LONG
                    
                    
                       SELECT CASE wMsg
                    
                           CASE %WM_CREATE
                             WinBeep 1800,800
                               ' Subclass
                     '           DialogID = getdlgctrlid ( ghWndInst )
                     '           oldProc = SetWindowLong( DialogID, %GWL_WNDPROC, CODEPTR(SubClassProc))
                               goldProc = SetWindowLong( ghWndInst, %GWL_WNDPROC, CODEPTR(SubClassProc))   ' SubClass Dialog1 ??
                    
                               'SetTimer hWnd, 1001, 500, 0
                               'SendMessage hwnd,%WM_TIMER, 1001, 0
                    
                           CASE %WM_DESTROY
                     '          SetWindowLong DialogID, %GWL_WNDPROC, oldProc
                              SetWindowLong ghWndInst, %GWL_WNDPROC, goldProc
                              PostQuitMessage 0
                              EXIT FUNCTION
                    
                    
                           CASE %WM_COMMAND 'control notifications
                    
                                 SELECT CASE LO(WORD,wParam)
                                    CASE %IDC_Button
                                       SELECT CASE HI(WORD,wParam)
                                          CASE %BN_CLICKED
                                             lblTEXT = "From child " & TIME$  ' Send message to Parent
                                             setWindowText( ghWndInst, lblTEXT )
                                          END SELECT
                                    CASE %IDC_Button1             ' Get size from Parent
                                       SELECT CASE HI(WORD,wParam)
                                          CASE %BN_CLICKED
                                              GetClientRect ghWndInst, tRect ' get size from parent client
                                              lblTEXT= STR$(trect.left) & "|" & STR$(trect.top) & "|" & _
                                              STR$(trect.right-trect.left) & "|" & STR$(trect.bottom-trect.top)
                                              setWindowText( ghWndInst, lblTEXT )
                                        END SELECT
                                 END SELECT
                    
                           CASE %WM_SIZE            'after its size has changed on local dialog
                                lblTEXT= "local size "& STR$(Lo(WORD,lParam)) & "|" & STR$(Hi(WORD,lParam))   'STR$(wParam)
                                setWindowText( hWnd, lblTEXT )
                    
                           CASE %WM_ERASEBKGND
                              hDC = wParam
                              DrawGradient hDC
                              FUNCTION = 1 : EXIT FUNCTION
                           CASE %WM_PAINT           'set when request is made to paint a portion of an application's window.
                              hDC = BeginPaint(hWnd, pPaint)
                              GetClientRect hWnd, tRect
                              SetBkMode hDC, %TRANSPARENT
                              SetTextColor hDC, %WHITE
                              DrawText hDC, "Child", -1, tRect, %DT_SINGLELINE OR %DT_CENTER OR %DT_VCENTER
                              EndPaint hWnd, pPaint
                              FUNCTION = 1 : EXIT FUNCTION
                    
                        CASE %WM_TIMER
                         ' SELECT CASE WPARAM
                         '   CASE 1001
                                lblTEXT= "Timer " & TIME$   & STR$(Lo(WORD,lParam)) & "|" & STR$(Hi(WORD,lParam))   'STR$(wParam)
                                setWindowText( hWnd, lblTEXT )
                            '  IF ghWndInst > 0 THEN
                              '   GetClientRect ghWndInst, tRect
                                 'SendMessage(hWnd, %WM_SIZE, wparam, lParam)
                               '   movewindow( hwnd, trect.left, trect.top, trect.right-trect.left, trect.bottom-trect.top, -1 )
                    
                             ' end if
                         '   end select
                    
                       END SELECT
                       FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)   'if not handled above, pass to Windows default message handler.
                    END FUNCTION
                    
                    '======================== SUBCLASS ============================================
                    FUNCTION SubClassProc(BYVAL hWnd AS DWORD, BYVAL wMsg AS DWORD, _
                                          BYVAL wParam AS DWORD, BYVAL lParam AS LONG) AS LONG
                      LOCAL lRes, oldProc AS DWORD
                      LOCAL lblTEXT AS ASCIIZ * 20
                    
                      SELECT CASE AS LONG wMsg
                    
                        CASE %WM_COMMAND
                     '       SELECT CASE LO(WORD,wParam)
                    
                                  lblTEXT= Time$ + STR$(wParam)
                                  setWindowText( hWnd, lblTEXT )
                                  Function = 0 : Exit Function
                           ' end select
                    
                       CASE %WM_SIZE   'after its size has changed.
                             lblTEXT= "SIZE of PARENT " 'STR$(wParam)
                             setWindowText( hWnd, lblTEXT )
                    
                      END SELECT
                    
                      FUNCTION = CallWindowProc(goldProc, hWnd, wMsg, wParam, lParam)
                    END FUNCTION
                    '------------------------------------------------------------------
                    
                    SUB DrawGradient (BYVAL hDC AS DWORD)
                       LOCAL rectFill AS RECT, rectClient AS RECT, fStep AS SINGLE, hBrush AS DWORD, lOnBand AS LONG
                       GetClientRect WindowFromDC(hDC), rectClient
                       fStep = rectClient.nbottom / 200
                       FOR lOnBand = 0 TO 199
                          SetRect rectFill, 0, lOnBand * fStep, rectClient.nright + 1, (lOnBand + 1) * fStep
                          hBrush = CreateSolidBrush(RGB(0, 0, 255 - lOnBand))
                          Fillrect hDC, rectFill, hBrush
                          DeleteObject hBrush
                       NEXT
                    END SUB
                    Last edited by Dave Biggs; 26 Oct 2017, 10:17 AM. Reason: Add modified test code
                    Rgds, Dave

                    Comment


                    • #11
                      I'm not sure what you are trying to accomplish, but I see a couple of problems with your code.

                      1: In the dialog call back just use CB.HNDL as the argument for your window initialization
                      2: In the register portion of the dll, W.Instance is the instance of the exe, not the handle of the exe so use EXE.INST
                      3: In the createwindow portion of the code, if you want a true child, use the exe handle instead of %NULL.

                      If you really want to handle all messages from the child window in the ddt call back you can do one of two things:
                      1: send messages to the ddt callback
                      2: in the register window portion of the dll where you set the callback procedure use the address of the dll callback or use setclasslong to change the callback (the window created in the dll does not require a callback resident in the dll).

                      PS: I found an additional problem:
                      Code:
                         WHILE GetMessage(Msg, %NULL, 0, 0) > 0
                            IF ISFALSE TranslateAccelerator (hWndMain, hAccel, Msg) THEN
                               IF ISFALSE ISDialogMessage (hWndMain, Msg) THEN
                                  TranslateMessage Msg
                                  DispatchMessage  Msg
                               END IF
                            END IF
                         WEND
                      This will cause the window in the dll to continue running when the main dialog is closed.
                      Last edited by Walt Decker; 26 Oct 2017, 12:13 PM. Reason: Additional problem with code
                      Walt Decker

                      Comment


                      • #12
                        RE:
                        Code:
                         FUNCTION initdll ALIAS "initdll"(BYVAL hInst AS LONG ) EXPORT AS LONG
                            LOCAL hwnd  AS DWORD
                            LOCAL lpCmdLine AS ASCIIZ PTR
                             ghWndInst = hInst                           ' Global handle to Dialog1 (Target?)    
                            hwnd = GetParent(hwnd)                      ' ??    
                            WINMAIN hwnd, 0, lpCmdLine, %SW_SHOW    
                            Function = ghWndInst
                        END FUNCTION
                        "hWnd" is always zero. That cannot be right. If it is "right" (as in "it is exactly what I intended to do" ) then I truly regret breaking my promise to myself to stay out of this "cooperate with a non-cooperating application" thread.

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

                        Comment


                        • #13
                          Thank you gentlemen,
                          I've been struggling with this for a while. Tested different variants but all failed to work. In the end you become blind.
                          It's the first time with a DLL so to blame on something I thought it worked differently. But suddenly it's just my bad knowledge.

                          When I get ready, the EXE-part will be replaced by a "loaded" routine that is not an EXE, It is a interpreter that build an "dialog". However, it can start a DLL. So I can't use EXE.inst

                          It would of course be better if the child was completely owned by the mother.

                          The code is appreciated and instructive and I see my misstakes.

                          Big Thanks again

                          Comment


                          • #14
                            I'm at a loss. You can not have "loaded" routine without having an exe first.
                            Walt Decker

                            Comment


                            • #15
                              For Mr. Sikstrom:

                              You started with a bad thread title. You don't 'subclass' a dialog or window you create in your program; the dialog or window procedure already receives all the messages ("events") which occur.

                              I guess you 'could' change the window procedure with a call to SetWindowLong(),but it makes exactly zero sense to do so because the new procedure ("the subclass proc") would get exactly what you get in the window procedure anyway.

                              For Mr. Biggs:

                              Added later: As this is an SDK style Window Proc you won't get %WM_INITDIALOG ~ try %WM_CREATE instead
                              You get WM_CREATE if you create the Window using CreateWindow() or CreateWindowEx(). However, if you create the window with one of the eight SDK "dialog" functions (CreateDialog[Indirect][Param] or DialogBox[Indirect][Param]) you get WM_INITDIALOG.

                              Yes, in both cases I am being kind of picky about terminology: re "window" vs "dialog" and re the meaning of "subclass."

                              But it's not like I haven't spoken up about programmers needing to be precise with their usage of certain words.. those words which have a specific meaning in the Windows' programming environment.


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

                              Comment


                              • #16
                                Hi Janne,

                                When I get ready, the EXE-part will be replaced by a "loaded" routine that is not an EXE, It is a interpreter that build an "dialog".
                                Is it possible for you to describe how the eventual target dialog will be created in more detail? - Is the 'interpreter' available / public?
                                Rgds, Dave

                                Comment


                                • #17
                                  Thank you for your interest in my problem.
                                  MCM: In my case, it's probably pure ignorance. I want to recall any events in a DLL. had never used a dll before. Maybe I used the wrong words?
                                  There is no public program and can not be downloaded.

                                  Short description, an EXE file starts and you log in
                                  From a menu, you select routines that create dialogs. These dialogs can I access and create a label, textbox and compile in a type of P-code myself. In this code, I can also start a DLL.
                                  The DLL file is expected to start in INITDLL, calling program sends address of the dialog.
                                  Because of the above, I thought the EXE file would not be EXE.INST?

                                  Is it possible to automatic capture the sender dialog address in the DLL?

                                  Comment


                                  • #18
                                    You may have a misunderstanding fundamental to the use of the Windows' Dynamic Link Library:

                                    this code, I can also start a DLL.
                                    The DLL file is expected to start in INITDLL, calling program sends address of the dialog.
                                    You don't start a DLL. A DLL cannot start anything else. You don't capture anything in a DLL.

                                    A DLL is a file. A DLL is simply the packaging for one or more procedures.

                                    The procedures you call have to do all the cool stuff.

                                    Is it possible to automatic capture the sender dialog address in the DLL?
                                    I have no clue what you mean by "Sender dialog address." A dialog does not have an memory [virtual] address. A dialog does not have a sender.

                                    A dialog can certainly CALL procedures which are stored in a DLL and pass data as an argument to those procedures.

                                    Maybe you need to back up a step and explain, in layman's terms, what you are trying to accomplish. Your member profile does not contain a location (PLEASE FIX) but I sense the possibility that English is not your first language. You may want to post in some other language. While English is certainly the predominant language here, we do have members from all over the world who, collectively, are fluent in many languages.

                                    MCM

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

                                    Comment


                                    • #19
                                      Hi Janne,

                                      Here is a link to a PB Gazette that has some introductory notes on using DLLs or "Application Extensions" type files as they are described in Explorer

                                      I'm trying to figure out the nature of your application / scope of your problem..

                                      Is the EXE file that the user 'logs in' to written by you?

                                      What kind of functions do the Dialogs / Menu options offer to the user?

                                      Is more than one Dialog selected at a time?

                                      What information is to be presented in the Window created as a result of the call to initdll() ?
                                      Last edited by Dave Biggs; 27 Oct 2017, 08:55 PM.
                                      Rgds, Dave

                                      Comment

                                      Working...
                                      X