|
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
|
2 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
3 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
5 |
|
6 #include "JumpListItem.h" |
|
7 |
|
8 #include <shellapi.h> |
|
9 #include <propvarutil.h> |
|
10 #include <propkey.h> |
|
11 |
|
12 #include "nsIFile.h" |
|
13 #include "nsNetUtil.h" |
|
14 #include "nsCRT.h" |
|
15 #include "nsNetCID.h" |
|
16 #include "nsCExternalHandlerService.h" |
|
17 #include "nsCycleCollectionParticipant.h" |
|
18 #include "mozilla/Preferences.h" |
|
19 #include "JumpListBuilder.h" |
|
20 #include "WinUtils.h" |
|
21 |
|
22 namespace mozilla { |
|
23 namespace widget { |
|
24 |
|
25 // ISUPPORTS Impl's |
|
26 NS_IMPL_ISUPPORTS(JumpListItem, |
|
27 nsIJumpListItem) |
|
28 |
|
29 NS_IMPL_ISUPPORTS_INHERITED(JumpListSeparator, |
|
30 JumpListItem, |
|
31 nsIJumpListSeparator) |
|
32 |
|
33 NS_IMPL_ISUPPORTS_INHERITED(JumpListLink, |
|
34 JumpListItem, |
|
35 nsIJumpListLink) |
|
36 |
|
37 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JumpListShortcut) |
|
38 NS_INTERFACE_MAP_ENTRY(nsIJumpListShortcut) |
|
39 NS_INTERFACE_MAP_END_INHERITING(JumpListItem) |
|
40 |
|
41 NS_IMPL_CYCLE_COLLECTION(JumpListShortcut, mHandlerApp) |
|
42 |
|
43 NS_IMPL_CYCLE_COLLECTING_ADDREF(JumpListShortcut) |
|
44 NS_IMPL_CYCLE_COLLECTING_RELEASE(JumpListShortcut) |
|
45 |
|
46 /* attribute short type; */ |
|
47 NS_IMETHODIMP JumpListItem::GetType(int16_t *aType) |
|
48 { |
|
49 NS_ENSURE_ARG_POINTER(aType); |
|
50 |
|
51 *aType = mItemType; |
|
52 |
|
53 return NS_OK; |
|
54 } |
|
55 |
|
56 /* boolean equals(nsIJumpListItem item); */ |
|
57 NS_IMETHODIMP JumpListItem::Equals(nsIJumpListItem *aItem, bool *aResult) |
|
58 { |
|
59 NS_ENSURE_ARG_POINTER(aItem); |
|
60 |
|
61 *aResult = false; |
|
62 |
|
63 int16_t theType = nsIJumpListItem::JUMPLIST_ITEM_EMPTY; |
|
64 if (NS_FAILED(aItem->GetType(&theType))) |
|
65 return NS_OK; |
|
66 |
|
67 // Make sure the types match. |
|
68 if (Type() != theType) |
|
69 return NS_OK; |
|
70 |
|
71 *aResult = true; |
|
72 |
|
73 return NS_OK; |
|
74 } |
|
75 |
|
76 /* link impl. */ |
|
77 |
|
78 /* attribute nsIURI uri; */ |
|
79 NS_IMETHODIMP JumpListLink::GetUri(nsIURI **aURI) |
|
80 { |
|
81 NS_IF_ADDREF(*aURI = mURI); |
|
82 |
|
83 return NS_OK; |
|
84 } |
|
85 |
|
86 NS_IMETHODIMP JumpListLink::SetUri(nsIURI *aURI) |
|
87 { |
|
88 mURI = aURI; |
|
89 |
|
90 return NS_OK; |
|
91 } |
|
92 |
|
93 /* attribute AString uriTitle; */ |
|
94 NS_IMETHODIMP JumpListLink::SetUriTitle(const nsAString &aUriTitle) |
|
95 { |
|
96 mUriTitle.Assign(aUriTitle); |
|
97 |
|
98 return NS_OK; |
|
99 } |
|
100 |
|
101 NS_IMETHODIMP JumpListLink::GetUriTitle(nsAString& aUriTitle) |
|
102 { |
|
103 aUriTitle.Assign(mUriTitle); |
|
104 |
|
105 return NS_OK; |
|
106 } |
|
107 |
|
108 /* readonly attribute long uriHash; */ |
|
109 NS_IMETHODIMP JumpListLink::GetUriHash(nsACString& aUriHash) |
|
110 { |
|
111 if (!mURI) |
|
112 return NS_ERROR_NOT_AVAILABLE; |
|
113 |
|
114 return mozilla::widget::FaviconHelper::HashURI(mCryptoHash, mURI, aUriHash); |
|
115 } |
|
116 |
|
117 /* boolean compareHash(in nsIURI uri); */ |
|
118 NS_IMETHODIMP JumpListLink::CompareHash(nsIURI *aUri, bool *aResult) |
|
119 { |
|
120 nsresult rv; |
|
121 |
|
122 if (!mURI) { |
|
123 *aResult = !aUri; |
|
124 return NS_OK; |
|
125 } |
|
126 |
|
127 NS_ENSURE_ARG_POINTER(aUri); |
|
128 |
|
129 nsAutoCString hash1, hash2; |
|
130 |
|
131 rv = mozilla::widget::FaviconHelper::HashURI(mCryptoHash, mURI, hash1); |
|
132 NS_ENSURE_SUCCESS(rv, rv); |
|
133 rv = mozilla::widget::FaviconHelper::HashURI(mCryptoHash, aUri, hash2); |
|
134 NS_ENSURE_SUCCESS(rv, rv); |
|
135 |
|
136 *aResult = hash1.Equals(hash2); |
|
137 |
|
138 return NS_OK; |
|
139 } |
|
140 |
|
141 /* boolean equals(nsIJumpListItem item); */ |
|
142 NS_IMETHODIMP JumpListLink::Equals(nsIJumpListItem *aItem, bool *aResult) |
|
143 { |
|
144 NS_ENSURE_ARG_POINTER(aItem); |
|
145 |
|
146 nsresult rv; |
|
147 |
|
148 *aResult = false; |
|
149 |
|
150 int16_t theType = nsIJumpListItem::JUMPLIST_ITEM_EMPTY; |
|
151 if (NS_FAILED(aItem->GetType(&theType))) |
|
152 return NS_OK; |
|
153 |
|
154 // Make sure the types match. |
|
155 if (Type() != theType) |
|
156 return NS_OK; |
|
157 |
|
158 nsCOMPtr<nsIJumpListLink> link = do_QueryInterface(aItem, &rv); |
|
159 if (NS_FAILED(rv)) |
|
160 return rv; |
|
161 |
|
162 // Check the titles |
|
163 nsAutoString title; |
|
164 link->GetUriTitle(title); |
|
165 if (!mUriTitle.Equals(title)) |
|
166 return NS_OK; |
|
167 |
|
168 // Call the internal object's equals() method to check. |
|
169 nsCOMPtr<nsIURI> theUri; |
|
170 bool equals = false; |
|
171 if (NS_SUCCEEDED(link->GetUri(getter_AddRefs(theUri)))) { |
|
172 if (!theUri) { |
|
173 if (!mURI) |
|
174 *aResult = true; |
|
175 return NS_OK; |
|
176 } |
|
177 if (NS_SUCCEEDED(theUri->Equals(mURI, &equals)) && equals) { |
|
178 *aResult = true; |
|
179 } |
|
180 } |
|
181 |
|
182 return NS_OK; |
|
183 } |
|
184 |
|
185 /* shortcut impl. */ |
|
186 |
|
187 /* attribute nsILocalHandlerApp app; */ |
|
188 NS_IMETHODIMP JumpListShortcut::GetApp(nsILocalHandlerApp **aApp) |
|
189 { |
|
190 NS_IF_ADDREF(*aApp = mHandlerApp); |
|
191 |
|
192 return NS_OK; |
|
193 } |
|
194 |
|
195 NS_IMETHODIMP JumpListShortcut::SetApp(nsILocalHandlerApp *aApp) |
|
196 { |
|
197 mHandlerApp = aApp; |
|
198 |
|
199 // Confirm the app is present on the system |
|
200 if (!ExecutableExists(mHandlerApp)) |
|
201 return NS_ERROR_FILE_NOT_FOUND; |
|
202 |
|
203 return NS_OK; |
|
204 } |
|
205 |
|
206 /* attribute long iconIndex; */ |
|
207 NS_IMETHODIMP JumpListShortcut::GetIconIndex(int32_t *aIconIndex) |
|
208 { |
|
209 NS_ENSURE_ARG_POINTER(aIconIndex); |
|
210 |
|
211 *aIconIndex = mIconIndex; |
|
212 return NS_OK; |
|
213 } |
|
214 |
|
215 NS_IMETHODIMP JumpListShortcut::SetIconIndex(int32_t aIconIndex) |
|
216 { |
|
217 mIconIndex = aIconIndex; |
|
218 return NS_OK; |
|
219 } |
|
220 |
|
221 /* attribute long iconURI; */ |
|
222 NS_IMETHODIMP JumpListShortcut::GetFaviconPageUri(nsIURI **aFaviconPageURI) |
|
223 { |
|
224 NS_IF_ADDREF(*aFaviconPageURI = mFaviconPageURI); |
|
225 |
|
226 return NS_OK; |
|
227 } |
|
228 |
|
229 NS_IMETHODIMP JumpListShortcut::SetFaviconPageUri(nsIURI *aFaviconPageURI) |
|
230 { |
|
231 mFaviconPageURI = aFaviconPageURI; |
|
232 return NS_OK; |
|
233 } |
|
234 |
|
235 /* boolean equals(nsIJumpListItem item); */ |
|
236 NS_IMETHODIMP JumpListShortcut::Equals(nsIJumpListItem *aItem, bool *aResult) |
|
237 { |
|
238 NS_ENSURE_ARG_POINTER(aItem); |
|
239 |
|
240 nsresult rv; |
|
241 |
|
242 *aResult = false; |
|
243 |
|
244 int16_t theType = nsIJumpListItem::JUMPLIST_ITEM_EMPTY; |
|
245 if (NS_FAILED(aItem->GetType(&theType))) |
|
246 return NS_OK; |
|
247 |
|
248 // Make sure the types match. |
|
249 if (Type() != theType) |
|
250 return NS_OK; |
|
251 |
|
252 nsCOMPtr<nsIJumpListShortcut> shortcut = do_QueryInterface(aItem, &rv); |
|
253 if (NS_FAILED(rv)) |
|
254 return rv; |
|
255 |
|
256 // Check the icon index |
|
257 //int32_t idx; |
|
258 //shortcut->GetIconIndex(&idx); |
|
259 //if (mIconIndex != idx) |
|
260 // return NS_OK; |
|
261 // No need to check the icon page URI either |
|
262 |
|
263 // Call the internal object's equals() method to check. |
|
264 nsCOMPtr<nsILocalHandlerApp> theApp; |
|
265 bool equals = false; |
|
266 if (NS_SUCCEEDED(shortcut->GetApp(getter_AddRefs(theApp)))) { |
|
267 if (!theApp) { |
|
268 if (!mHandlerApp) |
|
269 *aResult = true; |
|
270 return NS_OK; |
|
271 } |
|
272 if (NS_SUCCEEDED(theApp->Equals(mHandlerApp, &equals)) && equals) { |
|
273 *aResult = true; |
|
274 } |
|
275 } |
|
276 |
|
277 return NS_OK; |
|
278 } |
|
279 |
|
280 /* internal helpers */ |
|
281 |
|
282 // (static) Creates a ShellLink that encapsulate a separator. |
|
283 nsresult JumpListSeparator::GetSeparator(nsRefPtr<IShellLinkW>& aShellLink) |
|
284 { |
|
285 HRESULT hr; |
|
286 IShellLinkW* psl; |
|
287 |
|
288 // Create a IShellLink. |
|
289 hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, |
|
290 IID_IShellLinkW, (LPVOID*)&psl); |
|
291 if (FAILED(hr)) |
|
292 return NS_ERROR_UNEXPECTED; |
|
293 |
|
294 IPropertyStore* pPropStore = nullptr; |
|
295 hr = psl->QueryInterface(IID_IPropertyStore, (LPVOID*)&pPropStore); |
|
296 if (FAILED(hr)) |
|
297 return NS_ERROR_UNEXPECTED; |
|
298 |
|
299 PROPVARIANT pv; |
|
300 InitPropVariantFromBoolean(TRUE, &pv); |
|
301 |
|
302 pPropStore->SetValue(PKEY_AppUserModel_IsDestListSeparator, pv); |
|
303 pPropStore->Commit(); |
|
304 pPropStore->Release(); |
|
305 |
|
306 PropVariantClear(&pv); |
|
307 |
|
308 aShellLink = dont_AddRef(psl); |
|
309 |
|
310 return NS_OK; |
|
311 } |
|
312 |
|
313 // (static) Creates a ShellLink that encapsulate a shortcut to local apps. |
|
314 nsresult JumpListShortcut::GetShellLink(nsCOMPtr<nsIJumpListItem>& item, |
|
315 nsRefPtr<IShellLinkW>& aShellLink, |
|
316 nsCOMPtr<nsIThread> &aIOThread) |
|
317 { |
|
318 HRESULT hr; |
|
319 IShellLinkW* psl; |
|
320 nsresult rv; |
|
321 |
|
322 // Shell links: |
|
323 // http://msdn.microsoft.com/en-us/library/bb776891(VS.85).aspx |
|
324 // http://msdn.microsoft.com/en-us/library/bb774950(VS.85).aspx |
|
325 |
|
326 int16_t type; |
|
327 if (NS_FAILED(item->GetType(&type))) |
|
328 return NS_ERROR_INVALID_ARG; |
|
329 |
|
330 if (type != nsIJumpListItem::JUMPLIST_ITEM_SHORTCUT) |
|
331 return NS_ERROR_INVALID_ARG; |
|
332 |
|
333 nsCOMPtr<nsIJumpListShortcut> shortcut = do_QueryInterface(item, &rv); |
|
334 NS_ENSURE_SUCCESS(rv, rv); |
|
335 |
|
336 nsCOMPtr<nsILocalHandlerApp> handlerApp; |
|
337 rv = shortcut->GetApp(getter_AddRefs(handlerApp)); |
|
338 NS_ENSURE_SUCCESS(rv, rv); |
|
339 |
|
340 // Create a IShellLink |
|
341 hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, |
|
342 IID_IShellLinkW, (LPVOID*)&psl); |
|
343 if (FAILED(hr)) |
|
344 return NS_ERROR_UNEXPECTED; |
|
345 |
|
346 // Retrieve the app path, title, description and optional command line args. |
|
347 nsAutoString appPath, appTitle, appDescription, appArgs; |
|
348 int32_t appIconIndex = 0; |
|
349 |
|
350 // Path |
|
351 nsCOMPtr<nsIFile> executable; |
|
352 handlerApp->GetExecutable(getter_AddRefs(executable)); |
|
353 |
|
354 rv = executable->GetPath(appPath); |
|
355 NS_ENSURE_SUCCESS(rv, rv); |
|
356 |
|
357 // Command line parameters |
|
358 uint32_t count = 0; |
|
359 handlerApp->GetParameterCount(&count); |
|
360 for (uint32_t idx = 0; idx < count; idx++) { |
|
361 if (idx > 0) |
|
362 appArgs.Append(NS_LITERAL_STRING(" ")); |
|
363 nsAutoString param; |
|
364 rv = handlerApp->GetParameter(idx, param); |
|
365 if (NS_FAILED(rv)) |
|
366 return rv; |
|
367 appArgs.Append(param); |
|
368 } |
|
369 |
|
370 handlerApp->GetName(appTitle); |
|
371 handlerApp->GetDetailedDescription(appDescription); |
|
372 |
|
373 bool useUriIcon = false; // if we want to use the URI icon |
|
374 bool usedUriIcon = false; // if we did use the URI icon |
|
375 shortcut->GetIconIndex(&appIconIndex); |
|
376 |
|
377 nsCOMPtr<nsIURI> iconUri; |
|
378 rv = shortcut->GetFaviconPageUri(getter_AddRefs(iconUri)); |
|
379 if (NS_SUCCEEDED(rv) && iconUri) { |
|
380 useUriIcon = true; |
|
381 } |
|
382 |
|
383 // Store the title of the app |
|
384 if (appTitle.Length() > 0) { |
|
385 IPropertyStore* pPropStore = nullptr; |
|
386 hr = psl->QueryInterface(IID_IPropertyStore, (LPVOID*)&pPropStore); |
|
387 if (FAILED(hr)) |
|
388 return NS_ERROR_UNEXPECTED; |
|
389 |
|
390 PROPVARIANT pv; |
|
391 InitPropVariantFromString(appTitle.get(), &pv); |
|
392 |
|
393 pPropStore->SetValue(PKEY_Title, pv); |
|
394 pPropStore->Commit(); |
|
395 pPropStore->Release(); |
|
396 |
|
397 PropVariantClear(&pv); |
|
398 } |
|
399 |
|
400 // Store the rest of the params |
|
401 psl->SetPath(appPath.get()); |
|
402 psl->SetDescription(appDescription.get()); |
|
403 psl->SetArguments(appArgs.get()); |
|
404 |
|
405 if (useUriIcon) { |
|
406 nsString icoFilePath; |
|
407 rv = mozilla::widget::FaviconHelper::ObtainCachedIconFile(iconUri, |
|
408 icoFilePath, |
|
409 aIOThread, |
|
410 false); |
|
411 if (NS_SUCCEEDED(rv)) { |
|
412 // Always use the first icon in the ICO file |
|
413 // our encoded icon only has 1 resource |
|
414 psl->SetIconLocation(icoFilePath.get(), 0); |
|
415 usedUriIcon = true; |
|
416 } |
|
417 } |
|
418 |
|
419 // We didn't use an ICO via URI so fall back to the app icon |
|
420 if (!usedUriIcon) { |
|
421 psl->SetIconLocation(appPath.get(), appIconIndex); |
|
422 } |
|
423 |
|
424 aShellLink = dont_AddRef(psl); |
|
425 |
|
426 return NS_OK; |
|
427 } |
|
428 |
|
429 // If successful fills in the aSame parameter |
|
430 // aSame will be true if the path is in our icon cache |
|
431 static nsresult IsPathInOurIconCache(nsCOMPtr<nsIJumpListShortcut>& aShortcut, |
|
432 wchar_t *aPath, bool *aSame) |
|
433 { |
|
434 NS_ENSURE_ARG_POINTER(aPath); |
|
435 NS_ENSURE_ARG_POINTER(aSame); |
|
436 |
|
437 *aSame = false; |
|
438 |
|
439 // Construct the path of our jump list cache |
|
440 nsCOMPtr<nsIFile> jumpListCache; |
|
441 nsresult rv = NS_GetSpecialDirectory("ProfLDS", getter_AddRefs(jumpListCache)); |
|
442 NS_ENSURE_SUCCESS(rv, rv); |
|
443 rv = jumpListCache->AppendNative(nsDependentCString(FaviconHelper::kJumpListCacheDir)); |
|
444 NS_ENSURE_SUCCESS(rv, rv); |
|
445 nsAutoString jumpListCachePath; |
|
446 rv = jumpListCache->GetPath(jumpListCachePath); |
|
447 NS_ENSURE_SUCCESS(rv, rv); |
|
448 |
|
449 // Construct the parent path of the passed in path |
|
450 nsCOMPtr<nsIFile> passedInFile = do_CreateInstance("@mozilla.org/file/local;1"); |
|
451 NS_ENSURE_TRUE(passedInFile, NS_ERROR_FAILURE); |
|
452 nsAutoString passedInPath(aPath); |
|
453 rv = passedInFile->InitWithPath(passedInPath); |
|
454 nsCOMPtr<nsIFile> passedInParentFile; |
|
455 passedInFile->GetParent(getter_AddRefs(passedInParentFile)); |
|
456 nsAutoString passedInParentPath; |
|
457 rv = jumpListCache->GetPath(passedInParentPath); |
|
458 NS_ENSURE_SUCCESS(rv, rv); |
|
459 |
|
460 *aSame = jumpListCachePath.Equals(passedInParentPath); |
|
461 return NS_OK; |
|
462 } |
|
463 |
|
464 // (static) For a given IShellLink, create and return a populated nsIJumpListShortcut. |
|
465 nsresult JumpListShortcut::GetJumpListShortcut(IShellLinkW *pLink, nsCOMPtr<nsIJumpListShortcut>& aShortcut) |
|
466 { |
|
467 NS_ENSURE_ARG_POINTER(pLink); |
|
468 |
|
469 nsresult rv; |
|
470 HRESULT hres; |
|
471 |
|
472 nsCOMPtr<nsILocalHandlerApp> handlerApp = |
|
473 do_CreateInstance(NS_LOCALHANDLERAPP_CONTRACTID, &rv); |
|
474 NS_ENSURE_SUCCESS(rv, rv); |
|
475 |
|
476 wchar_t buf[MAX_PATH]; |
|
477 |
|
478 // Path |
|
479 hres = pLink->GetPath(buf, MAX_PATH, nullptr, SLGP_UNCPRIORITY); |
|
480 if (FAILED(hres)) |
|
481 return NS_ERROR_INVALID_ARG; |
|
482 |
|
483 nsCOMPtr<nsIFile> file; |
|
484 nsDependentString filepath(buf); |
|
485 rv = NS_NewLocalFile(filepath, false, getter_AddRefs(file)); |
|
486 NS_ENSURE_SUCCESS(rv, rv); |
|
487 |
|
488 rv = handlerApp->SetExecutable(file); |
|
489 NS_ENSURE_SUCCESS(rv, rv); |
|
490 |
|
491 // Parameters |
|
492 hres = pLink->GetArguments(buf, MAX_PATH); |
|
493 if (SUCCEEDED(hres)) { |
|
494 LPWSTR *arglist; |
|
495 int32_t numArgs; |
|
496 int32_t idx; |
|
497 |
|
498 arglist = ::CommandLineToArgvW(buf, &numArgs); |
|
499 if(arglist) { |
|
500 for (idx = 0; idx < numArgs; idx++) { |
|
501 // szArglist[i] is null terminated |
|
502 nsDependentString arg(arglist[idx]); |
|
503 handlerApp->AppendParameter(arg); |
|
504 } |
|
505 ::LocalFree(arglist); |
|
506 } |
|
507 } |
|
508 |
|
509 rv = aShortcut->SetApp(handlerApp); |
|
510 NS_ENSURE_SUCCESS(rv, rv); |
|
511 |
|
512 // Icon index or file location |
|
513 int iconIdx = 0; |
|
514 hres = pLink->GetIconLocation(buf, MAX_PATH, &iconIdx); |
|
515 if (SUCCEEDED(hres)) { |
|
516 // XXX How do we handle converting local files to images here? Do we need to? |
|
517 aShortcut->SetIconIndex(iconIdx); |
|
518 |
|
519 // Obtain the local profile directory and construct the output icon file path |
|
520 // We only set the Icon Uri if we're sure it was from our icon cache. |
|
521 bool isInOurCache; |
|
522 if (NS_SUCCEEDED(IsPathInOurIconCache(aShortcut, buf, &isInOurCache)) && |
|
523 isInOurCache) { |
|
524 nsCOMPtr<nsIURI> iconUri; |
|
525 nsAutoString path(buf); |
|
526 rv = NS_NewURI(getter_AddRefs(iconUri), path); |
|
527 if (NS_SUCCEEDED(rv)) { |
|
528 aShortcut->SetFaviconPageUri(iconUri); |
|
529 } |
|
530 } |
|
531 } |
|
532 |
|
533 // Do we need the title and description? Probably not since handler app doesn't compare |
|
534 // these in equals. |
|
535 |
|
536 return NS_OK; |
|
537 } |
|
538 |
|
539 // (static) ShellItems are used to encapsulate links to things. We currently only support URI links, |
|
540 // but more support could be added, such as local file and directory links. |
|
541 nsresult JumpListLink::GetShellItem(nsCOMPtr<nsIJumpListItem>& item, nsRefPtr<IShellItem2>& aShellItem) |
|
542 { |
|
543 IShellItem2 *psi = nullptr; |
|
544 nsresult rv; |
|
545 |
|
546 int16_t type; |
|
547 if (NS_FAILED(item->GetType(&type))) |
|
548 return NS_ERROR_INVALID_ARG; |
|
549 |
|
550 if (type != nsIJumpListItem::JUMPLIST_ITEM_LINK) |
|
551 return NS_ERROR_INVALID_ARG; |
|
552 |
|
553 nsCOMPtr<nsIJumpListLink> link = do_QueryInterface(item, &rv); |
|
554 NS_ENSURE_SUCCESS(rv, rv); |
|
555 |
|
556 nsCOMPtr<nsIURI> uri; |
|
557 rv = link->GetUri(getter_AddRefs(uri)); |
|
558 NS_ENSURE_SUCCESS(rv, rv); |
|
559 |
|
560 nsAutoCString spec; |
|
561 rv = uri->GetSpec(spec); |
|
562 NS_ENSURE_SUCCESS(rv, rv); |
|
563 |
|
564 // Create the IShellItem |
|
565 if (FAILED(WinUtils::SHCreateItemFromParsingName( |
|
566 NS_ConvertASCIItoUTF16(spec).get(), |
|
567 nullptr, IID_PPV_ARGS(&psi)))) { |
|
568 return NS_ERROR_INVALID_ARG; |
|
569 } |
|
570 |
|
571 // Set the title |
|
572 nsAutoString linkTitle; |
|
573 link->GetUriTitle(linkTitle); |
|
574 |
|
575 IPropertyStore* pPropStore = nullptr; |
|
576 HRESULT hres = psi->GetPropertyStore(GPS_DEFAULT, IID_IPropertyStore, (void**)&pPropStore); |
|
577 if (FAILED(hres)) |
|
578 return NS_ERROR_UNEXPECTED; |
|
579 |
|
580 PROPVARIANT pv; |
|
581 InitPropVariantFromString(linkTitle.get(), &pv); |
|
582 |
|
583 // May fail due to shell item access permissions. |
|
584 pPropStore->SetValue(PKEY_ItemName, pv); |
|
585 pPropStore->Commit(); |
|
586 pPropStore->Release(); |
|
587 |
|
588 PropVariantClear(&pv); |
|
589 |
|
590 aShellItem = dont_AddRef(psi); |
|
591 |
|
592 return NS_OK; |
|
593 } |
|
594 |
|
595 // (static) For a given IShellItem, create and return a populated nsIJumpListLink. |
|
596 nsresult JumpListLink::GetJumpListLink(IShellItem *pItem, nsCOMPtr<nsIJumpListLink>& aLink) |
|
597 { |
|
598 NS_ENSURE_ARG_POINTER(pItem); |
|
599 |
|
600 // We assume for now these are URI links, but through properties we could |
|
601 // query and create other types. |
|
602 nsresult rv; |
|
603 LPWSTR lpstrName = nullptr; |
|
604 |
|
605 if (SUCCEEDED(pItem->GetDisplayName(SIGDN_URL, &lpstrName))) { |
|
606 nsCOMPtr<nsIURI> uri; |
|
607 nsAutoString spec(lpstrName); |
|
608 |
|
609 rv = NS_NewURI(getter_AddRefs(uri), NS_ConvertUTF16toUTF8(spec)); |
|
610 if (NS_FAILED(rv)) |
|
611 return NS_ERROR_INVALID_ARG; |
|
612 |
|
613 aLink->SetUri(uri); |
|
614 |
|
615 ::CoTaskMemFree(lpstrName); |
|
616 } |
|
617 |
|
618 return NS_OK; |
|
619 } |
|
620 |
|
621 // Confirm the app is on the system |
|
622 bool JumpListShortcut::ExecutableExists(nsCOMPtr<nsILocalHandlerApp>& handlerApp) |
|
623 { |
|
624 nsresult rv; |
|
625 |
|
626 if (!handlerApp) |
|
627 return false; |
|
628 |
|
629 nsCOMPtr<nsIFile> executable; |
|
630 rv = handlerApp->GetExecutable(getter_AddRefs(executable)); |
|
631 if (NS_SUCCEEDED(rv) && executable) { |
|
632 bool exists; |
|
633 executable->Exists(&exists); |
|
634 return exists; |
|
635 } |
|
636 return false; |
|
637 } |
|
638 |
|
639 } // namespace widget |
|
640 } // namespace mozilla |
|
641 |