480 lines
12 KiB
C++
480 lines
12 KiB
C++
#include "priv.h"
|
|
#include "ishcut.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;
|
|
}
|