michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "JumpListItem.h" michael@0: michael@0: #include michael@0: #include michael@0: #include michael@0: michael@0: #include "nsIFile.h" michael@0: #include "nsNetUtil.h" michael@0: #include "nsCRT.h" michael@0: #include "nsNetCID.h" michael@0: #include "nsCExternalHandlerService.h" michael@0: #include "nsCycleCollectionParticipant.h" michael@0: #include "mozilla/Preferences.h" michael@0: #include "JumpListBuilder.h" michael@0: #include "WinUtils.h" michael@0: michael@0: namespace mozilla { michael@0: namespace widget { michael@0: michael@0: // ISUPPORTS Impl's michael@0: NS_IMPL_ISUPPORTS(JumpListItem, michael@0: nsIJumpListItem) michael@0: michael@0: NS_IMPL_ISUPPORTS_INHERITED(JumpListSeparator, michael@0: JumpListItem, michael@0: nsIJumpListSeparator) michael@0: michael@0: NS_IMPL_ISUPPORTS_INHERITED(JumpListLink, michael@0: JumpListItem, michael@0: nsIJumpListLink) michael@0: michael@0: NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(JumpListShortcut) michael@0: NS_INTERFACE_MAP_ENTRY(nsIJumpListShortcut) michael@0: NS_INTERFACE_MAP_END_INHERITING(JumpListItem) michael@0: michael@0: NS_IMPL_CYCLE_COLLECTION(JumpListShortcut, mHandlerApp) michael@0: michael@0: NS_IMPL_CYCLE_COLLECTING_ADDREF(JumpListShortcut) michael@0: NS_IMPL_CYCLE_COLLECTING_RELEASE(JumpListShortcut) michael@0: michael@0: /* attribute short type; */ michael@0: NS_IMETHODIMP JumpListItem::GetType(int16_t *aType) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aType); michael@0: michael@0: *aType = mItemType; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* boolean equals(nsIJumpListItem item); */ michael@0: NS_IMETHODIMP JumpListItem::Equals(nsIJumpListItem *aItem, bool *aResult) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aItem); michael@0: michael@0: *aResult = false; michael@0: michael@0: int16_t theType = nsIJumpListItem::JUMPLIST_ITEM_EMPTY; michael@0: if (NS_FAILED(aItem->GetType(&theType))) michael@0: return NS_OK; michael@0: michael@0: // Make sure the types match. michael@0: if (Type() != theType) michael@0: return NS_OK; michael@0: michael@0: *aResult = true; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* link impl. */ michael@0: michael@0: /* attribute nsIURI uri; */ michael@0: NS_IMETHODIMP JumpListLink::GetUri(nsIURI **aURI) michael@0: { michael@0: NS_IF_ADDREF(*aURI = mURI); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP JumpListLink::SetUri(nsIURI *aURI) michael@0: { michael@0: mURI = aURI; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* attribute AString uriTitle; */ michael@0: NS_IMETHODIMP JumpListLink::SetUriTitle(const nsAString &aUriTitle) michael@0: { michael@0: mUriTitle.Assign(aUriTitle); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP JumpListLink::GetUriTitle(nsAString& aUriTitle) michael@0: { michael@0: aUriTitle.Assign(mUriTitle); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* readonly attribute long uriHash; */ michael@0: NS_IMETHODIMP JumpListLink::GetUriHash(nsACString& aUriHash) michael@0: { michael@0: if (!mURI) michael@0: return NS_ERROR_NOT_AVAILABLE; michael@0: michael@0: return mozilla::widget::FaviconHelper::HashURI(mCryptoHash, mURI, aUriHash); michael@0: } michael@0: michael@0: /* boolean compareHash(in nsIURI uri); */ michael@0: NS_IMETHODIMP JumpListLink::CompareHash(nsIURI *aUri, bool *aResult) michael@0: { michael@0: nsresult rv; michael@0: michael@0: if (!mURI) { michael@0: *aResult = !aUri; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_ENSURE_ARG_POINTER(aUri); michael@0: michael@0: nsAutoCString hash1, hash2; michael@0: michael@0: rv = mozilla::widget::FaviconHelper::HashURI(mCryptoHash, mURI, hash1); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: rv = mozilla::widget::FaviconHelper::HashURI(mCryptoHash, aUri, hash2); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: *aResult = hash1.Equals(hash2); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* boolean equals(nsIJumpListItem item); */ michael@0: NS_IMETHODIMP JumpListLink::Equals(nsIJumpListItem *aItem, bool *aResult) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aItem); michael@0: michael@0: nsresult rv; michael@0: michael@0: *aResult = false; michael@0: michael@0: int16_t theType = nsIJumpListItem::JUMPLIST_ITEM_EMPTY; michael@0: if (NS_FAILED(aItem->GetType(&theType))) michael@0: return NS_OK; michael@0: michael@0: // Make sure the types match. michael@0: if (Type() != theType) michael@0: return NS_OK; michael@0: michael@0: nsCOMPtr link = do_QueryInterface(aItem, &rv); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: // Check the titles michael@0: nsAutoString title; michael@0: link->GetUriTitle(title); michael@0: if (!mUriTitle.Equals(title)) michael@0: return NS_OK; michael@0: michael@0: // Call the internal object's equals() method to check. michael@0: nsCOMPtr theUri; michael@0: bool equals = false; michael@0: if (NS_SUCCEEDED(link->GetUri(getter_AddRefs(theUri)))) { michael@0: if (!theUri) { michael@0: if (!mURI) michael@0: *aResult = true; michael@0: return NS_OK; michael@0: } michael@0: if (NS_SUCCEEDED(theUri->Equals(mURI, &equals)) && equals) { michael@0: *aResult = true; michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* shortcut impl. */ michael@0: michael@0: /* attribute nsILocalHandlerApp app; */ michael@0: NS_IMETHODIMP JumpListShortcut::GetApp(nsILocalHandlerApp **aApp) michael@0: { michael@0: NS_IF_ADDREF(*aApp = mHandlerApp); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP JumpListShortcut::SetApp(nsILocalHandlerApp *aApp) michael@0: { michael@0: mHandlerApp = aApp; michael@0: michael@0: // Confirm the app is present on the system michael@0: if (!ExecutableExists(mHandlerApp)) michael@0: return NS_ERROR_FILE_NOT_FOUND; michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* attribute long iconIndex; */ michael@0: NS_IMETHODIMP JumpListShortcut::GetIconIndex(int32_t *aIconIndex) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aIconIndex); michael@0: michael@0: *aIconIndex = mIconIndex; michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP JumpListShortcut::SetIconIndex(int32_t aIconIndex) michael@0: { michael@0: mIconIndex = aIconIndex; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* attribute long iconURI; */ michael@0: NS_IMETHODIMP JumpListShortcut::GetFaviconPageUri(nsIURI **aFaviconPageURI) michael@0: { michael@0: NS_IF_ADDREF(*aFaviconPageURI = mFaviconPageURI); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: NS_IMETHODIMP JumpListShortcut::SetFaviconPageUri(nsIURI *aFaviconPageURI) michael@0: { michael@0: mFaviconPageURI = aFaviconPageURI; michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* boolean equals(nsIJumpListItem item); */ michael@0: NS_IMETHODIMP JumpListShortcut::Equals(nsIJumpListItem *aItem, bool *aResult) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aItem); michael@0: michael@0: nsresult rv; michael@0: michael@0: *aResult = false; michael@0: michael@0: int16_t theType = nsIJumpListItem::JUMPLIST_ITEM_EMPTY; michael@0: if (NS_FAILED(aItem->GetType(&theType))) michael@0: return NS_OK; michael@0: michael@0: // Make sure the types match. michael@0: if (Type() != theType) michael@0: return NS_OK; michael@0: michael@0: nsCOMPtr shortcut = do_QueryInterface(aItem, &rv); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: michael@0: // Check the icon index michael@0: //int32_t idx; michael@0: //shortcut->GetIconIndex(&idx); michael@0: //if (mIconIndex != idx) michael@0: // return NS_OK; michael@0: // No need to check the icon page URI either michael@0: michael@0: // Call the internal object's equals() method to check. michael@0: nsCOMPtr theApp; michael@0: bool equals = false; michael@0: if (NS_SUCCEEDED(shortcut->GetApp(getter_AddRefs(theApp)))) { michael@0: if (!theApp) { michael@0: if (!mHandlerApp) michael@0: *aResult = true; michael@0: return NS_OK; michael@0: } michael@0: if (NS_SUCCEEDED(theApp->Equals(mHandlerApp, &equals)) && equals) { michael@0: *aResult = true; michael@0: } michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: /* internal helpers */ michael@0: michael@0: // (static) Creates a ShellLink that encapsulate a separator. michael@0: nsresult JumpListSeparator::GetSeparator(nsRefPtr& aShellLink) michael@0: { michael@0: HRESULT hr; michael@0: IShellLinkW* psl; michael@0: michael@0: // Create a IShellLink. michael@0: hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, michael@0: IID_IShellLinkW, (LPVOID*)&psl); michael@0: if (FAILED(hr)) michael@0: return NS_ERROR_UNEXPECTED; michael@0: michael@0: IPropertyStore* pPropStore = nullptr; michael@0: hr = psl->QueryInterface(IID_IPropertyStore, (LPVOID*)&pPropStore); michael@0: if (FAILED(hr)) michael@0: return NS_ERROR_UNEXPECTED; michael@0: michael@0: PROPVARIANT pv; michael@0: InitPropVariantFromBoolean(TRUE, &pv); michael@0: michael@0: pPropStore->SetValue(PKEY_AppUserModel_IsDestListSeparator, pv); michael@0: pPropStore->Commit(); michael@0: pPropStore->Release(); michael@0: michael@0: PropVariantClear(&pv); michael@0: michael@0: aShellLink = dont_AddRef(psl); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // (static) Creates a ShellLink that encapsulate a shortcut to local apps. michael@0: nsresult JumpListShortcut::GetShellLink(nsCOMPtr& item, michael@0: nsRefPtr& aShellLink, michael@0: nsCOMPtr &aIOThread) michael@0: { michael@0: HRESULT hr; michael@0: IShellLinkW* psl; michael@0: nsresult rv; michael@0: michael@0: // Shell links: michael@0: // http://msdn.microsoft.com/en-us/library/bb776891(VS.85).aspx michael@0: // http://msdn.microsoft.com/en-us/library/bb774950(VS.85).aspx michael@0: michael@0: int16_t type; michael@0: if (NS_FAILED(item->GetType(&type))) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: if (type != nsIJumpListItem::JUMPLIST_ITEM_SHORTCUT) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: nsCOMPtr shortcut = do_QueryInterface(item, &rv); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsCOMPtr handlerApp; michael@0: rv = shortcut->GetApp(getter_AddRefs(handlerApp)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Create a IShellLink michael@0: hr = CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER, michael@0: IID_IShellLinkW, (LPVOID*)&psl); michael@0: if (FAILED(hr)) michael@0: return NS_ERROR_UNEXPECTED; michael@0: michael@0: // Retrieve the app path, title, description and optional command line args. michael@0: nsAutoString appPath, appTitle, appDescription, appArgs; michael@0: int32_t appIconIndex = 0; michael@0: michael@0: // Path michael@0: nsCOMPtr executable; michael@0: handlerApp->GetExecutable(getter_AddRefs(executable)); michael@0: michael@0: rv = executable->GetPath(appPath); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Command line parameters michael@0: uint32_t count = 0; michael@0: handlerApp->GetParameterCount(&count); michael@0: for (uint32_t idx = 0; idx < count; idx++) { michael@0: if (idx > 0) michael@0: appArgs.Append(NS_LITERAL_STRING(" ")); michael@0: nsAutoString param; michael@0: rv = handlerApp->GetParameter(idx, param); michael@0: if (NS_FAILED(rv)) michael@0: return rv; michael@0: appArgs.Append(param); michael@0: } michael@0: michael@0: handlerApp->GetName(appTitle); michael@0: handlerApp->GetDetailedDescription(appDescription); michael@0: michael@0: bool useUriIcon = false; // if we want to use the URI icon michael@0: bool usedUriIcon = false; // if we did use the URI icon michael@0: shortcut->GetIconIndex(&appIconIndex); michael@0: michael@0: nsCOMPtr iconUri; michael@0: rv = shortcut->GetFaviconPageUri(getter_AddRefs(iconUri)); michael@0: if (NS_SUCCEEDED(rv) && iconUri) { michael@0: useUriIcon = true; michael@0: } michael@0: michael@0: // Store the title of the app michael@0: if (appTitle.Length() > 0) { michael@0: IPropertyStore* pPropStore = nullptr; michael@0: hr = psl->QueryInterface(IID_IPropertyStore, (LPVOID*)&pPropStore); michael@0: if (FAILED(hr)) michael@0: return NS_ERROR_UNEXPECTED; michael@0: michael@0: PROPVARIANT pv; michael@0: InitPropVariantFromString(appTitle.get(), &pv); michael@0: michael@0: pPropStore->SetValue(PKEY_Title, pv); michael@0: pPropStore->Commit(); michael@0: pPropStore->Release(); michael@0: michael@0: PropVariantClear(&pv); michael@0: } michael@0: michael@0: // Store the rest of the params michael@0: psl->SetPath(appPath.get()); michael@0: psl->SetDescription(appDescription.get()); michael@0: psl->SetArguments(appArgs.get()); michael@0: michael@0: if (useUriIcon) { michael@0: nsString icoFilePath; michael@0: rv = mozilla::widget::FaviconHelper::ObtainCachedIconFile(iconUri, michael@0: icoFilePath, michael@0: aIOThread, michael@0: false); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: // Always use the first icon in the ICO file michael@0: // our encoded icon only has 1 resource michael@0: psl->SetIconLocation(icoFilePath.get(), 0); michael@0: usedUriIcon = true; michael@0: } michael@0: } michael@0: michael@0: // We didn't use an ICO via URI so fall back to the app icon michael@0: if (!usedUriIcon) { michael@0: psl->SetIconLocation(appPath.get(), appIconIndex); michael@0: } michael@0: michael@0: aShellLink = dont_AddRef(psl); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // If successful fills in the aSame parameter michael@0: // aSame will be true if the path is in our icon cache michael@0: static nsresult IsPathInOurIconCache(nsCOMPtr& aShortcut, michael@0: wchar_t *aPath, bool *aSame) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(aPath); michael@0: NS_ENSURE_ARG_POINTER(aSame); michael@0: michael@0: *aSame = false; michael@0: michael@0: // Construct the path of our jump list cache michael@0: nsCOMPtr jumpListCache; michael@0: nsresult rv = NS_GetSpecialDirectory("ProfLDS", getter_AddRefs(jumpListCache)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: rv = jumpListCache->AppendNative(nsDependentCString(FaviconHelper::kJumpListCacheDir)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: nsAutoString jumpListCachePath; michael@0: rv = jumpListCache->GetPath(jumpListCachePath); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Construct the parent path of the passed in path michael@0: nsCOMPtr passedInFile = do_CreateInstance("@mozilla.org/file/local;1"); michael@0: NS_ENSURE_TRUE(passedInFile, NS_ERROR_FAILURE); michael@0: nsAutoString passedInPath(aPath); michael@0: rv = passedInFile->InitWithPath(passedInPath); michael@0: nsCOMPtr passedInParentFile; michael@0: passedInFile->GetParent(getter_AddRefs(passedInParentFile)); michael@0: nsAutoString passedInParentPath; michael@0: rv = jumpListCache->GetPath(passedInParentPath); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: *aSame = jumpListCachePath.Equals(passedInParentPath); michael@0: return NS_OK; michael@0: } michael@0: michael@0: // (static) For a given IShellLink, create and return a populated nsIJumpListShortcut. michael@0: nsresult JumpListShortcut::GetJumpListShortcut(IShellLinkW *pLink, nsCOMPtr& aShortcut) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(pLink); michael@0: michael@0: nsresult rv; michael@0: HRESULT hres; michael@0: michael@0: nsCOMPtr handlerApp = michael@0: do_CreateInstance(NS_LOCALHANDLERAPP_CONTRACTID, &rv); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: wchar_t buf[MAX_PATH]; michael@0: michael@0: // Path michael@0: hres = pLink->GetPath(buf, MAX_PATH, nullptr, SLGP_UNCPRIORITY); michael@0: if (FAILED(hres)) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: nsCOMPtr file; michael@0: nsDependentString filepath(buf); michael@0: rv = NS_NewLocalFile(filepath, false, getter_AddRefs(file)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: rv = handlerApp->SetExecutable(file); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Parameters michael@0: hres = pLink->GetArguments(buf, MAX_PATH); michael@0: if (SUCCEEDED(hres)) { michael@0: LPWSTR *arglist; michael@0: int32_t numArgs; michael@0: int32_t idx; michael@0: michael@0: arglist = ::CommandLineToArgvW(buf, &numArgs); michael@0: if(arglist) { michael@0: for (idx = 0; idx < numArgs; idx++) { michael@0: // szArglist[i] is null terminated michael@0: nsDependentString arg(arglist[idx]); michael@0: handlerApp->AppendParameter(arg); michael@0: } michael@0: ::LocalFree(arglist); michael@0: } michael@0: } michael@0: michael@0: rv = aShortcut->SetApp(handlerApp); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Icon index or file location michael@0: int iconIdx = 0; michael@0: hres = pLink->GetIconLocation(buf, MAX_PATH, &iconIdx); michael@0: if (SUCCEEDED(hres)) { michael@0: // XXX How do we handle converting local files to images here? Do we need to? michael@0: aShortcut->SetIconIndex(iconIdx); michael@0: michael@0: // Obtain the local profile directory and construct the output icon file path michael@0: // We only set the Icon Uri if we're sure it was from our icon cache. michael@0: bool isInOurCache; michael@0: if (NS_SUCCEEDED(IsPathInOurIconCache(aShortcut, buf, &isInOurCache)) && michael@0: isInOurCache) { michael@0: nsCOMPtr iconUri; michael@0: nsAutoString path(buf); michael@0: rv = NS_NewURI(getter_AddRefs(iconUri), path); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: aShortcut->SetFaviconPageUri(iconUri); michael@0: } michael@0: } michael@0: } michael@0: michael@0: // Do we need the title and description? Probably not since handler app doesn't compare michael@0: // these in equals. michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // (static) ShellItems are used to encapsulate links to things. We currently only support URI links, michael@0: // but more support could be added, such as local file and directory links. michael@0: nsresult JumpListLink::GetShellItem(nsCOMPtr& item, nsRefPtr& aShellItem) michael@0: { michael@0: IShellItem2 *psi = nullptr; michael@0: nsresult rv; michael@0: michael@0: int16_t type; michael@0: if (NS_FAILED(item->GetType(&type))) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: if (type != nsIJumpListItem::JUMPLIST_ITEM_LINK) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: nsCOMPtr link = do_QueryInterface(item, &rv); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsCOMPtr uri; michael@0: rv = link->GetUri(getter_AddRefs(uri)); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: nsAutoCString spec; michael@0: rv = uri->GetSpec(spec); michael@0: NS_ENSURE_SUCCESS(rv, rv); michael@0: michael@0: // Create the IShellItem michael@0: if (FAILED(WinUtils::SHCreateItemFromParsingName( michael@0: NS_ConvertASCIItoUTF16(spec).get(), michael@0: nullptr, IID_PPV_ARGS(&psi)))) { michael@0: return NS_ERROR_INVALID_ARG; michael@0: } michael@0: michael@0: // Set the title michael@0: nsAutoString linkTitle; michael@0: link->GetUriTitle(linkTitle); michael@0: michael@0: IPropertyStore* pPropStore = nullptr; michael@0: HRESULT hres = psi->GetPropertyStore(GPS_DEFAULT, IID_IPropertyStore, (void**)&pPropStore); michael@0: if (FAILED(hres)) michael@0: return NS_ERROR_UNEXPECTED; michael@0: michael@0: PROPVARIANT pv; michael@0: InitPropVariantFromString(linkTitle.get(), &pv); michael@0: michael@0: // May fail due to shell item access permissions. michael@0: pPropStore->SetValue(PKEY_ItemName, pv); michael@0: pPropStore->Commit(); michael@0: pPropStore->Release(); michael@0: michael@0: PropVariantClear(&pv); michael@0: michael@0: aShellItem = dont_AddRef(psi); michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // (static) For a given IShellItem, create and return a populated nsIJumpListLink. michael@0: nsresult JumpListLink::GetJumpListLink(IShellItem *pItem, nsCOMPtr& aLink) michael@0: { michael@0: NS_ENSURE_ARG_POINTER(pItem); michael@0: michael@0: // We assume for now these are URI links, but through properties we could michael@0: // query and create other types. michael@0: nsresult rv; michael@0: LPWSTR lpstrName = nullptr; michael@0: michael@0: if (SUCCEEDED(pItem->GetDisplayName(SIGDN_URL, &lpstrName))) { michael@0: nsCOMPtr uri; michael@0: nsAutoString spec(lpstrName); michael@0: michael@0: rv = NS_NewURI(getter_AddRefs(uri), NS_ConvertUTF16toUTF8(spec)); michael@0: if (NS_FAILED(rv)) michael@0: return NS_ERROR_INVALID_ARG; michael@0: michael@0: aLink->SetUri(uri); michael@0: michael@0: ::CoTaskMemFree(lpstrName); michael@0: } michael@0: michael@0: return NS_OK; michael@0: } michael@0: michael@0: // Confirm the app is on the system michael@0: bool JumpListShortcut::ExecutableExists(nsCOMPtr& handlerApp) michael@0: { michael@0: nsresult rv; michael@0: michael@0: if (!handlerApp) michael@0: return false; michael@0: michael@0: nsCOMPtr executable; michael@0: rv = handlerApp->GetExecutable(getter_AddRefs(executable)); michael@0: if (NS_SUCCEEDED(rv) && executable) { michael@0: bool exists; michael@0: executable->Exists(&exists); michael@0: return exists; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: } // namespace widget michael@0: } // namespace mozilla michael@0: