From cfbc575b61364426dc67ac66d482b9088198c0be Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Mon, 9 Sep 2013 17:09:47 +0200 Subject: Windows: Fix/Improve closing of native file dialogs. IFileDialog::close() only works from callbacks. Try to find the dialog window and send it a WM_CLOSE in addition. Change-Id: Id0f89f8781564e19e4763d43a71df55d5299fb35 Reviewed-by: Joerg Bornemann --- .../platforms/windows/qwindowsdialoghelpers.cpp | 76 ++++++++++++++++++---- 1 file changed, 65 insertions(+), 11 deletions(-) (limited to 'src/plugins/platforms') diff --git a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp index b46b7a1d23..4add6cd634 100644 --- a/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp +++ b/src/plugins/platforms/windows/qwindowsdialoghelpers.cpp @@ -389,6 +389,16 @@ static inline QString guidToString(const GUID &g) inline QDebug operator<<(QDebug d, const GUID &g) { d.nospace() << guidToString(g); return d; } +// Return an allocated wchar_t array from a QString, reserve more memory if desired. +static wchar_t *qStringToWCharArray(const QString &s, size_t reserveSize = 0) +{ + const size_t stringSize = s.size(); + wchar_t *result = new wchar_t[qMax(stringSize + 1, reserveSize)]; + s.toWCharArray(result); + result[stringSize] = 0; + return result; +} + namespace QWindowsDialogs { /*! @@ -602,6 +612,44 @@ void QWindowsDialogHelperBase::stopTimer() } } +#ifndef Q_OS_WINCE +// Find a file dialog window created by IFileDialog by process id, window +// title and class, which starts with a hash '#'. + +struct FindDialogContext +{ + explicit FindDialogContext(const QString &titleIn) + : title(qStringToWCharArray(titleIn)), processId(GetCurrentProcessId()), hwnd(0) {} + + const QScopedArrayPointer title; + const DWORD processId; + HWND hwnd; // contains the HWND of the window found. +}; + +static BOOL CALLBACK findDialogEnumWindowsProc(HWND hwnd, LPARAM lParam) +{ + FindDialogContext *context = reinterpret_cast(lParam); + DWORD winPid = 0; + GetWindowThreadProcessId(hwnd, &winPid); + if (winPid != context->processId) + return TRUE; + wchar_t buf[256]; + if (!RealGetWindowClass(hwnd, buf, sizeof(buf)/sizeof(wchar_t)) || buf[0] != L'#') + return TRUE; + if (!GetWindowTextW(hwnd, buf, sizeof(buf)/sizeof(wchar_t)) || wcscmp(buf, context->title.data())) + return TRUE; + context->hwnd = hwnd; + return FALSE; +} + +static inline HWND findDialogWindow(const QString &title) +{ + FindDialogContext context(title); + EnumWindows(findDialogEnumWindowsProc, reinterpret_cast(&context)); + return context.hwnd; +} +#endif // !Q_OS_WINCE + template void QWindowsDialogHelperBase::hide() { @@ -844,7 +892,7 @@ signals: void filterSelected(const QString & filter); public slots: - virtual void close() { m_fileDialog->Close(S_OK); } + virtual void close(); protected: explicit QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data); @@ -868,6 +916,7 @@ private: bool m_hideFiltersDetails; bool m_hasDefaultSuffix; QWindowsFileDialogSharedData m_data; + QString m_title; }; QWindowsNativeFileDialogBase::QWindowsNativeFileDialogBase(const QWindowsFileDialogSharedData &data) : @@ -911,6 +960,7 @@ bool QWindowsNativeFileDialogBase::init(const CLSID &clsId, const IID &iid) void QWindowsNativeFileDialogBase::setWindowTitle(const QString &title) { + m_title = title; m_fileDialog->SetTitle(reinterpret_cast(title.utf16())); } @@ -1291,6 +1341,20 @@ bool QWindowsNativeFileDialogBase::onFileOk() return true; } +void QWindowsNativeFileDialogBase::close() +{ + m_fileDialog->Close(S_OK); +#ifndef Q_OS_WINCE + // IFileDialog::Close() does not work unless invoked from a callback. + // Try to find the window and send it a WM_CLOSE in addition. + const HWND hwnd = findDialogWindow(m_title); + if (QWindowsContext::verboseDialogs) + qDebug() << __FUNCTION__ << "closing" << hwnd; + if (hwnd && IsWindowVisible(hwnd)) + PostMessageW(hwnd, WM_CLOSE, 0, 0); +#endif // !Q_OS_WINCE +} + HRESULT QWindowsNativeFileDialogEventHandler::OnFolderChanging(IFileDialog *, IShellItem *item) { m_nativeFileDialog->onFolderChange(item); @@ -1755,16 +1819,6 @@ QList QWindowsXpNativeFileDialog::execExistingDir(HWND owner) return selectedFiles; } -// Return an allocated wchar_t array from a QString, reserve more memory if desired. -static wchar_t *qStringToWCharArray(const QString &s, size_t reserveSize = 0) -{ - const size_t stringSize = s.size(); - wchar_t *result = new wchar_t[qMax(stringSize + 1, reserveSize)]; - s.toWCharArray(result); - result[stringSize] = 0; - return result; -} - // Open/Save files void QWindowsXpNativeFileDialog::populateOpenFileName(OPENFILENAME *ofn, HWND owner) const { -- cgit v1.2.3