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 base::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 base::string16& full_path, 37 const base::string16& directory, 38 const base::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 base::string16(), 0); 58 } 59 60 bool OpenItemViaShellNoZoneCheck(const base::FilePath& full_path) { 61 return OpenAnyViaShell(full_path.value(), base::string16(), base::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 base::string16& app_id, 84 const base::string16& app_icon, 85 const base::string16& relaunch_command, 86 const base::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 base::string16& app_id, HWND hwnd) { 116 SetAppDetailsForWindow(app_id, 117 base::string16(), 118 base::string16(), 119 base::string16(), 120 hwnd); 121 } 122 123 void SetAppIconForWindow(const base::string16& app_icon, HWND hwnd) { 124 SetAppDetailsForWindow(base::string16(), 125 app_icon, 126 base::string16(), 127 base::string16(), 128 hwnd); 129 } 130 131 void SetRelaunchDetailsForWindow(const base::string16& relaunch_command, 132 const base::string16& display_name, 133 HWND hwnd) { 134 SetAppDetailsForWindow(base::string16(), 135 base::string16(), 136 relaunch_command, 137 display_name, 138 hwnd); 139 } 140 141 bool IsAeroGlassEnabled() { 142 // For testing in Win8 (where it is not possible to disable composition) the 143 // user can specify this command line switch to mimic the behavior. In this 144 // mode, cross-HWND transparency is not supported and various types of 145 // widgets fallback to more simplified rendering behavior. 146 if (CommandLine::ForCurrentProcess()->HasSwitch( 147 switches::kDisableDwmComposition)) 148 return false; 149 150 if (base::win::GetVersion() < base::win::VERSION_VISTA) 151 return false; 152 // If composition is not enabled, we behave like on XP. 153 BOOL enabled = FALSE; 154 return SUCCEEDED(DwmIsCompositionEnabled(&enabled)) && enabled; 155 } 156 157 } // namespace win 158 } // namespace ui 159