# CPearson's Child of Desktop Mod



## JLouis (Jan 2, 2023)

I found this on this site and need to adapt it to my current userform as a "Child of Desktop." I've tried modifying the code but keep getting an error as shown in the attachment. Can someone explain to me what needs to happen to avoid this message and use the code only as a "Child of Desktop?" I've made it prtSafe. 

Resource URL : Pearson Software Consulting

Download example workbook : http://www.cpearson.com/Zips/SetParent.zip

Can anyone assist in adapting this to an existing userform? The code is way above my paygrade.

Thanks.


----------



## Dan_W (Jan 2, 2023)

Can you identify which part of the code is causing the error? 
Also, just to confirm, you're using 64bit Office, right? I wish adding PtrSafe was all that was required in order to make the declarations 64bit compatible.
I'll take a look at the original code, but it help if you can find out which is causing the error. Thanks.


----------



## Dan_W (Jan 2, 2023)

Sorry another - I've just looked at the article, and it sounds an awful like a project that one of the experts on this forum has done:



Jaafar Tribak said:


> The following code will lock a modeless userform to the workbook window so if the workbook is moved,resized, maximized etc , the userform will follow it... Essentially, the userform becomes confined within the workbook client area.


If that's what you're after, I can definitely confirm that it works for 64bit Office. The code and a sample workbook is available here on the forum: How to make a userform folow the workbook window


----------



## JLouis (Jan 2, 2023)

Thanks for jumping in. I actually reversed the process by clearing items on the Pearson UF and adding my items to it. Worked very well, but I know there's a lot of garbage I don't need in that code. I'm going to try as you suggest and use Jaafar's code. I'll let you know how it goes.

Thanks again.


----------



## JLouis (Jan 2, 2023)

OK, I tried Jaafar's code and it worked as advertised but it is not suitable to my application. Perason's code glues the userform to the left part of the screen and snugs it up to the top. It doesn't move regardless of other WB activity. That's what I needed.

Unless I'm not using it correctly, with Jaafar's code it uses the default UF position which you can move where you want and it will stay there as long as you are using the form uninterrupted. Once you reload the form it goes back to the default. Great piece of code.

Thanks for helping out.


----------



## JLouis (Jan 2, 2023)

Dan_W, I'm not sure what part of the code is throwing the error. I just don't understand it and can't follow the process. Using Pearson's userform, I just deleted all the items on it and when it errored out upon intialization I deleted the code to the controls I deleted. I then copied/pasted my items and code to the form. Did a search in the project replacing the name of the old UF with the new name and it worked perfectly. Pretty dirty, but it worked.


----------



## Dan_W (Jan 2, 2023)

I had a feeling you might not be able to find it easily - CP has coded it so that it traps the errors and doesn't tell you where they originated. There will be a line in the code saying: `On Error Goto [SOMETHING]` If you delete that line then it should then tell you where the error occurs. But I'll have a look at the code.


----------



## Dan_W (Jan 2, 2023)

HI. I've taken a crack up updating the code to make it both 32bit/64bit compatible. Two of the three modules needed to change: frmSetParent and modSupport. I have reproduced them both below. For the purpose of testing whether they adjustments work, please can you make sure that you try it on a 'fresh' version of the workbook - that is to say, in an untouched state as unzippped. It should just then be a matter of replacing the code completely for each of the two modules.

As always, please make sure you have saved all open workbooks because when working APIs it is entirely possible (if not painfully predictable) that Excel will crash.

Hopefully this works! Let me know how it goes.

Here is the updated code for *frmSetParent*


