我在Microsoft文档中找不到任何内容,所以我只是想知道是否有人知道,是否可以指定IFileDialog
的起始位置?具体来说,我想第一次打开对话框,让它在父窗口的中心打开。
除了以某种方式挂钩潜在的WM_*
消息之外,我没有看到一种直接的方式来做到这一点。
是否可以使用SetWindowPos
之类的内容?
答案 0 :(得分:4)
shell的IFileDialog实现支持IOleWindow接口(请注意,它似乎没有记录...)。但是必须先打开对话框,然后才能获取其窗口句柄。
因此,诀窍是使用IFileDialogEvents界面订阅对话框的事件,获取窗口句柄,然后移动它,如下面的示例所示。我选择OnSelectionChange是因为它似乎是个好地方。当然,这是要适应的(您不想每次选择更改时都移动窗口...)。
class Events : public IFileDialogEvents
{
// poor man's IUnknown implementation :-)
STDMETHODIMP QueryInterface(REFIID riid, void **ppvObject) { *ppvObject = NULL; return E_NOINTERFACE; }
STDMETHODIMP_(ULONG) AddRef() { return 1; };
STDMETHODIMP_(ULONG) Release() { return 1; }
STDMETHODIMP OnFileOk(IFileDialog *pfd) { return S_OK; }
STDMETHODIMP OnFolderChanging(IFileDialog *pfd, IShellItem *psiFolder) { return S_OK; }
STDMETHODIMP OnShareViolation(IFileDialog *pfd, IShellItem *psi, FDE_SHAREVIOLATION_RESPONSE *pResponse) { return S_OK; }
STDMETHODIMP OnTypeChange(IFileDialog *pfd) { return S_OK; }
STDMETHODIMP OnOverwrite(IFileDialog *pfd, IShellItem *psi, FDE_OVERWRITE_RESPONSE *pResponse) { return S_OK; }
STDMETHODIMP OnFolderChange(IFileDialog *pfd) { return S_OK; }
STDMETHODIMP OnSelectionChange(IFileDialog *pfd) {
IOleWindow *window;
if (SUCCEEDED(pfd->QueryInterface(&window)))
{
HWND hwnd;
if (SUCCEEDED(window->GetWindow(&hwnd)))
{
MoveWindow(hwnd, 0, 0, 600, 600, FALSE);
}
window->Release();
}
return S_OK;
}
};
int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow)
{
CoInitialize(NULL);
IFileOpenDialog *dlg;
if (SUCCEEDED(CoCreateInstance(CLSID_FileOpenDialog, NULL, CLSCTX_ALL, IID_PPV_ARGS(&dlg))))
{
DWORD cookie;
Events *evts = new Events();
dlg->Advise(evts, &cookie);
dlg->Show(NULL);
dlg->Unadvise(cookie);
dlg->Release();
delete evts;
}
CoUninitialize();
}
答案 1 :(得分:2)
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;
}