Announcement

Collapse
No announcement yet.

Window Handle

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

  • Dominic Mitchell
    replied
    Get window, and other API functions, can get a handle, but you must pass the Handle to the Dialog/Window/VBForm etc to get some handle (This is where I think I lost everyone, but hey I can lose myself sometimes trying to understand enough to ask the "Right Question"
    Must, no. Optional, yes.

    I could write an app, and be able to obtain the handle of any window in that app from any function(within the same app or another process) without needing to know the handle of any window in that app.

    Leave a comment:


  • Cliff Nichols
    replied
    Thanx Fred, the code is similar to one train of thought that I had.
    I have been sitting back and reading how things spun off to some debate (Although fun to watch, amazed how the question could be spun so hard )

    Anyways as to my original question, I think the simple answer is, unless you pass the handle to the function/sub that needs it, then you need the handle itself to begin with. (Aka in this case call it Dialog, Window, ParentWindow, VB-Form, whatever)

    In all cases (DDT, SDK, PB, API, MyProgLanguageOfChoice, etc...) it boils down to
    1. Callback Function (in this case CBHNDL is known and used (or passed to other functions
    2. Register a function to process my messages (in this case, lets say FUNCTION Dialog_Proc( _
      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
      ) AS LONG
      hWnd is passed and used.
    3. Get window, and other API functions, can get a handle, but you must pass the Handle to the Dialog/Window/VBForm etc to get some handle (This is where I think I lost everyone, but hey I can lose myself sometimes trying to understand enough to ask the "Right Question"


    Thats when I came up with my own solution (or I think I have), that no Global, and still be able to get the Handle I need to pass to perform some operation. (Although probably re-creating the wheel, or some other trick) but lets say I had the below.

    Demo Dialog Handle Prob.bas -----> This creates my solution to the problem
    Code:
    #COMPILE DLL
    #DIM ALL
    
    #INCLUDE "Win32API.inc"
    DECLARE FUNCTION LIBMAIN (BYVAL hInstance   AS LONG, _
                      BYVAL fwdReason   AS LONG, _
                      BYVAL lpvReserved AS LONG) AS LONG
    
    DECLARE FUNCTION AppMsgPump() AS LONG
    DECLARE FUNCTION CreateMyDialog ALIAS "CreateMyDialog"() AS LONG
    DECLARE FUNCTION SetGetDlg(BYREF SetHwndDlg AS DWORD, BYREF GetHwndDlg AS DWORD)AS DWORD
    DECLARE FUNCTION CallMyDialogHandle ALIAS "CallMyDialogHandle"() AS LONG
    
    
    '-------------------------------------------------------------------------------
    ' 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
                 FUNCTION = 1   'success!
                 'FUNCTION = 0   'failure!  This will prevent the EXE from running.
             CASE %DLL_PROCESS_DETACH
                 FUNCTION = 1   'success!
                 'FUNCTION = 0   'failure!
             CASE %DLL_THREAD_ATTACH
                 FUNCTION = 1   'success!
                 'FUNCTION = 0   'failure!
             CASE %DLL_THREAD_DETACH
                 FUNCTION = 1   'success!
                 'FUNCTION = 0   'failure!
        END SELECT
    END FUNCTION
    
    FUNCTION AppMsgPump() AS LONG
         ON ERROR GOTO ErrHandler
         LOCAL tmsg AS TagMsg
    '*** Acquire and dispatch messages until a WM_QUIT message is received.
         WHILE ISTRUE GetMessage(tmsg, BYVAL %NULL, 0, 0)
              TranslateMessage tmsg
              DispatchMessage tmsg
         WEND
         FUNCTION = %True    'Function results
         EXIT FUNCTION       'Escape function so not to trigger error log
    ErrHandler:
         'Do some error handling
    END FUNCTION
    
    FUNCTION CreateMyDialog ALIAS "CreateMyDialog"() EXPORT AS LONG
        LOCAL hDlg  AS DWORD
         LOCAL TemphDlg AS DWORD
    
        DIALOG NEW %HWND_DESKTOP, "Dialog1", 70, 70, 201, 121, %WS_POPUP OR %WS_BORDER _
            OR %WS_DLGFRAME OR %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
            %WS_MINIMIZEBOX OR %WS_MAXIMIZEBOX OR %WS_CLIPSIBLINGS OR _
            %WS_VISIBLE OR %DS_MODALFRAME OR %DS_3DLOOK OR %DS_NOFAILCREATE OR _
            %DS_SETFONT, %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR _
            %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
    
    
    '*** Works
        SetGetDlg(hDlg, TemphDlg)
    
    END FUNCTION
    
    FUNCTION SetGetDlg(BYREF SetHwndDlg AS DWORD, BYREF GetHwndDlg AS DWORD)EXPORT AS DWORD
         ON ERROR GOTO ErrHandler
         STATIC TempHwndDlg AS DWORD
         IF SetHwndDlg <> 0 THEN
              GetHwndDlg = SetHwndDlg
              TempHwndDlg = SetHwndDlg
         ELSE
              GetHwndDlg = TempHwndDlg
         END IF
    MSGBOX "Dll Created Dlg Handle = " + STR$(TempHwndDlg)
         FUNCTION = %False             'Return %False if no errors   '<--- Not really needed but kept for readability
         EXIT FUNCTION                 'Exit function so correct value returned
    ErrHandler:                        'If error then jump to here
         FUNCTION = GetLastError()     'If error then return ErrorNumber
    END FUNCTION
    
    FUNCTION CallMyDialogHandle ALIAS "CallMyDialogHandle"() EXPORT AS LONG
        LOCAL hDlg  AS DWORD
         LOCAL TemphDlg AS DWORD
    '*** Works
    '    SetGetDlg(hDlg, TemphDlg)
        FUNCTION = TemphDlg
    END FUNCTION
    Test Problems.bas -----> This shows my solution works
    Code:
    #COMPILE EXE
    #DIM ALL
    #INCLUDE "Win32Api.inc"
    DECLARE FUNCTION CreateMyDialog LIB "Demo Dialog Handle Prob.dll" ALIAS "CreateMyDialog"() AS LONG
    DECLARE FUNCTION CallMyDialogHandle LIB "Demo Dialog Handle Prob.dll" ALIAS "CallMyDialogHandle"() AS LONG
    
    FUNCTION PBMAIN () AS LONG
         CreateMyDialog
    MSGBOX "Main App Calling returned " + STR$(CallMyDialogHandle)+ " as the Dialog Handle"
    END FUNCTION
    Its all still in testing, but sure beats the heck out of Losing track of Global variables, or accidentally declaring the same global variable for 2 completely different things

    Leave a comment:


  • Fred Harris
    replied
    I would expect one's success detecting this error during development rather than after installation would be directly related to the amount of effort expended and the quality of testing.
    I would expect that this error should manifest itself should one expend that amount of effort required to depress a button on said Dialog/Form, said Dialog/Form being further distinguished by having another control of the same ID as aformentioned button. And here's a DDT program with no Global hWnds if Cliff still needs it...

    Code:
    #Compile Exe
    #Dim All
    #Include "Win32Api.inc"
    %IDC_BUTTON    =   1250
    %IDC_EDIT1     =   1275
    %IDC_EDIT2     =   1300
    %IDC_EDIT3     =   1325
    %IDC_EDIT4     =   1350
    
    Sub XButton_OnClick()
      MsgBox("You Clicked The 'X' Button!")
    End Sub
    
    Callback Function ddtWndProc()
      Select Case CBMsg
        Case %WM_COMMAND
          If CBCtlMsg=%BN_CLICKED And CBCtl=%IDC_BUTTON Then
             Local szBuffer As Asciiz*64
             Local hParent,hCtrl As Dword
             MsgBox("Thanks!  I Needed That!")
             hParent=CBHndl
             szBuffer="hMainWnd=" & Trim$(Str$(hParent))
             Control Set Text CBHndl,%IDC_EDIT2,szBuffer
             hCtrl=GetDlgItem(hParent,%IDC_BUTTON)
             Control Set Text CBHndl,%IDC_EDIT4,"hButton=" & Trim$(Str$(hCtrl))
             Function=%TRUE
          End If
        Case %WM_SYSCOMMAND
          If (CBwParam And &HFFF0)=%SC_CLOSE Then
             Call XButton_OnClick()
          End If
      End Select
    End Function
    
    
    Function PBMain() As Long
      Local hMainWnd,hCtrl,iRetVal As Long
    
      Dialog New Pixels,0,"No Stinkin Globals!",100,100,375,200,%WS_OVERLAPPEDWINDOW Xor %WS_MAXIMIZEBOX To hMainWnd
      Control Add Button, hMainWnd,%IDC_BUTTON,"I'm A Button.  Click Me!", 60,20,250,25,%BS_DEFAULT or %WS_TABSTOP
      Control Add Label, hMainWnd,-1,"HMainWnd From PBMain()",10,70,220,25,%WS_CHILD Or %WS_VISIBLE
      Control Add Textbox, hMainWnd,%IDC_EDIT1,"", 235,70,125,25, %WS_CHILD Or %WS_VISIBLE Or %WS_BORDER
      hCtrl=GetDlgItem(hMainWnd,%IDC_EDIT1)
      SetWindowText(hCtrl,"hMainWnd=" & Trim$(Str$(hMainWnd)))
      Control Add Label, hMainWnd,-1,"HMainWnd From ddtWndProc()",10,100,220,25,%WS_CHILD Or %WS_VISIBLE
      Control Add Textbox, hMainWnd,%IDC_EDIT2,"", 235,100,125,25, %WS_CHILD Or %WS_VISIBLE Or %WS_BORDER
      Control Add Label, hMainWnd,-1,"hButton From PBMain()",10,130,200,25,%WS_CHILD Or %WS_VISIBLE
      Control Add Textbox, hMainWnd,%IDC_EDIT3,"", 235,130,125,25, %WS_CHILD Or %WS_VISIBLE Or %WS_BORDER
      hCtrl=GetDlgItem(hMainWnd,%IDC_BUTTON)
      Control Set Text hMainWnd,%IDC_EDIT3,"hButton=" & Trim$(Str$(hCtrl))
      Control Add Label, hMainWnd,-1,"hBtn From ddtWndProc()",10,160,200,25,%WS_CHILD Or %WS_VISIBLE
      Control Add Textbox, hMainWnd,%IDC_EDIT4,"", 235,160,125,25, %WS_CHILD Or %WS_VISIBLE Or %WS_BORDER
      Dialog Show Modal hMainWnd Call ddtWndProc To iRetVal
        
      PBMain=0
    End Function

    Leave a comment:


  • Michael Mattias
    replied
    I expect one would find it out fairly readily during program development, as Dominic's above listed code shows?
    I would expect one's success detecting this error during development rather than after installation would be directly related to the amount of effort expended and the quality of testing.

    MCM

    Leave a comment:


  • Fred Harris
    replied
    conflicting control ids

    Continuing further with this discussion of possible difficulties one might encounter if controls have conflicting (the same) control id, would it not luckily be true that any bugs caused by this would have to show up at development time, rather than later, for example on a client's machine?

    For example, say you have a button on your main form/dialog which you have given the id number 10500. Further, lets say you instantiated a common control such as a day-month calendar control (or whatever its called) on the same window with the button and by some chance one of its constituent controls also uses 10500 to identify something in it. It certainly could happen that GetDlgItem(hMainWnd,10500) would come up with the handle to some internal calendar object rather than your button. But it wouldn't be a variable type occurance would it? I mean a situation where one program run it comes up with one control and another run with another? Or one machine with the button control 10500 and another machine with the like numbered object in the calendar?

    It seems to me if my reasoning is correct that this issue is a minor potential problem for that reason. I expect one would find it out fairly readily during program development, as Dominic's above listed code shows?

    Leave a comment:


  • Dominic Mitchell
    replied
    ow, not only doesn't this app have any global hWnds it doesnt have any local ones either,
    other than for one Local hWnd for the CreateWindowEx() call in WinMain() to create the main
    program window. What I had to do to accomplish this is truely ugly (you'll laugh or be appalled
    when you see it), but all I wanted to do was prove a point. Here's the program...
    Ugly? It looks pretty normal to me. I use GetDlgItem/GetParent quite a bit.

    Leave a comment:


  • Dominic Mitchell
    replied
    But if you go to the trouble of setting up the callback for EnumChildWindows, how will that
    function solve your troubles, as you are still going to end up with a list of hWnds, multiple
    ones of which still have the same Ctrl ID? I'm assumming one would have to do further checks
    testing for the parent and so on?
    In a constrained environment, I use the GetParent check.
    For example, given a form with the following two controls:
    Code:
    Control              | Identifier               |   Background Color
    ---------------------|--------------------------|-------------------
    ListBox              | 1000(IDC_FORM1_LIST1)    |   Magenta
    ComboBox(CBS_SIMPLE) | 102 (IDC_FORM1_COMBO1)   |   White(default)
    The following code produces the wrong result because both controls are painted magenta.
    Code:
     
        CASE %WM_CTLCOLORLISTBOX                                             
          IF GetDlgCtrlID(lParam) = %IDC_FORM1_LIST1 THEN
            ' Return handle of brush used to paint background
            FUNCTION = GetProp(GetDlgItem(hWnd, %IDC_FORM1_LIST1), "BRUSH")
            EXIT FUNCTION
          END IF
    This code produces the correct result. Only the listbox is painted magenta.
    Code:
     
        CASE %WM_CTLCOLORLISTBOX                                             
          IF GetParent(lParam) = hWnd THEN
            IF GetDlgCtrlID(lParam) = %IDC_FORM1_LIST1 THEN
              ' Return handle of brush used to paint background
              FUNCTION = GetProp(GetDlgItem(hWnd, %IDC_FORM1_LIST1), "BRUSH")
              EXIT FUNCTION
            END IF  
          END IF
    The first code fails because the embedded ComboLBox of the ComboBox(CBS_SIMPLE) has an
    identifier of 1000. Both the listbox and combobox send the WM_CTLCOLORLISTBOX message
    to the parent window.

    I will also use the GetParent check during enumeration iff the enironment is constrained.
    The Layout Manager in Phoenix is an example of this where only certain types of parent
    containers are allowed.

    When I write custom controls that need to find each other via enumeration, I give each
    control class a unique ID that is assigned to each instance of the control. The docking
    and ActiveX containers in Phoenix depend heavily on this technique.

    For example.
    Code:
         
    $ID_TENANT        = "{78A356F1-5E32-4195-846E-7A5F872995B9}"
    
    '----------------------------------------------------------------------
    
    FUNCTION OnCreate(BYVAL hWnd AS DWORD, BYVAL lParam AS LONG) AS LONG
    
      LOCAL ptocd           AS OLECONTAINERDATA PTR
      LOCAL ptcs            AS CREATESTRUCT PTR
      LOCAL pthd            AS HOOKDATA PTR
      LOCAL dwThreadID      AS DWORD
      LOCAL lpfnOldWndProc  AS DWORD
      LOCAL pContainer      AS DWORD
      LOCAL hr              AS LONG
    
      ptcs = lParam
    
      ' Make sure the OLE library is loaded
      OleInitialize BYVAL %NULL
    
      ptocd = HeapAlloc(GetProcessHeap(), %HEAP_ZERO_MEMORY, SIZEOF(@ptocd))
      IF ISFALSE ptocd THEN
        FUNCTION = -1
        EXIT FUNCTION
      END IF
      SetWindowLong hWnd, 0, ptocd
    
      ' Control identifier
      SetProp hWnd, $ID_TENANT, &H584E4850???     ' PHNX
    
      ...
      
    END FUNCTION
      
    '----------------------------------------------------------------------
    '
    ' FUNCTION: OleContainerEnumProc
    ' PURPOSE:  Enumerates all OLE containers on the immediate parent
    '           window.
    '
    '----------------------------------------------------------------------
    
    FUNCTION OleContainerEnumProc _
      ( _
      BYVAL hWnd    AS DWORD, _ ' handle of child window
      BYVAL lParam  AS LONG _   ' address of enumeration data
      ) AS LONG
    
      LOCAL plRet AS LONG PTR
    
      plRet = lParam
    
      IF ISTRUE GetProp(hWnd, $ID_TENANT) THEN
        @plRet = %TRUE
        FUNCTION = %FALSE
        EXIT FUNCTION
      END IF
    
      FUNCTION = %TRUE
    
    END FUNCTION
    
    '----------------------------------------------------------------------
    '
    ' FUNCTION: HasOleContainer
    ' PURPOSE:  Returns True if an OLE container is present on a form.
    '
    '----------------------------------------------------------------------
    
    FUNCTION HasOleContainer _
      ( _
      BYVAL hWnd  AS DWORD _  ' handle of top-level window
      ) AS LONG
    
      LOCAL lRet  AS LONG
    
      EnumChildWindows hWnd, CODEPTR(OleContainerEnumProc), VARPTR(lRet)
    
      FUNCTION = lRet
    
    END FUNCTION

    As for Cliff, he asked this
    Is there a way to find the "Windows Handle" of a Dialog or Window that I created in one function
    so that it can be used in other functions? Without declaring my variable as global?....or IE:
    I know the Equates value for the Window, but if I need to get the Windows Handle outside the function
    it was created in, is there a way?
    This is very easy to accomplish. Either I don't understand what he asking, or he thinks this problem
    is a lot more difficult than it really is.

    Leave a comment:


  • Cliff Nichols
    replied
    This is turning into a "Proof of Concept" idea.
    Sure I could just easily have a Global Variable to hold the Handle to a Dialog, or pass the CBHNDL from my callback to a function.
    In these 2 cases I know what the Handle is. But lets say I have a function that is not passed the Handle, that I could still get the Handle from a local variable.

    With my above code, it seems to work. Although I have to expand on it.
    Hopefully shortly I will have a full working source for the idea.

    Leave a comment:


  • Fred Harris
    replied
    I honestly hadn't thought of that Dominic, but I see your point. Frequently I write my own grids, and when I do I always use ordinary buttons for the header row at the top (one for each column, of course), and I always also use buttons for the left side of the grid so that the user can click on a button to highlight a row for whatever application specific task might be required. Inside the custom control during its WM_CREATE message the grid builds itself and I just use an incrementing counter variable for the control ID parameter in the CreateWindow() calls for all these buttons. And since a grid can have virtually any number of rows or columns, there is no way of telling which range of numbers have been used up for control IDs.

    Now of course the plot thickens if you put one of these grids (or two of these grids, or three of these grids....) on a form/dialog, then for good measure add another button or two or three to the form/dialog not associated or part of the grid, i.e., a button that does something else.

    I can see where in that case a call to GetDlgItem(hParent,%CTRL_ID) will probably succeed and return when it encounters the first control (which may not be the one you want) with a ctrl id of %CTRL_ID. But if you go to the trouble of setting up the callback for EnumChildWindows, how will that function solve your troubles, as you are still going to end up with a list of hWnds, multiple ones of which still have the same Ctrl ID? I'm assumming one would have to do further checks testing for the parent and so on?

    In any case, in Cliff's case he was only asking about less complex cases than this, and I believe he'd be will served by GetDlgItem(). There are certainly many cases (in fact I'd go so far as to say the vast majority) where this simple function will give successful results, and it clearly will in the case Cliff presented. I don't follow DDT code very well at all, but I'm assumming most Api functions work in that context.

    Just to prove my point (and I fully understand yours now), below is a very simple app that has a 2 labels, three textboxes, and two buttons. One enters a length and a width in two of the textboxes, and the Area shows up in a third. The one button is for calculating the area and the other button is for clearing the form/dialog so that one can do another calculation. The only even slightly interesting thing about this app (which I'm sure isn't all that interesting to a coder such as yourself) is that all the controls are subclassed to allow entry to proceed without use of the mouse to reset focus. The program cycles through all the child window controls just by using the [ENTER] key.

    Now, not only doesn't this app have any global hWnds it doesnt have any local ones either, other than for one Local hWnd for the CreateWindowEx() call in WinMain() to create the main program window. What I had to do to accomplish this is truely ugly (you'll laugh or be appalled when you see it), but all I wanted to do was prove a point. Here's the program...

    Code:
    #Compile Exe
    #Include "Win32api.inc"
    %IDC_LABEL1   =   1500
    %IDC_LABEL2   =   1505
    %IDC_TEXT1    =   1510
    %IDC_TEXT2    =   1515
    %IDC_TEXT3    =   1520
    %IDC_BUTTON1  =   1525
    %IDC_BUTTON2  =   1530
    
    Global fnOldEditProc    As Long
    Global fnOldButtonProc  As Long
    
    Type WndEventArgs
      wParam                As Long          'Package parameters to Window Procedure in TYPE
      lParam                As Long
      hWnd                  As Dword
      hInst                 As Dword
    End Type
    
    
    Function fnNewEditProc(ByVal hWnd As Long,ByVal wMsg As Long,ByVal wParam As Long,ByVal lParam As Long) As Long
      If wMsg=%WM_CHAR Then
         Select Case Lowrd(wParam)
           Case 8      'backspace
             'backspace is OK
           Case 13     'backspace or enter key
             Select Case GetDlgCtrlID(hWnd)
               Case %IDC_TEXT1
                 Call SetFocus(GetDlgItem(GetParent(hWnd),%IDC_TEXT2))
               Case %IDC_TEXT2
                 Call SetFocus(GetDlgItem(GetParent(hWnd),%IDC_BUTTON1))
               Case %IDC_TEXT3
                 Call SetFocus(GetDlgItem(GetParent(hWnd),%IDC_BUTTON2))
             End Select
           Case 46
              'Decimal Point
           Case 48 To 57
             'A number key was pressed
           Case Else      'If any other key is pressed other than one of those listed above,
             wParam=0     'it will be contained in wParam and it will be collected here in
         End Select       'the 'Else' clause.  Here it will be 'eaten' rather than passed on
      End If              'to the original text box window procedure in User32.dll.  Therefore,
                          'it won't show up in the text box
      fnNewEditProc=CallWindowProc(fnOldEditProc,hWnd,wMsg,wParam,lParam)
    End Function
    
    
    Function fnNewButtonProc(ByVal hWnd As Long,ByVal wMsg As Long,ByVal wParam As Long,ByVal lParam As Long) As Long
      If wMsg=%WM_CHAR And wParam=13 And GetDlgCtrlID(hWnd) = %IDC_BUTTON1 Then
         SendMessage(GetParent(hWnd),%WM_COMMAND,MakDwd(%IDC_BUTTON1,%BN_CLICKED),GetDlgItem(hWnd,%IDC_BUTTON1))
      End If
      If wMsg=%WM_CHAR And wParam=13 And GetDlgCtrlID(hWnd) = %IDC_BUTTON2 Then
         SendMessage(GetParent(hWnd),%WM_COMMAND,MakDwd(%IDC_BUTTON2,%BN_CLICKED),GetDlgItem(hWnd,%IDC_BUTTON2))
      End If
    
      fnNewButtonProc=CallWindowProc(fnOldButtonProc,hWnd,wMsg,wParam,lParam)
    End Function
    
    
    Function fnWndProc_OnCreate(Wea As WndEventArgs) As Long
      Local lpCreateStruct As CREATESTRUCT Ptr
    
      lpCreateStruct=Wea.lParam   'Can use GetModuleHandle() here instead
      [email protected]
      CreateWindowEx 0,"static","Length",%WS_CHILD Or %WS_VISIBLE,10,10,80,25,Wea.hWnd,%IDC_LABEL1,Wea.hInst,Byval 0
      fnOldEditProc= _
      SetWindowLong _
      ( _
        CreateWindowEx(%WS_EX_CLIENTEDGE,"Edit","",%WS_CHILD Or %WS_VISIBLE,120,10,80,25,Wea.hWnd,%IDC_TEXT1,Wea.hInst,Byval 0), _
        %GWL_WNDPROC, _
        CodePtr(fnNewEditProc) _
      )
      CreateWindowEx 0,"static","Width",%WS_CHILD Or %WS_VISIBLE,10,60,80,25,Wea.hWnd,%IDC_LABEL2,Wea.hInst,Byval 0
      fnOldEditProc= _
      SetWindowLong _
      ( _
        CreateWindowEx(%WS_EX_CLIENTEDGE,"Edit","",%WS_CHILD Or %WS_VISIBLE,120,60,80,25,Wea.hWnd,%IDC_TEXT2,Wea.hInst,Byval 0), _
        %GWL_WNDPROC, _
        CodePtr(fnNewEditProc) _
      )
      fnOldButtonProc= _
      SetWindowLong _
      ( _
        CreateWindowEx(0,"Button","Calculate",%WS_CHILD Or %WS_VISIBLE,80,120,150,25,Wea.hWnd,%IDC_BUTTON1,Wea.hInst,Byval 0), _
        %GWL_WNDPROC, _
        CodePtr(fnNewButtonProc) _
      )
      CreateWindowEx %WS_EX_CLIENTEDGE,"Edit","",%WS_CHILD Or %WS_VISIBLE,80,180,150,25,Wea.hWnd,%IDC_TEXT3,Wea.hInst,Byval 0
      fnOldButtonProc= _
      SetWindowLong _
      ( _
        CreateWindowEx(0,"Button","Clear",%WS_CHILD Or %WS_VISIBLE,125,225,60,25,Wea.hWnd,%IDC_BUTTON2,Wea.hInst,Byval 0), _
        %GWL_WNDPROC, _
        CodePtr(fnNewButtonProc) _
      )
      SetFocus(GetDlgItem(wea.hWnd,%IDC_TEXT1))
    
      fnWndProc_OnCreate=0
    End Function
                     
    
    Sub cmdCalculate_Click(Wea As WndEventArgs)
      Local dblLength, dblWidth, dblArea As Double
      Local szBuffer As Asciiz*64
    
      GetWindowText(GetDlgItem(Wea.hWnd,%IDC_TEXT1),szBuffer,64)
      dblLength=Val(szBuffer)
      GetWindowText(GetDlgItem(Wea.hWnd,%IDC_TEXT2),szBuffer,64)
      dblWidth=Val(szBuffer)
      szBuffer="Area = " & Format$(dblLength*dblWidth,"######0.00")
      SetWindowText(GetDlgItem(Wea.hWnd,%IDC_TEXT3),szBuffer)
      SetFocus(GetDlgItem(Wea.hWnd,%IDC_BUTTON2))
    End Sub
    
    
    Sub cmdClear_Click(Wea As WndEventArgs)
      Local hEdit As Dword  'Only used locally to avoid bad practice of calling same function
                                               multiple times for same information.
      hEdit=GetDlgItem(Wea.hWnd,%IDC_TEXT1)
      SetWindowText(hEdit,"")
      SetFocus(hEdit)
      hEdit=GetDlgItem(Wea.hWnd,%IDC_TEXT2)
      SetWindowText(hEdit,"")
      hEdit=GetDlgItem(Wea.hWnd,%IDC_TEXT3)
      SetWindowText(hEdit,"")
    End Sub
    
    
    Function fnWndProc_OnCommand(Wea As WndEventArgs) As Long
      Select Case As Long Lowrd(wea.wParam)
        Case %IDC_BUTTON1
          If Hiwrd(Wea.wParam)=%BN_CLICKED Then
             Call cmdCalculate_Click(Wea)
          End If
        Case %IDC_BUTTON2
          If Hiwrd(Wea.wParam)=%BN_CLICKED Then
             Call cmdClear_Click(Wea)
          End If
      End Select
    
      fnWndProc_OnCommand=0
    End Function
    
    
    Function fnWndProc_OnDestroy(Wea As WndEventArgs) As Long
      Call PostQuitMessage(0)
      fnWndProc_OnDestroy=0
    End Function
    
    
    Function fnWndProc(ByVal hWnd As Long,ByVal wMsg As Long,ByVal wParam As Long,ByVal lParam As Long) As Long
      Local Wea As WndEventArgs
    
      Select Case As Long wMsg
        Case %WM_CREATE
          Wea.hWnd=hWnd : Wea.wParam=wParam : Wea.lParam=lParam
          fnWndProc=fnWndProc_OnCreate(Wea)
          Exit Function
        Case %WM_COMMAND
          Wea.hWnd=hWnd : Wea.wParam=wParam : Wea.lParam=lParam
          fnWndProc=fnWndProc_OnCommand(Wea)
          Exit Function
        Case %WM_DESTROY
          Wea.hWnd=hWnd : Wea.wParam=wParam : Wea.lParam=lParam
          fnWndProc=fnWndProc_OnDestroy(Wea)
          Exit Function
      End Select
    
      fnWndProc=DefWindowProc(hWnd,wMsg,wParam,lParam)
    End Function
    
    
    Function WinMain(ByVal hIns As Long,ByVal hPrev As Long,ByVal lpCL As Asciiz Ptr,ByVal iShow As Long) As Long
      Local winclass As WndClassEx
      Local szAppName As Asciiz*16
      Local Msg As tagMsg
      Local hWnd As Dword
    
      szAppName="Basic Stuff"
      winclass.cbSize=SizeOf(winclass)
      winclass.style=%CS_HREDRAW Or %CS_VREDRAW
      winclass.lpfnWndProc=CodePtr(fnWndProc)
      winclass.cbClsExtra=0
      winclass.cbWndExtra=0
      winclass.hInstance=hIns
      winclass.hIcon=LoadIcon(%NULL, ByVal %IDI_APPLICATION)
      winclass.hCursor=LoadCursor(%NULL, ByVal %IDC_ARROW)
      winclass.hbrBackground=%COLOR_BTNFACE+1
      winclass.lpszMenuName=%NULL
      winclass.lpszClassName=VarPtr(szAppName)
      Call RegisterClassEx(winclass)
      hWnd=CreateWindow(szAppName,"Basic Form",%WS_OVERLAPPEDWINDOW,200,100,325,300,0,0,hIns,ByVal 0)
      Call ShowWindow(hWnd,iShow)
      While GetMessage(Msg,%NULL,0,0)
        Call TranslateMessage(Msg)
        Call DispatchMessage(Msg)
      Wend
    
      Function=msg.wParam
    End Function

    Leave a comment:


  • Michael Mattias
    replied
    I have not dug into this too closely, but from what I have read here this is more an exercise in "using variables" and "managing my program's data" than in "doing cool stuff with Windows' Enumxxxx functions."

    DIALOG NEW returns "hDlg". Save it in a variable just like you'd save any other variable you need.

    Or, if you need it in a support function which is called from the dialog procedure for a window, pass CBHNDL as a parameter to that function

    Or, if you have two dialogs which need to be aware of each other and they do not have a parent-child relationship...

    Code:
     DIALOG NEW   ...  to hDlg1
       CONTROL ADD....
     DIALOG NEW       to hDlg2 
       CONTROL ADD 
    
     DIALOG SET USER hDlg1, 1, hDlg2
     DIALOG SET USER hdlg2, 1, hDlg1 
     DIALOG SHOW MODELESS hDlg1 CALL dlgProc1
     DIALOG SHOW MODELESS hDlg2 CALL dlgProc2
     DDT Message loop here
    If you have to, use DIALOG SHOW STATE hdlgx , %SW_HIDE to prevent a particular screen from showing until needed.

    In either DlgProc, you can always get a handle to the companion screen with
    Code:
         DIALOG GET USER CBHNDL, 1 TO hDlgCompanion
    I must be missing something here, since this is just too obvious.

    MCM
    Last edited by Michael Mattias; 16 Dec 2007, 09:51 AM.

    Leave a comment:


  • Dominic Mitchell
    replied
    GetDlgItem(hParent,CtrlID) will return the hWnd. The complement to this function seems to be GetDlgCtrlID(hWnd), which, if you know the hWnd, will return the CtrlID.
    At first glance, they would seem to be complements but that is only true in a single container(parent) environment.
    Because a function like EnumChildWindows returns the handles of all the descendants of a container, you cannot use
    GetDlgCtrlID to definitively determine that the control id it produces belongs to a control you created. Don't forget
    that controls embedded in complex controls can have the save identifiers as controls you created. This is something
    you have no control over.

    Leave a comment:


  • Cliff Nichols
    replied
    Couldn't Get it

    I tried many ways, but still could not "Find" the Windows Handle without already knowing the Windows Handle that I was trying to find.

    So I came up with my own way, that seems to work and eliminates my need for a global variable for the Windows Handle.

    Although I am still interested if someone can show me a working example Api functions I am fairly satisfied with the below code (unless I am breaking some rule that I have not thought of yet?)

    Code:
    #COMPILE EXE
    #DIM ALL
    #INCLUDE "WIN32API.INC"
    %IDD_DIALOG1 =  101
    %IDC_BUTTON1 = 1001
    DECLARE FUNCTION PBMAIN()
    DECLARE CALLBACK FUNCTION ShowDIALOG1Proc()
    DECLARE FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
    DECLARE FUNCTION SetGetDlg(BYREF SetHwndDlg AS DWORD, BYREF GetHwndDlg AS DWORD)AS DWORD
    
    FUNCTION PBMAIN()
        ShowDIALOG1 %HWND_DESKTOP
    END FUNCTION
    
    CALLBACK FUNCTION ShowDIALOG1Proc()
        SELECT CASE AS LONG CBMSG
            CASE %WM_INITDIALOG
            CASE %WM_NCACTIVATE
                STATIC hWndSaveFocus AS DWORD
                IF ISFALSE CBWPARAM THEN
                    ' Save control focus
                    hWndSaveFocus = GetFocus()
                ELSEIF hWndSaveFocus THEN
                    ' Restore control focus
                    SetFocus(hWndSaveFocus)
                    hWndSaveFocus = 0
                END IF
    
            CASE %WM_COMMAND
                ' Process control notifications
                SELECT CASE AS LONG CBCTL
                    CASE %IDC_BUTTON1
                        IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
    
                             LOCAL TempSetDlg AS DWORD
                             LOCAL TempGetDlg AS DWORD
                             SetGetDlg(TempSetDlg, TempGetDlg)
    MSGBOX FUNCNAME$ + $CR + STR$(TempGetDlg)
    
                        END IF
    
                END SELECT
        END SELECT
    END FUNCTION
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Dialogs **
    '------------------------------------------------------------------------------
    FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
        LOCAL lRslt AS LONG
        LOCAL hDlg  AS DWORD
         LOCAL TemphDlg AS DWORD
         
        DIALOG NEW hParent, "Dialog1", 70, 70, 201, 121, %WS_POPUP OR %WS_BORDER _
            OR %WS_DLGFRAME OR %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
            %WS_MINIMIZEBOX OR %WS_MAXIMIZEBOX OR %WS_CLIPSIBLINGS OR _
            %WS_VISIBLE OR %DS_MODALFRAME OR %DS_3DLOOK OR %DS_NOFAILCREATE OR _
            %DS_SETFONT, %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR _
            %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
    
    
    '*** Works
        SetGetDlg(hDlg, TemphDlg)
    
    
    '*** Works but only because I know the Windows Handle
        LOCAL retvar AS DWORD
    
        DIALOG SET USER hDlg, 1, hDlg
        DIALOG GET USER hDlg, 1 TO retvar
    MSGBOX FUNCNAME$ + $CR + STR$(retvar)
    
    
    '*** Doesn't work ???? because I need the Handle to get the handle?
        DIALOG SET USER %IDD_DIALOG1, 1, hDlg
        DIALOG GET USER %IDD_DIALOG1, 1 TO retvar
    MSGBOX FUNCNAME$ + $CR + STR$(retvar)
    
    
    
        CONTROL ADD BUTTON, hDlg, %IDC_BUTTON1, "Button1", 5, 5, 45, 20
        DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
        FUNCTION = lRslt
    END FUNCTION
    '------------------------------------------------------------------------------
    
    
    FUNCTION SetGetDlg(BYREF SetHwndDlg AS DWORD, BYREF GetHwndDlg AS DWORD)AS DWORD
         ON ERROR GOTO ErrHandler
         STATIC TempHwndDlg AS DWORD
         IF SetHwndDlg <> 0 THEN
              GetHwndDlg = SetHwndDlg
              TempHwndDlg = SetHwndDlg
         ELSE
              GetHwndDlg = TempHwndDlg
         END IF
         FUNCTION = %False             'Return %False if no errors   '<--- Not really needed but kept for readability
         EXIT FUNCTION                 'Exit function so correct value returned
    ErrHandler:                        'If error then jump to here
         FUNCTION = GetLastError()     'If error then return ErrorNumber
    END FUNCTION
    

    Leave a comment:


  • Fred Harris
    replied
    If you know the control id of a window (and you've got to know it cuz you had to set it to create the window), GetDlgItem(hParent,CtrlID) will return the hWnd. The complement to this function seems to be GetDlgCtrlID(hWnd), which, if you know the hWnd, will return the CtrlID.

    Leave a comment:


  • Michael Mattias
    replied
    >> I wonder if there is a SDK equivalent to DIALOG GET USER" or if it is a Compiler thing?
    > See SetProp, GetProp and RemoveProp

    See also GetWindowLong[Ptr], SetWindowLong[Ptr] functions.

    MCM

    Leave a comment:


  • Dominic Mitchell
    replied
    I suppose I could do a GUID thing, but always avoided them from my VB days and using OCX's, unless I am mistaken on that concept?
    A GUID has nothing to do with OCX's in this case. It is just one way to uniquely identify a window.
    This avoids the need to check for window class, or caption, or both.

    One area where uniquely identifying a window comes in handy, is when enumerating controls on a window.
    Many controls usually consist of a container with embedded controls. These complex or compound controls`
    can cause problems when using the EnumChildWindows function. Uniquely identifying the control is the only
    nontrivial method that can be used to tell whether the control passed to the application-defined callback
    is one you created.

    Leave a comment:


  • Kev Peel
    replied
    Originally posted by Cliff Nichols View Post
    I wonder if there is a SDK equivalent to DIALOG GET USER" or if it is a Compiler thing?
    See SetProp, GetProp and RemoveProp

    Leave a comment:


  • Cliff Nichols
    replied
    Thank you Pierre,
    I wonder if there is a SDK equivalent to "DIALOG GET USER" or if it is a Compiler thing?

    @Dominic
    I suppose I could do a GUID thing, but always avoided them from my VB days and using OCX's, unless I am mistaken on that concept?

    Leave a comment:


  • Pierre Bellisle
    replied
    One more way...

    Code:
    #COMPILE EXE '#Win 8.04#
    #DIM ALL
    #REGISTER NONE
    #INCLUDE "Win32Api.inc" '#2005-01-27#
     
    %Label1   = 101
    %Label2   = 102
    %Button1  = 201
    '______________________________________________________________________________
     
    CALLBACK FUNCTION DlgProc2
     LOCAL hMainDlg AS DWORD
     
     SELECT CASE CBMSG
     
       CASE %WM_INITDIALOG
         DIALOG GET USER CBHNDL, 1 TO hMainDlg
         CONTROL SET TEXT CBHNDL, %Label1, "Main handle is " & HEX$(hMainDlg)
         PostMessage hMainDlg, %WM_USER + 500, CBHNDL, 0
     
      END SELECT
     
    END FUNCTION
    '______________________________________________________________________________
     
    FUNCTION Dialog2(hMainDlg AS DWORD) AS LONG
     LOCAL hChildDlg AS DWORD
     
     DIALOG NEW hMainDlg ,"Child dialog", , , 175, 75, _
                %WS_CAPTION OR %WS_MINIMIZEBOX OR %WS_SYSMENU, 0 TO hChildDlg
     CONTROL ADD LABEL, hChildDlg, %Label1, "Label 2", 55, 30, 90, 12
     DIALOG SET USER hChildDlg, 1, hMainDlg
     DIALOG SHOW MODAL hChildDlg CALL DlgProc2
     
    END FUNCTION
    '______________________________________________________________________________
     
    CALLBACK FUNCTION DlgProc
     
     SELECT CASE CBMSG
     
       CASE %WM_COMMAND
         SELECT CASE LOWRD(CBWPARAM)
           CASE %Button1
             IF CBCTLMSG = %BN_CLICKED OR CBCTLMSG = 1 THEN
               Dialog2(CBHNDL)
             END IF
         END SELECT
     
       CASE %WM_USER + 500
         CONTROL SET TEXT CBHNDL, %Label1, "Child handle is " & HEX$(CBWPARAM)
     
      END SELECT
     
    END FUNCTION
    '______________________________________________________________________________
     
    FUNCTION PBMAIN()
     LOCAL hMainDlg AS DWORD
     
     DIALOG NEW %HWND_DESKTOP ,"Main dialog", , , 200, 170, _
                %WS_CAPTION OR %WS_MINIMIZEBOX OR %WS_SYSMENU, 0 TO hMainDlg
     SetClassLong hMainDlg, %GCL_HICON, LoadIcon(BYVAL %NULL, BYVAL %IDI_INFORMATION) 'Set a nice icon
     CONTROL ADD LABEL, hMainDlg, %Label1,  "Child handle", 15, 15, 170, 15
     CONTROL ADD BUTTON, hMainDlg, %Button1, "Child", 155, 145, 35, 15
     DIALOG SHOW MODAL hMainDlg CALL DlgProc
     
    END FUNCTION
    '______________________________________________________________________________
    Last edited by Pierre Bellisle; 14 Dec 2007, 08:46 PM.

    Leave a comment:


  • Dominic Mitchell
    replied
    Any way to do what I am thinking? (probable answer is "NO") or in this case I am most likely stuck with a Global variable to hold the value?
    The answer is yes.
    Use the EnumWindows function.
    You can simplify the process by assigning a GUID to the window as a property and just checking for that using GetProp.

    One side question that could be interesting. Is it better to declare the variable for the Windows Handle to be declared as DWORD or as LONG?
    They are DWORDs, but you can use either long or dword since failure is indicated by a zero value.

    Leave a comment:


  • Cliff Nichols
    started a topic Window Handle

    Window Handle

    This may be an answer of "NO" but I thought I would ask anyways.
    Is there a way to find the "Windows Handle" of a Dialog or Window that I created in one function so that it can be used in other functions? Without declaring my variable as global?....or IE: I know the Equates value for the Window, but if I need to get the Windows Handle outside the function it was created in, is there a way?

    I know there are API's for current Window, next window etc, but to my knowledge they are for use of enumerating Windows. Which does me no good unless I know the Windows Handle I am looking for.

    For example from PbForms
    Code:
    #PBFORMS CREATED V1.51
    '------------------------------------------------------------------------------
    ' The first line in this file is a PB/Forms metastatement.
    ' It should ALWAYS be the first line of the file. Other   
    ' PB/Forms metastatements are placed at the beginning and 
    ' end of "Named Blocks" of code that should be edited     
    ' with PBForms only. Do not manually edit or delete these 
    ' metastatements or PB/Forms will not be able to reread   
    ' the file correctly.  See the PB/Forms documentation for 
    ' more information.                                       
    ' Named blocks begin like this:    #PBFORMS BEGIN ...     
    ' Named blocks end like this:      #PBFORMS END ...       
    ' Other PB/Forms metastatements such as:                  
    '     #PBFORMS DECLARATIONS                               
    ' are used by PB/Forms to insert additional code.         
    ' Feel free to make changes anywhere else in the file.    
    '------------------------------------------------------------------------------
    
    #COMPILE EXE
    #DIM ALL
    
    '------------------------------------------------------------------------------
    '   ** Includes **
    '------------------------------------------------------------------------------
    #PBFORMS BEGIN INCLUDES 
    #IF NOT %DEF(%WINAPI)
        #INCLUDE "WIN32API.INC"
    #ENDIF
    #PBFORMS END INCLUDES
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Constants **
    '------------------------------------------------------------------------------
    #PBFORMS BEGIN CONSTANTS 
    %IDD_DIALOG1 = 101     '<--- I know this value, but Windows Handle not known until the Window is created
    #PBFORMS END CONSTANTS
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Declarations **
    '------------------------------------------------------------------------------
    DECLARE CALLBACK FUNCTION ShowDIALOG1Proc()
    DECLARE FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
    #PBFORMS DECLARATIONS
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Main Application Entry Point **
    '------------------------------------------------------------------------------
    FUNCTION PBMAIN()
        ShowDIALOG1 %HWND_DESKTOP
    END FUNCTION
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** CallBacks **
    '------------------------------------------------------------------------------
    CALLBACK FUNCTION ShowDIALOG1Proc()
    
        SELECT CASE AS LONG CBMSG
            CASE %WM_INITDIALOG
                ' Initialization handler
    
            CASE %WM_NCACTIVATE
                STATIC hWndSaveFocus AS DWORD
                IF ISFALSE CBWPARAM THEN
                    ' Save control focus
                    hWndSaveFocus = GetFocus()
                ELSEIF hWndSaveFocus THEN
                    ' Restore control focus
                    SetFocus(hWndSaveFocus)
                    hWndSaveFocus = 0
                END IF
    
            CASE %WM_COMMAND
                ' Process control notifications
                SELECT CASE AS LONG CBCTL
    
                END SELECT
        END SELECT
    END FUNCTION
    '------------------------------------------------------------------------------
    
    '------------------------------------------------------------------------------
    '   ** Dialogs **
    '------------------------------------------------------------------------------
    FUNCTION ShowDIALOG1(BYVAL hParent AS DWORD) AS LONG
        LOCAL lRslt AS LONG
    
    #PBFORMS BEGIN DIALOG %IDD_DIALOG1->->
        LOCAL hDlg  AS DWORD     '<---Only valid in this function unless I make it global?
    
        DIALOG NEW hParent, "Dialog1", 70, 70, 201, 121, %WS_POPUP OR %WS_BORDER _
            OR %WS_DLGFRAME OR %WS_THICKFRAME OR %WS_CAPTION OR %WS_SYSMENU OR _
            %WS_MINIMIZEBOX OR %WS_MAXIMIZEBOX OR %WS_CLIPSIBLINGS OR _
            %WS_VISIBLE OR %DS_MODALFRAME OR %DS_3DLOOK OR %DS_NOFAILCREATE OR _
            %DS_SETFONT, %WS_EX_CONTROLPARENT OR %WS_EX_LEFT OR _
            %WS_EX_LTRREADING OR %WS_EX_RIGHTSCROLLBAR, TO hDlg
    #PBFORMS END DIALOG
    
        DIALOG SHOW MODAL hDlg, CALL ShowDIALOG1Proc TO lRslt
    
    #PBFORMS BEGIN CLEANUP %IDD_DIALOG1
    #PBFORMS END CLEANUP
    
        FUNCTION = lRslt
    END FUNCTION
    '------------------------------------------------------------------------------
    Any way to do what I am thinking? (probable answer is "NO") or in this case I am most likely stuck with a Global variable to hold the value?

    One side question that could be interesting. Is it better to declare the variable for the Windows Handle to be declared as DWORD or as LONG?
    From my knowledge both SDK and DDT return %NULL if the window could not be created, or the Handle to the Window if it could. But I never checked to see if the Handle value was always in the range of a DWORD or a LONG?
    (maybe another mute question, but "Inquiring Minds what to know")
Working...
X