```
Option Explicit
Option Compare Text
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' frmSetParent
' This form illustrates the SetParent procedure to make a userform the a child window
' of no window, the Excel Application window, the Excel Desktop Window, and the Active
' Window.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

'''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Window Class Names
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Const C_EXCEL_APP_WINDOWCLASS = "XLMAIN"
Private Const C_EXCEL_DESK_WINDOWCLASS = "XLDESK"
Private Const C_EXCEL_WINDOW_WINDOWCLASS = "EXCEL7"
Private Const C_VBA_USERFORM_WINDOWCLASS = "ThunderDFrame"

'''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Window HWnds
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private ApplicationHWnd As LongPtr
Private ExcelDeskHWnd As LongPtr
Private ActiveWindowHWnd As LongPtr
Private UserFormHWnd As LongPtr
Private WindowsDesktopHWnd As LongPtr

'''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Other Consts
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Const MAX_PATH = 260
Private Const GA_ROOT As Long = 2
Private Const GA_ROOTOWNER As Long = 3
Private Const GA_PARENT As Long = 1
Private Const GWL_HWNDPARENT As Long = -8
Private Const GW_OWNER = 4

'''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Windows API Functions
'''''''''''''''''''''''''''''''''''''''''''''''''''''''

#If VBA7 Then

    #If Win64 Then
        Private Declare PtrSafe Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongPtrA" (ByVal hwnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As LongPtr) As Long
        Private Declare PtrSafe Function GetWindowLong Lib "user32.dll" Alias "GetWindowLongPtrA" (ByVal hwnd As LongPtr, ByVal nIndex As Long) As Long
    #Else
        Private Declare PtrSafe Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" (ByVal hwnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
        Private Declare PtrSafe Function GetWindowLong Lib "user32.dll" Alias "GetWindowLongA" (ByVal hwnd As LongPtr, ByVal nIndex As Long) As Long
    #End If
    
    Private Declare PtrSafe Function SetParent Lib "user32" (ByVal hWndChild As LongPtr, ByVal hWndNewParent As LongPtr) As LongPtr
    Private Declare PtrSafe Function GetDesktopWindow Lib "user32" () As LongPtr
    Private Declare PtrSafe Function FindWindow Lib "user32" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
    Private Declare PtrSafe Function FindWindowEx Lib "user32" (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, ByVal lpsz1 As String, ByVal lpsz2 As String) As LongPtr
    Private Declare PtrSafe Function GetClassName Lib "user32" (ByVal hwnd As LongPtr, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
    Private Declare PtrSafe Function SetForegroundWindow Lib "user32" (ByVal hwnd As LongPtr) As Long
    Private Declare PtrSafe Function GetAncestor Lib "user32" (ByVal hwnd As LongPtr, ByVal gaFlags As Long) As LongPtr
    Private Declare PtrSafe Function GetWindow Lib "user32" (ByVal hwnd As LongPtr, ByVal wCmd As Long) As LongPtr
    Private Declare PtrSafe Function GetParent Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
#Else
    Private Enum LongPtr
        [_]
    End Enum
    Private Declare Function SetParent Lib "user32" (ByVal hWndChild As LongPtr, ByVal hWndNewParent As LongPtr) As LongPtr
    Private Declare Function GetDesktopWindow Lib "user32" () As LongPtr
    Private Declare Function FindWindow Lib "user32" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
    Private Declare Function FindWindowEx Lib "user32" (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, ByVal lpsz1 As String, ByVal lpsz2 As String) As LongPtr
    Private Declare Function GetClassName Lib "user32" (ByVal hwnd As LongPtr, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
    Private Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As LongPtr) As Long
    Private Declare Function GetWindowLong Lib "user32" (ByVal hwnd As LongPtr, ByVal nIndex As Long) As LongPtr
    Private Declare Function GetAncestor Lib "user32" (ByVal hwnd As LongPtr, ByVal gaFlags As Long) As LongPtr
    Private Declare Function SetWindowLong Lib "user32" (ByVal hwnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As LongPtr) As LongPtr
    Private Declare Function GetWindow Lib "user32" (ByVal hwnd As LongPtr, ByVal wCmd As Long) As LongPtr
    Private Declare Function GetParent Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
#End If

Private Sub DisplayLabels()
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
' DipsplayLabelText
' This gets the various HWnds if they are not already
' set and updates the label captions on the form.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim ParentHWnd As LongPtr
Dim ParentWindowClass As String
Dim AncestorWindow As Long
'Dim WinLong As Long
Dim OwnerWindow As LongPtr
Dim ClassName As String
Dim S As String



'''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Get The HWnds
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
'''''''''''''''''''''''''''''''
' HWnd of the Excel Application
'''''''''''''''''''''''''''''''
If ApplicationHWnd = 0 Then
    ApplicationHWnd = FindWindow(lpClassName:=C_EXCEL_APP_WINDOWCLASS, lpWindowName:=Application.Caption)
End If

'''''''''''''''''''''''''''''''
' HWnd of the Excel Desktop
'''''''''''''''''''''''''''''''
If ExcelDeskHWnd = 0 Then
    ExcelDeskHWnd = FindWindowEx(hWnd1:=ApplicationHWnd, hWnd2:=0&, lpsz1:=C_EXCEL_DESK_WINDOWCLASS, lpsz2:=vbNullString)
End If

'''''''''''''''''''''''''''''''
' HWnd of the ActiveWindow
'''''''''''''''''''''''''''''''
If ActiveWindowHWnd = 0 Then
    ActiveWindowHWnd = FindWindowEx(hWnd1:=ExcelDeskHWnd, hWnd2:=0&, lpsz1:=C_EXCEL_WINDOW_WINDOWCLASS, lpsz2:=Application.ActiveWindow.Caption)
End If

'''''''''''''''''''''''''''''''
' HWnd of the UserForm
'''''''''''''''''''''''''''''''
If UserFormHWnd = 0 Then
    UserFormHWnd = FindWindow(lpClassName:=C_VBA_USERFORM_WINDOWCLASS, lpWindowName:=Me.Caption)
End If
    
''''''''''''''''''''''''''''''''''''''''''''''''''''''
' update the Option Button Captions with WindowText
''''''''''''''''''''''''''''''''''''''''''''''''''''''
Me.optActiveWindow.Caption = "Active Window (" & GetHWndWindowText(ActiveWindowHWnd) & ")"
Me.optApplication.Caption = "Application (" & GetHWndWindowText(ApplicationHWnd) & ")"

'''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Update Labels with HWnds and Parent HWnds.
' Use GetWindowLong rather than GetParent to
' retrieve the Parent windows.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''

'''''''''''''''''''''
' Windows Desktop
'''''''''''''''''''''
ClassName = GetWindowClassName(GetDesktopWindow())
Me.lblWindowsDesktopHWnd.Caption = "Windows Desktop -- HWnd: " & CStr(GetDesktopWindow()) & _
    "  (Window Class: " & ClassName & ")"

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' frmSetParent UserForm.   Class Name "ThunderDFrame".
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
ParentHWnd = GetWindowLong(UserFormHWnd, GWL_HWNDPARENT)
ClassName = GetWindowClassName(UserFormHWnd)
ParentWindowClass = GetWindowClassName(ParentHWnd)
Me.lblThisFormHWnd.Caption = "UserForm -- HWnd: " & CStr(UserFormHWnd) & " (Window Class: " & ClassName & _
    ")   Parent HWnd: " & CStr(ParentHWnd) & "  (Window Class: " & ParentWindowClass & ")"


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' ActiveWindow. Class Name "EXCEL7".
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
ParentHWnd = GetWindowLong(ActiveWindowHWnd, GWL_HWNDPARENT)
ClassName = GetWindowClassName(ActiveWindowHWnd)
ParentWindowClass = GetWindowClassName(ParentHWnd)
Me.lblActiveWindowHWnd.Caption = "ActiveWindow -- HWnd: " & CStr(ActiveWindowHWnd) & " (Window Class: " & ClassName & _
    ")   Parent HWnd: " & CStr(ParentHWnd) & "  (Window Class: " & ParentWindowClass & ")"

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Information About The Excel Desktop. Class Name "XLDESK"
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
ParentHWnd = GetWindowLong(ApplicationHWnd, GWL_HWNDPARENT)
ParentHWnd = GetWindowLong(ExcelDeskHWnd, GWL_HWNDPARENT)
ClassName = GetWindowClassName(ExcelDeskHWnd)
ParentWindowClass = GetWindowClassName(ParentHWnd)
Me.lblDesktopHWnd.Caption = "Excel Desktop -- HWnd: " & CStr(ExcelDeskHWnd) & " (Window Class: " & ClassName & _
    ")   Parent HWnd: " & CStr(ParentHWnd) & "  (Window Class: " & ParentWindowClass & ")"

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Information About The Application Window. Class Name "XLMAIN"
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
ParentHWnd = GetWindowLong(ApplicationHWnd, GWL_HWNDPARENT)
ClassName = GetWindowClassName(ApplicationHWnd)
ParentWindowClass = GetWindowClassName(ParentHWnd)
Me.lblApplicationHWnd.Caption = "Excel Application -- HWnd: " & CStr(ApplicationHWnd) & " (Window Class: " & ClassName & _
    ")   Parent HWnd: " & CStr(ParentHWnd) & "  (Window Class: " & ParentWindowClass & ")"

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Display information about the various Ancestor values: GA_ROOT, GA_ROOTOWNER, and GA_PARENT.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
AncestorWindow = GetAncestor(UserFormHWnd, GA_ROOT)
ClassName = GetWindowClassName(AncestorWindow)
S = "The Ancestor (GA_ROOT) of this UserForm is " & CStr(AncestorWindow) & "  (Window Class: " & ClassName & ")"

AncestorWindow = GetAncestor(UserFormHWnd, GA_ROOTOWNER)
ClassName = GetWindowClassName(AncestorWindow)
S = S & vbCrLf & "The Ancestor (GA_ROOTOWNER) of this UserForm is " & CStr(AncestorWindow) & "  (Window Class: " & ClassName & ")"

AncestorWindow = GetAncestor(UserFormHWnd, GA_PARENT)
ClassName = GetWindowClassName(AncestorWindow)
Me.lblUserFormStatus.Caption = S & vbCrLf & "The Ancestor (GA_PARENT) of this UserForm is " & CStr(AncestorWindow) & "  (Window Class: " & ClassName & ")"

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Display informationa about this form's owner.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
OwnerWindow = GetWindow(UserFormHWnd, GW_OWNER)
If OwnerWindow Then
    Me.lblOwner.Caption = "The Owner Window of this UserForm is HWnd: " & CStr(OwnerWindow) _
        & "  (Window Class: " & GetWindowClassName(OwnerWindow) & ")"
Else
    Me.lblOwner.Caption = "There is no owner window of this form."
End If

Me.Frame1.Repaint
Me.Repaint

End Sub



Private Sub MakeFormChildOfActiveWindow()
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' MakeFormChildOfActiveWindow
' This makes the form a child window of the ActiveWindow.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Dim Res As Long
Dim ParentHWnd As LongPtr
Dim ChildHWnd As LongPtr
Dim ErrNum As Long

''''''''''''''''''''''''''''''''''''''''''''''''
' Set Parent HWnd to ActiveWindowHWnd
''''''''''''''''''''''''''''''''''''''''''''''''

''''''''''''''''''''''''''''''''
' Updete the ActiveWindowHWnd
'''''''''''''''''''''''''''''''
If Application.ActiveWindow Is Nothing Then
    MsgBox "There is no active window."
    Exit Sub
End If
ActiveWindowHWnd = FindWindowEx(hWnd1:=ExcelDeskHWnd, hWnd2:=0&, lpsz1:=C_EXCEL_WINDOW_WINDOWCLASS, _
    lpsz2:=Application.ActiveWindow.Caption)
ParentHWnd = ActiveWindowHWnd
If ParentHWnd = 0 Then
    MsgBox "ParentHWnd Is 0 In MakeFormChildOfActiveWindow"
End If
''''''''''''''''''''''''''''''''''''''''''''''''
' Set Child HWnd to UserFormHWnd
''''''''''''''''''''''''''''''''''''''''''''''''
ChildHWnd = UserFormHWnd

''''''''''''''''''''''''''''''''''''''''''''''''
' Call SetParent to make ChildHWnd a child of
' ParentHWnd.
''''''''''''''''''''''''''''''''''''''''''''''''
Res = SetParent(hWndChild:=ChildHWnd, hWndNewParent:=ParentHWnd)
If Res = 0 Then
    '''''''''''''''''''''''''''''
    ' an error occurred
    '''''''''''''''''''''''''''''
    ErrNum = Err.LastDllError
    DisplayErrorText "Error With SetParent", ErrNum
Else
    Me.lblStatus.Caption = "The UserForm is a child of the ActiveWindow (Class: EXCEL7). Note that you cannot move the" & _
        " the form outside of the ActiveWindow, and that the form moves as you move the ActiveWindow. If" & _
        " you switch to another window such as another workbook, the form is not be visible until you restore" & _
        " the original window. Note that it is not possible to make a form a child of an individual worksheet tab."
End If
SetForegroundWindow UserFormHWnd
Me.Repaint
Me.Frame1.Repaint

End Sub

Private Sub MakeFormChildOfDesktop()
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' MakeFormChildOfDesktop
' This makes the form a child window of the Excel Desktop (this is what you see if you have
' no workbooks open or all workbooks minimized).
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Dim Res As Long
Dim ParentHWnd As LongPtr
Dim ChildHWnd As LongPtr
Dim ErrNum As Long

''''''''''''''''''''''''''''''''''''''''''''''''
' Set Parent HWnd to ActiveWindowHWnd
''''''''''''''''''''''''''''''''''''''''''''''''
ParentHWnd = ExcelDeskHWnd
''''''''''''''''''''''''''''''''''''''''''''''''
' Set Child HWnd to UserFormHWnd
''''''''''''''''''''''''''''''''''''''''''''''''
ChildHWnd = UserFormHWnd

''''''''''''''''''''''''''''''''''''''''''''''''
' Call SetParent to make ChildHWnd a child of
' ParentHWnd.
''''''''''''''''''''''''''''''''''''''''''''''''
Res = SetParent(hWndChild:=ChildHWnd, hWndNewParent:=ParentHWnd)
If Res = 0 Then
    '''''''''''''''''''''''''''''
    ' an error occurred
    '''''''''''''''''''''''''''''
    ErrNum = Err.LastDllError
    DisplayErrorText "Error With SetParent", ErrNum
Else
    Me.lblStatus.Caption = "The UserForm is a child of the Excel Desktop (Class XLDESK). The window may get lost behind the" & _
        " worksheet windows. In general, you'll never want to make the form a child of Excel Desktop unless you" & _
        " don't have any open workbooks, in which case it is better to make a form a child of the Application." & _
        " If the window gets lost, click on the Show Form button on Sheet1 to restore the form. The form will" & _
        " still be displayed if you minimize all open windows. Note that you cannot drag the form outside of the " & _
        " Excel Desktop's window."
End If
SetForegroundWindow UserFormHWnd
Me.Repaint
Me.Frame1.Repaint
End Sub

Private Sub MakeFormChildOfApplication()
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' MakeFormChildOfApplication
' This makes the form a child of the main application window.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Dim Res As Long
Dim ParentHWnd As LongPtr
Dim ChildHWnd As LongPtr
Dim ErrNum As Long

''''''''''''''''''''''''''''''''''''''''''''''''
' Set Parent HWnd to ActiveWindowHWnd
''''''''''''''''''''''''''''''''''''''''''''''''
ParentHWnd = ApplicationHWnd
If ParentHWnd = 0 Then
    MsgBox "ParentHWnd Is 0 In MakeFormChildOfApplication."
End If
''''''''''''''''''''''''''''''''''''''''''''''''
' Set Child HWnd to UserFormHWnd
''''''''''''''''''''''''''''''''''''''''''''''''
ChildHWnd = UserFormHWnd

''''''''''''''''''''''''''''''''''''''''''''''''
' Call SetParent to make ChildHWnd a child of
' ParentHWnd.
''''''''''''''''''''''''''''''''''''''''''''''''
Res = SetParent(hWndChild:=ChildHWnd, hWndNewParent:=ParentHWnd)
If Res = 0 Then
    '''''''''''''''''''''''''''''
    ' an error occurred
    '''''''''''''''''''''''''''''
    ErrNum = Err.LastDllError
    DisplayErrorText "Error With SetParent", ErrNum
Else
    Me.lblStatus.Caption = "The UserForm is a child of the Excel Application (Class XLMAIN). Note that the form will be visible even" & _
        " as you open and close windows, or minimize windows. If you restore the Excel window and move it around on the" & _
        " screen, the form will move with the Application window."
End If
SetForegroundWindow UserFormHWnd
Me.Frame1.Repaint
Me.Repaint
End Sub

Private Sub MakeFormChildOfNothing()
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' MakeFormChildOfNothing
' Sets the parent of the form to 0&
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Dim Res As Long
Dim ParentHWnd As LongPtr
Dim ChildHWnd As LongPtr
Dim ErrNum As Long

''''''''''''''''''''''''''''''''''''''''''''''''
' Set Parent HWnd to ActiveWindowHWnd
''''''''''''''''''''''''''''''''''''''''''''''''
'ParentHWnd = 0&
ParentHWnd = GetDesktopWindow()

''''''''''''''''''''''''''''''''''''''''''''''''
' Set Child HWnd to UserFormHWnd
''''''''''''''''''''''''''''''''''''''''''''''''
ChildHWnd = UserFormHWnd

''''''''''''''''''''''''''''''''''''''''''''''''
' Call SetParent to make ChildHWnd a child of
' ParentHWnd.
''''''''''''''''''''''''''''''''''''''''''''''''
Res = SetParent(hWndChild:=ChildHWnd, hWndNewParent:=ParentHWnd)
'Res = SetWindowLong(hwnd:=ChildHWnd, nIndex:=GWL_HWNDPARENT, dwNewLong:=0&)
If Res = 0 Then
    '''''''''''''''''''''''''''''
    ' an error occurred
    '''''''''''''''''''''''''''''
    ErrNum = Err.LastDllError
    DisplayErrorText "Error With SetParent", ErrNum
Else
    Me.lblStatus.Caption = "The UserForm is a child of the Windows Desktop (see the GA_PARENT item above -- it has the same" & _
                           " window handle as the Windows Desktop). The Parent Window shows as XLMAIN because XLMAIN is the " & _
                           " owner of the window (see the GA_ROOTOWNER item above.)  Note that you can move the Excel Application" & _
                           " window and the form will remain at its original location on the screen. You can also move the" & _
                           " form outside of the Application's main window. This is the default behavior of an Excel Userform."
End If
SetForegroundWindow UserFormHWnd
Me.Repaint
Me.Frame1.Repaint
End Sub

Private Sub btnAbout_Click()
''''''''''''''''''''''''''''''''''''''''''
' btnAbout_Click
' Displays an "about" message box.
''''''''''''''''''''''''''''''''''''''''''
    MsgBox "By Chip Pearson, www.cpearson.com, chip@cpearson.com", vbOKOnly, "SetParent Demonstration Form"
End Sub

Private Sub btnClose_Click()
''''''''''''''''''''''''''''''''''''''''''
' btnClose_Click
' Unloads the form
''''''''''''''''''''''''''''''''''''''''''
    Unload Me
End Sub


Private Sub lblUserFormStatus_Click()

End Sub

Private Sub optActiveWindow_Click()
''''''''''''''''''''''''''''''''''''''''''
' optActiveWindow_Click
' Makes the form a child of the active
' window.
''''''''''''''''''''''''''''''''''''''''''
    MakeFormChildOfActiveWindow
    DisplayLabels
End Sub

Private Sub optApplication_Click()
''''''''''''''''''''''''''''''''''''''''''
' optApplication_Click
' Makes the form a child of the application
' window.
''''''''''''''''''''''''''''''''''''''''''
    MakeFormChildOfApplication
    DisplayLabels
End Sub

Private Sub optDesk_Click()
''''''''''''''''''''''''''''''''''''''''''
' optDesk_Click
' Makes the form a child window of the
' Excel Desktop.
''''''''''''''''''''''''''''''''''''''''''
    MakeFormChildOfDesktop
    DisplayLabels
End Sub

Private Sub optNothing_Click()
''''''''''''''''''''''''''''''''''''''''''
' optNothing_Click
' Sets the ParentHWnd to 0&
''''''''''''''''''''''''''''''''''''''''''
    MakeFormChildOfNothing
    DisplayLabels
End Sub

Private Sub UserForm_Initialize()
    DisplayLabels
    Me.optNothing.Value = True
End Sub

Private Sub UserForm_Terminate()
    Debug.Print "TERMINATE"
End Sub
```


