#include "priv.h" #include "ishcut.h" #include "assocurl.h" #include "shlwapi.h" #include "resource.h" #include "shlguid.h" STDMETHODIMP Intshcut::QueryStatus( const GUID *pguidCmdGroup, ULONG cCmds, MSOCMD rgCmds[], MSOCMDTEXT *pcmdtext ) { return E_NOTIMPL; } struct SHORTCUT_ICON_PARAMS { WCHAR *pwszFileName; WCHAR *pwszShortcutUrl; BSTR bstrIconUrl; ~SHORTCUT_ICON_PARAMS() { if(pwszFileName) { LocalFree(pwszFileName); pwszFileName = NULL; } if(bstrIconUrl) { SysFreeString(bstrIconUrl); bstrIconUrl = NULL; } if(pwszShortcutUrl) { SHFree(pwszShortcutUrl); pwszShortcutUrl = NULL; } } }; const WCHAR wszDefaultShortcutIconName[] = ISHCUT_DEFAULT_FAVICONW; const WCHAR wszDefaultShortcutIconNameAtRoot[] = ISHCUT_DEFAULT_FAVICONATROOTW; extern const LARGE_INTEGER c_li0 ; VOID GetIconUrlFromLinkTag( IHTMLDocument2* pHTMLDocument, BSTR *pbstrIconUrl ) { HRESULT hres; IHTMLLinkElement *pLink = NULL; hres = SearchForElementInHead(pHTMLDocument, OLESTR("REL"), OLESTR("SHORTCUT ICON"), IID_IHTMLLinkElement, (LPUNKNOWN *)&pLink); if(S_OK == hres) { hres = pLink->get_href(pbstrIconUrl); pLink->Release(); } } BOOL SetIconForShortcut( WCHAR *pwszIconUrl, INamedPropertyBag *pNamedBag ) { // Do it synchronously on this thread BOOL fRet = FALSE; WCHAR wszCacheFileName[MAX_PATH]; HRESULT hr; ASSERT(pNamedBag); hr = URLDownloadToCacheFileW(NULL, pwszIconUrl, wszCacheFileName, sizeof(wszCacheFileName), NULL, NULL); if(S_OK == hr) { // 77657 security bug: we must not call LoadImage because the Win9x version can // crash with buffer overrun if given a corrupt icon. ExtractIcon helps validate the file // to prevent that specific crash. HICON hIcon = ExtractIcon(g_hinst, wszCacheFileName, 0); if(hIcon) // It is really an Icon { // Make this icon sticky in cache SetUrlCacheEntryGroupW(pwszIconUrl, INTERNET_CACHE_GROUP_ADD, CACHEGROUP_ID_BUILTIN_STICKY, NULL, 0, NULL); DestroyIcon(hIcon); // get the file - set the icon and return fRet = TRUE; // We Got the icon file - even if we are unable set it // Store this url away in the shortcut file PROPSPEC rgpropspec[2]; PROPVARIANT rgpropvar[2]; PROPVARIANT var; LBSTR::CString strUrl; if ( pwszIconUrl ) { strUrl = pwszIconUrl; } else { strUrl.Empty(); } var.vt = VT_BSTR; var.bstrVal = strUrl; hr = pNamedBag->WritePropertyNPB(ISHCUT_INISTRING_SECTIONW, ISHCUT_INISTRING_ICONFILEW, &var); if ( S_OK == hr ) { LBSTR::CString strIndex; strIndex = L"1"; var.vt = VT_BSTR; var.bstrVal = strIndex; hr = pNamedBag->WritePropertyNPB(ISHCUT_INISTRING_SECTIONW, ISHCUT_INISTRING_ICONINDEXW, &var); } // Update the intsite database - whether or not the // shortcut file was updated. This is because we need to // ensure that the intsite db is updated even if the shortcut file name is not known IPropertySetStorage *ppropsetstg; IPropertyStorage *ppropstg; rgpropspec[0].ulKind = PRSPEC_PROPID; rgpropspec[0].propid = PID_INTSITE_ICONINDEX; rgpropspec[1].ulKind = PRSPEC_PROPID; rgpropspec[1].propid = PID_INTSITE_ICONFILE; rgpropvar[0].vt = VT_I4; rgpropvar[0].lVal = 1; rgpropvar[1].vt = VT_LPWSTR; rgpropvar[1].pwszVal = pwszIconUrl; hr = pNamedBag->QueryInterface(IID_IPropertySetStorage,(LPVOID *)&ppropsetstg); if(SUCCEEDED(hr)) { hr = ppropsetstg->Open(FMTID_InternetSite, STGM_READWRITE, &ppropstg); ppropsetstg->Release(); } if(SUCCEEDED(hr)) { hr = ppropstg->WriteMultiple(2, rgpropspec, rgpropvar, 0); ppropstg->Commit(STGC_DEFAULT); ppropstg->Release(); } } } return fRet; } HRESULT PreUpdateShortcutIcon(IUniformResourceLocatorW *purlW, LPTSTR pszHashItem, int* piIndex, UINT* puFlags, int* piImageIndex, LPWSTR *ppwszURL) { ASSERT(pszHashItem); ASSERT(piIndex); ASSERT(puFlags); ASSERT(piImageIndex); HRESULT hr; ASSERT(purlW); if(purlW) { hr = purlW->GetURL(ppwszURL); if(S_OK == hr) { hr = GetGenericURLIcon(pszHashItem, MAX_PATH, piIndex); if (SUCCEEDED(hr)) { SHFILEINFO fi = {0}; if (SHGetFileInfo(pszHashItem, 0, &fi, sizeof(SHFILEINFO), SHGFI_SYSICONINDEX)) { *piImageIndex = fi.iIcon; } else { *piImageIndex = -1; } } } } else { hr = E_INVALIDARG; } return hr; } DWORD DownloadAndSetIconForShortCutThreadProc( LPVOID pIn ) { HINSTANCE hShdocvw = LoadLibrary(TEXT("shdocvw.dll")); SHORTCUT_ICON_PARAMS *pParams = (SHORTCUT_ICON_PARAMS *)pIn; WCHAR *pwszShortcutFilePath = pParams->pwszFileName; WCHAR *pwszIconUrl = pParams->bstrIconUrl; WCHAR wszFullUrl[MAX_URL_STRING]; LPWSTR pwszBaseUrl = NULL; DWORD cchFullUrlSize = ARRAYSIZE(wszFullUrl); TCHAR szHash[MAX_PATH]; IPersistFile * ppf = NULL; BOOL fRet = FALSE; INT iImageIndex; INT iIconIndex; UINT uFlags = 0; HRESULT hr; IUniformResourceLocatorW *purlW = NULL; HRESULT hresCoInit = E_FAIL; hresCoInit = CoInitialize(NULL); ASSERT(hShdocvw); hr = CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER, IID_IUniformResourceLocatorW, (LPVOID *)&purlW); ASSERT(purlW); if((S_OK == hr) && purlW) { if(S_OK == hr) { if(pwszShortcutFilePath) { hr = purlW->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf); if(S_OK == hr) { ASSERT(ppf); hr = ppf->Load(pwszShortcutFilePath, STGM_READWRITE); } } else if(pParams->pwszShortcutUrl) { // Use the URL to init the shortcut hr = purlW->SetURL(pParams->pwszShortcutUrl, IURL_SETURL_FL_GUESS_PROTOCOL); } else { hr = E_FAIL; // Can't create an object and init it } } } if((S_OK == hr) && (purlW)) { hr = PreUpdateShortcutIcon(purlW, szHash, &iIconIndex, &uFlags, &iImageIndex, (LPWSTR *)&pwszBaseUrl); INamedPropertyBag *pNamedBag = NULL; hr = purlW->QueryInterface(IID_INamedPropertyBag,(LPVOID *)&pNamedBag); if((S_OK == hr) && (pNamedBag)) { if(pwszIconUrl) { WCHAR *pwszIconFullUrl; if(pwszBaseUrl) { hr = UrlCombineW(pwszBaseUrl, pwszIconUrl, wszFullUrl, &cchFullUrlSize, 0); ASSERT(S_OK == hr); if(SUCCEEDED(hr)) { pwszIconFullUrl = wszFullUrl; } } else { pwszIconFullUrl = pwszIconUrl; // try it as it is } fRet = SetIconForShortcut( pwszIconFullUrl, pNamedBag); } if((FALSE == fRet) && (pwszBaseUrl)) { hr = UrlCombineW(pwszBaseUrl, wszDefaultShortcutIconNameAtRoot, wszFullUrl, &cchFullUrlSize, 0); fRet = SetIconForShortcut(wszFullUrl, pNamedBag); } pNamedBag->Release(); } } if(fRet) { SHUpdateImage(szHash, iIconIndex, uFlags, iImageIndex); } if(ppf) { ppf->Save(NULL, FALSE); // Save off Icon related stuff ppf->Release(); } if(purlW) purlW->Release(); if(pParams) delete pParams; if(pwszBaseUrl) SHFree(pwszBaseUrl); if(SUCCEEDED(hresCoInit)) CoUninitialize(); //FreeLibraryAndExitThread(hShdocvw); -- Need a FreeLibraryAndExitThread for thread pools return fRet; } STDMETHODIMP Intshcut::_DoIconDownload() { SHORTCUT_ICON_PARAMS *pIconParams; BOOL fThreadStarted = FALSE; HRESULT hr = S_OK; pIconParams = new SHORTCUT_ICON_PARAMS; if(pIconParams) { if(_punkSite) { IServiceProvider *psp; hr = _punkSite->QueryInterface(IID_IServiceProvider, (LPVOID *)&psp); if(SUCCEEDED(hr)) { IWebBrowser2 *pwb=NULL; hr = psp->QueryService(SID_SHlinkFrame, IID_IWebBrowser2, (LPVOID *)&pwb); if(SUCCEEDED(hr)) { IDispatch *pdisp = NULL; ASSERT(pwb); hr = pwb->get_Document(&pdisp); if(pdisp) { IHTMLDocument2 *pHTMLDocument; ASSERT(SUCCEEDED(hr)); hr = pdisp->QueryInterface(IID_IHTMLDocument2, (void **)(&pHTMLDocument)); if(SUCCEEDED(hr)) { ASSERT(pHTMLDocument); GetIconUrlFromLinkTag(pHTMLDocument, &(pIconParams->bstrIconUrl)); pHTMLDocument->Release(); } pdisp->Release(); } pwb->Release(); } psp->Release(); } } if(m_pszFile) { pIconParams->pwszFileName = StrDupW(m_pszFile); } // Now fill in the URL of the shortcut hr = GetURLW(&(pIconParams->pwszShortcutUrl)); ASSERT(SUCCEEDED(hr)); if(S_OK == hr) { fThreadStarted = SHQueueUserWorkItem(DownloadAndSetIconForShortCutThreadProc, (LPVOID)(pIconParams), 0, (DWORD_PTR)NULL, (DWORD_PTR *)NULL, "shdocvw.dll", 0 ); } } if(FALSE == fThreadStarted) { if(pIconParams) { delete pIconParams; } } return fThreadStarted ? S_OK : E_FAIL; } STDMETHODIMP Intshcut::Exec( const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdexecopt, VARIANTARG *pvarargIn, VARIANTARG *pvarargOut ) { HRESULT hres = S_OK; if (pguidCmdGroup && IsEqualGUID(CGID_ShortCut, *pguidCmdGroup)) { switch(nCmdID) { case ISHCUTCMDID_DOWNLOADICON: { DWORD dwFlags = 0; BOOL fFetch = TRUE; WCHAR *pwszUrl; // Don't do it for FTP shortcuts if(SUCCEEDED(GetURLW(&pwszUrl))) { if((URL_SCHEME_FTP == GetUrlSchemeW(pwszUrl))) fFetch = FALSE; SHFree(pwszUrl); } if(fFetch && (InternetGetConnectedState(&dwFlags, 0))) hres = _DoIconDownload(); } break; default: break; } } return hres; }