#include "base/files/file_path.h"
#include "base/strings/string_util.h"
+#include "base/win/windows_version.h"
namespace ui {
namespace win {
+namespace {
+
+// Ensures that the Save As dialog is on-screen.
+UINT_PTR CALLBACK SaveAsDialogHook(HWND dialog, UINT message,
+ WPARAM wparam, LPARAM lparam) {
+ static const UINT kPrivateMessage = 0x2F3F;
+ switch (message) {
+ case WM_INITDIALOG: {
+ // Do nothing here. Just post a message to defer actual processing.
+ ::PostMessage(dialog, kPrivateMessage, 0, 0);
+ return TRUE;
+ }
+ case kPrivateMessage: {
+ // The dialog box is the parent of the current handle.
+ HWND real_dialog = ::GetParent(dialog);
+
+ // Retrieve the final size.
+ RECT dialog_rect;
+ ::GetWindowRect(real_dialog, &dialog_rect);
+
+ // Verify that the upper left corner is visible.
+ POINT point = { dialog_rect.left, dialog_rect.top };
+ HMONITOR monitor1 = ::MonitorFromPoint(point, MONITOR_DEFAULTTONULL);
+ point.x = dialog_rect.right;
+ point.y = dialog_rect.bottom;
+
+ // Verify that the lower right corner is visible.
+ HMONITOR monitor2 = ::MonitorFromPoint(point, MONITOR_DEFAULTTONULL);
+ if (monitor1 && monitor2)
+ return 0;
+
+ // Some part of the dialog box is not visible, fix it by moving is to the
+ // client rect position of the browser window.
+ HWND parent_window = ::GetParent(real_dialog);
+ if (!parent_window)
+ return 0;
+ WINDOWINFO parent_info;
+ parent_info.cbSize = sizeof(WINDOWINFO);
+ ::GetWindowInfo(parent_window, &parent_info);
+ ::SetWindowPos(
+ real_dialog,
+ NULL,
+ parent_info.rcClient.left,
+ parent_info.rcClient.top,
+ 0,
+ 0, // Size.
+ SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE | SWP_NOZORDER);
+
+ return 0;
+ }
+ }
+ return 0;
+}
+
+} // namespace
+
OpenFileName::OpenFileName(HWND parent_window, DWORD flags) {
::ZeroMemory(&openfilename_, sizeof(openfilename_));
openfilename_.lStructSize = sizeof(openfilename_);
arraysize(filename_buffer_));
}
+void OpenFileName::MaybeInstallWindowPositionHookForSaveAsOnXP() {
+ if (base::win::GetVersion() >= base::win::VERSION_VISTA)
+ return;
+
+ openfilename_.Flags |= OFN_ENABLEHOOK;
+ DCHECK(!openfilename_.lpfnHook);
+ openfilename_.lpfnHook = &SaveAsDialogHook;
+}
+
base::FilePath OpenFileName::GetSingleResult() {
base::FilePath directory;
std::vector<base::FilePath> filenames;
std::vector<base::FilePath>* filenames) {
DCHECK(filenames->empty());
const wchar_t* selection = openfilename_.lpstrFile;
- while (*selection) { // Empty string indicates end of list.
+ // The return value of |openfilename_.lpstrFile| is dependent on the
+ // value of the Multi-Select flag within |openfilename_|. If the flag is
+ // not set the return value will be a single null-terminated wide string.
+ // If it is set it will be more than one null-terminated wide string, itself
+ // terminated by an empty null-terminated wide string.
+ if (openfilename_.Flags & OFN_ALLOWMULTISELECT) {
+ while (*selection) { // Empty string indicates end of list.
+ filenames->push_back(base::FilePath(selection));
+ // Skip over filename and null-terminator.
+ selection += filenames->back().value().length() + 1;
+ }
+ } else {
filenames->push_back(base::FilePath(selection));
- // Skip over filename and null-terminator.
- selection += filenames->back().value().length() + 1;
}
if (filenames->size() == 1) {
// When there is one file, it contains the path and filename.