This is the code for *modSupport*.

```
ption Explicit
Option Compare Text
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' modSupport
' By Chip Pearson, chip@cpearson.com www.cpearson.com
'
' This module contains declarations and code that are used in support of the procedures in frmSetParent but aren't
' directly related to the topic of the workbook.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' used by FormatMessage
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Const FORMAT_MESSAGE_ALLOCATE_BUFFER = &H100
Private Const FORMAT_MESSAGE_ARGUMENT_ARRAY = &H2000
Private Const FORMAT_MESSAGE_FROM_HMODULE = &H800
Private Const FORMAT_MESSAGE_FROM_STRING = &H400
Private Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000
Private Const FORMAT_MESSAGE_IGNORE_INSERTS = &H200
Private Const FORMAT_MESSAGE_MAX_WIDTH_MASK = &HFF
Private Const FORMAT_MESSAGE_TEXT_LEN = 160 ' from ERRORS.H C++ include file.

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Various constants
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Const MAX_PATH = 260 ' Windows mandated value
Private Const GWL_HWNDPARENT As Long = -8
Private Const GW_OWNER = 4

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Windows API Declares
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
#If VBA7 Then
    Private Declare PtrSafe Function FormatMessage Lib "kernel32.dll" Alias "FormatMessageA" (ByVal dwFlags As Long, lpSource As Any, ByVal dwMessageId As Long, ByVal dwLanguageId As Long, ByVal lpBuffer As String, ByVal nSize As Long, Arguments As LongPtr) As Long
    Private Declare PtrSafe Function GetWindowLong Lib "user32" Alias "GetWindowLongPtrA" (ByVal hwnd As LongPtr, ByVal nIndex As Long) As LongPtr
    Private Declare PtrSafe Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As LongPtr, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
    Private Declare PtrSafe Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As LongPtr, ByVal lpString As String, ByVal cch As LongPtr) As Long
#Else
    Private Enum LongPtr
        [_]
    End Enum
    Private Declare Function FormatMessage Lib "kernel32.dll" Alias "FormatMessageA" (ByVal dwFlags As Long, lpSource As Any, ByVal dwMessageId As Long, ByVal dwLanguageId As Long, ByVal lpBuffer As String, ByVal nSize As Long, Arguments As LongPtr) As Long
    Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongPtrA" (ByVal hwnd As LongPtr, ByVal nIndex As Long) As LongPtr
    Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As LongPtr, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
    Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As LongPtr, ByVal lpString As String, ByVal cch As LongPtr) As Long
#End If

Public Function GetSystemErrorMessageText(ErrorNumber As Long) As String
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' GetSystemErrorMessageText
'
' This function gets the system error message text that corresponds to the error code returned by the
' GetLastError API function or the Err.LastDllError property. It may be used ONLY for these error codes.
' These are NOT the error numbers returned by Err.Number (for these errors, use Err.Description to get
' the description of the message).
' The error number MUST be the value returned by GetLastError or Err.LastDLLError.
'
' In general, you should use Err.LastDllError rather than GetLastError because under some circumstances the value of
' GetLastError will be reset to 0 before the value is returned to VB. Err.LastDllError will always reliably return
' the last error number raised in a DLL.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

    Dim ErrorText As String
    Dim TextLen As Long
    Dim FormatMessageResult As Long
    Dim LangID As Long
    
    LangID = 0&
    ErrorText = String$(FORMAT_MESSAGE_TEXT_LEN, " ")
    TextLen = Len(ErrorText)
    On Error Resume Next
    FormatMessageResult = 0&
    
    FormatMessageResult = FormatMessage( _
                    dwFlags:=FORMAT_MESSAGE_FROM_SYSTEM Or FORMAT_MESSAGE_IGNORE_INSERTS, _
                    lpSource:=0&, _
                    dwMessageId:=ErrorNumber, _
                    dwLanguageId:=0&, _
                    lpBuffer:=ErrorText, _
                    nSize:=TextLen, _
                    Arguments:=0&)
       
       
    On Error GoTo 0
    If FormatMessageResult > 0 Then
        ErrorText = TrimToNull(ErrorText)
        GetSystemErrorMessageText = ErrorText
    Else
        ' Format message didn't return any text. there is no text description for the specified error.
        GetSystemErrorMessageText = "NO ERROR DESCRIPTION AVAILABLE"
    End If
    
End Function

Public Sub DisplayErrorText(Context As String, ErrNum As Long)
'''''''''''''''''''''''''''''''''''''''''''''''''''
' Displays a standard error message box. For this
' procedure, ErrNum should be the number returned
' by the GetLastError API function or the value
' of Err.LastDllError. It is NOT the number
' returned by Err.Number.
'''''''''''''''''''''''''''''''''''''''''''''''''''
Dim ErrText As String
ErrText = GetSystemErrorMessageText(ErrNum)
MsgBox Context & vbCrLf & _
    "Error Number: " & CStr(ErrNum) & vbCrLf & _
    "Error Text:   " & ErrText, vbOKOnly


End Sub


Public Function TrimToNull(Text As String) As String
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' TrimToNull
' Returns all the text in Text to the left of the vbNullChar
' character.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Dim Pos As Integer
    Pos = InStr(1, Text, vbNullChar, vbTextCompare)
    If Pos > 0 Then
        TrimToNull = Left(Text, Pos - 1)
    Else
        TrimToNull = Text
    End If
End Function


Public Function GetWindowClassName(hwnd As LongPtr) As String
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' GetWindowClassName
' Returns the window class name of the specified HWnd. Returns
' vbNullString if an error occurred.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Dim ClassName As String
    Dim Length As Long
    Dim Res As Long
    If hwnd = 0 Then
        GetWindowClassName = "<none>"
        Exit Function
    End If
    ClassName = String$(MAX_PATH, vbNullChar)
    Length = Len(ClassName)
    Res = GetClassName(hwnd:=hwnd, lpClassName:=ClassName, nMaxCount:=Length)
    If Res = 0 Then
        DisplayErrorText Context:="Error Retrieiving Window Class for HWnd: " & CStr(hwnd), _
            ErrNum:=Err.LastDllError
        GetWindowClassName = vbNullString
    Else
        ClassName = TrimToNull(ClassName)
        GetWindowClassName = ClassName
    End If
End Function


Public Function GetHWndWindowText(hwnd As LongPtr) As String
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' GetHWndWindowText
' This returns the WindowText of the HWnd.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Dim Txt As String
    Dim Res As Long
    Dim L As Long
    Txt = String$(1024, vbNullChar)
    L = Len(Txt)
    Res = GetWindowText(hwnd, Txt, L)
    If Res Then
        Txt = TrimToNull(Txt)
        If Txt = vbNullString Then
            Txt = "<none>"
        End If
    Else
        Txt = vbNullString
    End If
    GetHWndWindowText = Txt

End Function



Public Function GetParentWindowClass(hwnd As LongPtr) As String
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' GetParentWindowClass
' Returns the window class name of the parent window of HWnd.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Dim ParentHWnd As LongPtr
    Dim ClassName As String
    ParentHWnd = GetWindowLong(hwnd:=hwnd, nIndex:=GWL_HWNDPARENT)
    If ParentHWnd = 0 Then
        DisplayErrorText Context:="Error Retrieiving Parent Window for HWnd: " & CStr(hwnd) & _
            " Window Class: " & GetWindowClassName(hwnd), ErrNum:=Err.LastDllError
        GetParentWindowClass = vbNullString
        Exit Function
    End If

    ClassName = GetWindowClassName(ParentHWnd)
    GetParentWindowClass = ClassName
End Function
```


