I am using the Common Dialog ShowOpen to select a file to open using VB6. How can I ensure that the control is centered over the calling form. If I use two screens often the dialog control opens on the other screen and is hidden behind other windows.
JohnKelly 0 Light Poster
Dani AI
Generated
A reliable fix is to skip the VB6 CommonDialog control and show the native Windows file dialog with a hook so you can reposition it during WM_INITDIALOG. That avoids the race/localization problems of the FindWindow+Timer approach described and ensures the dialog opens centered over the calling form (the same monitor as the owner). Below is a compact, drop‑in VB6 module you can use — call OpenFileCentered(Me.hWnd, "Title", "C:\") from a form.
' Module: modOpenFileCenter
Option Explicit
Public g_hOwner As Long
Public Type RECT
Left As Long: Top As Long: Right As Long: Bottom As Long
End Type
Public Type OPENFILENAME
lStructSize As Long
hwndOwner As Long
hInstance As Long
lpstrFilter As String
lpstrCustomFilter As String
nMaxCustFilter As Long
nFilterIndex As Long
lpstrFile As String
nMaxFile As Long
lpstrFileTitle As String
nMaxFileTitle As Long
lpstrInitialDir As String
lpstrTitle As String
Flags As Long
nFileOffset As Integer
nFileExtension As Integer
lpstrDefExt As String
lCustData As Long
lpfnHook As Long
lpTemplateName As String
End Type
Private Declare Function GetOpenFileName Lib "comdlg32.dll" Alias "GetOpenFileNameA" (pOpenfilename As OPENFILENAME) As Long
Private Declare Function GetWindowRect Lib "user32" Alias "GetWindowRect" (ByVal hwnd As Long, lpRect As RECT) As Long
Private Declare Function SetWindowPos Lib "user32" Alias "SetWindowPos" (ByVal hWnd As Long, ByVal hWndInsertAfter As Long, ByVal x As Long, ByVal y As Long, ByVal cx As Long, ByVal cy As Long, ByVal wFlags As Long) As Long
Private Const SWP_NOSIZE = &H1
Private Const SWP_NOZORDER = &H4
Private Const WM_INITDIALOG = &H110
Private Const OFN_EXPLORER = &H80000
Private Const OFN_ENABLEHOOK = &H20
Private Const OFN_FILEMUSTEXIST = &H1000
Public Function OpenFileCentered(ByVal hwndOwner As Long, Optional ByVal sTitle As String = "Open", Optional ByVal sInitDir As String = "") As String
Dim ofn As OPENFILENAME
Dim sFile As String
sFile = String$(260, 0)
g_hOwner = hwndOwner
With ofn
.lStructSize = LenB(ofn)
.hwndOwner = hwndOwner
.lpstrFilter = "All Files (*.*)" & Chr$(0) & "*.*" & Chr$(0)
.lpstrFile = sFile
.nMaxFile = Len(sFile)
.lpstrInitialDir = sInitDir & Chr$(0)
.lpstrTitle = sTitle & Chr$(0)
.Flags = OFN_EXPLORER Or OFN_FILEMUSTEXIST Or OFN_ENABLEHOOK
.lpfnHook = AddressOf OFNHookProc
End With
If GetOpenFileName(ofn) Then
OpenFileCentered = Left$(ofn.lpstrFile, InStr(ofn.lpstrFile, vbNullChar) - 1)
Else
OpenFileCentered = vbNullString
End If
End Function
Public Function OFNHookProc(ByVal hDlg As Long, ByVal uMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
If uMsg = WM_INITDIALOG Then
Dim rcDlg As RECT, rcOwner As RECT
GetWindowRect hDlg, rcDlg
GetWindowRect g_hOwner, rcOwner
Dim dlgW As Long, dlgH As Long, ownerW As Long, ownerH As Long
dlgW = rcDlg.Right - rcDlg.Left
dlgH = rcDlg.Bottom - rcDlg.Top
ownerW = rcOwner.Right - rcOwner.Left
ownerH = rcOwner.Bottom - rcOwner.Top
Dim newX As Long, newY As Long
newX = rcOwner.Left + (ownerW - dlgW) \ 2
newY = rcOwner.Top + (ownerH - dlgH) \ 2
SetWindowPos hDlg, 0, newX, newY, 0, 0, SWP_NOSIZE Or SWP_NOZORDER
End If
OFNHookProc = 0
End Function Notes, caveats and troubleshooting
- This centers on the owner window you pass (use
Me.hWnd). It avoids title/class matching and localization problems that make a FindWindow+Timer fragile. - If an external “always on top” window still covers the dialog, you can try briefly forcing the dialog to foreground (SetForegroundWindow / SetWindowPos with HWND_TOPMOST) — but Windows may block focus-stealing and forcing topmost can be intrusive, so use that only if necessary.
- If you prefer ’s polling approach, it still works on many systems, but needs careful class/title detection across OS/locales; the hook method is cleaner and runs at creation time.
Recommended Answers
Jump to Post— Comatose 290By screens you mean monitors right? As in, you have two monitors, and you click "open" in your app, and it loads the commondialog on the other monitor?
Jump to Post— Comatose 290Ok, I have bad news. As far as I can tell, it can't be done with a commondialog control box. This is because the calling procedure (your app) gets frozen when the call to .showopen takes place. So, you call show open, and everything halts until the user either cancels, …
All 5 Replies
Comatose 290 Taboo Programmer Team Colleague
By screens you mean monitors right? As in, you have two monitors, and you click "open" in your app, and it loads the commondialog on the other monitor?
JohnKelly 0 Light Poster
Yes that's right. If the user moves the form the common dialog always opens in the location it was first opened which could be on a different monitor.
By screens you mean monitors right? As in, you have two monitors, and you click "open" in your app, and it loads the commondialog on the other monitor?
Comatose 290 Taboo Programmer Team Colleague
Ok, I have bad news. As far as I can tell, it can't be done with a commondialog control box. This is because the calling procedure (your app) gets frozen when the call to .showopen takes place. So, you call show open, and everything halts until the user either cancels, or selects a file. I do, however, have a workaround.
Does it have to be centered on the form, or can it be just over the form? The reason I ask, is because if the form is maximized, it will be different code than if the form is a normal sized window.
If the form is a normal sized window, is it cool to align the dialog box with the left and top edges of the form? This will put it on the same screen, and it won't look bad unless the form is bigger than the dialog box. I have been able so far, to center it (top of the dialog is centered between the top and bottom of the form, and the left edge is dead centered between the left and right edges of the form), but it looks really goofy.
The work-around requires the use of the API, and eliminates the need for the common dialog control at all... the only downfall (if you can call it that) is that the dialog window is different than the commondialog window. It's still a dialog to show open, but it's the same one that Operating system uses. Let me know how this all sits with you so far, and then I can proceed.
JohnKelly 0 Light Poster
That solution seems fine. As long as the Dialog box is over the form somewhere the user will see it. The problem I have been having is that sometimes the Dialog box appears on the other monitor hidden behind a Window that has been set as on top and then the user can't see it and hence can't close the dialog to get focus back to the calling window.
Thanks for your help.
Ok, I have bad news. As far as I can tell, it can't be done with a commondialog control box. This is because the calling procedure (your app) gets frozen when the call to .showopen takes place. So, you call show open, and everything halts until the user either cancels, or selects a file. I do, however, have a workaround.
Does it have to be centered on the form, or can it be just over the form? The reason I ask, is because if the form is maximized, it will be different code than if the form is a normal sized window.
If the form is a normal sized window, is it cool to align the dialog box with the left and top edges of the form? This will put it on the same screen, and it won't look bad unless the form is bigger than the dialog box. I have been able so far, to center it (top of the dialog is centered between the top and bottom of the form, and the left edge is dead centered between the left and right edges of the form), but it looks really goofy.
The work-around requires the use of the API, and eliminates the need for the common dialog control at all... the only downfall (if you can call it that) is that the dialog window is different than the commondialog window. It's still a dialog to show open, but it's the same one that Operating system uses. Let me know how this all sits with you so far, and then I can proceed.
Comatose 290 Taboo Programmer Team Colleague
A Little Bit Here. Basically, There is a module, and the module contains the API Declarations, The Required UDT's (User Defined Types) and a public function that when called, will show the dialogbox, and return what the user selected to the calling procedure (like in a variable) filename = dialogbox or whatever. As soon as the dialogbox is launched (in this example, with a command button), it enables the timer control. When the program is first run, the timer is not enabled (no need to be, since we only need to check for the dialogbox when we call the function to show the dialog box). The timers interval is set to 100 milliseconds... you can lower this if you want, but it seems to work pretty efficiently.
The timer code, basically looks for the dialog box window, and if it doesn't find it, it just exits the sub, and waits for the timer to fire again.... at 100 milliseconds, this doesn't take long. If it does find the dialogbox (this is done using the findwindow API) then it gets the dialog box's dimensions (left, right, top and bottom in pixels). It also gets the form's dimensions, and then calculates the width and height of the dialog box. It then calls movewindow to move the dialogbox flush with the left edge and top edge of the form, and then quites the timer.
The code itself is overly commented, so that you know exactly what's going on, and why. If you have any questions, or suggestions, just let me know.
This attachment is potentially unsafe to open. It may be an executable that is capable of making changes to your file system, or it may require specific software to open. Use caution and only open this attachment if you are comfortable working with zip files.
Be a part of the DaniWeb community
We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.