1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* ***** BEGIN LICENSE BLOCK *****
3 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 * The contents of this file are subject to the Mozilla Public License Version
6 * 1.1 (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 * http://www.mozilla.org/MPL/
10 * Software distributed under the License is distributed on an "AS IS" basis,
11 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 * for the specific language governing rights and limitations under the
15 * The Original Code is mozilla.org code.
17 * The Initial Developer of the Original Code is
19 * Portions created by the Initial Developer are Copyright (C) 2009
20 * the Initial Developer. All Rights Reserved.
23 * Jim Mathies <jmathies@mozilla.com>
25 * Alternatively, the contents of this file may be used under the terms of
26 * either the GNU General Public License Version 2 or later (the "GPL"), or
27 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 * in which case the provisions of the GPL or the LGPL are applicable instead
29 * of those above. If you wish to allow use of your version of this file only
30 * under the terms of either the GPL or the LGPL, and not to allow others to
31 * use your version of this file under the terms of the MPL, indicate your
32 * decision by deleting the provisions above and replace them with the notice
33 * and other provisions required by the GPL or the LGPL. If you do not delete
34 * the provisions above, a recipient may use your version of this file under
35 * the terms of any one of the MPL, the GPL or the LGPL.
37 * ***** END LICENSE BLOCK ***** */
39 #if MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7
41 #include "JumpListItem.h"
44 #include <propvarutil.h>
48 #include "nsILocalFile.h"
49 #include "nsNetUtil.h"
52 #include "nsCExternalHandlerService.h"
53 #include "nsCycleCollectionParticipant.h"
58 // SHCreateItemFromParsingName is only available on vista and up. We only load this if we
59 // need to call it on win7+.
60 JumpListLink::SHCreateItemFromParsingNamePtr
JumpListLink::createItemFromParsingName
= nsnull
;
61 const PRUnichar
JumpListLink::kSehllLibraryName
[] = L
"shell32.dll";
62 HMODULE
JumpListLink::sShellDll
= nsnull
;
65 NS_IMPL_ISUPPORTS1(JumpListItem
,
68 NS_IMPL_ISUPPORTS_INHERITED1(JumpListSeparator
,
72 NS_IMPL_ISUPPORTS_INHERITED1(JumpListLink
,
76 NS_IMPL_CYCLE_COLLECTION_CLASS(JumpListShortcut
)
78 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JumpListShortcut
)
79 NS_INTERFACE_MAP_ENTRY(nsIJumpListShortcut
)
80 NS_INTERFACE_MAP_END_INHERITING(JumpListItem
)
82 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(JumpListShortcut
)
83 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mHandlerApp
)
84 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
86 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(JumpListShortcut
)
87 NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mHandlerApp
)
88 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
90 NS_IMPL_CYCLE_COLLECTING_ADDREF(JumpListShortcut
)
91 NS_IMPL_CYCLE_COLLECTING_RELEASE(JumpListShortcut
)
93 /* attribute short type; */
94 NS_IMETHODIMP
JumpListItem::GetType(PRInt16
*aType
)
96 NS_ENSURE_ARG_POINTER(aType
);
103 /* boolean equals(nsIJumpListItem item); */
104 NS_IMETHODIMP
JumpListItem::Equals(nsIJumpListItem
*aItem
, PRBool
*aResult
)
106 NS_ENSURE_ARG_POINTER(aItem
);
110 PRInt16 theType
= nsIJumpListItem::JUMPLIST_ITEM_EMPTY
;
111 if (NS_FAILED(aItem
->GetType(&theType
)))
114 // Make sure the types match.
115 if (Type() != theType
)
125 /* attribute nsIURI uri; */
126 NS_IMETHODIMP
JumpListLink::GetUri(nsIURI
**aURI
)
128 NS_IF_ADDREF(*aURI
= mURI
);
133 NS_IMETHODIMP
JumpListLink::SetUri(nsIURI
*aURI
)
140 /* attribute AString uriTitle; */
141 NS_IMETHODIMP
JumpListLink::SetUriTitle(const nsAString
&aUriTitle
)
143 mUriTitle
.Assign(aUriTitle
);
148 NS_IMETHODIMP
JumpListLink::GetUriTitle(nsAString
& aUriTitle
)
150 aUriTitle
.Assign(mUriTitle
);
155 /* readonly attribute long uriHash; */
156 NS_IMETHODIMP
JumpListLink::GetUriHash(nsACString
& aUriHash
)
159 return NS_ERROR_NOT_AVAILABLE
;
161 return HashURI(mURI
, aUriHash
);
164 /* boolean compareHash(in nsIURI uri); */
165 NS_IMETHODIMP
JumpListLink::CompareHash(nsIURI
*aUri
, PRBool
*aResult
)
174 NS_ENSURE_ARG_POINTER(aUri
);
176 nsCAutoString hash1
, hash2
;
178 rv
= HashURI(mURI
, hash1
);
179 NS_ENSURE_SUCCESS(rv
, rv
);
180 rv
= HashURI(aUri
, hash2
);
181 NS_ENSURE_SUCCESS(rv
, rv
);
183 *aResult
= hash1
.Equals(hash2
);
188 /* boolean equals(nsIJumpListItem item); */
189 NS_IMETHODIMP
JumpListLink::Equals(nsIJumpListItem
*aItem
, PRBool
*aResult
)
191 NS_ENSURE_ARG_POINTER(aItem
);
197 PRInt16 theType
= nsIJumpListItem::JUMPLIST_ITEM_EMPTY
;
198 if (NS_FAILED(aItem
->GetType(&theType
)))
201 // Make sure the types match.
202 if (Type() != theType
)
205 nsCOMPtr
<nsIJumpListLink
> link
= do_QueryInterface(aItem
, &rv
);
211 link
->GetUriTitle(title
);
212 if (!mUriTitle
.Equals(title
))
215 // Call the internal object's equals() method to check.
216 nsCOMPtr
<nsIURI
> theUri
;
217 PRBool equals
= PR_FALSE
;
218 if (NS_SUCCEEDED(link
->GetUri(getter_AddRefs(theUri
)))) {
224 if (NS_SUCCEEDED(theUri
->Equals(mURI
, &equals
)) && equals
) {
234 /* attribute nsILocalHandlerApp app; */
235 NS_IMETHODIMP
JumpListShortcut::GetApp(nsILocalHandlerApp
**aApp
)
237 NS_IF_ADDREF(*aApp
= mHandlerApp
);
242 NS_IMETHODIMP
JumpListShortcut::SetApp(nsILocalHandlerApp
*aApp
)
246 // Confirm the app is present on the system
247 if (!ExecutableExists(mHandlerApp
))
248 return NS_ERROR_FILE_NOT_FOUND
;
253 /* attribute long iconIndex; */
254 NS_IMETHODIMP
JumpListShortcut::GetIconIndex(PRInt32
*aIconIndex
)
256 NS_ENSURE_ARG_POINTER(aIconIndex
);
258 *aIconIndex
= mIconIndex
;
262 NS_IMETHODIMP
JumpListShortcut::SetIconIndex(PRInt32 aIconIndex
)
264 mIconIndex
= aIconIndex
;
268 /* boolean equals(nsIJumpListItem item); */
269 NS_IMETHODIMP
JumpListShortcut::Equals(nsIJumpListItem
*aItem
, PRBool
*aResult
)
271 NS_ENSURE_ARG_POINTER(aItem
);
277 PRInt16 theType
= nsIJumpListItem::JUMPLIST_ITEM_EMPTY
;
278 if (NS_FAILED(aItem
->GetType(&theType
)))
281 // Make sure the types match.
282 if (Type() != theType
)
285 nsCOMPtr
<nsIJumpListShortcut
> shortcut
= do_QueryInterface(aItem
, &rv
);
289 // Check the icon index
291 //shortcut->GetIconIndex(&idx);
292 //if (mIconIndex != idx)
295 // Call the internal object's equals() method to check.
296 nsCOMPtr
<nsILocalHandlerApp
> theApp
;
297 PRBool equals
= PR_FALSE
;
298 if (NS_SUCCEEDED(shortcut
->GetApp(getter_AddRefs(theApp
)))) {
304 if (NS_SUCCEEDED(theApp
->Equals(mHandlerApp
, &equals
)) && equals
) {
312 /* internal helpers */
314 // (static) Creates a ShellLink that encapsulate a separator.
315 nsresult
JumpListSeparator::GetSeparator(nsRefPtr
<IShellLinkW
>& aShellLink
)
320 // Create a IShellLink.
321 hr
= CoCreateInstance(CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
322 IID_IShellLinkW
, (LPVOID
*)&psl
);
324 return NS_ERROR_UNEXPECTED
;
326 IPropertyStore
* pPropStore
= nsnull
;
327 hr
= psl
->QueryInterface(IID_IPropertyStore
, (LPVOID
*)&pPropStore
);
329 return NS_ERROR_UNEXPECTED
;
332 InitPropVariantFromBoolean(TRUE
, &pv
);
334 pPropStore
->SetValue(PKEY_AppUserModel_IsDestListSeparator
, pv
);
335 pPropStore
->Commit();
336 pPropStore
->Release();
338 PropVariantClear(&pv
);
340 aShellLink
= dont_AddRef(psl
);
345 // (static) Creates a ShellLink that encapsulate a shortcut to local apps.
346 nsresult
JumpListShortcut::GetShellLink(nsCOMPtr
<nsIJumpListItem
>& item
, nsRefPtr
<IShellLinkW
>& aShellLink
)
353 // http://msdn.microsoft.com/en-us/library/bb776891(VS.85).aspx
354 // http://msdn.microsoft.com/en-us/library/bb774950(VS.85).aspx
357 if (NS_FAILED(item
->GetType(&type
)))
358 return NS_ERROR_INVALID_ARG
;
360 if (type
!= nsIJumpListItem::JUMPLIST_ITEM_SHORTCUT
)
361 return NS_ERROR_INVALID_ARG
;
363 nsCOMPtr
<nsIJumpListShortcut
> shortcut
= do_QueryInterface(item
, &rv
);
364 NS_ENSURE_SUCCESS(rv
, rv
);
366 nsCOMPtr
<nsILocalHandlerApp
> handlerApp
;
367 rv
= shortcut
->GetApp(getter_AddRefs(handlerApp
));
368 NS_ENSURE_SUCCESS(rv
, rv
);
370 // Create a IShellLink
371 hr
= CoCreateInstance(CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
,
372 IID_IShellLinkW
, (LPVOID
*)&psl
);
374 return NS_ERROR_UNEXPECTED
;
376 // Retrieve the app path, title, description and optional command line args.
377 nsAutoString appPath
, appTitle
, appDescription
, appArgs
;
378 PRInt32 appIconIndex
= 0;
381 nsCOMPtr
<nsIFile
> executable
;
382 handlerApp
->GetExecutable(getter_AddRefs(executable
));
383 nsCOMPtr
<nsILocalFile
> localFile
= do_QueryInterface(executable
, &rv
);
384 NS_ENSURE_SUCCESS(rv
, rv
);
386 rv
= localFile
->GetPath(appPath
);
387 NS_ENSURE_SUCCESS(rv
, rv
);
389 // Command line parameters
391 handlerApp
->GetParameterCount(&count
);
392 for (PRUint32 idx
= 0; idx
< count
; idx
++) {
394 appArgs
.Append(NS_LITERAL_STRING(" "));
396 rv
= handlerApp
->GetParameter(idx
, param
);
399 appArgs
.Append(param
);
402 handlerApp
->GetName(appTitle
);
403 handlerApp
->GetDetailedDescription(appDescription
);
404 shortcut
->GetIconIndex(&appIconIndex
);
406 // Store the title of the app
407 if (appTitle
.Length() > 0) {
408 IPropertyStore
* pPropStore
= nsnull
;
409 hr
= psl
->QueryInterface(IID_IPropertyStore
, (LPVOID
*)&pPropStore
);
411 return NS_ERROR_UNEXPECTED
;
414 InitPropVariantFromString(appTitle
.get(), &pv
);
416 pPropStore
->SetValue(PKEY_Title
, pv
);
417 pPropStore
->Commit();
418 pPropStore
->Release();
420 PropVariantClear(&pv
);
423 // Store the rest of the params
424 psl
->SetPath(appPath
.get());
425 psl
->SetDescription(appDescription
.get());
426 psl
->SetArguments(appArgs
.get());
427 psl
->SetIconLocation(appPath
.get(), appIconIndex
);
429 aShellLink
= dont_AddRef(psl
);
434 // (static) For a given IShellLink, create and return a populated nsIJumpListShortcut.
435 nsresult
JumpListShortcut::GetJumpListShortcut(IShellLinkW
*pLink
, nsCOMPtr
<nsIJumpListShortcut
>& aShortcut
)
437 NS_ENSURE_ARG_POINTER(pLink
);
442 nsCOMPtr
<nsILocalHandlerApp
> handlerApp
=
443 do_CreateInstance(NS_LOCALHANDLERAPP_CONTRACTID
, &rv
);
444 NS_ENSURE_SUCCESS(rv
, rv
);
446 PRUnichar buf
[MAX_PATH
];
449 hres
= pLink
->GetPath((LPWSTR
)&buf
, MAX_PATH
, NULL
, SLGP_UNCPRIORITY
);
451 return NS_ERROR_INVALID_ARG
;
453 nsCOMPtr
<nsILocalFile
> file
;
454 nsDependentString
filepath(buf
);
455 rv
= NS_NewLocalFile(filepath
, PR_FALSE
, getter_AddRefs(file
));
456 NS_ENSURE_SUCCESS(rv
, rv
);
458 rv
= handlerApp
->SetExecutable(file
);
459 NS_ENSURE_SUCCESS(rv
, rv
);
462 hres
= pLink
->GetArguments((LPWSTR
)&buf
, MAX_PATH
);
463 if (SUCCEEDED(hres
)) {
468 arglist
= ::CommandLineToArgvW(buf
, &numArgs
);
470 for (idx
= 0; idx
< numArgs
; idx
++) {
471 // szArglist[i] is null terminated
472 nsDependentString
arg(arglist
[idx
]);
473 handlerApp
->AppendParameter(arg
);
475 ::LocalFree(arglist
);
479 rv
= aShortcut
->SetApp(handlerApp
);
480 NS_ENSURE_SUCCESS(rv
, rv
);
482 // Icon index or file location
484 hres
= pLink
->GetIconLocation((LPWSTR
)&buf
, MAX_PATH
, &iconIdx
);
485 if (SUCCEEDED(hres
)) {
486 // XXX How do we handle converting local files to images here? Do we need to?
487 aShortcut
->SetIconIndex(iconIdx
);
490 // Do we need the title and description? Probably not since handler app doesn't compare
496 // (static) ShellItems are used to encapsulate links to things. We currently only support URI links,
497 // but more support could be added, such as local file and directory links.
498 nsresult
JumpListLink::GetShellItem(nsCOMPtr
<nsIJumpListItem
>& item
, nsRefPtr
<IShellItem2
>& aShellItem
)
500 IShellItem2
*psi
= nsnull
;
504 if (NS_FAILED(item
->GetType(&type
)))
505 return NS_ERROR_INVALID_ARG
;
507 if (type
!= nsIJumpListItem::JUMPLIST_ITEM_LINK
)
508 return NS_ERROR_INVALID_ARG
;
510 nsCOMPtr
<nsIJumpListLink
> link
= do_QueryInterface(item
, &rv
);
511 NS_ENSURE_SUCCESS(rv
, rv
);
513 nsCOMPtr
<nsIURI
> uri
;
514 rv
= link
->GetUri(getter_AddRefs(uri
));
515 NS_ENSURE_SUCCESS(rv
, rv
);
518 rv
= uri
->GetSpec(spec
);
519 NS_ENSURE_SUCCESS(rv
, rv
);
521 // Load vista+ SHCreateItemFromParsingName
522 if (createItemFromParsingName
== nsnull
) {
524 return NS_ERROR_UNEXPECTED
;
525 sShellDll
= ::LoadLibraryW(kSehllLibraryName
);
527 createItemFromParsingName
= (SHCreateItemFromParsingNamePtr
)GetProcAddress(sShellDll
, "SHCreateItemFromParsingName");
528 if (createItemFromParsingName
== nsnull
)
529 return NS_ERROR_UNEXPECTED
;
532 // Create the IShellItem
533 if (FAILED(createItemFromParsingName(NS_ConvertASCIItoUTF16(spec
).get(),
534 NULL
, IID_PPV_ARGS(&psi
))))
535 return NS_ERROR_INVALID_ARG
;
538 nsAutoString linkTitle
;
539 link
->GetUriTitle(linkTitle
);
541 IPropertyStore
* pPropStore
= nsnull
;
542 HRESULT hres
= psi
->GetPropertyStore(GPS_DEFAULT
, IID_IPropertyStore
, (void**)&pPropStore
);
544 return NS_ERROR_UNEXPECTED
;
547 InitPropVariantFromString(linkTitle
.get(), &pv
);
549 // May fail due to shell item access permissions.
550 pPropStore
->SetValue(PKEY_ItemName
, pv
);
551 pPropStore
->Commit();
552 pPropStore
->Release();
554 PropVariantClear(&pv
);
556 aShellItem
= dont_AddRef(psi
);
561 // (static) For a given IShellItem, create and return a populated nsIJumpListLink.
562 nsresult
JumpListLink::GetJumpListLink(IShellItem
*pItem
, nsCOMPtr
<nsIJumpListLink
>& aLink
)
564 NS_ENSURE_ARG_POINTER(pItem
);
566 // We assume for now these are URI links, but through properties we could
567 // query and create other types.
569 LPWSTR lpstrName
= NULL
;
571 if (SUCCEEDED(pItem
->GetDisplayName(SIGDN_URL
, &lpstrName
))) {
572 nsCOMPtr
<nsIURI
> uri
;
573 nsAutoString
spec(lpstrName
);
575 rv
= NS_NewURI(getter_AddRefs(uri
), NS_ConvertUTF16toUTF8(spec
));
577 return NS_ERROR_INVALID_ARG
;
581 ::CoTaskMemFree(lpstrName
);
587 // Confirm the app is on the system
588 PRBool
JumpListShortcut::ExecutableExists(nsCOMPtr
<nsILocalHandlerApp
>& handlerApp
)
595 nsCOMPtr
<nsIFile
> executable
;
596 rv
= handlerApp
->GetExecutable(getter_AddRefs(executable
));
597 if (NS_SUCCEEDED(rv
) && executable
) {
599 executable
->Exists(&exists
);
605 nsresult
JumpListLink::HashURI(nsIURI
*aUri
, nsACString
& aUriHash
)
610 return NS_ERROR_INVALID_ARG
;
613 rv
= aUri
->GetSpec(spec
);
614 NS_ENSURE_SUCCESS(rv
, rv
);
617 mCryptoHash
= do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID
, &rv
);
618 NS_ENSURE_SUCCESS(rv
, rv
);
621 rv
= mCryptoHash
->Init(nsICryptoHash::MD5
);
622 NS_ENSURE_SUCCESS(rv
, rv
);
623 rv
= mCryptoHash
->Update(reinterpret_cast<const PRUint8
*>(spec
.BeginReading()), spec
.Length());
624 NS_ENSURE_SUCCESS(rv
, rv
);
625 rv
= mCryptoHash
->Finish(PR_TRUE
, aUriHash
);
626 NS_ENSURE_SUCCESS(rv
, rv
);
631 } // namespace widget
632 } // namespace mozilla
634 #endif // MOZ_WINSDK_TARGETVER >= MOZ_NTDDI_WIN7