/* * urlprop.cpp - Implementation for URLProp class. */ #include "priv.h" #include // SHIsConsistentPidl #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); } /*---------------------------------------------------------- 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); // constrain the size to a ushort if (cb && !HIWORD(cb)) { // Create a IDLIST LPITEMIDLIST pidl = IEILCreate(cb); if (pidl) { hres = E_FAIL; // Read its contents if (GetPrivateProfileStruct(c_szIntshcut, TEXT("IDList"), (LPVOID)pidl, cb, pszFile)) { if (SHIsConsistentPidl(pidl, cb)) { *ppidl = pidl; hres = S_OK; } } if (FAILED(hres)) { ILFree(pidl); } } 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 }