1*6777b538SAndroid Build Coastguard Worker // Copyright 2012 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "base/win/shortcut.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <objbase.h>
8*6777b538SAndroid Build Coastguard Worker
9*6777b538SAndroid Build Coastguard Worker #include <propkey.h>
10*6777b538SAndroid Build Coastguard Worker #include <shlobj.h>
11*6777b538SAndroid Build Coastguard Worker #include <wrl/client.h>
12*6777b538SAndroid Build Coastguard Worker
13*6777b538SAndroid Build Coastguard Worker #include "base/files/block_tests_writing_to_special_dirs.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/files/file_util.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/logging.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_util.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/strings/utf_string_conversions.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/threading/scoped_blocking_call.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/win/scoped_propvariant.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/win/win_util.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/win/windows_version.h"
22*6777b538SAndroid Build Coastguard Worker
23*6777b538SAndroid Build Coastguard Worker namespace base {
24*6777b538SAndroid Build Coastguard Worker namespace win {
25*6777b538SAndroid Build Coastguard Worker
26*6777b538SAndroid Build Coastguard Worker namespace {
27*6777b538SAndroid Build Coastguard Worker
28*6777b538SAndroid Build Coastguard Worker using Microsoft::WRL::ComPtr;
29*6777b538SAndroid Build Coastguard Worker
30*6777b538SAndroid Build Coastguard Worker // Initializes |i_shell_link| and |i_persist_file| (releasing them first if they
31*6777b538SAndroid Build Coastguard Worker // are already initialized).
32*6777b538SAndroid Build Coastguard Worker // If |shortcut| is not NULL, loads |shortcut| into |i_persist_file|.
33*6777b538SAndroid Build Coastguard Worker // If any of the above steps fail, both |i_shell_link| and |i_persist_file| will
34*6777b538SAndroid Build Coastguard Worker // be released.
InitializeShortcutInterfaces(const wchar_t * shortcut,ComPtr<IShellLink> * i_shell_link,ComPtr<IPersistFile> * i_persist_file)35*6777b538SAndroid Build Coastguard Worker void InitializeShortcutInterfaces(const wchar_t* shortcut,
36*6777b538SAndroid Build Coastguard Worker ComPtr<IShellLink>* i_shell_link,
37*6777b538SAndroid Build Coastguard Worker ComPtr<IPersistFile>* i_persist_file) {
38*6777b538SAndroid Build Coastguard Worker // Reset in the inverse order of acquisition.
39*6777b538SAndroid Build Coastguard Worker i_persist_file->Reset();
40*6777b538SAndroid Build Coastguard Worker i_shell_link->Reset();
41*6777b538SAndroid Build Coastguard Worker
42*6777b538SAndroid Build Coastguard Worker ComPtr<IShellLink> shell_link;
43*6777b538SAndroid Build Coastguard Worker if (FAILED(::CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
44*6777b538SAndroid Build Coastguard Worker IID_PPV_ARGS(&shell_link)))) {
45*6777b538SAndroid Build Coastguard Worker return;
46*6777b538SAndroid Build Coastguard Worker }
47*6777b538SAndroid Build Coastguard Worker ComPtr<IPersistFile> persist_file;
48*6777b538SAndroid Build Coastguard Worker if (FAILED(shell_link.As(&persist_file)))
49*6777b538SAndroid Build Coastguard Worker return;
50*6777b538SAndroid Build Coastguard Worker if (shortcut && FAILED(persist_file->Load(shortcut, STGM_READWRITE)))
51*6777b538SAndroid Build Coastguard Worker return;
52*6777b538SAndroid Build Coastguard Worker i_shell_link->Swap(shell_link);
53*6777b538SAndroid Build Coastguard Worker i_persist_file->Swap(persist_file);
54*6777b538SAndroid Build Coastguard Worker }
55*6777b538SAndroid Build Coastguard Worker
56*6777b538SAndroid Build Coastguard Worker } // namespace
57*6777b538SAndroid Build Coastguard Worker
58*6777b538SAndroid Build Coastguard Worker ShortcutProperties::ShortcutProperties() = default;
59*6777b538SAndroid Build Coastguard Worker
60*6777b538SAndroid Build Coastguard Worker ShortcutProperties::ShortcutProperties(const ShortcutProperties& other) =
61*6777b538SAndroid Build Coastguard Worker default;
62*6777b538SAndroid Build Coastguard Worker
63*6777b538SAndroid Build Coastguard Worker ShortcutProperties::~ShortcutProperties() = default;
64*6777b538SAndroid Build Coastguard Worker
set_description(const std::wstring & description_in)65*6777b538SAndroid Build Coastguard Worker void ShortcutProperties::set_description(const std::wstring& description_in) {
66*6777b538SAndroid Build Coastguard Worker // Size restriction as per MSDN at http://goo.gl/OdNQq.
67*6777b538SAndroid Build Coastguard Worker DCHECK_LE(description_in.size(), static_cast<size_t>(INFOTIPSIZE));
68*6777b538SAndroid Build Coastguard Worker description = description_in;
69*6777b538SAndroid Build Coastguard Worker options |= PROPERTIES_DESCRIPTION;
70*6777b538SAndroid Build Coastguard Worker }
71*6777b538SAndroid Build Coastguard Worker
CreateOrUpdateShortcutLink(const FilePath & shortcut_path,const ShortcutProperties & properties,ShortcutOperation operation)72*6777b538SAndroid Build Coastguard Worker bool CreateOrUpdateShortcutLink(const FilePath& shortcut_path,
73*6777b538SAndroid Build Coastguard Worker const ShortcutProperties& properties,
74*6777b538SAndroid Build Coastguard Worker ShortcutOperation operation) {
75*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
76*6777b538SAndroid Build Coastguard Worker
77*6777b538SAndroid Build Coastguard Worker if (!BlockTestsWritingToSpecialDirs::CanWriteToPath(shortcut_path)) {
78*6777b538SAndroid Build Coastguard Worker return false;
79*6777b538SAndroid Build Coastguard Worker }
80*6777b538SAndroid Build Coastguard Worker // Make sure the parent directories exist when creating the shortcut.
81*6777b538SAndroid Build Coastguard Worker if (operation == ShortcutOperation::kCreateAlways &&
82*6777b538SAndroid Build Coastguard Worker !base::CreateDirectory(shortcut_path.DirName())) {
83*6777b538SAndroid Build Coastguard Worker DLOG(ERROR) << "CreateDirectory " << shortcut_path.DirName() << " failed";
84*6777b538SAndroid Build Coastguard Worker return false;
85*6777b538SAndroid Build Coastguard Worker }
86*6777b538SAndroid Build Coastguard Worker // A target is required unless |operation| is kUpdateExisting.
87*6777b538SAndroid Build Coastguard Worker if (operation != ShortcutOperation::kUpdateExisting &&
88*6777b538SAndroid Build Coastguard Worker !(properties.options & ShortcutProperties::PROPERTIES_TARGET)) {
89*6777b538SAndroid Build Coastguard Worker NOTREACHED();
90*6777b538SAndroid Build Coastguard Worker return false;
91*6777b538SAndroid Build Coastguard Worker }
92*6777b538SAndroid Build Coastguard Worker
93*6777b538SAndroid Build Coastguard Worker bool shortcut_existed = PathExists(shortcut_path);
94*6777b538SAndroid Build Coastguard Worker
95*6777b538SAndroid Build Coastguard Worker // Interfaces to the old shortcut when replacing an existing shortcut.
96*6777b538SAndroid Build Coastguard Worker ComPtr<IShellLink> old_i_shell_link;
97*6777b538SAndroid Build Coastguard Worker ComPtr<IPersistFile> old_i_persist_file;
98*6777b538SAndroid Build Coastguard Worker
99*6777b538SAndroid Build Coastguard Worker // Interfaces to the shortcut being created/updated.
100*6777b538SAndroid Build Coastguard Worker ComPtr<IShellLink> i_shell_link;
101*6777b538SAndroid Build Coastguard Worker ComPtr<IPersistFile> i_persist_file;
102*6777b538SAndroid Build Coastguard Worker switch (operation) {
103*6777b538SAndroid Build Coastguard Worker case ShortcutOperation::kCreateAlways:
104*6777b538SAndroid Build Coastguard Worker InitializeShortcutInterfaces(nullptr, &i_shell_link, &i_persist_file);
105*6777b538SAndroid Build Coastguard Worker break;
106*6777b538SAndroid Build Coastguard Worker case ShortcutOperation::kUpdateExisting:
107*6777b538SAndroid Build Coastguard Worker InitializeShortcutInterfaces(shortcut_path.value().c_str(), &i_shell_link,
108*6777b538SAndroid Build Coastguard Worker &i_persist_file);
109*6777b538SAndroid Build Coastguard Worker break;
110*6777b538SAndroid Build Coastguard Worker case ShortcutOperation::kReplaceExisting:
111*6777b538SAndroid Build Coastguard Worker InitializeShortcutInterfaces(shortcut_path.value().c_str(),
112*6777b538SAndroid Build Coastguard Worker &old_i_shell_link, &old_i_persist_file);
113*6777b538SAndroid Build Coastguard Worker // Confirm |shortcut_path| exists and is a shortcut by verifying
114*6777b538SAndroid Build Coastguard Worker // |old_i_persist_file| was successfully initialized in the call above. If
115*6777b538SAndroid Build Coastguard Worker // so, initialize the interfaces to begin writing a new shortcut (to
116*6777b538SAndroid Build Coastguard Worker // overwrite the current one if successful).
117*6777b538SAndroid Build Coastguard Worker if (old_i_persist_file.Get())
118*6777b538SAndroid Build Coastguard Worker InitializeShortcutInterfaces(nullptr, &i_shell_link, &i_persist_file);
119*6777b538SAndroid Build Coastguard Worker break;
120*6777b538SAndroid Build Coastguard Worker default:
121*6777b538SAndroid Build Coastguard Worker NOTREACHED();
122*6777b538SAndroid Build Coastguard Worker }
123*6777b538SAndroid Build Coastguard Worker
124*6777b538SAndroid Build Coastguard Worker // Return false immediately upon failure to initialize shortcut interfaces.
125*6777b538SAndroid Build Coastguard Worker if (!i_persist_file.Get())
126*6777b538SAndroid Build Coastguard Worker return false;
127*6777b538SAndroid Build Coastguard Worker
128*6777b538SAndroid Build Coastguard Worker if ((properties.options & ShortcutProperties::PROPERTIES_TARGET) &&
129*6777b538SAndroid Build Coastguard Worker FAILED(i_shell_link->SetPath(properties.target.value().c_str()))) {
130*6777b538SAndroid Build Coastguard Worker return false;
131*6777b538SAndroid Build Coastguard Worker }
132*6777b538SAndroid Build Coastguard Worker
133*6777b538SAndroid Build Coastguard Worker if ((properties.options & ShortcutProperties::PROPERTIES_WORKING_DIR) &&
134*6777b538SAndroid Build Coastguard Worker FAILED(i_shell_link->SetWorkingDirectory(
135*6777b538SAndroid Build Coastguard Worker properties.working_dir.value().c_str()))) {
136*6777b538SAndroid Build Coastguard Worker return false;
137*6777b538SAndroid Build Coastguard Worker }
138*6777b538SAndroid Build Coastguard Worker
139*6777b538SAndroid Build Coastguard Worker if (properties.options & ShortcutProperties::PROPERTIES_ARGUMENTS) {
140*6777b538SAndroid Build Coastguard Worker if (FAILED(i_shell_link->SetArguments(properties.arguments.c_str())))
141*6777b538SAndroid Build Coastguard Worker return false;
142*6777b538SAndroid Build Coastguard Worker } else if (old_i_persist_file.Get()) {
143*6777b538SAndroid Build Coastguard Worker wchar_t current_arguments[MAX_PATH] = {0};
144*6777b538SAndroid Build Coastguard Worker if (SUCCEEDED(
145*6777b538SAndroid Build Coastguard Worker old_i_shell_link->GetArguments(current_arguments, MAX_PATH))) {
146*6777b538SAndroid Build Coastguard Worker i_shell_link->SetArguments(current_arguments);
147*6777b538SAndroid Build Coastguard Worker }
148*6777b538SAndroid Build Coastguard Worker }
149*6777b538SAndroid Build Coastguard Worker
150*6777b538SAndroid Build Coastguard Worker if ((properties.options & ShortcutProperties::PROPERTIES_DESCRIPTION) &&
151*6777b538SAndroid Build Coastguard Worker FAILED(i_shell_link->SetDescription(properties.description.c_str()))) {
152*6777b538SAndroid Build Coastguard Worker return false;
153*6777b538SAndroid Build Coastguard Worker }
154*6777b538SAndroid Build Coastguard Worker
155*6777b538SAndroid Build Coastguard Worker if ((properties.options & ShortcutProperties::PROPERTIES_ICON) &&
156*6777b538SAndroid Build Coastguard Worker FAILED(i_shell_link->SetIconLocation(properties.icon.value().c_str(),
157*6777b538SAndroid Build Coastguard Worker properties.icon_index))) {
158*6777b538SAndroid Build Coastguard Worker return false;
159*6777b538SAndroid Build Coastguard Worker }
160*6777b538SAndroid Build Coastguard Worker
161*6777b538SAndroid Build Coastguard Worker bool has_app_id =
162*6777b538SAndroid Build Coastguard Worker (properties.options & ShortcutProperties::PROPERTIES_APP_ID) != 0;
163*6777b538SAndroid Build Coastguard Worker bool has_dual_mode =
164*6777b538SAndroid Build Coastguard Worker (properties.options & ShortcutProperties::PROPERTIES_DUAL_MODE) != 0;
165*6777b538SAndroid Build Coastguard Worker bool has_toast_activator_clsid =
166*6777b538SAndroid Build Coastguard Worker (properties.options &
167*6777b538SAndroid Build Coastguard Worker ShortcutProperties::PROPERTIES_TOAST_ACTIVATOR_CLSID) != 0;
168*6777b538SAndroid Build Coastguard Worker if (has_app_id || has_dual_mode || has_toast_activator_clsid) {
169*6777b538SAndroid Build Coastguard Worker ComPtr<IPropertyStore> property_store;
170*6777b538SAndroid Build Coastguard Worker if (FAILED(i_shell_link.As(&property_store)) || !property_store.Get())
171*6777b538SAndroid Build Coastguard Worker return false;
172*6777b538SAndroid Build Coastguard Worker
173*6777b538SAndroid Build Coastguard Worker if (has_app_id && !SetAppIdForPropertyStore(property_store.Get(),
174*6777b538SAndroid Build Coastguard Worker properties.app_id.c_str())) {
175*6777b538SAndroid Build Coastguard Worker return false;
176*6777b538SAndroid Build Coastguard Worker }
177*6777b538SAndroid Build Coastguard Worker if (has_dual_mode && !SetBooleanValueForPropertyStore(
178*6777b538SAndroid Build Coastguard Worker property_store.Get(), PKEY_AppUserModel_IsDualMode,
179*6777b538SAndroid Build Coastguard Worker properties.dual_mode)) {
180*6777b538SAndroid Build Coastguard Worker return false;
181*6777b538SAndroid Build Coastguard Worker }
182*6777b538SAndroid Build Coastguard Worker if (has_toast_activator_clsid &&
183*6777b538SAndroid Build Coastguard Worker !SetClsidForPropertyStore(property_store.Get(),
184*6777b538SAndroid Build Coastguard Worker PKEY_AppUserModel_ToastActivatorCLSID,
185*6777b538SAndroid Build Coastguard Worker properties.toast_activator_clsid)) {
186*6777b538SAndroid Build Coastguard Worker return false;
187*6777b538SAndroid Build Coastguard Worker }
188*6777b538SAndroid Build Coastguard Worker }
189*6777b538SAndroid Build Coastguard Worker
190*6777b538SAndroid Build Coastguard Worker // Release the interfaces to the old shortcut to make sure it doesn't prevent
191*6777b538SAndroid Build Coastguard Worker // overwriting it if needed.
192*6777b538SAndroid Build Coastguard Worker old_i_persist_file.Reset();
193*6777b538SAndroid Build Coastguard Worker old_i_shell_link.Reset();
194*6777b538SAndroid Build Coastguard Worker
195*6777b538SAndroid Build Coastguard Worker HRESULT result = i_persist_file->Save(shortcut_path.value().c_str(), TRUE);
196*6777b538SAndroid Build Coastguard Worker
197*6777b538SAndroid Build Coastguard Worker // Release the interfaces in case the SHChangeNotify call below depends on
198*6777b538SAndroid Build Coastguard Worker // the operations above being fully completed.
199*6777b538SAndroid Build Coastguard Worker i_persist_file.Reset();
200*6777b538SAndroid Build Coastguard Worker i_shell_link.Reset();
201*6777b538SAndroid Build Coastguard Worker
202*6777b538SAndroid Build Coastguard Worker // If we successfully created/updated the icon, notify the shell that we have
203*6777b538SAndroid Build Coastguard Worker // done so.
204*6777b538SAndroid Build Coastguard Worker if (!SUCCEEDED(result))
205*6777b538SAndroid Build Coastguard Worker return false;
206*6777b538SAndroid Build Coastguard Worker
207*6777b538SAndroid Build Coastguard Worker SHChangeNotify(shortcut_existed ? SHCNE_UPDATEITEM : SHCNE_CREATE,
208*6777b538SAndroid Build Coastguard Worker SHCNF_PATH | SHCNF_FLUSH, shortcut_path.value().c_str(),
209*6777b538SAndroid Build Coastguard Worker nullptr);
210*6777b538SAndroid Build Coastguard Worker
211*6777b538SAndroid Build Coastguard Worker return true;
212*6777b538SAndroid Build Coastguard Worker }
213*6777b538SAndroid Build Coastguard Worker
ResolveShortcutProperties(const FilePath & shortcut_path,uint32_t options,ShortcutProperties * properties)214*6777b538SAndroid Build Coastguard Worker bool ResolveShortcutProperties(const FilePath& shortcut_path,
215*6777b538SAndroid Build Coastguard Worker uint32_t options,
216*6777b538SAndroid Build Coastguard Worker ShortcutProperties* properties) {
217*6777b538SAndroid Build Coastguard Worker DCHECK(options && properties);
218*6777b538SAndroid Build Coastguard Worker ScopedBlockingCall scoped_blocking_call(FROM_HERE, BlockingType::MAY_BLOCK);
219*6777b538SAndroid Build Coastguard Worker
220*6777b538SAndroid Build Coastguard Worker if (options & ~ShortcutProperties::PROPERTIES_ALL)
221*6777b538SAndroid Build Coastguard Worker NOTREACHED() << "Unhandled property is used.";
222*6777b538SAndroid Build Coastguard Worker
223*6777b538SAndroid Build Coastguard Worker ComPtr<IShellLink> i_shell_link;
224*6777b538SAndroid Build Coastguard Worker
225*6777b538SAndroid Build Coastguard Worker // Get pointer to the IShellLink interface.
226*6777b538SAndroid Build Coastguard Worker if (FAILED(::CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER,
227*6777b538SAndroid Build Coastguard Worker IID_PPV_ARGS(&i_shell_link)))) {
228*6777b538SAndroid Build Coastguard Worker return false;
229*6777b538SAndroid Build Coastguard Worker }
230*6777b538SAndroid Build Coastguard Worker
231*6777b538SAndroid Build Coastguard Worker ComPtr<IPersistFile> persist;
232*6777b538SAndroid Build Coastguard Worker // Query IShellLink for the IPersistFile interface.
233*6777b538SAndroid Build Coastguard Worker if (FAILED(i_shell_link.As(&persist)))
234*6777b538SAndroid Build Coastguard Worker return false;
235*6777b538SAndroid Build Coastguard Worker
236*6777b538SAndroid Build Coastguard Worker // Load the shell link.
237*6777b538SAndroid Build Coastguard Worker if (FAILED(persist->Load(shortcut_path.value().c_str(), STGM_READ)))
238*6777b538SAndroid Build Coastguard Worker return false;
239*6777b538SAndroid Build Coastguard Worker
240*6777b538SAndroid Build Coastguard Worker // Reset |properties|.
241*6777b538SAndroid Build Coastguard Worker properties->options = 0;
242*6777b538SAndroid Build Coastguard Worker
243*6777b538SAndroid Build Coastguard Worker wchar_t temp[MAX_PATH];
244*6777b538SAndroid Build Coastguard Worker if (options & ShortcutProperties::PROPERTIES_TARGET) {
245*6777b538SAndroid Build Coastguard Worker if (FAILED(
246*6777b538SAndroid Build Coastguard Worker i_shell_link->GetPath(temp, MAX_PATH, nullptr, SLGP_UNCPRIORITY))) {
247*6777b538SAndroid Build Coastguard Worker return false;
248*6777b538SAndroid Build Coastguard Worker }
249*6777b538SAndroid Build Coastguard Worker properties->set_target(FilePath(temp));
250*6777b538SAndroid Build Coastguard Worker }
251*6777b538SAndroid Build Coastguard Worker
252*6777b538SAndroid Build Coastguard Worker if (options & ShortcutProperties::PROPERTIES_WORKING_DIR) {
253*6777b538SAndroid Build Coastguard Worker if (FAILED(i_shell_link->GetWorkingDirectory(temp, MAX_PATH)))
254*6777b538SAndroid Build Coastguard Worker return false;
255*6777b538SAndroid Build Coastguard Worker properties->set_working_dir(FilePath(temp));
256*6777b538SAndroid Build Coastguard Worker }
257*6777b538SAndroid Build Coastguard Worker
258*6777b538SAndroid Build Coastguard Worker if (options & ShortcutProperties::PROPERTIES_ARGUMENTS) {
259*6777b538SAndroid Build Coastguard Worker if (FAILED(i_shell_link->GetArguments(temp, MAX_PATH)))
260*6777b538SAndroid Build Coastguard Worker return false;
261*6777b538SAndroid Build Coastguard Worker properties->set_arguments(temp);
262*6777b538SAndroid Build Coastguard Worker }
263*6777b538SAndroid Build Coastguard Worker
264*6777b538SAndroid Build Coastguard Worker if (options & ShortcutProperties::PROPERTIES_DESCRIPTION) {
265*6777b538SAndroid Build Coastguard Worker // Note: description length constrained by MAX_PATH.
266*6777b538SAndroid Build Coastguard Worker if (FAILED(i_shell_link->GetDescription(temp, MAX_PATH)))
267*6777b538SAndroid Build Coastguard Worker return false;
268*6777b538SAndroid Build Coastguard Worker properties->set_description(temp);
269*6777b538SAndroid Build Coastguard Worker }
270*6777b538SAndroid Build Coastguard Worker
271*6777b538SAndroid Build Coastguard Worker if (options & ShortcutProperties::PROPERTIES_ICON) {
272*6777b538SAndroid Build Coastguard Worker int temp_index;
273*6777b538SAndroid Build Coastguard Worker if (FAILED(i_shell_link->GetIconLocation(temp, MAX_PATH, &temp_index))) {
274*6777b538SAndroid Build Coastguard Worker return false;
275*6777b538SAndroid Build Coastguard Worker }
276*6777b538SAndroid Build Coastguard Worker properties->set_icon(FilePath(temp), temp_index);
277*6777b538SAndroid Build Coastguard Worker }
278*6777b538SAndroid Build Coastguard Worker
279*6777b538SAndroid Build Coastguard Worker if (options & (ShortcutProperties::PROPERTIES_APP_ID |
280*6777b538SAndroid Build Coastguard Worker ShortcutProperties::PROPERTIES_DUAL_MODE |
281*6777b538SAndroid Build Coastguard Worker ShortcutProperties::PROPERTIES_TOAST_ACTIVATOR_CLSID)) {
282*6777b538SAndroid Build Coastguard Worker ComPtr<IPropertyStore> property_store;
283*6777b538SAndroid Build Coastguard Worker if (FAILED(i_shell_link.As(&property_store)))
284*6777b538SAndroid Build Coastguard Worker return false;
285*6777b538SAndroid Build Coastguard Worker
286*6777b538SAndroid Build Coastguard Worker if (options & ShortcutProperties::PROPERTIES_APP_ID) {
287*6777b538SAndroid Build Coastguard Worker ScopedPropVariant pv_app_id;
288*6777b538SAndroid Build Coastguard Worker if (property_store->GetValue(PKEY_AppUserModel_ID, pv_app_id.Receive()) !=
289*6777b538SAndroid Build Coastguard Worker S_OK) {
290*6777b538SAndroid Build Coastguard Worker return false;
291*6777b538SAndroid Build Coastguard Worker }
292*6777b538SAndroid Build Coastguard Worker switch (pv_app_id.get().vt) {
293*6777b538SAndroid Build Coastguard Worker case VT_EMPTY:
294*6777b538SAndroid Build Coastguard Worker properties->set_app_id(std::wstring());
295*6777b538SAndroid Build Coastguard Worker break;
296*6777b538SAndroid Build Coastguard Worker case VT_LPWSTR:
297*6777b538SAndroid Build Coastguard Worker properties->set_app_id(pv_app_id.get().pwszVal);
298*6777b538SAndroid Build Coastguard Worker break;
299*6777b538SAndroid Build Coastguard Worker default:
300*6777b538SAndroid Build Coastguard Worker NOTREACHED() << "Unexpected variant type: " << pv_app_id.get().vt;
301*6777b538SAndroid Build Coastguard Worker return false;
302*6777b538SAndroid Build Coastguard Worker }
303*6777b538SAndroid Build Coastguard Worker }
304*6777b538SAndroid Build Coastguard Worker
305*6777b538SAndroid Build Coastguard Worker if (options & ShortcutProperties::PROPERTIES_DUAL_MODE) {
306*6777b538SAndroid Build Coastguard Worker ScopedPropVariant pv_dual_mode;
307*6777b538SAndroid Build Coastguard Worker if (property_store->GetValue(PKEY_AppUserModel_IsDualMode,
308*6777b538SAndroid Build Coastguard Worker pv_dual_mode.Receive()) != S_OK) {
309*6777b538SAndroid Build Coastguard Worker return false;
310*6777b538SAndroid Build Coastguard Worker }
311*6777b538SAndroid Build Coastguard Worker switch (pv_dual_mode.get().vt) {
312*6777b538SAndroid Build Coastguard Worker case VT_EMPTY:
313*6777b538SAndroid Build Coastguard Worker properties->set_dual_mode(false);
314*6777b538SAndroid Build Coastguard Worker break;
315*6777b538SAndroid Build Coastguard Worker case VT_BOOL:
316*6777b538SAndroid Build Coastguard Worker properties->set_dual_mode(pv_dual_mode.get().boolVal == VARIANT_TRUE);
317*6777b538SAndroid Build Coastguard Worker break;
318*6777b538SAndroid Build Coastguard Worker default:
319*6777b538SAndroid Build Coastguard Worker NOTREACHED() << "Unexpected variant type: " << pv_dual_mode.get().vt;
320*6777b538SAndroid Build Coastguard Worker return false;
321*6777b538SAndroid Build Coastguard Worker }
322*6777b538SAndroid Build Coastguard Worker }
323*6777b538SAndroid Build Coastguard Worker
324*6777b538SAndroid Build Coastguard Worker if (options & ShortcutProperties::PROPERTIES_TOAST_ACTIVATOR_CLSID) {
325*6777b538SAndroid Build Coastguard Worker ScopedPropVariant pv_toast_activator_clsid;
326*6777b538SAndroid Build Coastguard Worker if (property_store->GetValue(PKEY_AppUserModel_ToastActivatorCLSID,
327*6777b538SAndroid Build Coastguard Worker pv_toast_activator_clsid.Receive()) !=
328*6777b538SAndroid Build Coastguard Worker S_OK) {
329*6777b538SAndroid Build Coastguard Worker return false;
330*6777b538SAndroid Build Coastguard Worker }
331*6777b538SAndroid Build Coastguard Worker switch (pv_toast_activator_clsid.get().vt) {
332*6777b538SAndroid Build Coastguard Worker case VT_EMPTY:
333*6777b538SAndroid Build Coastguard Worker properties->set_toast_activator_clsid(CLSID_NULL);
334*6777b538SAndroid Build Coastguard Worker break;
335*6777b538SAndroid Build Coastguard Worker case VT_CLSID:
336*6777b538SAndroid Build Coastguard Worker properties->set_toast_activator_clsid(
337*6777b538SAndroid Build Coastguard Worker *(pv_toast_activator_clsid.get().puuid));
338*6777b538SAndroid Build Coastguard Worker break;
339*6777b538SAndroid Build Coastguard Worker default:
340*6777b538SAndroid Build Coastguard Worker NOTREACHED() << "Unexpected variant type: "
341*6777b538SAndroid Build Coastguard Worker << pv_toast_activator_clsid.get().vt;
342*6777b538SAndroid Build Coastguard Worker return false;
343*6777b538SAndroid Build Coastguard Worker }
344*6777b538SAndroid Build Coastguard Worker }
345*6777b538SAndroid Build Coastguard Worker }
346*6777b538SAndroid Build Coastguard Worker
347*6777b538SAndroid Build Coastguard Worker return true;
348*6777b538SAndroid Build Coastguard Worker }
349*6777b538SAndroid Build Coastguard Worker
ResolveShortcut(const FilePath & shortcut_path,FilePath * target_path,std::wstring * args)350*6777b538SAndroid Build Coastguard Worker bool ResolveShortcut(const FilePath& shortcut_path,
351*6777b538SAndroid Build Coastguard Worker FilePath* target_path,
352*6777b538SAndroid Build Coastguard Worker std::wstring* args) {
353*6777b538SAndroid Build Coastguard Worker uint32_t options = 0;
354*6777b538SAndroid Build Coastguard Worker if (target_path)
355*6777b538SAndroid Build Coastguard Worker options |= ShortcutProperties::PROPERTIES_TARGET;
356*6777b538SAndroid Build Coastguard Worker if (args)
357*6777b538SAndroid Build Coastguard Worker options |= ShortcutProperties::PROPERTIES_ARGUMENTS;
358*6777b538SAndroid Build Coastguard Worker DCHECK(options);
359*6777b538SAndroid Build Coastguard Worker
360*6777b538SAndroid Build Coastguard Worker ShortcutProperties properties;
361*6777b538SAndroid Build Coastguard Worker if (!ResolveShortcutProperties(shortcut_path, options, &properties))
362*6777b538SAndroid Build Coastguard Worker return false;
363*6777b538SAndroid Build Coastguard Worker
364*6777b538SAndroid Build Coastguard Worker if (target_path)
365*6777b538SAndroid Build Coastguard Worker *target_path = properties.target;
366*6777b538SAndroid Build Coastguard Worker if (args)
367*6777b538SAndroid Build Coastguard Worker *args = properties.arguments;
368*6777b538SAndroid Build Coastguard Worker return true;
369*6777b538SAndroid Build Coastguard Worker }
370*6777b538SAndroid Build Coastguard Worker
371*6777b538SAndroid Build Coastguard Worker } // namespace win
372*6777b538SAndroid Build Coastguard Worker } // namespace base
373