----------



## JLouis (Jan 2, 2023)

Thanks for all the work! Here's what I got:

Type Mismatch:

```
AncestorWindow = GetAncestor(UserFormHWnd, GA_ROOT)
ClassName = GetWindowClassName(AncestorWindow)
S = "The Ancestor (GA_ROOT) of this UserForm is " & CStr(AncestorWindow) & "  (Window Class: " & ClassName & ")"
```

PS:  Missing the "O" in option explicit for module code.



So I removed the ancestor code just ot see what it would do and got this error as shown in the screenshot.


----------



## Dan_W (Jan 3, 2023)

My apologies - I thought I sent it last night, but it's sat here as a draft. I have to head out but will do it when I get back from lunch in an hour.


----------



## JLouis (Jan 2, 2023)

I found this on this site and need to adapt it to my current userform as a "Child of Desktop." I've tried modifying the code but keep getting an error as shown in the attachment. Can someone explain to me what needs to happen to avoid this message and use the code only as a "Child of Desktop?" I've made it prtSafe. 

Resource URL : Pearson Software Consulting

Download example workbook : http://www.cpearson.com/Zips/SetParent.zip

Can anyone assist in adapting this to an existing userform? The code is way above my paygrade.

Thanks.


----------



## Dan_W (Jan 3, 2023)

