windows-nt/Source/XPSP1/NT/shell/shdocvw/iscmdt.cpp
2020-09-26 16:20:57 +08:00

481 lines
12 KiB
C++

#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;
}