Home | History | Annotate | Download | only in win
      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