I'm surprised that you got that particular error message, though, re: FindWindow. What I might do is post a copy of the cleanly and revised workbook and we will see if that works for you.


----------



## Dan_W (Jan 3, 2023)

Round Two - here we go... Here is the updated code for *frmSetParent*


```
Option Explicit
Option Compare Text
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' frmSetParent
' This form illustrates the SetParent procedure to make a userform the a child window
' of no window, the Excel Application window, the Excel Desktop Window, and the Active
' Window.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

'''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Window Class Names
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Const C_EXCEL_APP_WINDOWCLASS = "XLMAIN"
Private Const C_EXCEL_DESK_WINDOWCLASS = "XLDESK"
Private Const C_EXCEL_WINDOW_WINDOWCLASS = "EXCEL7"
Private Const C_VBA_USERFORM_WINDOWCLASS = "ThunderDFrame"

'''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Window HWnds
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private ApplicationHWnd As LongPtr
Private ExcelDeskHWnd As LongPtr
Private ActiveWindowHWnd As LongPtr
Private UserFormHWnd As LongPtr
Private WindowsDesktopHWnd As LongPtr

'''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Other Consts
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Const MAX_PATH = 260
Private Const GA_ROOT As Long = 2
Private Const GA_ROOTOWNER As Long = 3
Private Const GA_PARENT As Long = 1
Private Const GWL_HWNDPARENT As Long = -8
Private Const GW_OWNER = 4

'''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Windows API Functions
'''''''''''''''''''''''''''''''''''''''''''''''''''''''

#If VBA7 Then

    #If Win64 Then
        Private Declare PtrSafe Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongPtrA" (ByVal hwnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As LongPtr) As Long
        Private Declare PtrSafe Function GetWindowLong Lib "user32.dll" Alias "GetWindowLongPtrA" (ByVal hwnd As LongPtr, ByVal nIndex As Long) As Long
    #Else
        Private Declare PtrSafe Function SetWindowLong Lib "user32.dll" Alias "SetWindowLongA" (ByVal hwnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
        Private Declare PtrSafe Function GetWindowLong Lib "user32.dll" Alias "GetWindowLongA" (ByVal hwnd As LongPtr, ByVal nIndex As Long) As Long
    #End If
    
    Private Declare PtrSafe Function SetParent Lib "user32" (ByVal hWndChild As LongPtr, ByVal hWndNewParent As LongPtr) As LongPtr
    Private Declare PtrSafe Function GetDesktopWindow Lib "user32" () As LongPtr
    Private Declare PtrSafe Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
    Private Declare PtrSafe Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, ByVal lpsz1 As String, ByVal lpsz2 As String) As LongPtr
    Private Declare PtrSafe Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As LongPtr, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
    Private Declare PtrSafe Function SetForegroundWindow Lib "user32" (ByVal hwnd As LongPtr) As Long
    Private Declare PtrSafe Function GetAncestor Lib "user32" (ByVal hwnd As LongPtr, ByVal gaFlags As Long) As LongPtr
    Private Declare PtrSafe Function GetWindow Lib "user32" (ByVal hwnd As LongPtr, ByVal wCmd As Long) As LongPtr
    Private Declare PtrSafe Function GetParent Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
#Else
    Private Enum LongPtr
        [_]
    End Enum
    Private Declare Function SetParent Lib "user32" (ByVal hWndChild As LongPtr, ByVal hWndNewParent As LongPtr) As LongPtr
    Private Declare Function GetDesktopWindow Lib "user32" () As LongPtr
    Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As LongPtr
    Private Declare Function FindWindowEx Lib "user32" Alias "FindWindowExA" (ByVal hWnd1 As LongPtr, ByVal hWnd2 As LongPtr, ByVal lpsz1 As String, ByVal lpsz2 As String) As LongPtr
    Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As LongPtr, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
    Private Declare Function SetForegroundWindow Lib "user32" (ByVal hwnd As LongPtr) As Long
    Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As LongPtr, ByVal nIndex As Long) As LongPtr
    Private Declare Function GetAncestor Lib "user32" (ByVal hwnd As LongPtr, ByVal gaFlags As Long) As LongPtr
    Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hwnd As LongPtr, ByVal nIndex As Long, ByVal dwNewLong As LongPtr) As LongPtr
    Private Declare Function GetWindow Lib "user32" (ByVal hwnd As LongPtr, ByVal wCmd As Long) As LongPtr
    Private Declare Function GetParent Lib "user32" (ByVal hwnd As LongPtr) As LongPtr
#End If

Private Sub DisplayLabels()
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
' DipsplayLabelText
' This gets the various HWnds if they are not already
' set and updates the label captions on the form.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim ParentHWnd As LongPtr
Dim ParentWindowClass As String
Dim AncestorWindow As LongPtr
'Dim WinLong As Long
Dim OwnerWindow As LongPtr
Dim ClassName As String
Dim S As String



'''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Get The HWnds
'''''''''''''''''''''''''''''''''''''''''''''''''''''''
'''''''''''''''''''''''''''''''
' HWnd of the Excel Application
'''''''''''''''''''''''''''''''
If ApplicationHWnd = 0 Then
    ApplicationHWnd = FindWindow(lpClassName:=C_EXCEL_APP_WINDOWCLASS, lpWindowName:=Application.Caption)
End If

'''''''''''''''''''''''''''''''
' HWnd of the Excel Desktop
'''''''''''''''''''''''''''''''
If ExcelDeskHWnd = 0 Then
    ExcelDeskHWnd = FindWindowEx(hWnd1:=ApplicationHWnd, hWnd2:=0&, lpsz1:=C_EXCEL_DESK_WINDOWCLASS, lpsz2:=vbNullString)
End If

'''''''''''''''''''''''''''''''
' HWnd of the ActiveWindow
'''''''''''''''''''''''''''''''
If ActiveWindowHWnd = 0 Then
    ActiveWindowHWnd = FindWindowEx(hWnd1:=ExcelDeskHWnd, hWnd2:=0&, lpsz1:=C_EXCEL_WINDOW_WINDOWCLASS, lpsz2:=Application.ActiveWindow.Caption)
End If

'''''''''''''''''''''''''''''''
' HWnd of the UserForm
'''''''''''''''''''''''''''''''
If UserFormHWnd = 0 Then
    UserFormHWnd = FindWindow(lpClassName:=C_VBA_USERFORM_WINDOWCLASS, lpWindowName:=Me.Caption)
End If
    
''''''''''''''''''''''''''''''''''''''''''''''''''''''
' update the Option Button Captions with WindowText
''''''''''''''''''''''''''''''''''''''''''''''''''''''
Me.optActiveWindow.Caption = "Active Window (" & GetHWndWindowText(ActiveWindowHWnd) & ")"
Me.optApplication.Caption = "Application (" & GetHWndWindowText(ApplicationHWnd) & ")"

'''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Update Labels with HWnds and Parent HWnds.
' Use GetWindowLong rather than GetParent to
' retrieve the Parent windows.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''

'''''''''''''''''''''
' Windows Desktop
'''''''''''''''''''''
ClassName = GetWindowClassName(GetDesktopWindow())
Me.lblWindowsDesktopHWnd.Caption = "Windows Desktop -- HWnd: " & CStr(GetDesktopWindow()) & _
    "  (Window Class: " & ClassName & ")"

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' frmSetParent UserForm.   Class Name "ThunderDFrame".
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
ParentHWnd = GetWindowLong(UserFormHWnd, GWL_HWNDPARENT)
ClassName = GetWindowClassName(UserFormHWnd)
ParentWindowClass = GetWindowClassName(ParentHWnd)
Me.lblThisFormHWnd.Caption = "UserForm -- HWnd: " & CStr(UserFormHWnd) & " (Window Class: " & ClassName & _
    ")   Parent HWnd: " & CStr(ParentHWnd) & "  (Window Class: " & ParentWindowClass & ")"


''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' ActiveWindow. Class Name "EXCEL7".
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
ParentHWnd = GetWindowLong(ActiveWindowHWnd, GWL_HWNDPARENT)
ClassName = GetWindowClassName(ActiveWindowHWnd)
ParentWindowClass = GetWindowClassName(ParentHWnd)
Me.lblActiveWindowHWnd.Caption = "ActiveWindow -- HWnd: " & CStr(ActiveWindowHWnd) & " (Window Class: " & ClassName & _
    ")   Parent HWnd: " & CStr(ParentHWnd) & "  (Window Class: " & ParentWindowClass & ")"

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Information About The Excel Desktop. Class Name "XLDESK"
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
ParentHWnd = GetWindowLong(ApplicationHWnd, GWL_HWNDPARENT)
ParentHWnd = GetWindowLong(ExcelDeskHWnd, GWL_HWNDPARENT)
ClassName = GetWindowClassName(ExcelDeskHWnd)
ParentWindowClass = GetWindowClassName(ParentHWnd)
Me.lblDesktopHWnd.Caption = "Excel Desktop -- HWnd: " & CStr(ExcelDeskHWnd) & " (Window Class: " & ClassName & _
    ")   Parent HWnd: " & CStr(ParentHWnd) & "  (Window Class: " & ParentWindowClass & ")"

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Information About The Application Window. Class Name "XLMAIN"
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
ParentHWnd = GetWindowLong(ApplicationHWnd, GWL_HWNDPARENT)
ClassName = GetWindowClassName(ApplicationHWnd)
ParentWindowClass = GetWindowClassName(ParentHWnd)
Me.lblApplicationHWnd.Caption = "Excel Application -- HWnd: " & CStr(ApplicationHWnd) & " (Window Class: " & ClassName & _
    ")   Parent HWnd: " & CStr(ParentHWnd) & "  (Window Class: " & ParentWindowClass & ")"

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Display information about the various Ancestor values: GA_ROOT, GA_ROOTOWNER, and GA_PARENT.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
AncestorWindow = GetAncestor(UserFormHWnd, GA_ROOT)
ClassName = GetWindowClassName(AncestorWindow)
S = "The Ancestor (GA_ROOT) of this UserForm is " & CStr(AncestorWindow) & "  (Window Class: " & ClassName & ")"

AncestorWindow = GetAncestor(UserFormHWnd, GA_ROOTOWNER)
ClassName = GetWindowClassName(AncestorWindow)
S = S & vbCrLf & "The Ancestor (GA_ROOTOWNER) of this UserForm is " & CStr(AncestorWindow) & "  (Window Class: " & ClassName & ")"

AncestorWindow = GetAncestor(UserFormHWnd, GA_PARENT)
ClassName = GetWindowClassName(AncestorWindow)
Me.lblUserFormStatus.Caption = S & vbCrLf & "The Ancestor (GA_PARENT) of this UserForm is " & CStr(AncestorWindow) & "  (Window Class: " & ClassName & ")"

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Display informationa about this form's owner.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
OwnerWindow = GetWindow(UserFormHWnd, GW_OWNER)
If OwnerWindow Then
    Me.lblOwner.Caption = "The Owner Window of this UserForm is HWnd: " & CStr(OwnerWindow) _
        & "  (Window Class: " & GetWindowClassName(OwnerWindow) & ")"
Else
    Me.lblOwner.Caption = "There is no owner window of this form."
End If

Me.Frame1.Repaint
Me.Repaint

End Sub

Private Sub MakeFormChildOfActiveWindow()
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' MakeFormChildOfActiveWindow
' This makes the form a child window of the ActiveWindow.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Dim Res As Long
Dim ParentHWnd As LongPtr
Dim ChildHWnd As LongPtr
Dim ErrNum As Long

''''''''''''''''''''''''''''''''''''''''''''''''
' Set Parent HWnd to ActiveWindowHWnd
''''''''''''''''''''''''''''''''''''''''''''''''

''''''''''''''''''''''''''''''''
' Updete the ActiveWindowHWnd
'''''''''''''''''''''''''''''''
If Application.ActiveWindow Is Nothing Then
    MsgBox "There is no active window."
    Exit Sub
End If
ActiveWindowHWnd = FindWindowEx(hWnd1:=ExcelDeskHWnd, hWnd2:=0&, lpsz1:=C_EXCEL_WINDOW_WINDOWCLASS, _
    lpsz2:=Application.ActiveWindow.Caption)
ParentHWnd = ActiveWindowHWnd
If ParentHWnd = 0 Then
    MsgBox "ParentHWnd Is 0 In MakeFormChildOfActiveWindow"
End If
''''''''''''''''''''''''''''''''''''''''''''''''
' Set Child HWnd to UserFormHWnd
''''''''''''''''''''''''''''''''''''''''''''''''
ChildHWnd = UserFormHWnd

''''''''''''''''''''''''''''''''''''''''''''''''
' Call SetParent to make ChildHWnd a child of
' ParentHWnd.
''''''''''''''''''''''''''''''''''''''''''''''''
Res = SetParent(hWndChild:=ChildHWnd, hWndNewParent:=ParentHWnd)
If Res = 0 Then
    '''''''''''''''''''''''''''''
    ' an error occurred
    '''''''''''''''''''''''''''''
    ErrNum = Err.LastDllError
    DisplayErrorText "Error With SetParent", ErrNum
Else
    Me.lblStatus.Caption = "The UserForm is a child of the ActiveWindow (Class: EXCEL7). Note that you cannot move the" & _
        " the form outside of the ActiveWindow, and that the form moves as you move the ActiveWindow. If" & _
        " you switch to another window such as another workbook, the form is not be visible until you restore" & _
        " the original window. Note that it is not possible to make a form a child of an individual worksheet tab."
End If
SetForegroundWindow UserFormHWnd
Me.Repaint
Me.Frame1.Repaint

End Sub

Private Sub MakeFormChildOfDesktop()
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' MakeFormChildOfDesktop
' This makes the form a child window of the Excel Desktop (this is what you see if you have
' no workbooks open or all workbooks minimized).
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Dim Res As Long
Dim ParentHWnd As LongPtr
Dim ChildHWnd As LongPtr
Dim ErrNum As Long

''''''''''''''''''''''''''''''''''''''''''''''''
' Set Parent HWnd to ActiveWindowHWnd
''''''''''''''''''''''''''''''''''''''''''''''''
ParentHWnd = ExcelDeskHWnd
''''''''''''''''''''''''''''''''''''''''''''''''
' Set Child HWnd to UserFormHWnd
''''''''''''''''''''''''''''''''''''''''''''''''
ChildHWnd = UserFormHWnd

''''''''''''''''''''''''''''''''''''''''''''''''
' Call SetParent to make ChildHWnd a child of
' ParentHWnd.
''''''''''''''''''''''''''''''''''''''''''''''''
Res = SetParent(hWndChild:=ChildHWnd, hWndNewParent:=ParentHWnd)
If Res = 0 Then
    '''''''''''''''''''''''''''''
    ' an error occurred
    '''''''''''''''''''''''''''''
    ErrNum = Err.LastDllError
    DisplayErrorText "Error With SetParent", ErrNum
Else
    Me.lblStatus.Caption = "The UserForm is a child of the Excel Desktop (Class XLDESK). The window may get lost behind the" & _
        " worksheet windows. In general, you'll never want to make the form a child of Excel Desktop unless you" & _
        " don't have any open workbooks, in which case it is better to make a form a child of the Application." & _
        " If the window gets lost, click on the Show Form button on Sheet1 to restore the form. The form will" & _
        " still be displayed if you minimize all open windows. Note that you cannot drag the form outside of the " & _
        " Excel Desktop's window."
End If
SetForegroundWindow UserFormHWnd
Me.Repaint
Me.Frame1.Repaint
End Sub

Private Sub MakeFormChildOfApplication()
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' MakeFormChildOfApplication
' This makes the form a child of the main application window.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Dim Res As Long
Dim ParentHWnd As LongPtr
Dim ChildHWnd As LongPtr
Dim ErrNum As Long

''''''''''''''''''''''''''''''''''''''''''''''''
' Set Parent HWnd to ActiveWindowHWnd
''''''''''''''''''''''''''''''''''''''''''''''''
ParentHWnd = ApplicationHWnd
If ParentHWnd = 0 Then
    MsgBox "ParentHWnd Is 0 In MakeFormChildOfApplication."
End If
''''''''''''''''''''''''''''''''''''''''''''''''
' Set Child HWnd to UserFormHWnd
''''''''''''''''''''''''''''''''''''''''''''''''
ChildHWnd = UserFormHWnd

''''''''''''''''''''''''''''''''''''''''''''''''
' Call SetParent to make ChildHWnd a child of
' ParentHWnd.
''''''''''''''''''''''''''''''''''''''''''''''''
Res = SetParent(hWndChild:=ChildHWnd, hWndNewParent:=ParentHWnd)
If Res = 0 Then
    '''''''''''''''''''''''''''''
    ' an error occurred
    '''''''''''''''''''''''''''''
    ErrNum = Err.LastDllError
    DisplayErrorText "Error With SetParent", ErrNum
Else
    Me.lblStatus.Caption = "The UserForm is a child of the Excel Application (Class XLMAIN). Note that the form will be visible even" & _
        " as you open and close windows, or minimize windows. If you restore the Excel window and move it around on the" & _
        " screen, the form will move with the Application window."
End If
SetForegroundWindow UserFormHWnd
Me.Frame1.Repaint
Me.Repaint
End Sub

Private Sub MakeFormChildOfNothing()
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' MakeFormChildOfNothing
' Sets the parent of the form to 0&
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Dim Res As Long
Dim ParentHWnd As LongPtr
Dim ChildHWnd As LongPtr
Dim ErrNum As Long

''''''''''''''''''''''''''''''''''''''''''''''''
' Set Parent HWnd to ActiveWindowHWnd
''''''''''''''''''''''''''''''''''''''''''''''''
'ParentHWnd = 0&
ParentHWnd = GetDesktopWindow()

''''''''''''''''''''''''''''''''''''''''''''''''
' Set Child HWnd to UserFormHWnd
''''''''''''''''''''''''''''''''''''''''''''''''
ChildHWnd = UserFormHWnd

''''''''''''''''''''''''''''''''''''''''''''''''
' Call SetParent to make ChildHWnd a child of
' ParentHWnd.
''''''''''''''''''''''''''''''''''''''''''''''''
Res = SetParent(hWndChild:=ChildHWnd, hWndNewParent:=ParentHWnd)
'Res = SetWindowLong(hwnd:=ChildHWnd, nIndex:=GWL_HWNDPARENT, dwNewLong:=0&)
If Res = 0 Then
    '''''''''''''''''''''''''''''
    ' an error occurred
    '''''''''''''''''''''''''''''
    ErrNum = Err.LastDllError
    DisplayErrorText "Error With SetParent", ErrNum
Else
    Me.lblStatus.Caption = "The UserForm is a child of the Windows Desktop (see the GA_PARENT item above -- it has the same" & _
                           " window handle as the Windows Desktop). The Parent Window shows as XLMAIN because XLMAIN is the " & _
                           " owner of the window (see the GA_ROOTOWNER item above.)  Note that you can move the Excel Application" & _
                           " window and the form will remain at its original location on the screen. You can also move the" & _
                           " form outside of the Application's main window. This is the default behavior of an Excel Userform."
End If
SetForegroundWindow UserFormHWnd
Me.Repaint
Me.Frame1.Repaint
End Sub

Private Sub btnAbout_Click()
''''''''''''''''''''''''''''''''''''''''''
' btnAbout_Click
' Displays an "about" message box.
''''''''''''''''''''''''''''''''''''''''''
    MsgBox "By Chip Pearson, www.cpearson.com, chip@cpearson.com", vbOKOnly, "SetParent Demonstration Form"
End Sub

Private Sub btnClose_Click()
''''''''''''''''''''''''''''''''''''''''''
' btnClose_Click
' Unloads the form
''''''''''''''''''''''''''''''''''''''''''
    Unload Me
End Sub

Private Sub lblDesktopHWnd_Click()

End Sub

Private Sub optActiveWindow_Click()
''''''''''''''''''''''''''''''''''''''''''
' optActiveWindow_Click
' Makes the form a child of the active
' window.
''''''''''''''''''''''''''''''''''''''''''
    MakeFormChildOfActiveWindow
    DisplayLabels
End Sub

Private Sub optApplication_Click()
''''''''''''''''''''''''''''''''''''''''''
' optApplication_Click
' Makes the form a child of the application
' window.
''''''''''''''''''''''''''''''''''''''''''
    MakeFormChildOfApplication
    DisplayLabels
End Sub

Private Sub optDesk_Click()
''''''''''''''''''''''''''''''''''''''''''
' optDesk_Click
' Makes the form a child window of the
' Excel Desktop.
''''''''''''''''''''''''''''''''''''''''''
    MakeFormChildOfDesktop
    DisplayLabels
End Sub

Private Sub optNothing_Click()
''''''''''''''''''''''''''''''''''''''''''
' optNothing_Click
' Sets the ParentHWnd to 0&
''''''''''''''''''''''''''''''''''''''''''
    MakeFormChildOfNothing
    DisplayLabels
End Sub

Private Sub UserForm_Initialize()
    DisplayLabels
    Me.optNothing.Value = True
End Sub

Private Sub UserForm_Terminate()
    Debug.Print "TERMINATE"
End Sub
```


