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