1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ui/base/win/shell.h" 6 7 #include <dwmapi.h> 8 #include <shlobj.h> // Must be before propkey. 9 #include <propkey.h> 10 #include <shellapi.h> 11 12 #include "base/command_line.h" 13 #include "base/files/file_path.h" 14 #include "base/native_library.h" 15 #include "base/strings/string_util.h" 16 #include "base/win/metro.h" 17 #include "base/win/scoped_comptr.h" 18 #include "base/win/win_util.h" 19 #include "base/win/windows_version.h" 20 #include "ui/base/ui_base_switches.h" 21 22 namespace ui { 23 namespace win { 24 25 // Show the Windows "Open With" dialog box to ask the user to pick an app to 26 // open the file with. 27 bool OpenItemWithExternalApp(const string16& full_path) { 28 SHELLEXECUTEINFO sei = { sizeof(sei) }; 29 sei.fMask = SEE_MASK_FLAG_DDEWAIT; 30 sei.nShow = SW_SHOWNORMAL; 31 sei.lpVerb = L"openas"; 32 sei.lpFile = full_path.c_str(); 33 return (TRUE == ::ShellExecuteExW(&sei)); 34 } 35 36 bool OpenAnyViaShell(const string16& full_path, 37 const string16& directory, 38 const string16& args, 39 DWORD mask) { 40 SHELLEXECUTEINFO sei = { sizeof(sei) }; 41 sei.fMask = mask; 42 sei.nShow = SW_SHOWNORMAL; 43 sei.lpFile = full_path.c_str(); 44 sei.lpDirectory = directory.c_str(); 45 if (!args.empty()) 46 sei.lpParameters = args.c_str(); 47 48 if (::ShellExecuteExW(&sei)) 49 return true; 50 if (::GetLastError() == ERROR_NO_ASSOCIATION) 51 return OpenItemWithExternalApp(full_path); 52 return false; 53 } 54 55 bool OpenItemViaShell(const base::FilePath& full_path) { 56 return OpenAnyViaShell(full_path.value(), full_path.DirName().value(), 57 string16(), 0); 58 } 59 60 bool OpenItemViaShellNoZoneCheck(const base::FilePath& full_path) { 61 return OpenAnyViaShell(full_path.value(), string16(), string16(), 62 SEE_MASK_NOZONECHECKS | SEE_MASK_FLAG_DDEWAIT); 63 } 64 65 bool PreventWindowFromPinning(HWND hwnd) { 66 // This functionality is only available on Win7+. It also doesn't make sense 67 // to do this for Chrome Metro. 68 if (base::win::GetVersion() < base::win::VERSION_WIN7 || 69 base::win::IsMetroProcess()) 70 return false; 71 base::win::ScopedComPtr<IPropertyStore> pps; 72 HRESULT result = SHGetPropertyStoreForWindow( 73 hwnd, __uuidof(*pps), reinterpret_cast<void**>(pps.Receive())); 74 if (FAILED(result)) 75 return false; 76 77 return base::win::SetBooleanValueForPropertyStore( 78 pps, PKEY_AppUserModel_PreventPinning, true); 79 } 80 81 // TODO(calamity): investigate moving this out of the UI thread as COM 82 // operations may spawn nested message loops which can cause issues. 83 void SetAppDetailsForWindow(const string16& app_id, 84 const string16& app_icon, 85 const string16& relaunch_command, 86 const string16& relaunch_display_name, 87 HWND hwnd) { 88 // This functionality is only available on Win7+. It also doesn't make sense 89 // to do this for Chrome Metro. 90 if (base::win::GetVersion() < base::win::VERSION_WIN7 || 91 base::win::IsMetroProcess()) 92 return; 93 base::win::ScopedComPtr<IPropertyStore> pps; 94 HRESULT result = SHGetPropertyStoreForWindow( 95 hwnd, __uuidof(*pps), reinterpret_cast<void**>(pps.Receive())); 96 if (S_OK == result) { 97 if (!app_id.empty()) 98 base::win::SetAppIdForPropertyStore(pps, app_id.c_str()); 99 if (!app_icon.empty()) { 100 base::win::SetStringValueForPropertyStore( 101 pps, PKEY_AppUserModel_RelaunchIconResource, app_icon.c_str()); 102 } 103 if (!relaunch_command.empty()) { 104 base::win::SetStringValueForPropertyStore( 105 pps, PKEY_AppUserModel_RelaunchCommand, relaunch_command.c_str()); 106 } 107 if (!relaunch_display_name.empty()) { 108 base::win::SetStringValueForPropertyStore( 109 pps, PKEY_AppUserModel_RelaunchDisplayNameResource, 110 relaunch_display_name.c_str()); 111 } 112 } 113 } 114 115 void SetAppIdForWindow(const string16& app_id, HWND hwnd) { 116 SetAppDetailsForWindow(app_id, string16(), string16(), string16(), hwnd); 117 } 118 119 void SetAppIconForWindow(const string16& app_icon, HWND hwnd) { 120 SetAppDetailsForWindow(string16(), app_icon, string16(), string16(), hwnd); 121 } 122 123 void SetRelaunchDetailsForWindow(const string16& relaunch_command, 124 const string16& display_name, 125 HWND hwnd) { 126 SetAppDetailsForWindow(string16(), 127 string16(), 128 relaunch_command, 129 display_name, 130 hwnd); 131 } 132 133 bool IsAeroGlassEnabled() { 134 // For testing in Win8 (where it is not possible to disable composition) the 135 // user can specify this command line switch to mimic the behavior. In this 136 // mode, cross-HWND transparency is not supported and various types of 137 // widgets fallback to more simplified rendering behavior. 138 if (CommandLine::ForCurrentProcess()->HasSwitch( 139 switches::kDisableDwmComposition)) 140 return false; 141 142 if (base::win::GetVersion() < base::win::VERSION_VISTA) 143 return false; 144 // If composition is not enabled, we behave like on XP. 145 BOOL enabled = FALSE; 146 return SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled; 147 } 148 149 } // namespace win 150 } // namespace ui 151