----------



## Dan_W (Jan 3, 2023)

The updated code for *modSupport*.


```
Option Explicit
Option Compare Text
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' modSupport
' By Chip Pearson, chip@cpearson.com www.cpearson.com
'
' This module contains declarations and code that are used in support of the procedures in frmSetParent but aren't
' directly related to the topic of the workbook.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' used by FormatMessage
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Const FORMAT_MESSAGE_ALLOCATE_BUFFER = &H100
Private Const FORMAT_MESSAGE_ARGUMENT_ARRAY = &H2000
Private Const FORMAT_MESSAGE_FROM_HMODULE = &H800
Private Const FORMAT_MESSAGE_FROM_STRING = &H400
Private Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000
Private Const FORMAT_MESSAGE_IGNORE_INSERTS = &H200
Private Const FORMAT_MESSAGE_MAX_WIDTH_MASK = &HFF
Private Const FORMAT_MESSAGE_TEXT_LEN = 160 ' from ERRORS.H C++ include file.

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Various constants
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Const MAX_PATH = 260 ' Windows mandated value
Private Const GWL_HWNDPARENT As Long = -8
Private Const GW_OWNER = 4

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Windows API Declares
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
#If VBA7 Then
    #If Win64 Then
        Private Declare PtrSafe Function GetWindowLong Lib "user32.dll" Alias "GetWindowLongPtrA" (ByVal hwnd As LongPtr, ByVal nIndex As Long) As Long
    #Else
        Private Declare PtrSafe Function GetWindowLong Lib "user32.dll" Alias "GetWindowLongA" (ByVal hwnd As LongPtr, ByVal nIndex As Long) As Long
    #End If
    Private Declare PtrSafe Function FormatMessage Lib "kernel32.dll" Alias "FormatMessageA" (ByVal dwFlags As Long, lpSource As Any, ByVal dwMessageId As Long, ByVal dwLanguageId As Long, ByVal lpBuffer As String, ByVal nSize As Long, Arguments As LongPtr) As Long
    Private Declare PtrSafe Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As LongPtr, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
    Private Declare PtrSafe Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As LongPtr, ByVal lpString As String, ByVal cch As Long) As Long
#Else
    Private Enum LongPtr
        [_]
    End Enum
    Private Declare Function FormatMessage Lib "kernel32.dll" Alias "FormatMessageA" (ByVal dwFlags As Long, lpSource As Any, ByVal dwMessageId As Long, ByVal dwLanguageId As Long, ByVal lpBuffer As String, ByVal nSize As Long, Arguments As LongPtr) As Long
    Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hwnd As LongPtr, ByVal nIndex As Long) As LongPtr
    Private Declare Function GetClassName Lib "user32" Alias "GetClassNameA" (ByVal hwnd As LongPtr, ByVal lpClassName As String, ByVal nMaxCount As Long) As Long
    Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (ByVal hwnd As LongPtr, ByVal lpString As String, ByVal cch As Long) As Long
#End If

Public Function GetSystemErrorMessageText(ErrorNumber As Long) As String
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' GetSystemErrorMessageText
'
' This function gets the system error message text that corresponds to the error code returned by the
' GetLastError API function or the Err.LastDllError property. It may be used ONLY for these error codes.
' These are NOT the error numbers returned by Err.Number (for these errors, use Err.Description to get
' the description of the message).
' The error number MUST be the value returned by GetLastError or Err.LastDLLError.
'
' In general, you should use Err.LastDllError rather than GetLastError because under some circumstances the value of
' GetLastError will be reset to 0 before the value is returned to VB. Err.LastDllError will always reliably return
' the last error number raised in a DLL.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

    Dim ErrorText As String
    Dim TextLen As Long
    Dim FormatMessageResult As Long
    Dim LangID As Long
    
    LangID = 0&
    ErrorText = String$(FORMAT_MESSAGE_TEXT_LEN, " ")
    TextLen = Len(ErrorText)
    On Error Resume Next
    FormatMessageResult = 0&
    
    FormatMessageResult = FormatMessage( _
                    dwFlags:=FORMAT_MESSAGE_FROM_SYSTEM Or FORMAT_MESSAGE_IGNORE_INSERTS, _
                    lpSource:=0&, _
                    dwMessageId:=ErrorNumber, _
                    dwLanguageId:=0&, _
                    lpBuffer:=ErrorText, _
                    nSize:=TextLen, _
                    Arguments:=0&)
       
       
    On Error GoTo 0
    If FormatMessageResult > 0 Then
        ErrorText = TrimToNull(ErrorText)
        GetSystemErrorMessageText = ErrorText
    Else
        ' Format message didn't return any text. there is no text description for the specified error.
        GetSystemErrorMessageText = "NO ERROR DESCRIPTION AVAILABLE"
    End If
    
End Function

Public Sub DisplayErrorText(Context As String, ErrNum As Long)
'''''''''''''''''''''''''''''''''''''''''''''''''''
' Displays a standard error message box. For this
' procedure, ErrNum should be the number returned
' by the GetLastError API function or the value
' of Err.LastDllError. It is NOT the number
' returned by Err.Number.
'''''''''''''''''''''''''''''''''''''''''''''''''''
Dim ErrText As String
ErrText = GetSystemErrorMessageText(ErrNum)
MsgBox Context & vbCrLf & _
    "Error Number: " & CStr(ErrNum) & vbCrLf & _
    "Error Text:   " & ErrText, vbOKOnly


End Sub


Public Function TrimToNull(Text As String) As String
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' TrimToNull
' Returns all the text in Text to the left of the vbNullChar
' character.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Dim Pos As Integer
    Pos = InStr(1, Text, vbNullChar, vbTextCompare)
    If Pos > 0 Then
        TrimToNull = Left(Text, Pos - 1)
    Else
        TrimToNull = Text
    End If
End Function


Public Function GetWindowClassName(hwnd As LongPtr) As String
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' GetWindowClassName
' Returns the window class name of the specified HWnd. Returns
' vbNullString if an error occurred.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Dim ClassName As String
    Dim Length As Long
    Dim Res As Long
    If hwnd = 0 Then
        GetWindowClassName = "<none>"
        Exit Function
    End If
    ClassName = String$(MAX_PATH, vbNullChar)
    Length = Len(ClassName)
    Res = GetClassName(hwnd:=hwnd, lpClassName:=ClassName, nMaxCount:=Length)
    If Res = 0 Then
        DisplayErrorText Context:="Error Retrieiving Window Class for HWnd: " & CStr(hwnd), _
            ErrNum:=Err.LastDllError
        GetWindowClassName = vbNullString
    Else
        ClassName = TrimToNull(ClassName)
        GetWindowClassName = ClassName
    End If
End Function


Public Function GetHWndWindowText(hwnd As LongPtr) As String
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' GetHWndWindowText
' This returns the WindowText of the HWnd.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Dim Txt As String
    Dim Res As Long
    Dim L As Long
    Txt = String$(1024, vbNullChar)
    L = Len(Txt)
    Res = GetWindowText(hwnd, Txt, L)
    If Res Then
        Txt = TrimToNull(Txt)
        If Txt = vbNullString Then
            Txt = "<none>"
        End If
    Else
        Txt = vbNullString
    End If
    GetHWndWindowText = Txt

End Function



Public Function GetParentWindowClass(hwnd As LongPtr) As String
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' GetParentWindowClass
' Returns the window class name of the parent window of HWnd.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
    Dim ParentHWnd As LongPtr
    Dim ClassName As String
    ParentHWnd = GetWindowLong(hwnd:=hwnd, nIndex:=GWL_HWNDPARENT)
    If ParentHWnd = 0 Then
        DisplayErrorText Context:="Error Retrieiving Parent Window for HWnd: " & CStr(hwnd) & _
            " Window Class: " & GetWindowClassName(hwnd), ErrNum:=Err.LastDllError
        GetParentWindowClass = vbNullString
        Exit Function
    End If

    ClassName = GetWindowClassName(ParentHWnd)
    GetParentWindowClass = ClassName
End Function
```


----------



## Dan_W (Jan 4, 2023)

Hi - any luck with the code?


----------

