Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1461)

Side by Side Diff: app/win_util.cc

Issue 858006: Remove some unnecessary dependencies on net from app/win_util and app/resourc... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « app/win_util.h ('k') | app/win_util_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "app/win_util.h" 5 #include "app/win_util.h"
6 6
7 #include <commdlg.h> 7 #include <commdlg.h>
8 #include <dwmapi.h> 8 #include <dwmapi.h>
9 #include <shellapi.h> 9 #include <shellapi.h>
10 #include <shlobj.h> 10 #include <shlobj.h>
11 11
12 #include <algorithm> 12 #include <algorithm>
13 13
14 #include "app/gfx/codec/png_codec.h" 14 #include "app/gfx/codec/png_codec.h"
15 #include "app/gfx/gdi_util.h" 15 #include "app/gfx/gdi_util.h"
16 #include "app/l10n_util.h" 16 #include "app/l10n_util.h"
17 #include "app/l10n_util_win.h" 17 #include "app/l10n_util_win.h"
18 #include "base/base_switches.h" 18 #include "base/base_switches.h"
19 #include "base/command_line.h" 19 #include "base/command_line.h"
20 #include "base/file_util.h" 20 #include "base/file_util.h"
21 #include "base/logging.h" 21 #include "base/logging.h"
22 #include "base/native_library.h" 22 #include "base/native_library.h"
23 #include "base/registry.h" 23 #include "base/registry.h"
24 #include "base/scoped_comptr_win.h" 24 #include "base/scoped_comptr_win.h"
25 #include "base/scoped_handle.h" 25 #include "base/scoped_handle.h"
26 #include "base/scoped_handle_win.h" 26 #include "base/scoped_handle_win.h"
27 #include "base/string_util.h" 27 #include "base/string_util.h"
28 #include "base/win_util.h" 28 #include "base/win_util.h"
29 #include "grit/app_strings.h"
30 #include "net/base/mime_util.h"
31 29
32 // Ensure that we pick up this link library. 30 // Ensure that we pick up this link library.
33 #pragma comment(lib, "dwmapi.lib") 31 #pragma comment(lib, "dwmapi.lib")
34 32
35 namespace win_util { 33 namespace win_util {
36 34
37 const int kAutoHideTaskbarThicknessPx = 2; 35 const int kAutoHideTaskbarThicknessPx = 2;
38 36
39 namespace { 37 namespace {
40 38
41 const wchar_t kShell32[] = L"shell32.dll"; 39 const wchar_t kShell32[] = L"shell32.dll";
42 const char kSHGetPropertyStoreForWindow[] = "SHGetPropertyStoreForWindow"; 40 const char kSHGetPropertyStoreForWindow[] = "SHGetPropertyStoreForWindow";
43 41
44 // Define the type of SHGetPropertyStoreForWindow is SHGPSFW. 42 // Define the type of SHGetPropertyStoreForWindow is SHGPSFW.
45 typedef DECLSPEC_IMPORT HRESULT (STDAPICALLTYPE *SHGPSFW)(HWND hwnd, 43 typedef DECLSPEC_IMPORT HRESULT (STDAPICALLTYPE *SHGPSFW)(HWND hwnd,
46 REFIID riid, 44 REFIID riid,
47 void** ppv); 45 void** ppv);
48
49 // Enforce visible dialog box.
50 UINT_PTR CALLBACK SaveAsDialogHook(HWND dialog, UINT message,
51 WPARAM wparam, LPARAM lparam) {
52 static const UINT kPrivateMessage = 0x2F3F;
53 switch (message) {
54 case WM_INITDIALOG: {
55 // Do nothing here. Just post a message to defer actual processing.
56 PostMessage(dialog, kPrivateMessage, 0, 0);
57 return TRUE;
58 }
59 case kPrivateMessage: {
60 // The dialog box is the parent of the current handle.
61 HWND real_dialog = GetParent(dialog);
62
63 // Retrieve the final size.
64 RECT dialog_rect;
65 GetWindowRect(real_dialog, &dialog_rect);
66
67 // Verify that the upper left corner is visible.
68 POINT point = { dialog_rect.left, dialog_rect.top };
69 HMONITOR monitor1 = MonitorFromPoint(point, MONITOR_DEFAULTTONULL);
70 point.x = dialog_rect.right;
71 point.y = dialog_rect.bottom;
72
73 // Verify that the lower right corner is visible.
74 HMONITOR monitor2 = MonitorFromPoint(point, MONITOR_DEFAULTTONULL);
75 if (monitor1 && monitor2)
76 return 0;
77
78 // Some part of the dialog box is not visible, fix it by moving is to the
79 // client rect position of the browser window.
80 HWND parent_window = GetParent(real_dialog);
81 if (!parent_window)
82 return 0;
83 WINDOWINFO parent_info;
84 parent_info.cbSize = sizeof(WINDOWINFO);
85 GetWindowInfo(parent_window, &parent_info);
86 SetWindowPos(real_dialog, NULL,
87 parent_info.rcClient.left,
88 parent_info.rcClient.top,
89 0, 0, // Size.
90 SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOSIZE |
91 SWP_NOZORDER);
92
93 return 0;
94 }
95 }
96 return 0;
97 }
98
99 } // namespace 46 } // namespace
100 47
101 std::wstring FormatSystemTime(const SYSTEMTIME& time, 48 std::wstring FormatSystemTime(const SYSTEMTIME& time,
102 const std::wstring& format) { 49 const std::wstring& format) {
103 // If the format string is empty, just use the default format. 50 // If the format string is empty, just use the default format.
104 LPCTSTR format_ptr = NULL; 51 LPCTSTR format_ptr = NULL;
105 if (!format.empty()) 52 if (!format.empty())
106 format_ptr = format.c_str(); 53 format_ptr = format.c_str();
107 54
108 int buffer_size = GetTimeFormat(LOCALE_USER_DEFAULT, NULL, &time, format_ptr, 55 int buffer_size = GetTimeFormat(LOCALE_USER_DEFAULT, NULL, &time, format_ptr,
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
195 // open the file with. 142 // open the file with.
196 bool OpenItemWithExternalApp(const std::wstring& full_path) { 143 bool OpenItemWithExternalApp(const std::wstring& full_path) {
197 SHELLEXECUTEINFO sei = { sizeof(sei) }; 144 SHELLEXECUTEINFO sei = { sizeof(sei) };
198 sei.fMask = SEE_MASK_FLAG_DDEWAIT; 145 sei.fMask = SEE_MASK_FLAG_DDEWAIT;
199 sei.nShow = SW_SHOWNORMAL; 146 sei.nShow = SW_SHOWNORMAL;
200 sei.lpVerb = L"openas"; 147 sei.lpVerb = L"openas";
201 sei.lpFile = full_path.c_str(); 148 sei.lpFile = full_path.c_str();
202 return (TRUE == ::ShellExecuteExW(&sei)); 149 return (TRUE == ::ShellExecuteExW(&sei));
203 } 150 }
204 151
205 // Get the file type description from the registry. This will be "Text Document"
206 // for .txt files, "JPEG Image" for .jpg files, etc. If the registry doesn't
207 // have an entry for the file type, we return false, true if the description was
208 // found. 'file_ext' must be in form ".txt".
209 static bool GetRegistryDescriptionFromExtension(const std::wstring& file_ext,
210 std::wstring* reg_description) {
211 DCHECK(reg_description);
212 RegKey reg_ext(HKEY_CLASSES_ROOT, file_ext.c_str(), KEY_READ);
213 std::wstring reg_app;
214 if (reg_ext.ReadValue(NULL, &reg_app) && !reg_app.empty()) {
215 RegKey reg_link(HKEY_CLASSES_ROOT, reg_app.c_str(), KEY_READ);
216 if (reg_link.ReadValue(NULL, reg_description))
217 return true;
218 }
219 return false;
220 }
221
222 std::wstring FormatFilterForExtensions(
223 const std::vector<std::wstring>& file_ext,
224 const std::vector<std::wstring>& ext_desc,
225 bool include_all_files) {
226 const std::wstring all_ext = L"*.*";
227 const std::wstring all_desc = l10n_util::GetString(IDS_APP_SAVEAS_ALL_FILES);
228
229 DCHECK(file_ext.size() >= ext_desc.size());
230
231 std::wstring result;
232
233 for (size_t i = 0; i < file_ext.size(); ++i) {
234 std::wstring ext = file_ext[i];
235 std::wstring desc;
236 if (i < ext_desc.size())
237 desc = ext_desc[i];
238
239 if (ext.empty()) {
240 // Force something reasonable to appear in the dialog box if there is no
241 // extension provided.
242 include_all_files = true;
243 continue;
244 }
245
246 if (desc.empty()) {
247 DCHECK(ext.find(L'.') != std::wstring::npos);
248 std::wstring first_extension = ext.substr(ext.find(L'.'));
249 size_t first_separator_index = first_extension.find(L';');
250 if (first_separator_index != std::wstring::npos)
251 first_extension = first_extension.substr(0, first_separator_index);
252
253 // Find the extension name without the preceeding '.' character.
254 std::wstring ext_name = first_extension;
255 size_t ext_index = ext_name.find_first_not_of(L'.');
256 if (ext_index != std::wstring::npos)
257 ext_name = ext_name.substr(ext_index);
258
259 if (!GetRegistryDescriptionFromExtension(first_extension, &desc)) {
260 // The extension doesn't exist in the registry. Create a description
261 // based on the unknown extension type (i.e. if the extension is .qqq,
262 // the we create a description "QQQ File (.qqq)").
263 include_all_files = true;
264 desc = l10n_util::GetStringF(IDS_APP_SAVEAS_EXTENSION_FORMAT,
265 l10n_util::ToUpper(ext_name),
266 ext_name);
267 }
268 if (desc.empty())
269 desc = L"*." + ext_name;
270 }
271
272 result.append(desc.c_str(), desc.size() + 1); // Append NULL too.
273 result.append(ext.c_str(), ext.size() + 1);
274 }
275
276 if (include_all_files) {
277 result.append(all_desc.c_str(), all_desc.size() + 1);
278 result.append(all_ext.c_str(), all_ext.size() + 1);
279 }
280
281 result.append(1, '\0'); // Double NULL required.
282 return result;
283 }
284
285 bool SaveFileAs(HWND owner,
286 const std::wstring& suggested_name,
287 std::wstring* final_name) {
288 std::wstring file_ext = file_util::GetFileExtensionFromPath(suggested_name);
289 file_ext.insert(0, L"*.");
290 std::wstring filter = FormatFilterForExtensions(
291 std::vector<std::wstring>(1, file_ext),
292 std::vector<std::wstring>(),
293 true);
294 unsigned index = 1;
295 return SaveFileAsWithFilter(owner,
296 suggested_name,
297 filter,
298 L"",
299 false,
300 &index,
301 final_name);
302 }
303
304 bool SaveFileAsWithFilter(HWND owner,
305 const std::wstring& suggested_name,
306 const std::wstring& filter,
307 const std::wstring& def_ext,
308 bool ignore_suggested_ext,
309 unsigned* index,
310 std::wstring* final_name) {
311 DCHECK(final_name);
312 // Having an empty filter makes for a bad user experience. We should always
313 // specify a filter when saving.
314 DCHECK(!filter.empty());
315 std::wstring file_part = file_util::GetFilenameFromPath(suggested_name);
316
317 // The size of the in/out buffer in number of characters we pass to win32
318 // GetSaveFileName. From MSDN "The buffer must be large enough to store the
319 // path and file name string or strings, including the terminating NULL
320 // character. ... The buffer should be at least 256 characters long.".
321 // _IsValidPathComDlg does a copy expecting at most MAX_PATH, otherwise will
322 // result in an error of FNERR_INVALIDFILENAME. So we should only pass the
323 // API a buffer of at most MAX_PATH.
324 wchar_t file_name[MAX_PATH];
325 base::wcslcpy(file_name, file_part.c_str(), arraysize(file_name));
326
327 OPENFILENAME save_as;
328 // We must do this otherwise the ofn's FlagsEx may be initialized to random
329 // junk in release builds which can cause the Places Bar not to show up!
330 ZeroMemory(&save_as, sizeof(save_as));
331 save_as.lStructSize = sizeof(OPENFILENAME);
332 save_as.hwndOwner = owner;
333 save_as.hInstance = NULL;
334
335 save_as.lpstrFilter = filter.empty() ? NULL : filter.c_str();
336
337 save_as.lpstrCustomFilter = NULL;
338 save_as.nMaxCustFilter = 0;
339 save_as.nFilterIndex = *index;
340 save_as.lpstrFile = file_name;
341 save_as.nMaxFile = arraysize(file_name);
342 save_as.lpstrFileTitle = NULL;
343 save_as.nMaxFileTitle = 0;
344
345 // Set up the initial directory for the dialog.
346 std::wstring directory = file_util::GetDirectoryFromPath(suggested_name);
347 save_as.lpstrInitialDir = directory.c_str();
348 save_as.lpstrTitle = NULL;
349 save_as.Flags = OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ENABLESIZING |
350 OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST;
351 save_as.lpstrDefExt = &def_ext[0];
352 save_as.lCustData = NULL;
353
354 if (win_util::GetWinVersion() < win_util::WINVERSION_VISTA) {
355 // The save as on Windows XP remembers its last position,
356 // and if the screen resolution changed, it will be off screen.
357 save_as.Flags |= OFN_ENABLEHOOK;
358 save_as.lpfnHook = &SaveAsDialogHook;
359 }
360
361 // Must be NULL or 0.
362 save_as.pvReserved = NULL;
363 save_as.dwReserved = 0;
364
365 if (!GetSaveFileName(&save_as)) {
366 // Zero means the dialog was closed, otherwise we had an error.
367 DWORD error_code = CommDlgExtendedError();
368 if (error_code != 0) {
369 NOTREACHED() << "GetSaveFileName failed with code: " << error_code;
370 }
371 return false;
372 }
373
374 // Return the user's choice.
375 final_name->assign(save_as.lpstrFile);
376 *index = save_as.nFilterIndex;
377
378 // Figure out what filter got selected from the vector with embedded nulls.
379 // NOTE: The filter contains a string with embedded nulls, such as:
380 // JPG Image\0*.jpg\0All files\0*.*\0\0
381 // The filter index is 1-based index for which pair got selected. So, using
382 // the example above, if the first index was selected we need to skip 1
383 // instance of null to get to "*.jpg".
384 std::vector<std::wstring> filters;
385 if (!filter.empty() && save_as.nFilterIndex > 0)
386 SplitString(filter, '\0', &filters);
387 std::wstring filter_selected;
388 if (!filters.empty())
389 filter_selected = filters[(2 * (save_as.nFilterIndex - 1)) + 1];
390
391 // Get the extension that was suggested to the user (when the Save As dialog
392 // was opened). For saving web pages, we skip this step since there may be
393 // 'extension characters' in the title of the web page.
394 std::wstring suggested_ext;
395 if (!ignore_suggested_ext)
396 suggested_ext = file_util::GetFileExtensionFromPath(suggested_name);
397
398 // If we can't get the extension from the suggested_name, we use the default
399 // extension passed in. This is to cover cases like when saving a web page,
400 // where we get passed in a name without an extension and a default extension
401 // along with it.
402 if (suggested_ext.empty())
403 suggested_ext = def_ext;
404
405 *final_name =
406 AppendExtensionIfNeeded(*final_name, filter_selected, suggested_ext);
407 return true;
408 }
409
410 std::wstring AppendExtensionIfNeeded(const std::wstring& filename,
411 const std::wstring& filter_selected,
412 const std::wstring& suggested_ext) {
413 std::wstring return_value = filename;
414
415 // Get the extension the user ended up selecting.
416 std::wstring selected_ext = file_util::GetFileExtensionFromPath(filename);
417
418 if (filter_selected.empty() || filter_selected == L"*.*") {
419 // If the user selects 'All files' we respect any extension given to us from
420 // the File Save dialog. We also strip any trailing dots, which matches
421 // Windows Explorer and is needed because Windows doesn't allow filenames
422 // to have trailing dots. The GetSaveFileName dialog will not return a
423 // string with only one or more dots.
424 size_t index = return_value.find_last_not_of(L'.');
425 if (index < return_value.size() - 1)
426 return_value.resize(index + 1);
427 } else {
428 // User selected a specific filter (not *.*) so we need to check if the
429 // extension provided has the same mime type. If it doesn't we append the
430 // extension.
431 std::string suggested_mime_type, selected_mime_type;
432 if (suggested_ext != selected_ext &&
433 (!net::GetMimeTypeFromExtension(suggested_ext, &suggested_mime_type) ||
434 !net::GetMimeTypeFromExtension(selected_ext, &selected_mime_type) ||
435 suggested_mime_type != selected_mime_type)) {
436 return_value.append(L".");
437 return_value.append(suggested_ext);
438 }
439 }
440
441 return return_value;
442 }
443
444 // Adjust the window to fit, returning true if the window was resized or moved. 152 // Adjust the window to fit, returning true if the window was resized or moved.
445 static bool AdjustWindowToFit(HWND hwnd, const RECT& bounds) { 153 static bool AdjustWindowToFit(HWND hwnd, const RECT& bounds) {
446 // Get the monitor. 154 // Get the monitor.
447 HMONITOR hmon = MonitorFromRect(&bounds, MONITOR_DEFAULTTONEAREST); 155 HMONITOR hmon = MonitorFromRect(&bounds, MONITOR_DEFAULTTONEAREST);
448 if (!hmon) { 156 if (!hmon) {
449 NOTREACHED() << "Unable to find default monitor"; 157 NOTREACHED() << "Unable to find default monitor";
450 // No monitor available. 158 // No monitor available.
451 return false; 159 return false;
452 } 160 }
453 161
(...skipping 413 matching lines...) Expand 10 before | Expand all | Expand 10 after
867 hwnd, __uuidof(*pps), reinterpret_cast<void**>(pps.Receive())); 575 hwnd, __uuidof(*pps), reinterpret_cast<void**>(pps.Receive()));
868 if (S_OK == result) { 576 if (S_OK == result) {
869 SetAppIdForPropertyStore(pps, app_id.c_str()); 577 SetAppIdForPropertyStore(pps, app_id.c_str());
870 } 578 }
871 579
872 // Cleanup. 580 // Cleanup.
873 base::UnloadNativeLibrary(shell32_library); 581 base::UnloadNativeLibrary(shell32_library);
874 } 582 }
875 583
876 } // namespace win_util 584 } // namespace win_util
OLDNEW
« no previous file with comments | « app/win_util.h ('k') | app/win_util_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698