IFileDialog
does not provide a way to control the dialog's location, but this can be achieved by subclassing the dialog.
The WM_WINDOWPOSCHANGING
message is:
Sent to a window whose size, position, or place in the Z order is
about to change as a result of a call to the SetWindowPos function or
another window-management function.
A window receives this message through its WindowProc function.
So if we intercept this message, we can change its parameters to point to the location we want, before the window is moved there. We can do this by subclassing the dialog, which changes the dialog's window procedure with our own window procedure. Our custom window procedure may look like this:
LRESULT MyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (msg == WM_WINDOWPOSCHANGING)
{
WINDOWPOS* wp = (WINDOWPOS*)lParam;
wp->x = 100;
wp->y = 100;
}
return CallWindowProc(owp, hwnd, msg, wParam, lParam);
}
The dialog is subclassed with the SetWindowLong
function. However in order to use that function we need to know the dialog's HWND
. We can get the dialog's handle, in turn, by setting up a temporary hook with SetWindowsHookEx
that would match on the dialog's title, for example, and remove itself upon subclassing the window that matches the given title:
LRESULT CALLBACK GetMsgProc(
_In_ int code,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
if (code == HC_ACTION)
{
MSG* msg = (MSG*)lParam;
WCHAR title[120];
GetWindowText(msg->hwnd, title, sizeof(title));
if (lstrcmpW(title, L"MyTest01") == 0)
{
if (sizeof(long long) == 8)
owp = (WNDPROC)SetWindowLongPtr(msg->hwnd, GWLP_WNDPROC, (LONG_PTR)MyWndProc);
else
owp = (WNDPROC)SetWindowLong(msg->hwnd, GWLP_WNDPROC, (LONG_PTR)MyWndProc);
LRESULT r = CallNextHookEx(hhk, code, wParam, lParam);
UnhookWindowsHookEx(hhk);
return r;
}
}
return CallNextHookEx(hhk, code, wParam, lParam);
}
The entire example:
#include <windows.h>
#include <shobjidl.h>
HHOOK hhk = NULL;
WNDPROC owp = NULL;
LRESULT MyWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
if (msg == WM_WINDOWPOSCHANGING)
{
WINDOWPOS* wp = (WINDOWPOS*)lParam;
wp->x = 100;
wp->y = 100;
(WNDPROC)SetWindowLongPtr(hwnd, GWLP_WNDPROC, (LONG_PTR)owp);
}
return CallWindowProc(owp, hwnd, msg, wParam, lParam);
}
LRESULT CALLBACK GetMsgProc(
_In_ int code,
_In_ WPARAM wParam,
_In_ LPARAM lParam
)
{
if (code == HC_ACTION)
{
MSG* msg = (MSG*)lParam;
WCHAR title[120];
GetWindowText(msg->hwnd, title, sizeof(title));
if (lstrcmpW(title, L"MyTestIFileOpenDialog01") == 0)
{
if (sizeof(long long) == 8)
owp = (WNDPROC)SetWindowLongPtr(msg->hwnd, GWLP_WNDPROC, (LONG_PTR)MyWndProc);
else
owp = (WNDPROC)SetWindowLong(msg->hwnd, GWLP_WNDPROC, (LONG_PTR)MyWndProc);
LRESULT r = CallNextHookEx(hhk, code, wParam, lParam);
UnhookWindowsHookEx(hhk);
return r;
}
}
return CallNextHookEx(hhk, code, wParam, lParam);
}
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
HRESULT hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED |
COINIT_DISABLE_OLE1DDE);
if (SUCCEEDED(hr))
{
IFileOpenDialog *pFileOpen;
// Create the FileOpenDialog object.
hr = CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL,
IID_IFileOpenDialog, reinterpret_cast<void**>(&pFileOpen));
if (SUCCEEDED(hr))
{
hhk = SetWindowsHookEx(WH_GETMESSAGE, GetMsgProc, NULL, GetCurrentThreadId());
pFileOpen->SetTitle(L"MyTestIFileOpenDialog01");
// Show the Open dialog box.
hr = pFileOpen->Show(NULL);
// Get the file name from the dialog box.
if (SUCCEEDED(hr))
{
IShellItem *pItem;
hr = pFileOpen->GetResult(&pItem);
if (SUCCEEDED(hr))
{
PWSTR pszFilePath;
hr = pItem->GetDisplayName(SIGDN_FILESYSPATH, &pszFilePath);
// Display the file name to the user.
if (SUCCEEDED(hr))
{
MessageBox(NULL, pszFilePath, L"File Path", MB_OK);
CoTaskMemFree(pszFilePath);
}
pItem->Release();
}
}
pFileOpen->Release();
}
CoUninitialize();
}
return 0;
}
IFileDialog
or you need something likeOpenFileDialog
orGetOpenFileName
– GratitudeIFileOpenDialog
is the preferred solution on Vista and later. It replacesGetOpenFileName()
. However,GetOpenFileName()
supports hooking, which allows access to the dialog's HWND and thus can be positioned manually.IFileOpenDialog
does not expose that same functionality. – Wilkes