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

2063 lines
48 KiB
C++

/*
* urlprop.cpp - Implementation for URLProp class.
*/
#include "priv.h"
#include "ishcut.h"
STDAPI_(LPITEMIDLIST) IEILCreate(UINT cbSize);
#define MAX_BUF_INT (1 + 10 + 1) // -2147483647
const TCHAR c_szIntshcut[] = ISHCUT_INISTRING_SECTION;
#ifdef DEBUG
BOOL IsValidPCURLProp(PCURLProp pcurlprop)
{
return (IS_VALID_READ_PTR(pcurlprop, CURLProp) &&
(NULL == pcurlprop->m_hstg ||
IS_VALID_HANDLE(pcurlprop->m_hstg, PROPSTG)));
}
BOOL IsValidPCIntshcutProp(PCIntshcutProp pcisprop)
{
return (IS_VALID_READ_PTR(pcisprop, CIntshcutProp) &&
IS_VALID_STRUCT_PTR(pcisprop, CURLProp));
}
BOOL IsValidPCIntsiteProp(PCIntsiteProp pcisprop)
{
return (IS_VALID_READ_PTR(pcisprop, CIntsiteProp) &&
IS_VALID_STRUCT_PTR(pcisprop, CURLProp));
}
#endif
BOOL AnyMeatW(LPCWSTR pcsz)
{
ASSERT(! pcsz || IS_VALID_STRING_PTRW(pcsz, -1));
return(pcsz ? StrSpnW(pcsz, L" \t") < lstrlenW(pcsz) : FALSE);
}
BOOL AnyMeatA(LPCSTR pcsz)
{
ASSERT(! pcsz || IS_VALID_STRING_PTRA(pcsz, -1));
return(pcsz ? StrSpnA(pcsz, " \t") < lstrlenA(pcsz) : FALSE);
}
/*----------------------------------------------------------
Purpose: Read an arbitrary named string from the .ini file.
Returns: S_OK if the name exists
S_FALSE if it doesn't
E_OUTOFMEMORY
*/
HRESULT ReadStringFromFile(IN LPCTSTR pszFile,
IN LPCTSTR pszSectionName,
IN LPCTSTR pszName,
OUT LPWSTR * ppwsz,
IN CHAR * pszBuf)
{
HRESULT hres = E_OUTOFMEMORY;
ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
ASSERT(IS_VALID_STRING_PTR(pszName, -1));
ASSERT(IS_VALID_WRITE_PTR(ppwsz, PWSTR));
*ppwsz = (LPWSTR)LocalAlloc(LPTR, SIZEOF(WCHAR) * INTERNET_MAX_URL_LENGTH);
if (*ppwsz)
{
DWORD cch;
hres = S_OK;
cch = SHGetIniString(pszSectionName, pszName,
*ppwsz, INTERNET_MAX_URL_LENGTH, pszFile);
if (0 == cch)
{
hres = S_FALSE;
LocalFree(*ppwsz);
*ppwsz = NULL;
}
}
return hres;
}
/*----------------------------------------------------------
Purpose: Read an arbitrary named string from the .ini file.
Return a BSTR
Returns: S_OK if the name exists
S_FALSE if it doesn't
E_OUTOFMEMORY
*/
HRESULT ReadBStrFromFile(IN LPCTSTR pszFile,
IN LPCTSTR pszSectionName,
IN LPCTSTR pszName,
OUT BSTR * pBStr)
{
CHAR szTempBuf[INTERNET_MAX_URL_LENGTH];
WCHAR *pwsz;
HRESULT hres = E_OUTOFMEMORY;
*pBStr = NULL;
ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
ASSERT(IS_VALID_STRING_PTR(pszName, -1));
ASSERT(IS_VALID_WRITE_PTR(pBStr, PWSTR));
// (Pass in an empty string so we can determine from the return
// value whether there is any text associated with this name.)
hres = ReadStringFromFile(pszFile, pszSectionName, pszName, &pwsz, szTempBuf);
if (S_OK == hres)
{
*pBStr = SysAllocString(pwsz);
LocalFree(pwsz);
pwsz = NULL;
}
return hres;
}
/*----------------------------------------------------------
Purpose: read an arbitrary named unsigend int from the .ini file. note in order to implement
ReadSignedFromFile one'll need to use ReadStringFromFile and then StrToIntEx. this is
because GetPrivateProfileInt can't return a negative.
Returns: S_OK if the name exists
S_FALSE if it doesn't
E_OUTOFMEMORY
*/
HRESULT
ReadUnsignedFromFile(
IN LPCTSTR pszFile,
IN LPCTSTR pszSectionName,
IN LPCTSTR pszName,
IN LPDWORD pdwVal)
{
HRESULT hr;
int iValue;
ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
ASSERT(IS_VALID_STRING_PTR(pszSectionName, -1));
ASSERT(IS_VALID_STRING_PTR(pszName, -1));
if (NULL == pdwVal)
return E_INVALIDARG;
*pdwVal = 0;
hr = S_OK;
iValue = GetPrivateProfileInt(pszSectionName, pszName, 1, pszFile);
if (1 == iValue) {
iValue = GetPrivateProfileInt(pszSectionName, pszName, 2, pszFile);
hr = (2 != iValue) ? S_OK : S_FALSE;
ASSERT(S_FALSE == hr || 1 == iValue);
}
if (S_OK == hr)
*pdwVal = (DWORD)iValue;
return hr;
}
/*----------------------------------------------------------
Purpose: Write number to URL (ini) file
*/
HRESULT WriteSignedToFile(IN LPCTSTR pszFile,
IN LPCTSTR pszSectionName,
IN LPCTSTR pszName,
IN int nVal)
{
HRESULT hres;
TCHAR szVal[MAX_BUF_INT];
int cch;
ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
ASSERT(IS_VALID_STRING_PTR(pszName, -1));
cch = wnsprintf(szVal, ARRAYSIZE(szVal), TEXT("%d"), nVal);
ASSERT(cch > 0);
ASSERT(cch < SIZECHARS(szVal));
ASSERT(cch == lstrlen(szVal));
hres = WritePrivateProfileString(pszSectionName, pszName, szVal,
pszFile) ? S_OK : E_FAIL;
return hres;
}
/*----------------------------------------------------------
Purpose: Write number to URL (ini) file
*/
HRESULT WriteUnsignedToFile(IN LPCTSTR pszFile,
IN LPCTSTR pszSectionName,
IN LPCTSTR pszName,
IN DWORD nVal)
{
HRESULT hres;
TCHAR szVal[MAX_BUF_INT];
int cch;
ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
ASSERT(IS_VALID_STRING_PTR(pszName, -1));
cch = wnsprintf(szVal, ARRAYSIZE(szVal), TEXT("%u"), nVal);
ASSERT(cch > 0);
ASSERT(cch < SIZECHARS(szVal));
ASSERT(cch == lstrlen(szVal));
hres = WritePrivateProfileString(pszSectionName, pszName, szVal,
pszFile) ? S_OK : E_FAIL;
return hres;
}
/*----------------------------------------------------------
Purpose: Write binary data to URL (ini) file
*/
HRESULT WriteBinaryToFile(IN LPCTSTR pszFile,
IN LPCTSTR pszSectionName,
IN LPCTSTR pszName,
IN LPVOID pvData,
IN DWORD cbSize)
{
HRESULT hres;
ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
ASSERT(IS_VALID_STRING_PTR(pszName, -1));
hres = (WritePrivateProfileStruct(pszSectionName, pszName, pvData, cbSize, pszFile))
? S_OK : E_FAIL;
return hres;
}
/*----------------------------------------------------------
Purpose: Read the hotkey from the URL (ini) file
*/
HRESULT ReadBinaryFromFile(IN LPCTSTR pszFile,
IN LPCTSTR pszSectionName,
IN LPCTSTR pszName,
IN LPVOID pvData,
IN DWORD cbData)
{
HRESULT hres = S_FALSE;
ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
memset(pvData, 0, cbData);
if (GetPrivateProfileStruct(pszSectionName, pszName, pvData, cbData, pszFile))
hres = S_OK;
return hres;
}
/*----------------------------------------------------------
Purpose: Real the URL from the URL (ini) file
*/
HRESULT
ReadURLFromFile(
IN LPCTSTR pszFile,
IN LPCTSTR pszSectionName,
OUT LPTSTR * ppsz)
{
HRESULT hres = E_OUTOFMEMORY;
*ppsz = (LPTSTR)LocalAlloc(LPTR, SIZEOF(TCHAR) * INTERNET_MAX_URL_LENGTH);
if (*ppsz)
{
DWORD cch;
cch = SHGetIniString(pszSectionName, ISHCUT_INISTRING_URL,
*ppsz, INTERNET_MAX_URL_LENGTH, pszFile);
if (0 != cch)
{
PathRemoveBlanks(*ppsz);
hres = S_OK;
}
else
{
LocalFree(*ppsz);
*ppsz = NULL;
hres = S_FALSE;
}
}
return hres;
}
/*----------------------------------------------------------
Purpose: Read the icon location from the URL (ini) file
Returns: S_OK value was obtained from file
S_FALSE value wasn't in file
E_OUTOFMEMORY
*/
HRESULT
ReadIconLocation(
IN LPCTSTR pszFile,
OUT LPWSTR * ppwsz,
OUT int * pniIcon,
IN CHAR * pszBuf)
{
HRESULT hres = E_OUTOFMEMORY;
DWORD cch;
ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
ASSERT(IS_VALID_WRITE_PTR(ppwsz, PTSTR));
ASSERT(IS_VALID_WRITE_PTR(pniIcon, INT));
*ppwsz = NULL;
*pniIcon = 0;
*ppwsz = (LPWSTR)LocalAlloc(LPTR, SIZEOF(WCHAR) * MAX_PATH);
if (*ppwsz)
{
hres = S_FALSE; // assume no value exists in the file
cch = SHGetIniString(c_szIntshcut,
ISHCUT_INISTRING_ICONFILE, *ppwsz,
MAX_PATH, pszFile);
if (0 != cch)
{
TCHAR szIndex[MAX_BUF_INT];
// The icon index is all ASCII so don't need SHGetIniString
cch = GetPrivateProfileString(c_szIntshcut,
ISHCUT_INISTRING_ICONINDEX, c_szNULL,
szIndex, SIZECHARS(szIndex),
pszFile);
if (0 != cch)
{
if (StrToIntEx(szIndex, 0, pniIcon))
hres = S_OK;
}
}
if (S_OK != hres)
{
LocalFree(*ppwsz);
*ppwsz = NULL;
}
}
return hres;
}
/*----------------------------------------------------------
Purpose: Write icon location to URL (ini) file
*/
HRESULT
WriteIconFile(
IN LPCTSTR pszFile,
IN LPCWSTR pszIconFile)
{
HRESULT hres = S_OK;
ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
ASSERT(! pszIconFile ||
IS_VALID_STRING_PTRW(pszIconFile, -1));
if (*pszFile)
{
if (AnyMeatW(pszIconFile))
{
hres = SHSetIniString(c_szIntshcut, ISHCUT_INISTRING_ICONFILE, pszIconFile,
pszFile) ? S_OK : E_FAIL;
}
else
{
// NOTE: since this function removes both the file and the index
// values, then this function must be called *after* any call
// to WriteIconIndex. One way to do this is make sure
// PID_IS_ICONINDEX < PID_IS_ICONFILE, since the index will
// be enumerated first.
hres = (SHDeleteIniString(c_szIntshcut, ISHCUT_INISTRING_ICONFILE,
pszFile) &&
DeletePrivateProfileString(c_szIntshcut, ISHCUT_INISTRING_ICONINDEX,
pszFile))
? S_OK : E_FAIL;
}
}
return hres;
}
/*----------------------------------------------------------
Purpose: Write icon index to URL (ini) file
*/
HRESULT
WriteIconIndex(
IN LPCTSTR pszFile,
IN int niIcon)
{
HRESULT hres;
if (*pszFile)
hres = WriteSignedToFile(pszFile, c_szIntshcut, ISHCUT_INISTRING_ICONINDEX, niIcon);
else
hres = S_FALSE;
return hres;
}
/*----------------------------------------------------------
Purpose: Read the hotkey from the URL (ini) file
*/
HRESULT
ReadHotkey(
IN LPCTSTR pszFile,
IN WORD * pwHotkey)
{
HRESULT hres = S_FALSE;
TCHAR szHotkey[MAX_BUF_INT];
DWORD cch;
ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
ASSERT(IS_VALID_WRITE_PTR(pwHotkey, WORD));
*pwHotkey = 0;
cch = GetPrivateProfileString(c_szIntshcut,
TEXT("Hotkey"), c_szNULL,
szHotkey, SIZECHARS(szHotkey),
pszFile);
if (0 != cch)
{
int nVal;
if (StrToIntEx(szHotkey, 0, &nVal))
{
*pwHotkey = nVal;
hres = S_OK;
}
}
return hres;
}
/*----------------------------------------------------------
Purpose: Write hotkey to URL (ini) file
*/
HRESULT
WriteHotkey(
IN LPCTSTR pszFile,
IN WORD wHotkey)
{
HRESULT hres = S_FALSE;
ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
if (*pszFile)
{
if (wHotkey)
{
hres = WriteUnsignedToFile(pszFile, c_szIntshcut, TEXT("Hotkey"), wHotkey);
}
else
{
hres = DeletePrivateProfileString(c_szIntshcut, TEXT("Hotkey"), pszFile)
? S_OK
: E_FAIL;
}
}
return hres;
}
/*----------------------------------------------------------
Purpose: Read the working directory from the URL (ini) file
*/
HRESULT
ReadWorkingDirectory(
IN LPCTSTR pszFile,
OUT LPWSTR * ppwsz)
{
HRESULT hres = E_OUTOFMEMORY;
TCHAR szPath[MAX_PATH];
DWORD cch;
ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
ASSERT(IS_VALID_WRITE_PTR(ppwsz, PWSTR));
*ppwsz = NULL;
*ppwsz = (LPWSTR)LocalAlloc(LPTR, SIZEOF(WCHAR) * MAX_PATH);
if (*ppwsz)
{
hres = S_FALSE;
cch = SHGetIniString(c_szIntshcut,
ISHCUT_INISTRING_WORKINGDIR,
szPath, SIZECHARS(szPath), pszFile);
if (0 != cch)
{
TCHAR szFullPath[MAX_PATH];
PTSTR pszFileName;
if (0 < GetFullPathName(szPath, SIZECHARS(szFullPath), szFullPath,
&pszFileName))
{
SHTCharToUnicode(szFullPath, *ppwsz, MAX_PATH);
hres = S_OK;
}
}
if (S_OK != hres)
{
LocalFree(*ppwsz);
*ppwsz = NULL;
}
}
return hres;
}
/*----------------------------------------------------------
Purpose: Write the working directory to the URL (ini) file.
*/
HRESULT
WriteGenericString(
IN LPCTSTR pszFile,
IN LPCTSTR pszSectionName,
IN LPCTSTR pszName,
IN LPCWSTR pwsz) OPTIONAL
{
HRESULT hres = S_FALSE;
ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
ASSERT(IS_VALID_STRING_PTR(pszName, -1));
ASSERT(! pwsz || IS_VALID_STRING_PTRW(pwsz, -1));
if (*pszFile)
{
if (AnyMeatW(pwsz))
{
hres = (SHSetIniString(pszSectionName, pszName, pwsz,
pszFile)) ? S_OK : E_FAIL;
}
else
{
hres = (SHDeleteIniString(pszSectionName, pszName, pszFile))
? S_OK : E_FAIL;
}
}
return hres;
}
/*----------------------------------------------------------
Purpose: Read the show-command flag from the URL (ini) file
*/
HRESULT
ReadShowCmd(
IN LPCTSTR pszFile,
OUT PINT pnShowCmd)
{
HRESULT hres = S_FALSE;
TCHAR szT[MAX_BUF_INT];
DWORD cch;
ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
ASSERT(IS_VALID_WRITE_PTR(pnShowCmd, INT));
*pnShowCmd = SW_NORMAL;
cch = GetPrivateProfileString(c_szIntshcut,
TEXT("ShowCommand"), c_szNULL, szT,
SIZECHARS(szT), pszFile);
if (0 != cch)
{
if (StrToIntEx(szT, 0, pnShowCmd))
{
hres = S_OK;
}
}
return hres;
}
/*----------------------------------------------------------
Purpose: Write showcmd to URL (ini) file
*/
HRESULT
WriteShowCmd(
IN LPCTSTR pszFile,
IN int nShowCmd)
{
HRESULT hres = S_FALSE;
ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
if (*pszFile)
{
if (SW_NORMAL != nShowCmd)
{
hres = WriteSignedToFile(pszFile, c_szIntshcut, TEXT("ShowCommand"), nShowCmd);
}
else
{
hres = DeletePrivateProfileString(c_szIntshcut, TEXT("ShowCommand"), pszFile)
? S_OK
: E_FAIL;
}
}
return hres;
}
/*----------------------------------------------------------
Purpose: Read the IDList from the URL (ini) file
*/
HRESULT
ReadIDList(
IN LPCTSTR pszFile,
OUT LPITEMIDLIST *ppidl)
{
HRESULT hres = S_FALSE;
ULONG cb;
ASSERT(ppidl);
// Delete the old one if any.
if (*ppidl)
{
ILFree(*ppidl);
*ppidl = NULL;
}
// Read the size of the IDLIST
cb = GetPrivateProfileInt(c_szIntshcut, TEXT("ILSize"), 0, pszFile);
if (cb)
{
// Create a IDLIST
LPITEMIDLIST pidl = IEILCreate(cb);
if (pidl)
{
// Read its contents
if (GetPrivateProfileStruct(c_szIntshcut, TEXT("IDList"), (LPVOID)pidl, cb, pszFile))
{
*ppidl = pidl;
hres = S_OK;
}
else
{
ILFree(pidl);
hres = E_FAIL;
}
}
else
{
hres = E_OUTOFMEMORY;
}
}
return hres;
}
HRESULT
WriteStream(
IN LPCTSTR pszFile,
IN IStream *pStream,
IN LPCTSTR pszStreamName,
IN LPCTSTR pszSizeName)
{
HRESULT hr = E_FAIL;
ULARGE_INTEGER li = {0};
if(pStream)
IStream_Size(pStream, &li);
if (li.LowPart)
{
ASSERT(!li.HighPart);
LPVOID pv = LocalAlloc(LPTR, li.LowPart);
if (pv && SUCCEEDED(hr = IStream_Read(pStream, pv, li.LowPart)))
{
// we have loaded the data properly, time to write it out
if (SUCCEEDED(hr = WriteUnsignedToFile(pszFile, c_szIntshcut, pszSizeName, li.LowPart)))
hr = WriteBinaryToFile(pszFile, c_szIntshcut, pszStreamName, pv, li.LowPart);
}
if (pv)
{
LocalFree(pv);
pv = NULL;
}
}
else
{
// delete the keys if
// 1. pStream is NULL, or
// 2. pStream in empty (cbPidl == 0).
if (DeletePrivateProfileString(c_szIntshcut, pszSizeName, pszFile) &&
DeletePrivateProfileString(c_szIntshcut, pszStreamName, pszFile))
{
hr = S_OK;
}
}
return hr;
}
/*----------------------------------------------------------
Purpose: Write IDList to URL (ini) file
*/
HRESULT
WriteIDList(
IN LPCTSTR pszFile,
IN IStream *pStream)
{
return WriteStream(pszFile, pStream, TEXT("IDList"), TEXT("ILSize"));
}
/********************************** Methods **********************************/
//==========================================================================================
// URLProp class implementation
//==========================================================================================
#ifdef DEBUG
/*----------------------------------------------------------
Purpose: Dump the properties in this object
*/
STDMETHODIMP_(void) URLProp::Dump(void)
{
if (IsFlagSet(g_dwDumpFlags, DF_URLPROP))
{
PropStg_Dump(m_hstg, 0);
}
}
#endif
/*----------------------------------------------------------
Purpose: Constructor for URLProp
*/
URLProp::URLProp(void) : m_cRef(1)
{
// Don't validate this until after construction.
m_hstg = NULL;
ASSERT(IS_VALID_STRUCT_PTR(this, CURLProp));
return;
}
/*----------------------------------------------------------
Purpose: Destructor for URLProp
*/
URLProp::~URLProp(void)
{
ASSERT(IS_VALID_STRUCT_PTR(this, CURLProp));
if (m_hstg)
{
PropStg_Destroy(m_hstg);
m_hstg = NULL;
}
ASSERT(IS_VALID_STRUCT_PTR(this, CURLProp));
return;
}
STDMETHODIMP_(ULONG) URLProp::AddRef()
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) URLProp::Release()
{
m_cRef--;
if (m_cRef > 0)
return m_cRef;
delete this;
return 0;
}
/*----------------------------------------------------------
Purpose: IUnknown::QueryInterface method for URLProp
*/
STDMETHODIMP URLProp::QueryInterface(REFIID riid, void **ppvObj)
{
if (IsEqualIID(riid, IID_IUnknown) ||
IsEqualIID(riid, IID_IPropertyStorage))
{
*ppvObj = SAFECAST(this, IPropertyStorage *);
}
else
{
*ppvObj = NULL;
return E_NOINTERFACE;
}
AddRef();
return NOERROR;
}
/*----------------------------------------------------------
Purpose: Initialize the object
Returns: S_OK
E_OUTOFMEMORY
*/
STDMETHODIMP URLProp::Init(void)
{
HRESULT hres = S_OK;
// Don't stomp on ourselves if this has already been initialized
if (NULL == m_hstg)
{
hres = PropStg_Create(&m_hstg, PSTGF_DEFAULT);
}
return hres;
}
/*----------------------------------------------------------
Purpose: Helper function that retrieves the string property
*/
STDMETHODIMP
URLProp::GetProp(
IN PROPID pid,
IN LPTSTR pszBuf,
IN int cchBuf)
{
HRESULT hres;
PROPSPEC propspec;
PROPVARIANT propvar;
ASSERT(pszBuf);
propspec.ulKind = PRSPEC_PROPID;
propspec.propid = pid;
*pszBuf = TEXT('\0');
hres = ReadMultiple(1, &propspec, &propvar);
if (SUCCEEDED(hres))
{
if (VT_LPWSTR == propvar.vt)
{
SHUnicodeToTChar(propvar.pwszVal, pszBuf, cchBuf);
hres = S_OK;
}
else
{
if (VT_EMPTY != propvar.vt && VT_ILLEGAL != propvar.vt)
TraceMsg(TF_WARNING, "URLProp::GetProp: expected propid %#lx to be VT_LPWSTR, but is %s", pid, Dbg_GetVTName(propvar.vt));
hres = S_FALSE;
}
PropVariantClear(&propvar);
}
return hres;
}
/*----------------------------------------------------------
Purpose: Helper function that retrieves the word property
*/
STDMETHODIMP
URLProp::GetProp(
IN PROPID pid,
IN int * piVal)
{
HRESULT hres;
PROPSPEC propspec;
PROPVARIANT propvar;
ASSERT(piVal);
propspec.ulKind = PRSPEC_PROPID;
propspec.propid = pid;
*piVal = 0;
hres = ReadMultiple(1, &propspec, &propvar);
if (SUCCEEDED(hres))
{
if (VT_I4 == propvar.vt)
{
*piVal = propvar.lVal;
hres = S_OK;
}
else
{
if (VT_EMPTY != propvar.vt && VT_ILLEGAL != propvar.vt)
TraceMsg(TF_WARNING, "URLProp::GetProp: expected propid %#lx to be VT_I4, but is %s", pid, Dbg_GetVTName(propvar.vt));
hres = S_FALSE;
}
PropVariantClear(&propvar);
}
return hres;
}
/*----------------------------------------------------------
Purpose: Helper function that retrieves the word property
*/
STDMETHODIMP
URLProp::GetProp(
IN PROPID pid,
IN LPDWORD pdwVal)
{
HRESULT hres;
PROPSPEC propspec;
PROPVARIANT propvar;
ASSERT(pdwVal);
propspec.ulKind = PRSPEC_PROPID;
propspec.propid = pid;
*pdwVal = 0;
hres = ReadMultiple(1, &propspec, &propvar);
if (SUCCEEDED(hres))
{
if (VT_UI4 == propvar.vt)
{
*pdwVal = propvar.ulVal;
hres = S_OK;
}
else
{
if (VT_EMPTY != propvar.vt && VT_ILLEGAL != propvar.vt)
TraceMsg(TF_WARNING, "URLProp::GetProp: expected propid %#lx to be VT_UI4, but is %s", pid, Dbg_GetVTName(propvar.vt));
hres = S_FALSE;
}
PropVariantClear(&propvar);
}
return hres;
}
/*----------------------------------------------------------
Purpose: Helper function that retrieves the word property
*/
STDMETHODIMP
URLProp::GetProp(
IN PROPID pid,
IN WORD * pwVal)
{
HRESULT hres;
PROPSPEC propspec;
PROPVARIANT propvar;
ASSERT(pwVal);
propspec.ulKind = PRSPEC_PROPID;
propspec.propid = pid;
*pwVal = 0;
hres = ReadMultiple(1, &propspec, &propvar);
if (SUCCEEDED(hres))
{
if (VT_UI2 == propvar.vt)
{
*pwVal = propvar.uiVal;
hres = S_OK;
}
else
{
if (VT_EMPTY != propvar.vt && VT_ILLEGAL != propvar.vt)
TraceMsg(TF_WARNING, "URLProp::GetProp: expected propid %#lx to be VT_UI2, but is %s", pid, Dbg_GetVTName(propvar.vt));
hres = S_FALSE;
}
PropVariantClear(&propvar);
}
return hres;
}
/*----------------------------------------------------------
Purpose: Helper function that retrieves the IStream property
*/
STDMETHODIMP
URLProp::GetProp(
IN PROPID pid,
IN IStream **ppStream)
{
HRESULT hres;
PROPSPEC propspec;
PROPVARIANT propvar;
ASSERT(ppStream);
propspec.ulKind = PRSPEC_PROPID;
propspec.propid = pid;
*ppStream = 0;
hres = ReadMultiple(1, &propspec, &propvar);
if (SUCCEEDED(hres))
{
if (VT_STREAM == propvar.vt)
{
*ppStream = propvar.pStream;
hres = S_OK;
}
else
{
if (VT_EMPTY != propvar.vt && VT_ILLEGAL != propvar.vt && propvar.lVal != 0)
TraceMsg(TF_WARNING, "URLProp::GetProp: expected propid %#lx to be VT_STREAM, but is %s", pid, Dbg_GetVTName(propvar.vt));
hres = S_FALSE;
}
// Do not PropVariantClear(&propvar), because it will call pStream->Release().
}
return hres;
}
/*----------------------------------------------------------
Purpose: Helper function that sets the string property
*/
STDMETHODIMP
URLProp::SetProp(
IN PROPID pid,
IN LPCTSTR psz) OPTIONAL
{
HRESULT hres;
PROPSPEC propspec;
PROPVARIANT propvar;
// WARNING:: this function gets called as part of ShellExecute which can be
// called by 16 bit apps so don't put mondo strings on stack...
WCHAR *pwsz = NULL;
propspec.ulKind = PRSPEC_PROPID;
propspec.propid = pid;
if (psz && *psz)
{
SHStrDup(psz, &pwsz);
propvar.vt = VT_LPWSTR;
propvar.pwszVal = pwsz;
}
else
propvar.vt = VT_EMPTY;
hres = WriteMultiple(1, &propspec, &propvar, 0);
if (pwsz)
CoTaskMemFree(pwsz);
return hres;
}
/*----------------------------------------------------------
Purpose: Helper function that sets the int property
*/
STDMETHODIMP
URLProp::SetProp(
IN PROPID pid,
IN int iVal)
{
PROPSPEC propspec;
PROPVARIANT propvar;
propspec.ulKind = PRSPEC_PROPID;
propspec.propid = pid;
propvar.vt = VT_I4;
propvar.lVal = iVal;
return WriteMultiple(1, &propspec, &propvar, 0);
}
/*----------------------------------------------------------
Purpose: Helper function that sets the dword property
*/
STDMETHODIMP
URLProp::SetProp(
IN PROPID pid,
IN DWORD dwVal)
{
HRESULT hres;
PROPSPEC propspec;
PROPVARIANT propvar;
propspec.ulKind = PRSPEC_PROPID;
propspec.propid = pid;
propvar.vt = VT_UI4;
propvar.ulVal = dwVal;
hres = WriteMultiple(1, &propspec, &propvar, 0);
return hres;
}
/*----------------------------------------------------------
Purpose: Helper function that sets the word property
*/
STDMETHODIMP
URLProp::SetProp(
IN PROPID pid,
IN WORD wVal)
{
HRESULT hres;
PROPSPEC propspec;
PROPVARIANT propvar;
propspec.ulKind = PRSPEC_PROPID;
propspec.propid = pid;
propvar.vt = VT_UI2;
propvar.uiVal = wVal;
hres = WriteMultiple(1, &propspec, &propvar, 0);
return hres;
}
/*----------------------------------------------------------
Purpose: Helper function that sets the IStream* property
*/
STDMETHODIMP
URLProp::SetProp(
IN PROPID pid,
IN IStream *pStream)
{
HRESULT hres;
PROPSPEC propspec;
PROPVARIANT propvar;
propspec.ulKind = PRSPEC_PROPID;
propspec.propid = pid;
propvar.vt = VT_STREAM;
propvar.pStream = pStream;
hres = WriteMultiple(1, &propspec, &propvar, 0);
return hres;
}
STDMETHODIMP URLProp::IsDirty(void)
{
return PropStg_IsDirty(m_hstg);
}
STDMETHODIMP URLProp::ReadMultiple(IN ULONG cpspec,
IN const PROPSPEC rgpropspec[],
IN PROPVARIANT rgpropvar[])
{
HRESULT hres = PropStg_ReadMultiple(m_hstg, cpspec, rgpropspec, rgpropvar);
if (SUCCEEDED(hres))
{
// Set the accessed time
SYSTEMTIME st;
GetSystemTime(&st);
SystemTimeToFileTime(&st, &m_ftAccessed);
}
return hres;
}
STDMETHODIMP URLProp::WriteMultiple(IN ULONG cpspec,
IN const PROPSPEC rgpropspec[],
IN const PROPVARIANT rgpropvar[],
IN PROPID propidFirst)
{
HRESULT hres = PropStg_WriteMultiple(m_hstg, cpspec, rgpropspec,
rgpropvar, propidFirst);
if (SUCCEEDED(hres))
{
// Set the modified time
SYSTEMTIME st;
GetSystemTime(&st);
SystemTimeToFileTime(&st, &m_ftModified);
}
return hres;
}
STDMETHODIMP URLProp::DeleteMultiple(ULONG cpspec, const PROPSPEC rgpropspec[])
{
return PropStg_DeleteMultiple(m_hstg, cpspec, rgpropspec);
}
STDMETHODIMP URLProp::ReadPropertyNames(ULONG cpropid, const PROPID rgpropid[], LPWSTR rgpwszName[])
{
return E_NOTIMPL;
}
STDMETHODIMP URLProp::WritePropertyNames(ULONG cpropid, const PROPID rgpropid[], const LPWSTR rgpwszName[])
{
return E_NOTIMPL;
}
/*----------------------------------------------------------
Purpose: IPropertyStorage::DeletePropertyNames method for URLProp
*/
STDMETHODIMP
URLProp::DeletePropertyNames(
IN ULONG cpropid,
IN const PROPID rgpropid[])
{
return E_NOTIMPL;
}
/*----------------------------------------------------------
Purpose: IPropertyStorage::SetClass method for URLProp
*/
STDMETHODIMP
URLProp::SetClass(
IN REFCLSID rclsid)
{
CopyMemory(&m_clsid, &rclsid, SIZEOF(m_clsid));
return S_OK;
}
/*----------------------------------------------------------
Purpose: IPropertyStorage::Commit method for URLProp
*/
STDMETHODIMP
URLProp::Commit(
IN DWORD dwFlags)
{
return E_NOTIMPL;
}
/*----------------------------------------------------------
Purpose: IPropertyStorage::Revert method for URLProp
*/
STDMETHODIMP URLProp::Revert(void)
{
#ifdef DEBUG
Dump();
#endif
return E_NOTIMPL;
}
/*----------------------------------------------------------
Purpose: IPropertyStorage::Enum method for URLProp
*/
STDMETHODIMP URLProp::Enum(IEnumSTATPROPSTG ** ppenum)
{
*ppenum = NULL;
return E_NOTIMPL;
}
/*----------------------------------------------------------
Purpose: IPropertyStorage::Stat method for URLProp
*/
STDMETHODIMP
URLProp::Stat(
IN STATPROPSETSTG * pstat)
{
HRESULT hres = STG_E_INVALIDPARAMETER;
if (IS_VALID_WRITE_PTR(pstat, STATPROPSETSTG))
{
pstat->fmtid = m_fmtid;
pstat->clsid = m_clsid;
pstat->grfFlags = m_grfFlags;
pstat->mtime = m_ftModified;
pstat->ctime = m_ftCreated;
pstat->atime = m_ftAccessed;
hres = S_OK;
}
return hres;
}
/*----------------------------------------------------------
Purpose: IPropertyStorage::SetTimes method for URLProp
*/
STDMETHODIMP
URLProp::SetTimes(
IN const FILETIME * pftModified, OPTIONAL
IN const FILETIME * pftCreated, OPTIONAL
IN const FILETIME * pftAccessed) OPTIONAL
{
HRESULT hres;
if (pftModified && !IS_VALID_READ_PTR(pftModified, FILETIME) ||
pftCreated && !IS_VALID_READ_PTR(pftCreated, FILETIME) ||
pftAccessed && !IS_VALID_READ_PTR(pftAccessed, FILETIME))
{
hres = STG_E_INVALIDPARAMETER;
}
else
{
if (pftModified)
m_ftModified = *pftModified;
if (pftCreated)
m_ftCreated = *pftCreated;
if (pftAccessed)
m_ftAccessed = *pftAccessed;
hres = S_OK;
}
return hres;
}
#ifdef DEBUG
STDMETHODIMP_(void) IntshcutProp::Dump(void)
{
if (IsFlagSet(g_dwDumpFlags, DF_URLPROP))
{
TraceMsg(TF_ALWAYS, " IntshcutProp obj: %s", m_szFile);
URLProp::Dump();
}
}
#endif
IntshcutProp::IntshcutProp(void)
{
// Don't validate this until after construction.
*m_szFile = 0;
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcutProp));
}
IntshcutProp::~IntshcutProp(void)
{
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcutProp));
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcutProp));
}
// (These are not related to PID_IS_*)
#define IPROP_ICONINDEX 0
#define IPROP_ICONFILE 1
#define IPROP_HOTKEY 2
#define IPROP_WORKINGDIR 3
#define IPROP_SHOWCMD 4
#define IPROP_WHATSNEW 5
#define IPROP_AUTHOR 6
#define IPROP_DESC 7
#define IPROP_COMMENT 8
#define IPROP_URL 9 // these two must be the last
#define IPROP_SCHEME 10 // in this list. See LoadFromFile.
#define CPROP_INTSHCUT 11 // Count of properties
// (we don't write the URL or the scheme in the massive write sweep)
#define CPROP_INTSHCUT_WRITE (CPROP_INTSHCUT - 2)
/*----------------------------------------------------------
Purpose: Load the basic property info like URL.
Returns:
Cond: --
*/
STDMETHODIMP IntshcutProp::LoadFromFile(LPCTSTR pszFile)
{
HRESULT hres;
LPWSTR pwszBuf;
LPTSTR pszBuf;
CHAR *pszTempBuf;
static const PROPSPEC rgpropspec[CPROP_INTSHCUT] =
{
// This must be initialized in the same order as how the
// IPROP_* values were defined.
{ PRSPEC_PROPID, PID_IS_ICONINDEX },
{ PRSPEC_PROPID, PID_IS_ICONFILE },
{ PRSPEC_PROPID, PID_IS_HOTKEY },
{ PRSPEC_PROPID, PID_IS_WORKINGDIR },
{ PRSPEC_PROPID, PID_IS_SHOWCMD },
{ PRSPEC_PROPID, PID_IS_WHATSNEW },
{ PRSPEC_PROPID, PID_IS_AUTHOR },
{ PRSPEC_PROPID, PID_IS_DESCRIPTION },
{ PRSPEC_PROPID, PID_IS_COMMENT },
{ PRSPEC_PROPID, PID_IS_URL },
{ PRSPEC_PROPID, PID_IS_SCHEME },
};
PROPVARIANT rgpropvar[CPROP_INTSHCUT] = { 0 };
ASSERT(pszFile);
// try to allocate a temporary buffer, don't put on stack as this may be called
// by 16 bit apps through the shellexecute thunk
pszTempBuf = (CHAR*)LocalAlloc(LMEM_FIXED, INTERNET_MAX_URL_LENGTH * sizeof(CHAR));
if (!pszTempBuf)
return E_OUTOFMEMORY;
if (!g_fRunningOnNT)
{
// Flush the cache first to encourage Win95 kernel to zero-out
// its buffer. Kernel GP-faults with hundreds of writes made to
// ini files.
WritePrivateProfileString(NULL, NULL, NULL, pszFile);
}
// Get the URL
hres = ReadURLFromFile(pszFile, c_szIntshcut, &pszBuf);
if (S_OK == hres)
{
// Call this method because it does more work before
// setting the property
SetURLProp(pszBuf, (IURL_SETURL_FL_GUESS_PROTOCOL | IURL_SETURL_FL_USE_DEFAULT_PROTOCOL));
LocalFree(pszBuf);
pszBuf = NULL;
}
// Get the IDList
LPITEMIDLIST pidl = NULL;
hres = ReadIDList(pszFile, &pidl);
if (S_OK == hres)
{
// Call this method because it does more work before
// setting the property
SetIDListProp(pidl);
ILFree(pidl);
}
#ifndef UNIX
// Get icon location
int nVal;
hres = ReadIconLocation(pszFile, &pwszBuf, &nVal, pszTempBuf);
if (S_OK == hres)
{
rgpropvar[IPROP_ICONFILE].vt = VT_LPWSTR;
rgpropvar[IPROP_ICONFILE].pwszVal = pwszBuf;
rgpropvar[IPROP_ICONINDEX].vt = VT_I4;
rgpropvar[IPROP_ICONINDEX].lVal = nVal;
}
// Get the hotkey
WORD wHotkey;
hres = ReadHotkey(pszFile, &wHotkey);
if (S_OK == hres)
{
rgpropvar[IPROP_HOTKEY].vt = VT_UI2;
rgpropvar[IPROP_HOTKEY].uiVal = wHotkey;
}
// Get the working directory
hres = ReadWorkingDirectory(pszFile, &pwszBuf);
if (S_OK == hres)
{
rgpropvar[IPROP_WORKINGDIR].vt = VT_LPWSTR;
rgpropvar[IPROP_WORKINGDIR].pwszVal = pwszBuf;
}
// Get the showcmd flag
hres = ReadShowCmd(pszFile, &nVal);
rgpropvar[IPROP_SHOWCMD].vt = VT_I4;
if (S_OK == hres)
rgpropvar[IPROP_SHOWCMD].lVal = nVal;
else
rgpropvar[IPROP_SHOWCMD].lVal = SW_NORMAL;
// Get the What's New bulletin
hres = ReadStringFromFile(pszFile, c_szIntshcut, ISHCUT_INISTRING_WHATSNEW, &pwszBuf, pszTempBuf);
if (S_OK == hres)
{
rgpropvar[IPROP_WHATSNEW].vt = VT_LPWSTR;
rgpropvar[IPROP_WHATSNEW].pwszVal = pwszBuf;
}
// Get the Author
hres = ReadStringFromFile(pszFile, c_szIntshcut, ISHCUT_INISTRING_AUTHOR, &pwszBuf, pszTempBuf);
if (S_OK == hres)
{
rgpropvar[IPROP_AUTHOR].vt = VT_LPWSTR;
rgpropvar[IPROP_AUTHOR].pwszVal = pwszBuf;
}
// Get the Description
hres = ReadStringFromFile(pszFile, c_szIntshcut, ISHCUT_INISTRING_DESC, &pwszBuf, pszTempBuf);
if (S_OK == hres)
{
rgpropvar[IPROP_DESC].vt = VT_LPWSTR;
rgpropvar[IPROP_DESC].pwszVal = pwszBuf;
}
// Get the Comment
hres = ReadStringFromFile(pszFile, c_szIntshcut, ISHCUT_INISTRING_COMMENT, &pwszBuf, pszTempBuf);
if (S_OK == hres)
{
rgpropvar[IPROP_COMMENT].vt = VT_LPWSTR;
rgpropvar[IPROP_COMMENT].pwszVal = pwszBuf;
}
#endif /* !UNIX */
// Write it all out to our in-memory storage. Note we're using
// CPROP_INTSHCUT_WRITE, which should be the size of the array minus the
// url and scheme propids, since they were written separately
// above.
hres = WriteMultiple(CPROP_INTSHCUT_WRITE, (PROPSPEC *)rgpropspec, rgpropvar, 0);
if (SUCCEEDED(hres))
{
// Unmark *all* these properties, since we're initializing from
// the file
PropStg_DirtyMultiple(m_hstg, ARRAYSIZE(rgpropspec), rgpropspec, FALSE);
}
// Get the times. We don't support the Accessed time for internet
// shortcuts updating this field would cause the shortcut to be
// constantly written to disk to record the Accessed time simply
// when a property is read. A huge perf hit!
ZeroMemory(&m_ftAccessed, sizeof(m_ftAccessed));
DWORD cbData = SIZEOF(m_ftModified);
ReadBinaryFromFile(pszFile, c_szIntshcut, ISHCUT_INISTRING_MODIFIED, &m_ftModified, cbData);
// Free up the buffers that we allocated
int cprops;
PROPVARIANT * ppropvar;
for (cprops = ARRAYSIZE(rgpropvar), ppropvar = rgpropvar; 0 < cprops; cprops--)
{
if (VT_LPWSTR == ppropvar->vt)
{
ASSERT(ppropvar->pwszVal);
LocalFree(ppropvar->pwszVal);
ppropvar->pwszVal = NULL;
}
ppropvar++;
}
LocalFree((HLOCAL)pszTempBuf);
pszTempBuf = NULL;
return hres;
}
STDMETHODIMP IntshcutProp::Init(void)
{
return URLProp::Init();
}
STDMETHODIMP IntshcutProp::InitFromFile(LPCTSTR pszFile)
{
// Initialize the in-memory property storage from the file
// and database
HRESULT hres = Init();
if (SUCCEEDED(hres) && pszFile)
{
StrCpyN(m_szFile, pszFile, SIZECHARS(m_szFile));
hres = LoadFromFile(m_szFile);
}
else
m_szFile[0] = 0;
return hres;
}
typedef struct
{
LPTSTR pszFile;
} COMMITISDATA;
/*----------------------------------------------------------
Purpose: Commit the values for any known properties to the file
Note this callback is called only for dirty values.
Returns: S_OK if alright
S_FALSE to skip this value
error to stop
*/
STDAPI CommitISProp(
IN PROPID propid,
IN PROPVARIANT * ppropvar,
IN LPARAM lParam)
{
HRESULT hres = S_OK;
COMMITISDATA * pcd = (COMMITISDATA *)lParam;
ASSERT(ppropvar);
ASSERT(pcd);
LPWSTR pwsz;
USHORT uiVal;
LONG lVal;
IStream *pStream;
switch (propid)
{
case PID_IS_URL:
case PID_IS_ICONFILE:
case PID_IS_WORKINGDIR:
case PID_IS_WHATSNEW:
case PID_IS_AUTHOR:
case PID_IS_DESCRIPTION:
case PID_IS_COMMENT:
if (VT_LPWSTR == ppropvar->vt)
pwsz = ppropvar->pwszVal;
else
pwsz = NULL;
switch (propid)
{
case PID_IS_URL:
hres = WriteGenericString(pcd->pszFile, c_szIntshcut, ISHCUT_INISTRING_URL, pwsz);
break;
case PID_IS_ICONFILE:
hres = WriteIconFile(pcd->pszFile, pwsz);
break;
case PID_IS_WORKINGDIR:
hres = WriteGenericString(pcd->pszFile, c_szIntshcut, ISHCUT_INISTRING_WORKINGDIR, pwsz);
break;
case PID_IS_WHATSNEW:
hres = WriteGenericString(pcd->pszFile, c_szIntshcut, ISHCUT_INISTRING_WHATSNEW, pwsz);
break;
case PID_IS_AUTHOR:
hres = WriteGenericString(pcd->pszFile, c_szIntshcut, ISHCUT_INISTRING_AUTHOR, pwsz);
break;
case PID_IS_DESCRIPTION:
hres = WriteGenericString(pcd->pszFile, c_szIntshcut, ISHCUT_INISTRING_DESC, pwsz);
break;
case PID_IS_COMMENT:
hres = WriteGenericString(pcd->pszFile, c_szIntshcut, ISHCUT_INISTRING_COMMENT, pwsz);
break;
default:
ASSERT(0); // should never get here
break;
}
break;
case PID_IS_ICONINDEX:
if (VT_I4 == ppropvar->vt)
hres = WriteIconIndex(pcd->pszFile, ppropvar->lVal);
break;
case PID_IS_HOTKEY:
if (VT_UI2 == ppropvar->vt)
uiVal = ppropvar->uiVal;
else
uiVal = 0;
hres = WriteHotkey(pcd->pszFile, uiVal);
break;
case PID_IS_SHOWCMD:
if (VT_I4 == ppropvar->vt)
lVal = ppropvar->lVal;
else
lVal = SW_NORMAL;
hres = WriteShowCmd(pcd->pszFile, lVal);
break;
case PID_IS_SCHEME:
// Don't write this one out
break;
case PID_IS_IDLIST:
if (VT_STREAM == ppropvar->vt)
pStream = ppropvar->pStream;
else
pStream = NULL;
hres = WriteIDList(pcd->pszFile, pStream);
break;
default:
TraceMsg(TF_WARNING, "Don't know how to commit url property (%#lx)", propid);
ASSERT(0);
break;
}
#ifdef DEBUG
if (FAILED(hres))
TraceMsg(TF_WARNING, "Failed to save url property (%#lx) to file %s", propid, pcd->pszFile);
#endif
return hres;
}
/*----------------------------------------------------------
Purpose: IPropertyStorage::Commit method for URLProp
*/
STDMETHODIMP
IntshcutProp::Commit(
IN DWORD dwFlags)
{
HRESULT hres;
COMMITISDATA cd;
TraceMsg(TF_INTSHCUT, "Writing properties to \"%s\"", m_szFile);
cd.pszFile = m_szFile;
// Enumerate thru the dirty property values that get saved to the
// file
hres = PropStg_Enum(m_hstg, PSTGEF_DIRTY, CommitISProp, (LPARAM)&cd);
if (SUCCEEDED(hres))
{
// Now mark everything clean
PropStg_DirtyAll(m_hstg, FALSE);
// Save the times. Don't write out the Accessed time for perf.
// See LoadFromFile.
EVAL(SUCCEEDED(WriteBinaryToFile(m_szFile, c_szIntshcut, ISHCUT_INISTRING_MODIFIED, &m_ftModified,
SIZEOF(m_ftModified))));
}
#ifdef DEBUG
Dump();
#endif
return hres;
}
/*----------------------------------------------------------
Purpose: Helper function to set the file name.
*/
STDMETHODIMP
IntshcutProp::SetFileName(
IN LPCTSTR pszFile)
{
if(pszFile)
{
ASSERT(IS_VALID_STRING_PTR(pszFile, -1));
StrCpyN(m_szFile, pszFile, SIZECHARS(m_szFile));
}
else
{
*m_szFile = TEXT('\0');;
}
return S_OK;
}
/*----------------------------------------------------------
Purpose: Helper function that sets the URL.
*/
STDMETHODIMP
IntshcutProp::SetIDListProp(
LPCITEMIDLIST pcidl)
{
HRESULT hres;
IStream *pstmPidl;
if (pcidl)
{
// ???
// PERF: This loads OLE. Is this OK?
hres = CreateStreamOnHGlobal(NULL, TRUE, &pstmPidl);
if (SUCCEEDED(hres))
{
hres = ILSaveToStream(pstmPidl, pcidl);
if (SUCCEEDED(hres))
hres = SetProp(PID_IS_IDLIST, pstmPidl);
pstmPidl->Release();
}
}
else
{
hres = SetProp(PID_IS_IDLIST, NULL);
}
return hres;
}
/*----------------------------------------------------------
Purpose: Helper function that sets the URL. This function
optionally canonicalizes the string as well.
*/
STDMETHODIMP
IntshcutProp::SetURLProp(
IN LPCTSTR pszURL, OPTIONAL
IN DWORD dwFlags)
{
HRESULT hres;
// Warning this function can be called as part of shellexecute which can be
// thunked up to by a 16 bit app, so be carefull what you put on stack...
BOOL bChanged;
struct tbufs
{
TCHAR szUrl[INTERNET_MAX_URL_LENGTH];
TCHAR szUrlT[INTERNET_MAX_URL_LENGTH];
};
struct tbufs *ptbufs;
ptbufs = (struct tbufs *)LocalAlloc(LMEM_FIXED, sizeof(struct tbufs));
if (!ptbufs)
return E_OUTOFMEMORY;
hres = GetProp(PID_IS_URL, ptbufs->szUrl, INTERNET_MAX_URL_LENGTH);
bChanged = !(( !pszURL && S_OK != hres) ||
(pszURL && S_OK == hres && 0 == StrCmp(pszURL, ptbufs->szUrl)));
hres = S_OK;
if (bChanged)
{
if (NULL == pszURL)
{
hres = SetProp(PID_IS_URL, pszURL);
if (S_OK == hres)
hres = SetProp(PID_IS_SCHEME, URL_SCHEME_UNKNOWN);
}
else
{
DWORD dwFlagsT = UQF_CANONICALIZE;
// Translate the URL
if (IsFlagSet(dwFlags, IURL_SETURL_FL_GUESS_PROTOCOL))
SetFlag(dwFlagsT, UQF_GUESS_PROTOCOL);
if (IsFlagSet(dwFlags, IURL_SETURL_FL_USE_DEFAULT_PROTOCOL))
SetFlag(dwFlagsT, UQF_USE_DEFAULT_PROTOCOL);
// Translate the URL
hres = IURLQualify(pszURL, dwFlagsT, ptbufs->szUrlT, NULL, NULL);
if (SUCCEEDED(hres))
{
// Is the URL different after being translated?
bChanged = (0 != StrCmp(ptbufs->szUrlT, ptbufs->szUrl));
hres = S_OK;
if (bChanged)
{
// Yes; validate and get the scheme
PARSEDURL pu;
pu.cbSize = SIZEOF(pu);
hres = ParseURL(ptbufs->szUrlT, &pu);
if (S_OK == hres)
hres = SetProp(PID_IS_URL, ptbufs->szUrlT);
if (S_OK == hres)
hres = SetProp(PID_IS_SCHEME, (DWORD)pu.nScheme);
}
}
}
}
LocalFree((HLOCAL)ptbufs);
ptbufs = NULL;
return hres;
}
/*----------------------------------------------------------
Purpose: Helper function that sets the string property
*/
STDMETHODIMP
IntshcutProp::SetProp(
IN PROPID pid,
IN LPCTSTR psz) OPTIONAL
{
HRESULT hr;
// WARNING:: this function gets called as part of ShellExecute which can be
// called by 16 bit apps so don't put mondo strings on stack...
LPCWSTR pszUrl = psz;
LPWSTR pszTemp = NULL;
// For URLs, we need to check for security spoofs
if (PID_IS_URL == pid && psz && IsSpecialUrl((LPWSTR)psz)) //FEATURE: remove cast
{
SHStrDup(psz, &pszTemp);
if (NULL != pszTemp)
{
// Unescape the url and look for a security context delimitor
hr = WrapSpecialUrlFlat(pszTemp, lstrlen(pszTemp)+1);
if (E_ACCESSDENIED == hr)
{
// Security delimitor found, so wack it off
SHRemoveURLTurd(pszTemp);
pszUrl = pszTemp;
}
}
else
{
return E_OUTOFMEMORY;
}
}
hr = super::SetProp(pid, pszUrl);
if (pszTemp)
{
CoTaskMemFree(pszTemp);
}
return hr;
}
STDAPI CIntshcutProp_CreateInstance(IUnknown *punkOuter, REFIID riid, void **ppvOut)
{
HRESULT hres;
*ppvOut = NULL;
if (punkOuter)
{
// No
hres = CLASS_E_NOAGGREGATION;
}
else
{
IUnknown * piunk = (IUnknown *)(IPropertyStorage *)new IntshcutProp;
if ( !piunk )
{
hres = E_OUTOFMEMORY;
}
else
{
hres = piunk->QueryInterface(riid, ppvOut);
piunk->Release();
}
}
return hres; // S_OK or E_NOINTERFACE
}