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