IFileDialog 没有提供控制对话框位置的方法,但这可以通过子类化对话框来实现。
WM_WINDOWPOSCHANGING 消息是:
发送到大小、位置或在 Z 顺序中的位置为的窗口
由于调用 SetWindowPos 函数或
另一个窗口管理功能。
窗口通过其 WindowProc 函数接收此消息。
因此,如果我们截获此消息,我们可以在窗口移动到那里之前将其参数更改为指向我们想要的位置。我们可以通过子类化对话框来做到这一点,它用我们自己的窗口过程更改对话框的窗口过程。我们的自定义窗口过程可能如下所示:
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);
}
该对话框使用SetWindowLong 函数进行子类化。然而,为了使用该功能,我们需要知道对话框的HWND。反过来,我们可以通过使用SetWindowsHookEx 设置一个临时钩子来获取对话框的句柄,该钩子将匹配对话框的标题,例如,在子类化与给定标题匹配的窗口时将其自身删除:
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);
}
整个例子:
#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;
}