Announcement

Collapse
No announcement yet.

CONTROL ADD "Custom" Not Working

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

  • CONTROL ADD "Custom" Not Working

    Hi all,

    Troubles with CONTROL ADD "Custom". I've created and registered a class successfully using:
    Code:
       szName 		= "MyControl"
       wc.cbSize 		= SizeOf(wc)
       wc.style 		= %CS_HREDRAW OR %CS_VREDRAW OR %CS_PARENTDC OR %CS_GLOBALCLASS
       wc.lpfnWndProc 	= CodePtr(frmMain_DLGPROC)  
       wc.cbClsExtra 	= 0
       wc.cbWndExtra 	= 0
       wc.hInstance 	= GetModuleHandle (ByVal 0)
       wc.hIcon 		= %NULL
       wc.hCursor 		= LoadCursor(%NULL, ByVal %IDC_ARROW )
       wc.hbrBackground 	= GetStockObject(%NULL_BRUSH)
       wc.lpszMenuName 	= %NULL
       wc.lpszClassName 	= VarPtr(szName)
       wc.hIconSm 		= %NULL
    	
       lSuccess = RegisterClassEx(wc)
    But when I create the control using:
    Code:
       Control Add "MyControl", hDlg, %MYCONTROL, "Title", 1,50,300,150, %WS_VISIBLE Or %WS_TABSTOP Or %WS_CHILD, 0&
    no hWnd to the control is created: CONTROL HANDLE returns 0. In addition, ERR is 0 after the CONTROL ADD call.

    The actual "control" is a DLL that has it's own functions for drawing and updating the control contents; all it needs
    is a valid control hWnd. For example, the C code for creating & presenting the control is just three lines:
    Code:
       hwndControl = GetDlgItem(hWnd, IDCUSTOM);
       hControlData = ControlCreate();    // DLL call: Creates the control and returns a handle to the control's data
       ControlAttachWindow(hControlData, hwndControl);    // DLL call: Attaches the control to the control's window handle
    This leads me to wonder, are there certain types of "custom" controls that aren't compatible with DDT? If not, anyone have
    any idea what I'm doing wrong?

    Thanks!



    ------------------
    Mark Newman
    Mark Newman

  • #2
    Are the DLL's LibMain and WinMain (frmMain_DLGPROC ?) exported,
    that is - do they end with EXPORT AS LONG ?

    Forgot - maybe you need to load the DLL before it can be used,
    with something like:
    Code:
    lRes = LoadLibrary("MYDLL.DLL")
    IF lRes THEN
      CONTROL ADD..  'etc.
    ELSE
      EXIT FUNCTION
    END IF
    ------------------



    [This message has been edited by Borje Hagsten (edited March 21, 2001).]

    Comment


    • #3
      Are the DLL's LibMain and WinMain (frmMain_DLGPROC ?) exported,
      that is - do they end with EXPORT AS LONG ?
      I don't have access to the DLL source, but if I run DEPENDS on the DLL I don't see them
      in the list of exported functions. (frmMain_DLGPROC is my PB callback function.)
      Is this a problem?

      Forgot - maybe you need to load the DLL before it can be used,
      with something like:

      lRes = LoadLibrary("MYDLL.DLL")
      IF lRes THEN
      CONTROL ADD.. 'etc.
      ELSE
      EXIT FUNCTION
      END IF
      Hmmm, didn't consider that, though the C sample code I'm using as a
      reference doesn't call LoadLibrary. I'll give it a try.

      Thanks!



      ------------------
      Mark Newman
      Mark Newman

      Comment


      • #4
        Mark,

        Does your include file register all the constants and function
        declares that are listed in the C header file?

        The C code version does not use "loadlibrary" since the compiled
        exe uses a *.lib for linking at loadtime, not runtime. This the
        way C/C++ links normally.

        Most custom controls have a registration function to register
        all the class data required. Does this one????

        Does "MyControl" match the control's class name?????????

        Just a few things to ponder!!!

        Cheers,
        Cecil

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

        Comment


        • #5
          Cecil,

          My port of the C header files is as complete as I can make it, though who knows how correct
          it is. The 3 or 4 functions I'm using just to get the control on the screen are pretty
          straightforward, so I think the DECLARES are ok.

          The DLL I'm using is primarily meant to be distributed with the application, so it isn't
          compiled statically.

          There isn't any ActiveX-type registration or class name since I'm using a DLL. That's why I
          created a class using the RegisterClassEx function in the hope that DDT would see the class
          and create the control. But perhaps DDT was not meant for DLL-type controls? Yet Borje Hagsten
          was able to create his ultra-cool 3D progress bars in straight PB code and create them using
          CONTROL ADD <custom>, so I figure there must be a way.



          ------------------
          Mark Newman
          Mark Newman

          Comment


          • #6
            Mark,

            I think you misunderstood me. No mention of Active-X, yuuuk!
            Most custom controls register the class data the way you did.
            Point, does your classname match the dll classname. This would
            be normally listed in the C header file as a constant, ie;

            #define MYCONTROLCLASS "XXXXWhatever"

            If the dll does the registration, which I suspect, all you need
            to do is list it in the CreateWindow function or whatever DDT
            uses.

            If you would like, email me the C header file:

            [email protected]

            I will take a look at it!!!!!

            Cheers,
            Cecil

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

            Comment


            • #7
              Hi Cecil,

              No mention of "MYCONTROLCLASS" in the C header files. If I understand things
              correctly, there must be one defined in order for it to be "on-screen". Hmmm.
              Maybe I'll run one of the compiled C examples and look for the class name with
              a "snooper"-type app. I think SysInternals has one?? I'll ask the vendor of
              this control too, though I haven't had the best of luck with them so far.



              ------------------
              Mark Newman
              Mark Newman

              Comment


              • #8
                Mark,

                Now you're cooking with gas!!! A window creation MUST have a class
                associated with it. Defines all the necessary stuff including
                the window procedure that a window needs to function properly.
                My guess, it's all in the dll.

                Now for the good stuff, what notifications does the control send
                to it's parent and what does it process internally????? This
                should be listed in the docs or header file somewhere. You'll
                need this info to comm corectly with the control.

                Cheers,
                Cecil

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

                Comment


                • #9
                  Okay, I mis-understood and thought it was your DLL. Using CONTROL ADD
                  for any kind of custom control class is no problem. Added a piece
                  of test code you can play around with and see that it works. The
                  control in your DLL probably only needs a handle of the created control,
                  so it knows where to perform its painting stuff.

                  What you need, is probably the header file in the form of an .INC file,
                  where ControlCreate() and ControlAttachWindow is declared. Or, the DLL
                  functions declared directly in your program.
                  Code:
                  '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                  ' Template
                  '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                  #COMPILE EXE
                  %MYCONTROL = 20
                  #INCLUDE "WIN32API.INC"
                   
                  '#INCLUDE "MYCONTROL.INC" '<- This one for the DLL!!!
                  ' ..or declared directly, like:
                  ' (Note, I have no idea what they look like - this just sample!)
                  ' DECLARE FUNCTION ControlCreate LIB "MYCONTROL.DLL" ALIAS _
                                    "ControlCreate" () AS LONG
                  ' DECLARE FUNCTION ControlAttachWindow LIB "MYCONTROL.DLL" ALIAS _
                                    "ControlAttachWindow" (BYVAL hControlData AS LONG, BYVAL hwndControl AS LONG) AS LONG
                   
                  DECLARE CALLBACK FUNCTION DlgProc() AS LONG
                   
                  '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                  ' Create dialog and controls, etc
                  '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                  FUNCTION PBMAIN () AS LONG
                    LOCAL hDlg AS LONG, hwndControl AS LONG, lSuccess AS LONG
                    LOCAL szName AS ASCIIZ * 20, wc AS WNDCLASSEX
                   
                    DIALOG NEW 0, "Custom control test",,, 240, 180, %WS_SYSMENU, 0 TO hDlg
                    CONTROL ADD BUTTON, hDlg, %IDOK, "&Ok", 180, 4, 50, 14, %WS_BORDER
                   
                    szName               = "MyControl"
                    wc.cbSize            = SIZEOF(wc)
                    wc.style             = %CS_HREDRAW OR %CS_VREDRAW OR %CS_PARENTDC OR %CS_GLOBALCLASS
                    wc.lpfnWndProc       = CODEPTR(frmMain_DLGPROC)
                    wc.cbClsExtra        = 0
                    wc.cbWndExtra        = 0
                    wc.hInstance         = GetModuleHandle (BYVAL 0)
                    wc.hIcon             = %NULL
                    wc.hCursor           = LoadCursor(%NULL, BYVAL %IDC_ARROW )
                    wc.hbrBackground     = GetStockObject(%NULL_BRUSH)
                    wc.lpszMenuName      = %NULL
                    wc.lpszClassName     = VARPTR(szName)
                    wc.hIconSm           = %NULL
                    lSuccess = RegisterClassEx(wc)
                   
                    CONTROL ADD "MyControl", hDlg, %MYCONTROL, "Click here", 4, 20, 228, 142, _
                                %WS_VISIBLE OR %WS_TABSTOP OR %WS_CHILD, %WS_EX_CLIENTEDGE
                   
                    hwndControl = GetDlgItem(hDlg, %MYCONTROL)
                  '  hControlData = ControlCreate()                 'DLL call: Creates the control and returns a handle to the control's data
                  '  CALL ControlAttachWindow(hControlData, hwndControl) 'DLL call: Attaches the control to the control's window handle
                   
                    DIALOG SHOW MODAL hDlg CALL DlgProc
                   
                  END FUNCTION
                   
                  '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                  ' Main callback
                  '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                  CALLBACK FUNCTION DlgProc() AS LONG
                    SELECT CASE CBMSG
                       CASE %WM_COMMAND
                          IF CBCTLMSG = %BN_CLICKED THEN
                             IF CBCTL = %IDOK THEN DIALOG END CBHNDL
                          END IF
                    END SELECT
                  END FUNCTION
                   
                  '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                  ' Custom control procedure
                  '¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤
                  FUNCTION frmMain_DLGPROC(BYVAL hWnd AS LONG, BYVAL wMsg AS LONG, _
                                           BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
                   
                    LOCAL ps AS PAINTSTRUCT, r AS RECT, zText AS ASCIIZ * 255
                   
                    SELECT CASE wMsg
                       CASE %WM_LBUTTONDOWN : BEEP     '<- just to see it works
                   
                       CASE %WM_PAINT
                        IF GetWindowText(hWnd, zText, SIZEOF(zText)) THEN  '<- if control has any text
                           BeginPaint hWnd, ps                             '<- start paint procedure
                             GetClientRect hWnd, r                         '<- get coordinates
                             SetBkMode ps.hDC, %TRANSPARENT                '<- set text mode
                             DrawText ps.hDC, zText, -1, r, %DT_SINGLELINE OR %DT_CENTER OR %DT_VCENTER
                           EndPaint hWnd, ps                               '<- end paint procedure
                           FUNCTION = 0 : EXIT FUNCTION                    '<- bail out..
                        end if
                   
                    END SELECT
                    FUNCTION = DefWindowProc(hWnd, wMsg, wParam, lParam)
                  END FUNCTION
                  ------------------


                  [This message has been edited by Borje Hagsten (edited March 21, 2001).]

                  Comment


                  • #10
                    No word yet from the DLL vendor as to the class name, so I'll have to try and find a
                    "snooper" app. Cecil, you're probably right in that the DLL has the RegisterClassEx()
                    call somewhere in one of the initialization functions. Just have to find it! BTW, the
                    DLL sends very few messages, just a couple of mouse click events. Likewise, I only need
                    to inform the control of basic events, such as WM_PAINT; it handles all the painting
                    chores.

                    Borje, the code you posted is very similar to what I'm doing, so it should work, eh?
                    I need to the get the class name of the control, so CONTROL ADD can create a child window
                    for the control to paint in. So close and yet so far!

                    Thanks!



                    ------------------
                    Mark Newman
                    Mark Newman

                    Comment


                    • #11
                      I don't see any problems with custom contols in DLL. (at least, under Win2000)
                      Borje's code after small modification
                      1) DLL
                      Code:
                         #Compile Dll "PbDll.Dll"
                         #Dim All
                         #Register None
                         #Include "Win32Api.Inc"
                         
                         Function frmMain_DLGPROC(ByVal hWnd As Long, ByVal wMsg As Long, _
                                                  ByVal wParam As Long, ByVal lParam As Long) As Long
                      
                         Local ps As PAINTSTRUCT, r As RECT, zText As Asciiz * 255
                         Select Case wMsg
                            Case %WM_LBUTTONDOWN : MsgBox "Oh"  '<- just to see it works
                            Case %WM_PAINT
                               If GetWindowText(hWnd, zText, SizeOf(zText)) Then  '<- if control has any text
                                  BeginPaint hWnd, ps                             '<- start paint procedure
                                  GetClientRect hWnd, r                         '<- get coordinates
                                  SetBkMode ps.hDC, %TRANSPARENT                '<- set text mode
                                  DrawText ps.hDC, zText, -1, r, %DT_SINGLELINE Or %DT_CENTER Or %DT_VCENTER
                                  EndPaint hWnd, ps                               '<- end paint procedure
                               End If
                         End Select
                         Function = DefWindowProc(hWnd, wMsg, wParam, lParam)
                         End Function
                      
                         Function LibMain(ByVal hInstance As Long, ByVal Reason As Long, ByVal Reserved  As Long) Export As Long
                            Select Case Reason
                               Case %DLL_PROCESS_ATTACH
                                  Dim szName As Asciiz * 20, wc As WNDCLASSEX
                                  szName               = "MyControl"
                                  wc.cbSize            = SizeOf(wc)
                                  wc.style             = %CS_HREDRAW Or %CS_VREDRAW Or %CS_PARENTDC Or %CS_GLOBALCLASS
                                  wc.lpfnWndProc       = CodePtr(frmMain_DLGPROC)
                                  wc.cbClsExtra        = 0
                             wc.cbWndExtra        = 0
                             wc.hInstance         = hInstance
                             wc.hIcon             = %NULL
                             wc.hCursor           = LoadCursor(%NULL, ByVal %IDC_ARROW )
                             wc.hbrBackground     = GetStockObject(%NULL_BRUSH)
                             wc.lpszMenuName      = %NULL
                             wc.lpszClassName     = VarPtr(szName)
                             wc.hIconSm           = %NULL
                             RegisterClassEx wc
                      
                        '  Case %DLL_PROCESS_DETACH
                         End Select
                        LibMain = 1
                      End Function
                      Exe
                      Code:
                         #Compile Exe
                         #Dim All
                         #Register None
                         %MYCONTROL = 20
                         #Include "WIN32API.INC"
                      
                         Function PbMain
                            Dim hDlg As Long, hwndControl As Long
                            LoadLibrary ("PbDll.Dll")
                            Dialog New 0, "Custom control test",,, 240, 180, %WS_CAPTION Or %WS_SYSMENU, 0 To hDlg
                            Control Add "MyControl", hDlg, %MYCONTROL, "Click here", 4, 20, 228, 142, _
                                       %WS_VISIBLE Or %WS_TABSTOP Or %WS_CHILD, %WS_EX_CLIENTEDGE
                            Dialog Show Modal hDlg
                        End Function

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

                      Comment


                      • #12
                        Originally posted by Mark Newman:
                        Hi all,
                        Troubles with CONTROL ADD "Custom".
                        But when I create the control using:
                        Code:
                           Control Add "MyControl", hDlg, %MYCONTROL, "Title", 1,50,300,150, %WS_VISIBLE Or %WS_TABSTOP Or %WS_CHILD, 0&
                        no hWnd to the control is created: CONTROL HANDLE returns 0. In addition, ERR is 0 after the CONTROL ADD call.
                        Please excuse this shot in the dark, but I seem to recall fixing something similar, by using a class name of max 8 characters.
                        That would be "MyControl" -> "MControl"

                        --
                        Best Regards
                        Peter Scheutz


                        ------------------
                        Best Regards
                        Peter Scheutz

                        Comment


                        • #13
                          An update - using the MS "Spy++" utility on the sample compiled C program I was able to
                          find the class name. I plugged that into the CONTROL ADD statement and Poof! DDT is now
                          creating a control window. So my window handles are:

                          Main dialog hWnd = 5506054
                          DLL Control hwnd = 1311912

                          which seem valid enough. The control window is now visible though the positioning
                          is off and the control contents are blank. Who cares! It's showing!!!

                          When I started this porting project, I never thought getting the 3 lines of code that show
                          the window would be so hard; I figured that some of the other functions that use double-
                          indirection (**var) would be the tough ones. Maybe they'll be easy in comparison! In any
                          case, thanks for all the help; there's only 1 line of code left!

                          ------------------
                          Mark Newman

                          [This message has been edited by Mark Newman (edited March 22, 2001).]
                          Mark Newman

                          Comment


                          • #14
                            Mark,

                            Great to hear. I would add WM_NOTIFY to your parent window's
                            procedure that the conrol belongs to. You might be surprised
                            at the messages you're missing. Most custom controls pass a
                            lot of notifications for the parent to either process or force
                            the control to process.

                            Just thought of another possible way to get the control class
                            name. Make a call to the ControlCreate() function. Pass the
                            handle to the API GetClassName() function. See below. This could
                            get the data you're looking for.

                            Code:
                            int GetClassName(
                              HWND hWnd,           // handle of window
                              LPTSTR lpClassName,  // address of buffer for class name
                              int nMaxCount        // size of buffer, in characters
                            );
                            Good luck with the control!!!!!!!!

                            Cheers,
                            Cecil

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

                            Comment

                            Working...
                            X