|
|
/*
* isurl.cpp - IUniformResourceLocator implementation for Intshcut class. */ #include "priv.h"
#include "ishcut.h"
#include "urlprop.h"
#include "shlwapi.h"
#include "infotip.h"
#include "resource.h"
#include <intshctp.h>
#include <mluisupp.h>
#define DM_PLUGGABLE DM_TRACE
#define DM_SHELLEXECOBJECT 0x80000000
extern HRESULT CreateTargetFrame(LPCOLESTR pszTargetName, LPUNKNOWN /*IN,OUT*/ *ppunk);
BOOL GetClassDefaultVerb( LPCTSTR pcszClass, LPTSTR pszDefaultVerbBuf, UINT cchBufLen) { // No; get the default verb
TCHAR szKey[MAX_PATH];
StrCpyN(szKey, pcszClass, SIZECHARS(szKey)); StrCatBuff(szKey, TEXT("\\"), SIZECHARS(szKey)); StrCatBuff(szKey, TEXT("shell"), SIZECHARS(szKey)); DWORD cbSize = CbFromCch(cchBufLen);
if (NO_ERROR != SHGetValue(HKEY_CLASSES_ROOT, szKey, NULL, NULL, pszDefaultVerbBuf, &cbSize) || !*pszDefaultVerbBuf) { // Default to "open" if the registry doesn't specify one
StrCpyN(pszDefaultVerbBuf, TEXT("open"), cchBufLen); }
return TRUE; }
#ifdef DEBUG
BOOL IsValidPCURLINVOKECOMMANDINFO( PCURLINVOKECOMMANDINFO pcurlici) { return(IS_VALID_READ_PTR(pcurlici, CURLINVOKECOMMANDINFO) && EVAL(pcurlici->dwcbSize >= SIZEOF(*pcurlici)) && FLAGS_ARE_VALID(pcurlici->dwFlags, ALL_IURL_INVOKECOMMAND_FLAGS) && (IsFlagClear(pcurlici->dwFlags, IURL_INVOKECOMMAND_FL_ALLOW_UI) || NULL == pcurlici->hwndParent || IS_VALID_HANDLE(pcurlici->hwndParent, WND)) && (IsFlagSet(pcurlici->dwFlags, IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB) || IS_VALID_STRING_PTR(pcurlici->pcszVerb, -1))); }
#endif
/********************************** Methods **********************************/
typedef struct { UINT idsVerb; UINT idsMenuHelp; LPCTSTR pszVerb; } ISCM;
const static ISCM g_rgiscm[] = { { IDS_MENUOPEN, IDS_MH_OPEN, TEXT("open") }, // IDCMD_ISCM_OPEN
{ IDS_SYNCHRONIZE, IDS_MH_SYNCHRONIZE, TEXT("update now")}, // IDCMD_ISCM_SYNC
{ IDS_MAKE_OFFLINE, IDS_MH_MAKE_OFFLINE, TEXT("subscribe")}, // IDCMD_ISCM_SUB
};
// WARNING - these must match their index into g_rgiscm
#define IDCMD_ISCM_OPEN 0
#define IDCMD_ISCM_SYNC 1
#define IDCMD_ISCM_SUB 2
BOOL _IsSubscribed(LPCWSTR pszUrl, BOOL *pfSubscribable) { BOOL fRet = FALSE; ISubscriptionMgr * pMgr; *pfSubscribable = FALSE; if (SUCCEEDED(CoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(ISubscriptionMgr, &pMgr)))) { pMgr->IsSubscribed(pszUrl, &fRet);
pMgr->Release(); }
if (!fRet) { //test if we CAN subscribe to this thing
if (!SHRestricted2W(REST_NoAddingSubscriptions, pszUrl, 0) && IsFeaturePotentiallyAvailable(CLSID_SubscriptionMgr)) { *pfSubscribable = IsSubscribableW(pszUrl); } } else *pfSubscribable = TRUE; return fRet; }
void _InsertISCM(UINT indexISCM, HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT uFlags) { TCHAR szMenu[CCH_MENUMAX]; uFlags |= MF_BYPOSITION | MF_STRING;
MLLoadShellLangString(g_rgiscm[indexISCM].idsVerb, szMenu, SIZECHARS(szMenu)); InsertMenu_PrivateNoMungeW(hmenu, indexMenu, uFlags, idCmdFirst + indexISCM, szMenu); }
// IContextMenu::QueryContextMenu handler for Intshcut
// The context menu handler adds the open verb for .url
// files. This is because we remove the shell\open\command
// key in Nashville for this file type.
STDMETHODIMP Intshcut::QueryContextMenu( IN HMENU hmenu, IN UINT indexMenu, IN UINT idCmdFirst, IN UINT idCmdLast, IN UINT uFlags) { //
// LEGACY - .URL files have to maintain an open verb in the registry - ZekeL - 14-APR-99
// we would like to just use the "open" verb here in the context menu extension,
// but we need to not duplicate the open verb that is added by DefCM
// on NT5+ shell32 we disable that verb so we can add it here.
// on earlier shell32 we want to add "open" any time we arent
// initialized by DefCM. if we think that DefCM added us,
// then we go ahead and allow the DefCM's open from the registry.
//
if (!m_fProbablyDefCM || GetUIVersion() >= 5) { _InsertISCM(IDCMD_ISCM_OPEN, hmenu, indexMenu, idCmdFirst, 0); if (-1 == GetMenuDefaultItem(hmenu, MF_BYCOMMAND, 0)) SetMenuDefaultItem(hmenu, indexMenu, MF_BYPOSITION); indexMenu++; }
#ifndef UNIX
/* v-sriran: 12/8/97
* disabling the context menu item for subscribe, separators etc. * because we are not supporting subscriptions right now */
// skip this if we only want default or if there is no room for more.
if (!(uFlags & CMF_DEFAULTONLY) && (idCmdLast - idCmdFirst >= ARRAYSIZE(g_rgiscm))) { WCHAR *pwszURL; if (SUCCEEDED(GetURLW(&pwszURL))) { BOOL bSubscribable = FALSE; //can be subscribed to
BOOL bSub = _IsSubscribed(pwszURL, &bSubscribable); m_bCheckForDelete = bSub && m_pszFile;
if (bSubscribable || bSub) { // add a separator for our subscription stuff
InsertMenu(hmenu, indexMenu++, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); UINT uMenuFlags = 0;
if (bSub) { uMenuFlags |= MF_CHECKED;
if (SHRestricted2W(REST_NoRemovingSubscriptions, pwszURL, 0)) { uMenuFlags |= MF_GRAYED; } }
_InsertISCM(IDCMD_ISCM_SUB, hmenu, indexMenu++, idCmdFirst, uMenuFlags);
if (bSub) { uMenuFlags = 0;
if (SHRestricted2W(REST_NoManualUpdates, NULL, 0)) { uMenuFlags |= MF_GRAYED; } _InsertISCM(IDCMD_ISCM_SYNC, hmenu, indexMenu++, idCmdFirst, uMenuFlags); } } SHFree(pwszURL); } }
#endif /* UNIX */
return ResultFromShort(ARRAYSIZE(g_rgiscm)); }
STDMETHODIMP Intshcut::InvokeCommand(IN LPCMINVOKECOMMANDINFO pici) { HRESULT hres = E_INVALIDARG;
ASSERT(pici);
if (pici && SIZEOF(*pici) <= pici->cbSize) { UINT idCmd;
if (0 == HIWORD(pici->lpVerb)) // Is the ID cmd given?
{ idCmd = LOWORD(pici->lpVerb); // Yes
// Old versions of ShellExec() didnt get the right default command - Zekel - 15-MAR-99
// since our QCM implementation doesnt add anything to the menu
// if we fix the QCM to work correctly, then this problem will go away.
// it sent 0xfffe instead. so just adjust here.
if (idCmd == 0xfffe && GetUIVersion() <= 4) idCmd = IDCMD_ISCM_OPEN; } else { // No; a language-independent verb was supplied
int i; LPCTSTR pszVerb; LPCMINVOKECOMMANDINFOEX piciex = (LPCMINVOKECOMMANDINFOEX)pici; ASSERT(SIZEOF(*piciex) <= piciex->cbSize);
WCHAR szVerb[40];
if (piciex->lpVerbW) { pszVerb = piciex->lpVerbW; } else { if (piciex->lpVerb) { ASSERT(lstrlenA(piciex->lpVerb) < ARRAYSIZE(szVerb)); SHAnsiToUnicode(piciex->lpVerb, szVerb, ARRAYSIZE(szVerb)); } else { szVerb[0] = L'\0'; } pszVerb = szVerb; }
idCmd = (UINT)-1; for (i = 0; i < ARRAYSIZE(g_rgiscm); i++) { if (0 == StrCmpI(g_rgiscm[i].pszVerb, pszVerb)) { idCmd = i; break; } } }
switch (idCmd) { case IDCMD_ISCM_OPEN: { URLINVOKECOMMANDINFO urlici;
urlici.dwcbSize = SIZEOF(urlici); urlici.hwndParent = pici->hwnd; urlici.pcszVerb = NULL; urlici.dwFlags = IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB;
if (IsFlagClear(pici->fMask, CMIC_MASK_FLAG_NO_UI)) { SetFlag(urlici.dwFlags, IURL_INVOKECOMMAND_FL_ALLOW_UI); } if (IsFlagSet(pici->fMask, SEE_MASK_FLAG_DDEWAIT)) { SetFlag(urlici.dwFlags, IURL_INVOKECOMMAND_FL_DDEWAIT); } hres = InvokeCommand(&urlici); m_bCheckForDelete = FALSE; } break;
case IDCMD_ISCM_SUB: case IDCMD_ISCM_SYNC: { hres = S_OK;
WCHAR *pwszURL; if (SUCCEEDED(GetURLW(&pwszURL))) { ISubscriptionMgr * pMgr; if (SUCCEEDED(JITCoCreateInstance(CLSID_SubscriptionMgr, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(ISubscriptionMgr, &pMgr), pici->hwnd, FIEF_FLAG_FORCE_JITUI))) { if (idCmd == IDCMD_ISCM_SUB) { BOOL bSubscribed;
pMgr->IsSubscribed(pwszURL, &bSubscribed);
if (!bSubscribed) { SHFILEINFO sfi = {0}; WCHAR wszName[MAX_PATH]; wszName[0] = 0; if (SHGetFileInfo(m_pszFile, 0, &sfi, sizeof(sfi), SHGFI_DISPLAYNAME)) { SHTCharToUnicode(sfi.szDisplayName, wszName, ARRAYSIZE(wszName)); }
if (!wszName[0]) StrCpyNW(wszName, pwszURL, ARRAYSIZE(wszName));
//all subscriptions to local .urls are treated as subscribing something
//that's already in Favorites, so user isn't forced to add it to their
//favorites as they subscribe.
if (SUCCEEDED(pMgr->CreateSubscription(pici->hwnd, pwszURL, wszName, CREATESUBS_FROMFAVORITES, SUBSTYPE_URL, NULL))) { pMgr->UpdateSubscription(pwszURL); } } else { pMgr->DeleteSubscription(pwszURL, pici->hwnd); } } else if (idCmd == IDCMD_ISCM_SYNC) { pMgr->UpdateSubscription(pwszURL); } pMgr->Release(); } SHFree(pwszURL); m_bCheckForDelete = FALSE; } break; }
default: hres = E_INVALIDARG; break; } }
return hres; }
/*----------------------------------------------------------
Purpose: IContextMenu::GetCommandString handler for Intshcut
*/ STDMETHODIMP Intshcut::GetCommandString( IN UINT_PTR idCmd, IN UINT uType, IN OUT UINT* puReserved, IN OUT LPSTR pszName, IN UINT cchMax) { HRESULT hres; TCHAR szMenu[CCH_MENUMAX];
ASSERT(NULL == puReserved); ASSERT(IS_VALID_WRITE_BUFFER(pszName, char, cchMax));
switch (uType) { case GCS_HELPTEXTA: case GCS_HELPTEXTW: if (idCmd < ARRAYSIZE(g_rgiscm)) { MLLoadString(g_rgiscm[idCmd].idsMenuHelp, szMenu, SIZECHARS(szMenu));
if (GCS_HELPTEXTA == uType) { UnicodeToAnsi(szMenu, pszName, cchMax); } else { StrCpyN((LPWSTR)pszName, szMenu, cchMax); } hres = NOERROR; } else { ASSERT(0); hres = E_INVALIDARG; } break;
case GCS_VALIDATEA: case GCS_VALIDATEW: hres = idCmd < ARRAYSIZE(g_rgiscm) ? S_OK : S_FALSE; break;
case GCS_VERBA: case GCS_VERBW: if (idCmd < ARRAYSIZE(g_rgiscm)) { LPCTSTR pszVerb = g_rgiscm[idCmd].pszVerb;
if (GCS_VERBA == uType) { UnicodeToAnsi(pszVerb, pszName, cchMax); } else { StrCpyN((LPWSTR)pszName, pszVerb, cchMax); } hres = NOERROR; } else { ASSERT(0); hres = E_INVALIDARG; } break;
default: hres = E_NOTIMPL; break; }
return hres; }
// IContextMenu2::HandleMenuMsg handler for Intshcut
STDMETHODIMP Intshcut::HandleMenuMsg(IN UINT uMsg, IN WPARAM wParam, IN LPARAM lParam) { return S_OK; }
// Returns the protocol scheme value (URL_SCHEME_*).
STDMETHODIMP_(DWORD) Intshcut::GetScheme(void) { DWORD dwScheme = URL_SCHEME_UNKNOWN;
if (SUCCEEDED(InitProp())) { m_pprop->GetProp(PID_IS_SCHEME, &dwScheme); } return dwScheme; }
// IUniformResourceLocator::SetURL handler for Intshcut
//
// Note:
// 1. SetURL clears the IDList, so that when we launch this shortcut,
// we will use the URL.
STDMETHODIMP Intshcut::SetURL( IN LPCTSTR pszURL, OPTIONAL IN DWORD dwFlags) { HRESULT hres = E_FAIL;
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut)); ASSERT(! pszURL || IS_VALID_STRING_PTR(pszURL, -1)); ASSERT(FLAGS_ARE_VALID(dwFlags, ALL_IURL_SETURL_FLAGS));
hres = InitProp(); if (SUCCEEDED(hres)) { hres = m_pprop->SetURLProp(pszURL, dwFlags); if (SUCCEEDED(hres)) { // if the path was set successfully, clear the pidl.
m_pprop->SetIDListProp(NULL); } }
return hres; }
/*----------------------------------------------------------
Purpose: IUniformResourceLocatorA::SetURL handler for Intshcut
Ansi version
*/ STDMETHODIMP Intshcut::SetURL( IN LPCSTR pcszURL, OPTIONAL IN DWORD dwInFlags) { if ( !pcszURL ) { return SetURL((LPCTSTR)NULL, dwInFlags); } else { WCHAR wszURL[MAX_URL_STRING];
ASSERT(IS_VALID_STRING_PTRA(pcszURL, -1));
AnsiToUnicode(pcszURL, wszURL, SIZECHARS(wszURL));
return SetURL(wszURL, dwInFlags); } }
STDMETHODIMP Intshcut::GetURLW(WCHAR **ppwsz) { LPTSTR pszURL; HRESULT hres = GetURL(&pszURL); if (S_OK == hres) { hres = SHStrDup(pszURL, ppwsz); SHFree(pszURL); } else hres = E_FAIL; // map S_FALSE to FAILED()
return hres; }
// IUniformResourceLocator::GetURL handler for Intshcut
STDMETHODIMP Intshcut::GetURL(LPTSTR * ppszURL) { HRESULT hres; TCHAR szURL[MAX_URL_STRING];
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut)); ASSERT(IS_VALID_WRITE_PTR(ppszURL, PTSTR));
*ppszURL = NULL;
hres = InitProp(); if (SUCCEEDED(hres)) { hres = m_pprop->GetProp(PID_IS_URL, szURL, SIZECHARS(szURL)); if (S_OK == hres) { // (+ 1) for null terminator.
int cch = lstrlen(szURL) + 1; *ppszURL = (PTSTR)SHAlloc(CbFromCch(cch)); if (*ppszURL) StrCpyN(*ppszURL, szURL, cch); else hres = E_OUTOFMEMORY; } }
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut)); ASSERT((hres == S_OK && IS_VALID_STRING_PTR(*ppszURL, -1)) || ((hres == S_FALSE || hres == E_OUTOFMEMORY) && ! *ppszURL));
return hres; }
/*----------------------------------------------------------
Purpose: IUniformResourceLocatorA::GetURL handler for Intshcut
Ansi version
*/ STDMETHODIMP Intshcut::GetURL(LPSTR * ppszURL) { HRESULT hres; TCHAR szURL[MAX_URL_STRING];
ASSERT(IS_VALID_WRITE_PTR(ppszURL, PSTR));
*ppszURL = NULL;
hres = InitProp(); if (SUCCEEDED(hres)) { hres = m_pprop->GetProp(PID_IS_URL, szURL, SIZECHARS(szURL));
if (S_OK == hres) { DWORD cch = WideCharToMultiByte(CP_ACP, 0, szURL, -1, NULL, 0, NULL, NULL); *ppszURL = (LPSTR)SHAlloc(CbFromCchA(cch + 1));
if (*ppszURL) UnicodeToAnsi(szURL, *ppszURL, cch); else hres = E_OUTOFMEMORY; } }
return hres; }
HRESULT HandlePluggableProtocol(LPCTSTR pszURL, LPCTSTR pszProtocol) { HRESULT hres = E_UNEXPECTED; HKEY hkey; TraceMsg(DM_PLUGGABLE, "HandlePluggableProtocol called");
if (RegOpenKeyEx(HKEY_CLASSES_ROOT, TEXT("PROTOCOLS\\Handler"), 0, KEY_READ, &hkey) == ERROR_SUCCESS) { HKEY hkeyProtocol; if (RegOpenKeyEx(hkey, pszProtocol, 0, KEY_READ, &hkeyProtocol) == ERROR_SUCCESS) { TraceMsg(DM_PLUGGABLE, "HandlePluggableProtocol found %s", pszProtocol); IUnknown* punk = NULL; // CreateTargetFrame's ppunk is [IN][OUT]
hres = CreateTargetFrame(NULL, &punk); if (SUCCEEDED(hres)) { IWebBrowser2* pauto; hres = punk->QueryInterface(IID_IWebBrowser2, (LPVOID*)&pauto); if (SUCCEEDED(hres)) { TraceMsg(DM_PLUGGABLE, "HandlePluggableProtocol calling navigate with %s", pszURL);
LBSTR::CString strUrl;
LPTSTR pstrUrl = strUrl.GetBuffer( MAX_URL_STRING );
if ( strUrl.GetAllocLength() < MAX_URL_STRING ) { TraceMsg( TF_WARNING, "HandlePluggableProtocol() - strUrl Allocation Failed!" );
strUrl.Empty(); } else { SHTCharToUnicode( pszURL, pstrUrl, MAX_URL_STRING );
// Let CString class own the buffer again.
strUrl.ReleaseBuffer(); }
pauto->Navigate( strUrl, PVAREMPTY, PVAREMPTY, PVAREMPTY, PVAREMPTY ); pauto->put_Visible(TRUE); pauto->Release(); } punk->Release(); } RegCloseKey(hkeyProtocol); } else { TraceMsg(DM_WARNING, "HandlePluggableProtocol can't find %s", pszProtocol); } RegCloseKey(hkey); } else { ASSERT(0); } return hres; }
HRESULT _IEExecFile_TryRunningWindow(VARIANT *pvarIn, DWORD cid) { HRESULT hr = E_FAIL; ASSERT(pvarIn);
IShellWindows *psw = WinList_GetShellWindows(TRUE); if (psw) { IUnknown *punk; if (SUCCEEDED(psw->_NewEnum(&punk))) { VARIANT var = {0}; IEnumVARIANT *penum;
//
// its too bad _NewEnum doesnt return an penum....
// this should never fail.
//
punk->QueryInterface(IID_PPV_ARG(IEnumVARIANT, &penum)); ASSERT(penum);
//
// this can be super spendy since every one of these
// items is marshalled.
//
// should we clone the stream here??
//
while (FAILED(hr) && S_OK == penum->Next(1, &var, NULL)) { ASSERT(var.vt == VT_DISPATCH); ASSERT(var.pdispVal); IOleCommandTarget *poct; if (SUCCEEDED(var.pdispVal->QueryInterface(IID_PPV_ARG(IOleCommandTarget, &poct)))) { CoAllowSetForegroundWindow(poct, NULL); hr = poct->Exec(&CGID_Explorer, cid, 0, pvarIn, NULL);
poct->Release(); } // this should release the pdisp
VariantClear(&var); }
punk->Release(); penum->Release(); } psw->Release(); }
TraceMsgW(DM_SHELLEXECOBJECT, "IEExecFile_Running returns 0x%X", hr); return hr; }
BOOL IsIESchemeHandler(LPTSTR pszVerb, LPTSTR pszScheme) { // if we fail to get any value at all, the we must assume that it
// is some protocol like about: or res: that is not in the registry
// so we default to success.
BOOL fRet = FALSE; TCHAR szExe[MAX_PATH];
if (SUCCEEDED(AssocQueryString(0, ASSOCSTR_EXECUTABLE, pszScheme, pszVerb, szExe, (LPDWORD)MAKEINTRESOURCE(SIZECHARS(szExe))))) { // if we find something and it aint us, then fail.
if ((StrStrI(szExe, TEXT("iexplore.exe")) || StrStrI(szExe, TEXT("explorer.exe")))) { fRet = TRUE;
TraceMsg(DM_SHELLEXECOBJECT, "IsIEScheme() found %s", szExe); } } else { // these are unregistered schemes, we are the only ones that
// should ever even use the unregistered schemes like
// res: or shell: so return TRUE here too.
fRet = *pszScheme && *pszScheme != TEXT('.'); } TraceMsg(DM_SHELLEXECOBJECT, "IsIEScheme() returns %d for %s", fRet, pszScheme); return fRet; }
HRESULT IEExecFile(LPTSTR pszVerb, LPTSTR pszScheme, DWORD cid, LPTSTR pszPath) { HRESULT hr = E_FAIL; ASSERT(pszVerb); ASSERT(pszScheme); ASSERT(pszPath); if (IsIESchemeHandler(pszVerb, pszScheme)) { VARIANT varIn = {0}; varIn.vt = VT_BSTR;
SHSTRW str; str.SetStr(pszPath); varIn.bstrVal = SysAllocString(str.GetStr()); if (varIn.bstrVal) { if (!SHRegGetBoolUSValue(REGSTR_PATH_MAIN, TEXT("AllowWindowReuse"), FALSE, TRUE) || FAILED(hr = _IEExecFile_TryRunningWindow(&varIn, cid))) { IOleCommandTarget *poct; if (SUCCEEDED(CoCreateInstance(CLSID_InternetExplorer, NULL, CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER, IID_PPV_ARG(IOleCommandTarget, &poct)))) { hr = poct->Exec(&CGID_Explorer, cid, 0, &varIn, NULL); poct->Release(); } }
SysFreeString(varIn.bstrVal); }
}
TraceMsg(DM_SHELLEXECOBJECT, "IEExecFile returns 0x%X for %s", hr, pszPath);
return hr; } /*----------------------------------------------------------
Purpose: IUniformResourceLocator::InvokeCommand for Intshcut
Note: 1. If the internet shortcut comes with a pidl, use it to ShellExec, otherwise use the URL.
*/ STDMETHODIMP Intshcut::InvokeCommand(PURLINVOKECOMMANDINFO purlici) { HRESULT hr = E_INVALIDARG; ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut)); ASSERT(IS_VALID_STRUCT_PTR(purlici, CURLINVOKECOMMANDINFO));
if (purlici && EVAL(SIZEOF(*purlici) == purlici->dwcbSize)) { //
// App compat. Don't use stack space for the URL. We use up 16-bit app
// stack space when we they shell exec urls.
//
LPWSTR pszURL = (LPWSTR)LocalAlloc(LPTR, MAX_URL_STRING * sizeof(WCHAR));
if (pszURL) { hr = InitProp(); if (SUCCEEDED(hr)) { //
// App Compat: Don't use up stack space.
//
LPWSTR pszT = (LPWSTR)LocalAlloc(LPTR, MAX_PATH * sizeof(WCHAR));
if (pszT) { SHELLEXECUTEINFO sei = {0}; LPITEMIDLIST pidl = NULL; LPTSTR pszProtocol = NULL; PARSEDURL pu; pu.nScheme = 0; // init to avoid bogus C4701 warning
sei.fMask = SEE_MASK_NO_HOOKS;
// check if we have a pidl for the target.
hr = GetIDListInternal(&pidl); if ((hr == S_OK) && pidl) { // yse, use the pidl to ShellExec.
sei.fMask |= SEE_MASK_INVOKEIDLIST; sei.lpIDList = pidl; } else { // no, get the URL and invoke class handler.
if (SUCCEEDED(hr)) { hr = m_pprop->GetProp(PID_IS_URL, pszURL, MAX_URL_STRING); } if (S_OK == hr) { hr = CopyURLProtocol(pszURL, &pszProtocol, &pu); if (hr == S_OK) { hr = IsProtocolRegistered(pszProtocol); if (FAILED(hr)) { if (SUCCEEDED(HandlePluggableProtocol(pszURL, pszProtocol))) { hr = S_OK; goto done; } }
if (SUCCEEDED(hr)) { hr = ResultFromWin32(RegOpenKeyExW(HKEY_CLASSES_ROOT, pszProtocol, 0, KEY_READ, &sei.hkeyClass)); sei.fMask |= SEE_MASK_CLASSKEY; } } } }
// the prop code returns S_FALSE when it fails to get anything
if (S_FALSE == hr) hr = URL_E_INVALID_SYNTAX; if (SUCCEEDED(hr)) { //
// App Compat: Don't use up stack space.
//
LPWSTR pszVerb = (LPWSTR)LocalAlloc(LPTR, MAX_PATH * sizeof(WCHAR));
if (pszVerb) { int nShowCmd; // Execute URL via registered protocol handler.
if (IsFlagClear(purlici->dwFlags, IURL_INVOKECOMMAND_FL_ALLOW_UI)) SetFlag(sei.fMask, SEE_MASK_FLAG_NO_UI);
if (purlici->dwFlags & IURL_INVOKECOMMAND_FL_DDEWAIT) SetFlag(sei.fMask, SEE_MASK_FLAG_DDEWAIT); if (IsFlagClear(purlici->dwFlags, IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB)) { sei.lpVerb = purlici->pcszVerb; } else { if (pszProtocol && GetClassDefaultVerb(pszProtocol, pszVerb, MAX_PATH)) sei.lpVerb = pszVerb; else ASSERT(! sei.lpVerb); }
ASSERT(m_pprop); if (SUCCEEDED(hr)) { m_pprop->GetProp(PID_IS_WORKINGDIR, pszT, MAX_PATH); m_pprop->GetProp(PID_IS_SHOWCMD, &nShowCmd); // inits to zero if not found
// if we have a file try using a direct connection
// to the shell to give the whole shortcut
if (m_pszFile && ((IsIEDefaultBrowser()) || (_IsInFavoritesFolder()))) { LPTSTR pszType = pszProtocol; if (pu.nScheme == URL_SCHEME_FILE) pszType = PathFindExtension(pszURL); hr = IEExecFile(pszVerb, pszType, SBCMDID_IESHORTCUT, m_pszFile); } else hr = E_FAIL;
// if we failed to pass it to IE, then we should just default
// to the old behavior
if (FAILED(hr)) {
sei.cbSize = SIZEOF(sei); sei.hwnd = purlici->hwndParent; sei.lpFile = pszURL; sei.lpDirectory = pszT; sei.nShow = nShowCmd ? nShowCmd : SW_NORMAL; // We have to special case "file:" URLs,
// because Nashville's Explorer typically handles
// file: URLs via DDE, which fails for executables
// (eg, "file://c:\windows\notepad.exe") and
// non-hostable docs (like text files).
//
// So in this case, we remove the protocol class
// and execute the suffix.
// App Compat: Don't use up stack space.
DWORD cchPath = MAX_PATH; LPWSTR pszPath = (LPWSTR)LocalAlloc(LPTR, cchPath * sizeof(WCHAR));
if (pszPath) { if (IsFlagSet(sei.fMask, SEE_MASK_CLASSKEY) && (URL_SCHEME_FILE == pu.nScheme) && SUCCEEDED(PathCreateFromUrl(pszURL, pszPath, &cchPath, 0))) { sei.hkeyClass = NULL; ClearFlag(sei.fMask, SEE_MASK_CLASSKEY); sei.lpFile = pszPath; }
if (m_pszFile && IsOS(OS_WHISTLERORGREATER)) { // this is the security context
// so that shellexec() can do zone checks
sei.lpClass = m_pszFile; sei.fMask |= SEE_MASK_HASTITLE | SEE_MASK_HASLINKNAME; }
TraceMsg(TF_INTSHCUT, "Intshcut::InvokeCommand(): Invoking %s verb on URL %s.", sei.lpVerb ? sei.lpVerb : TEXT("open"), sei.lpFile); hr = ShellExecuteEx(&sei) ? S_OK : IS_E_EXEC_FAILED;
LocalFree(pszPath); pszPath = NULL; } else { hr = E_OUTOFMEMORY; } } } if (hr != S_OK) TraceMsg(TF_WARNING, "Intshcut::InvokeCommand(): ShellExecuteEx() via registered protcol handler failed for %s.", pszURL);
LocalFree(pszVerb); pszVerb = NULL; } else { hr = E_OUTOFMEMORY; } }
done: if (pszProtocol) { LocalFree(pszProtocol); pszProtocol = NULL; } if (pidl) ILFree(pidl); if (sei.hkeyClass) RegCloseKey(sei.hkeyClass); if (FAILED(hr) && (purlici->dwFlags & IURL_INVOKECOMMAND_FL_ALLOW_UI)) { switch (hr) { case IS_E_EXEC_FAILED: break; case URL_E_INVALID_SYNTAX: MLShellMessageBox( purlici->hwndParent, MAKEINTRESOURCE(IDS_IS_EXEC_INVALID_SYNTAX), MAKEINTRESOURCE(IDS_SHORTCUT_ERROR_TITLE), (MB_OK | MB_ICONEXCLAMATION), pszURL); break; case URL_E_UNREGISTERED_PROTOCOL: { LPTSTR pszProtocol; if (CopyURLProtocol(pszURL, &pszProtocol, NULL) == S_OK) { MLShellMessageBox( purlici->hwndParent, MAKEINTRESOURCE(IDS_IS_EXEC_UNREGISTERED_PROTOCOL), MAKEINTRESOURCE(IDS_SHORTCUT_ERROR_TITLE), (MB_OK | MB_ICONEXCLAMATION), pszProtocol); LocalFree(pszProtocol); pszProtocol = NULL; } break; } case E_OUTOFMEMORY: MLShellMessageBox( purlici->hwndParent, MAKEINTRESOURCE(IDS_IS_EXEC_OUT_OF_MEMORY), MAKEINTRESOURCE(IDS_SHORTCUT_ERROR_TITLE), (MB_OK | MB_ICONEXCLAMATION)); break; default: ASSERT(hr == E_ABORT); break; } }
LocalFree(pszT); pszT = NULL; } else { hr = E_OUTOFMEMORY; } }
LocalFree(pszURL); pszURL = NULL; } else { hr = E_OUTOFMEMORY; } }
ASSERT(IS_VALID_STRUCT_PTR(this, CIntshcut)); ASSERT(hr == S_OK || hr == E_ABORT || hr == E_OUTOFMEMORY || hr == URL_E_INVALID_SYNTAX || hr == URL_E_UNREGISTERED_PROTOCOL || hr == IS_E_EXEC_FAILED || hr == E_INVALIDARG); return(hr); }
/*----------------------------------------------------------
Purpose: IUniformResourceLocatorA::InvokeCommand for Intshcut
Ansi version
*/ STDMETHODIMP Intshcut::InvokeCommand( IN PURLINVOKECOMMANDINFOA purlici)
{ HRESULT hres = E_INVALIDARG;
ASSERT(purlici); ASSERT(SIZEOF(*purlici) == purlici->dwcbSize);
if (SIZEOF(*purlici) == purlici->dwcbSize) { URLINVOKECOMMANDINFOW ici;
ici.dwcbSize = SIZEOF(ici); ici.dwFlags = purlici->dwFlags; ici.hwndParent = purlici->hwndParent;
ici.pcszVerb = NULL;
if (purlici->pcszVerb) { //
// App compat hack.
//
// Note: use local alloc here instead of the stack since 16-bit code
// can shell exec urls and we don't want to use up their stack.
//
int cch = lstrlenA(purlici->pcszVerb) + 1;
ici.pcszVerb = (LPWSTR)LocalAlloc(LPTR, cch * sizeof(WCHAR));
if (ici.pcszVerb) { AnsiToUnicode(purlici->pcszVerb, (LPWSTR)ici.pcszVerb, cch); } }
hres = InvokeCommand(&ici);
if (ici.pcszVerb) { LocalFree((void*)ici.pcszVerb); ici.pcszVerb = NULL; } }
return hres; }
STDMETHODIMP Intshcut::Create(REFFMTID fmtid, const CLSID *pclsid, DWORD grfFlags, DWORD grfMode, IPropertyStorage **pppropstg) { *pppropstg = NULL; return E_NOTIMPL; }
STDMETHODIMP Intshcut::Open(REFFMTID fmtid, DWORD grfMode, IPropertyStorage **pppropstg) { HRESULT hres = E_FAIL; // assume failure
*pppropstg = NULL;
if (IsEqualGUID(fmtid, FMTID_Intshcut)) { // Create a URLProp object for this format ID
hres = CIntshcutProp_CreateInstance(NULL, IID_PPV_ARG(IPropertyStorage, pppropstg)); if (SUCCEEDED(hres)) { // Initialize this object
IntshcutProp * pisprop = (IntshcutProp *)*pppropstg; hres = pisprop->InitFromFile(m_pszFile); } } else if (IsEqualGUID(fmtid, FMTID_InternetSite)) { // Create a URLProp object for this format ID
hres = CIntsiteProp_CreateInstance(NULL, IID_PPV_ARG(IPropertyStorage, pppropstg)); if (SUCCEEDED(hres)) { hres = InitProp(); if (SUCCEEDED(hres)) { TCHAR szURL[MAX_URL_STRING]; hres = m_pprop->GetProp(PID_IS_URL, szURL, SIZECHARS(szURL)); if (SUCCEEDED(hres)) { IntsiteProp * pisprop = (IntsiteProp *)*pppropstg; hres = pisprop->InitFromDB(szURL, this, FALSE); } }
if (FAILED(hres)) { (*pppropstg)->Release(); *pppropstg = NULL; } } }
return hres; }
STDMETHODIMP Intshcut::Delete(REFFMTID fmtid) { return STG_E_ACCESSDENIED; }
STDMETHODIMP Intshcut::Enum(OUT IEnumSTATPROPSETSTG ** ppenum) { *ppenum = NULL; return E_NOTIMPL; }
STDAPI GetStringPropURL(IPropertyStorage *ppropstg, PROPID propid, LPTSTR pszBuf, DWORD cchBuf) { HRESULT hres = GetStringProp(ppropstg, propid, pszBuf, cchBuf); if (SUCCEEDED(hres)) { // get rid of the query string for display
if (UrlIs(pszBuf, URLIS_HASQUERY)) UrlCombine(pszBuf, TEXT("?..."), pszBuf, &cchBuf, 0); } return hres; }
BOOL Intshcut::_TryLink(REFIID riid, void **ppvOut) { HRESULT hr = InitProp();
if (SUCCEEDED(hr) && URL_SCHEME_FILE == GetScheme()) { // This shortcut is not in the favorites folder as far as we know
TCHAR szURL[INTERNET_MAX_URL_LENGTH]; DWORD cch = SIZECHARS(szURL);
*szURL = 0;
m_pprop->GetProp(PID_IS_URL, szURL, SIZECHARS(szURL));
if (*szURL && SUCCEEDED(PathCreateFromUrl(szURL, szURL, &cch, 0))) { if (!_punkLink) { hr = _CreateShellLink(szURL, &_punkLink); }
if (_punkLink) { if (SUCCEEDED(_punkLink->QueryInterface(riid, ppvOut))) return TRUE; } }
if (FAILED(hr)) ATOMICRELEASE(_punkLink); }
return FALSE; }
STDMETHODIMP Intshcut::GetInfoTip(DWORD dwFlags, WCHAR **ppwszTip) { HRESULT hr = E_FAIL; IQueryInfo *pqi;
if (_TryLink(IID_PPV_ARG(IQueryInfo, &pqi))) { hr = pqi->GetInfoTip(dwFlags, ppwszTip); pqi->Release(); } if (FAILED(hr)) { static const ITEM_PROP c_rgTitleAndURL[] = { { &FMTID_InternetSite, PID_INTSITE_TITLE, GetStringProp, IDS_FAV_STRING }, { &FMTID_Intshcut, PID_IS_URL, GetStringPropURL, IDS_FAV_STRING }, { NULL, 0, 0, 0 }, };
hr = GetInfoTipFromStorage(SAFECAST(this, IPropertySetStorage *), c_rgTitleAndURL, ppwszTip); }
return hr;
}
STDMETHODIMP Intshcut::GetInfoFlags(DWORD *pdwFlags) { *pdwFlags = 0; #if 0
// This Function is commented out since it has not been tested.
// It can be uncommented if we provide support for providing offline cursor
// for shortucts. I think this needs updates to listview in comctl -- BharatS
LPSTR pszURL; if (S_OK == GetURL(&pszURL)) { BOOL fCached = UrlIsCached(pszUrl); if (!fCached) { CHAR szCanonicalizedUrlA[MAX_URL_STRING]; DWORD dwLen = ARRAYSIZE(szCanonicalizedUrlA); InternetCanonicalizeUrlA(pszURL, szCanonicalizedUrlA, &dwLen, 0); fCached = UrlIsMappedOrInCache(szCanonicalizedUrlA); } if (fCached) *pdwFlags |= QIF_CACHED; SHFree(pszURL); } return S_OK; #else
return E_NOTIMPL; #endif
}
/*----------------------------------------------------------
IQueryCodePage: */ STDMETHODIMP Intshcut::GetCodePage(UINT * puiCodePage) { HRESULT hres = E_FAIL; *puiCodePage = 0; // NULL out the code page.
if (IsFlagSet(m_dwFlags, ISF_CODEPAGE)) { *puiCodePage = m_uiCodePage; hres = S_OK; }
return hres; }
STDMETHODIMP Intshcut::SetCodePage(UINT uiCodePage) { SetFlag(m_dwFlags, ISF_CODEPAGE); m_uiCodePage = uiCodePage; return S_OK; }
/***************************** Exported Functions ****************************/
// This function was ported from URL.DLL. Normally, since our
// internet shortcut object has a context menu handler, we don't
// call this function.
//
// Only one thing needs this entry point: Exchange. Sigh.
//
// Instead of simply calling ShellExecuteEx to handle opening file
// attachments, they grovel thru the registry themselves. Of course,
// their code is incomplete and thinks a file-association needs to
// have an explicit \shell\open\command that works before it executes
// it. Hmm, it brings to mind a phrase, like:
//
//
//
// So, we export this API so they will work. But really the invoke
// occurs in the context menu handler for normal cases.
//
STDAPI_(void) OpenURL(HWND hwndParent, HINSTANCE hinst, LPSTR pszCmdLine, int nShowCmd) { HRESULT hr; HRESULT hrCoInit;
Intshcut * pIntshcut = new Intshcut; // This must be a 0 INITed memory allocation
WCHAR wszPath[MAX_PATH];
if (!pIntshcut) return;
hrCoInit = SHCoInitialize(); // gets called from rundll32 in browser only mode - hence we need to
// make sure that OLE has been init'ed
ASSERT(IS_VALID_HANDLE(hwndParent, WND)); ASSERT(IS_VALID_HANDLE(hinst, INSTANCE)); ASSERT(IS_VALID_STRING_PTRA(pszCmdLine, -1)); ASSERT(IsValidShowCmd(nShowCmd));
// Assume the entire command line is an Internet Shortcut file path.
TrimWhiteSpaceA(pszCmdLine);
TraceMsgA(TF_INTSHCUT, "OpenURL(): Trying to open Internet Shortcut %s.", pszCmdLine);
#ifndef UNIX
AnsiToUnicode(pszCmdLine, wszPath, SIZECHARS(wszPath)); hr = pIntshcut->LoadFromFile(wszPath);
#else /* UNIX */
#ifndef ANSI_SHELL32_ON_UNIX
// IEUNIX : Our Shell32 calls this function with unicode command line
hr = pIntshcut->LoadFromFile((LPWSTR)pszCmdLine); #else
hr = pIntshcut->LoadFromFile(pszCmdLine); #endif
#endif /* !UNIX */
if (hr == S_OK) { URLINVOKECOMMANDINFO urlici;
urlici.dwcbSize = SIZEOF(urlici); urlici.hwndParent = hwndParent; urlici.pcszVerb = NULL; urlici.dwFlags = (IURL_INVOKECOMMAND_FL_ALLOW_UI | IURL_INVOKECOMMAND_FL_USE_DEFAULT_VERB);
hr = pIntshcut->InvokeCommand(&urlici); }
if (hr != S_OK) { MLShellMessageBox( hwndParent, MAKEINTRESOURCE(IDS_IS_LOADFROMFILE_FAILED), MAKEINTRESOURCE(IDS_SHORTCUT_ERROR_TITLE), (MB_OK | MB_ICONEXCLAMATION), wszPath); }
pIntshcut->Release();
SHCoUninitialize(hrCoInit);
}
// INamedPropertyBag Methods
//
// Reads & writes properties from a section in the shortcut ini file
const TCHAR c_szSizeSuffix[] = TEXT("__Size");
STDMETHODIMP Intshcut::WritePropertyNPB( LPCOLESTR pszSectionNameW, /* [in] */ LPCOLESTR pszPropNameW, /* [out][in] */ PROPVARIANT *pVar) { const TCHAR *pszSectionName; const TCHAR *pszPropName; HRESULT hr; if((NULL == pszSectionNameW) || (NULL == pszPropNameW) || (NULL == pVar)) { return E_FAIL; }
if(S_OK != _CreateTemporaryBackingFile()) { ASSERT(NULL == m_pszTempFileName); return E_FAIL; }
ASSERT(m_pszTempFileName); pszSectionName = pszSectionNameW; pszPropName = pszPropNameW; // Write the appropriate value in depending on the type
switch(pVar->vt) { // NOTE: (andrewgu) these types we also can round-trip using the same code pass as for
// unsigned types, except bharats in a codereview recommended we comment these out because
// they'll look goofy in the *.ini file (you wrote -5 but see 4294967290 junk instead).
// VT_UINT is not listed as "may appear in an OLE property set" in <wtypes.h>.
/* case VT_I1:
case VT_I2: case VT_I4: case VT_INT: case VT_UINT: */
case VT_UI1: case VT_UI2: case VT_UI4: hr = WriteUnsignedToFile(m_pszTempFileName, pszSectionName, pszPropName, pVar->ulVal); break;
case VT_BSTR: hr = WriteGenericString(m_pszTempFileName, pszSectionName, pszPropName, pVar->bstrVal); break;
case VT_BLOB: { TCHAR *pszSizePropName = NULL; int cchPropName = lstrlen(pszPropName) + ARRAYSIZE(c_szSizeSuffix) + 1; DWORD dwAllocSize = cchPropName * sizeof(TCHAR); pszSizePropName = (TCHAR *)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, dwAllocSize); if(pszSizePropName) { DWORD dwBufferSize; StrCpyN(pszSizePropName, pszPropName, cchPropName); StrCatBuff(pszSizePropName, c_szSizeSuffix, cchPropName);
// OK Now - we have the name for the size
// we write it out
dwBufferSize = pVar->blob.cbSize; hr = WriteBinaryToFile(m_pszTempFileName, pszSectionName, pszSizePropName, (LPVOID)(&dwBufferSize), sizeof(DWORD));
if(S_OK == hr) { // Write out the buffer
hr = WriteBinaryToFile(m_pszTempFileName, pszSectionName, pszPropName, (LPVOID)(pVar->blob.pBlobData), dwBufferSize); }
LocalFree((LPVOID)pszSizePropName); pszSizePropName = NULL; } else { hr = E_OUTOFMEMORY; } break; } default: hr = WriteBinaryToFile(m_pszTempFileName, pszSectionName, pszPropName, (LPVOID)pVar, sizeof(PROPVARIANT)); break; }
return hr; }
STDMETHODIMP Intshcut::ReadPropertyNPB( /* [in] */ LPCOLESTR pszSectionNameW, /* [in] */ LPCOLESTR pszPropNameW, /* [out][in] */ PROPVARIANT *pVar) { const TCHAR *pszSectionName; const TCHAR *pszPropName; TCHAR *pszFileToReadFrom; HRESULT hr;
if((NULL == pszSectionNameW) || (NULL == pszPropNameW) || (NULL == pVar)) { if (NULL != pVar) pVar->vt = VT_ERROR;
return E_FAIL; }
if(m_pszTempFileName) { pszFileToReadFrom = m_pszTempFileName; } else if(m_pszFile) { pszFileToReadFrom = m_pszFile; } else { pVar->vt = VT_EMPTY; return S_FALSE; }
pszSectionName = pszSectionNameW; pszPropName = pszPropNameW;
switch(pVar->vt) { // NOTE: (andrewgu) these types we also can round-trip using the same code pass as for
// unsigned types, except bharats in a codereview recommended we comment these out because
// they'll look goofy in the *.ini file (you wrote -5 but see 4294967290 junk instead).
// VT_UINT is not listed as "may appear in an OLE property set" in <wtypes.h>.
/* case VT_I1:
case VT_I2: case VT_I4: case VT_INT: case VT_UINT: */
case VT_UI1: case VT_UI2: case VT_UI4: pVar->ulVal = 0; hr = ReadUnsignedFromFile(pszFileToReadFrom, pszSectionName, pszPropName, &(pVar->ulVal)); break;
case VT_BSTR: // It is a string
pVar->vt = VT_BSTR; pVar->bstrVal = NULL; hr = ReadBStrFromFile(pszFileToReadFrom, pszSectionName, pszPropName, &(pVar->bstrVal)); break;
case VT_BLOB: { TCHAR *pszSizePropName = NULL; int cchPropName = lstrlen(pszPropName) + ARRAYSIZE(c_szSizeSuffix) + 1; DWORD dwAllocSize = cchPropName * sizeof(TCHAR); pszSizePropName = (TCHAR *)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, dwAllocSize); if(pszSizePropName) { DWORD dwBufferSize; StrCpyN(pszSizePropName, pszPropName, cchPropName); StrCatBuff(pszSizePropName, c_szSizeSuffix, cchPropName); // Read the Size first
hr = ReadBinaryFromFile(pszFileToReadFrom, pszSectionName, pszSizePropName, &dwBufferSize, sizeof(DWORD)); if(S_OK == hr) { pVar->blob.pBlobData = (unsigned char *)CoTaskMemAlloc(dwBufferSize); if(pVar->blob.pBlobData) { hr = ReadBinaryFromFile(pszFileToReadFrom, pszSectionName, pszPropName, pVar->blob.pBlobData, dwBufferSize);
if(S_OK == hr) { pVar->blob.cbSize = dwBufferSize; } else { CoTaskMemFree(pVar->blob.pBlobData); } } }
LocalFree(pszSizePropName); pszSizePropName = NULL; } else { hr = E_OUTOFMEMORY; }
break; } default: { // all else
PROPVARIANT tmpPropvar = {0}; hr = ReadBinaryFromFile(pszFileToReadFrom, pszSectionName, pszPropName, &tmpPropvar, sizeof(PROPVARIANT)); if((S_OK == hr) && (tmpPropvar.vt == pVar->vt)) { memcpy(pVar, &tmpPropvar, sizeof(PROPVARIANT)); } else { pVar->vt = VT_ERROR; } break; }
}
if(hr != S_OK) { memset(pVar, 0, sizeof(PROPVARIANT)); pVar->vt = VT_EMPTY; }
return hr; }
STDMETHODIMP Intshcut::RemovePropertyNPB ( /* [in] */ LPCOLESTR pszSectionNameW, /* [in] */ LPCOLESTR pszPropNameW) { const TCHAR *pszSectionName; const TCHAR *pszPropName; HRESULT hr; TCHAR *pszFileToDeleteFrom;
// Return if there is no file name
if((NULL == pszSectionNameW) || (NULL == pszPropNameW)) { return E_FAIL; }
if(m_pszTempFileName) { pszFileToDeleteFrom = m_pszTempFileName; } else if(m_pszFile) { pszFileToDeleteFrom = m_pszFile; } else { return E_FAIL; } // Just delete the key corresponding to this property name
pszSectionName = pszSectionNameW; pszPropName = pszPropNameW;
hr = SHDeleteIniString(pszSectionName, pszPropName, pszFileToDeleteFrom)? S_OK : E_FAIL;
return hr; }
|