Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1755 lines
48 KiB

//---------------------------------------------------------------------------
//
// Copyright (c) Microsoft Corporation 1991-1993
//
// File: drivesx.c
//
// History:
// 05-19-94 GeorgeP Created.
//
//---------------------------------------------------------------------------
#include "shellprv.h"
#pragma hdrstop
#include "ids.h"
#pragma warning(disable: 4200) // Zero-sized array in struct
#pragma pack(1)
typedef struct _IDREGITEM
{
WORD cb;
BYTE bFlags;
BYTE bReserved; // This is to get DWORD alignment
CLSID clsid;
} IDREGITEM, *LPIDREGITEM;
typedef const IDREGITEM *LPCIDREGITEM;
typedef struct _IDLREGITEM
{
IDREGITEM idri;
USHORT cbNext;
} IDLREGITEM;
#pragma pack()
typedef struct
{
IShellFolder sf;
UINT cRef;
REGITEMSINFO rii;
LPTSTR pszMachine; // NULL if local
REQREGITEM sReqItems[];
} CRegItemsSF;
#pragma data_seg(".text", "CODE")
// HACKHACK: This has incestuous knowledge about the bFlags field
const IDLREGITEM c_idlNet =
{
{SIZEOF(IDREGITEM), SHID_ROOT_REGITEM, 0,
{ 0x208D2C60, 0x3AEA, 0x1069, 0xA2,0xD7,0x08,0x00,0x2B,0x30,0x30,0x9D, },},
0,
} ;
const IDLREGITEM c_idlDrives =
{
{SIZEOF(IDREGITEM), SHID_ROOT_REGITEM, 0,
{ 0x20D04FE0, 0x3AEA, 0x1069, 0xA2,0xD8,0x08,0x00,0x2B,0x30,0x30,0x9D, },},
0,
} ;
#pragma data_seg()
const TCHAR c_szRegValDeleteMessage[] = REGSTR_VAL_REGITEMDELETEMESSAGE;
const TCHAR c_szCrLfLf[] = TEXT("\r\n\n");
#define _RegItems_IsRegFromInfo(_lpInfo, _pidri) ((_lpInfo)->bFlags==(_pidri)->bFlags)
#define _RegItems_GetAttributesFromCLSID(pclsid) (SHGetAttributesFromCLSID(pclsid, SFGAO_CANMOVE | SFGAO_CANDELETE))
STDMETHODIMP CRegItems_GetAttributesOf(IShellFolder *psf, UINT cidl, LPCITEMIDLIST * apidl, ULONG * prgfInOut);
HRESULT RegItems_GetNameRemote(LPTSTR pszMachine, LPCREGITEMSINFO lpInfo, LPCITEMIDLIST pidl, LPSTRRET pStrRet);
BOOL _RegItems_IsReg(IShellFolder *psf, LPCITEMIDLIST pidl)
{
CRegItemsSF * this = IToClass(CRegItemsSF, sf, psf);
if ((pidl == NULL) || ILIsEmpty(pidl))
return FALSE;
return _RegItems_IsRegFromInfo(&this->rii, (LPCIDREGITEM)pidl);
}
void _RegItems_FillID(LPCREGITEMSINFO lpInfo, LPSHITEMID pid, const CLSID *pclsid)
{
LPIDREGITEM pidri = (LPIDREGITEM)pid;
pidri->cb = SIZEOF(IDREGITEM);
pidri->bFlags = lpInfo->bFlags;
pidri->bReserved = 0;
pidri->clsid = *pclsid;
}
BOOL _RegItems_NReqItem(LPCREGITEMSINFO lpInfo, const CLSID *pclsid)
{
int iReqItems = lpInfo->iReqItems - 1;
for ( ; iReqItems>=0; --iReqItems)
{
if (IsEqualGUID(pclsid, lpInfo->pReqItems[iReqItems].pclsid))
{
break;
}
}
return(iReqItems);
}
BOOL _RegItems_IsSubObject(LPCREGITEMSINFO lpInfo, const CLSID *pclsid)
{
TCHAR szClass[GUIDSTR_MAX];
LONG lSize = 0;
if (_RegItems_NReqItem(lpInfo, pclsid) >= 0)
{
return(TRUE);
}
StringFromGUID2A(pclsid, szClass, ARRAYSIZE(szClass));
// Acutually, I should probably do a RegOpenKey/RegCloseKey, but this
// is a faster way to see if a key exists
return RegQueryValue(lpInfo->hkRegItems, szClass, NULL, &lSize) == ERROR_SUCCESS;
}
HRESULT _RegItems_BindToObject(LPTSTR pszMachine, LPCREGITEMSINFO lpInfo,
LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, LPVOID * ppvOut, BOOL bOneLevel)
{
LPIDREGITEM pidri;
IPersistFolder * ppf;
LPCITEMIDLIST pidlNext, pidlHere, pidlAbs;
HRESULT hres;
if (!_RegItems_IsRegFromInfo(lpInfo, (LPCIDREGITEM)pidl))
{
return E_INVALIDARG;
}
if (!_RegItems_IsSubObject(lpInfo, &((LPCIDREGITEM)pidl)->clsid))
{
return E_INVALIDARG;
}
pidlNext = _ILNext(pidl);
if (ILIsEmpty(pidlNext))
{
pidlHere = pidl;
}
else
{
pidlHere = ILClone(pidl);
if (!pidlHere)
{
return E_OUTOFMEMORY;
}
_ILNext(pidlHere)->mkid.cb = 0;
}
pidri = (LPIDREGITEM)pidlHere;
pidlAbs = ILCombine(lpInfo->pidlThis, pidlHere);
if (pidlAbs)
{
IUnknown* punk;
hres = SHCoCreateInstance(NULL, &pidri->clsid, NULL, &IID_IUnknown, &punk);
if (SUCCEEDED(hres))
{
if (NULL != pszMachine)
{
// It's a remote registry item! Use IRemoteComputer
IRemoteComputer * premc;
hres = punk->lpVtbl->QueryInterface(punk, &IID_IRemoteComputer, &premc);
if (SUCCEEDED(hres))
{
hres = premc->lpVtbl->Initialize(premc, pszMachine, FALSE);
premc->lpVtbl->Release(premc);
}
#ifdef UNICODE
else
{
IRemoteComputerA * premca;
hres = punk->lpVtbl->QueryInterface(punk, &IID_IRemoteComputerA, &premca);
if (SUCCEEDED(hres))
{
CHAR szComputerA[MAX_PATH]; // BUGBUG: max_computername_len?
// Convert the computer name to ansi
WideCharToMultiByte(CP_ACP, 0, pszMachine, -1,
szComputerA, ARRAYSIZE(szComputerA),
NULL, NULL);
hres = premca->lpVtbl->Initialize(premca, szComputerA, FALSE);
premca->lpVtbl->Release(premca);
}
}
#endif // UNICODE
}
if (SUCCEEDED(hres))
{
IPersistFolder * ppf;
hres = punk->lpVtbl->QueryInterface(punk, &IID_IPersistFolder, &ppf);
if (SUCCEEDED(hres))
{
hres = ppf->lpVtbl->Initialize(ppf, pidlAbs);
if (SUCCEEDED(hres))
{
if (ILIsEmpty(pidlNext) || bOneLevel)
{
hres = ppf->lpVtbl->QueryInterface(ppf, riid, ppvOut);
}
else
{
IShellFolder *psfNext;
// Recurse down to the next level
hres = ppf->lpVtbl->QueryInterface(ppf, &IID_IShellFolder,
&psfNext);
if (SUCCEEDED(hres))
{
hres = psfNext->lpVtbl->BindToObject(psfNext,
pidlNext, pbc, riid, ppvOut);
psfNext->lpVtbl->Release(psfNext);
}
}
}
ppf->lpVtbl->Release(ppf);
}
}
punk->lpVtbl->Release(punk);
}
ILFree((LPITEMIDLIST)pidlAbs);
}
else
{
hres = E_OUTOFMEMORY;
}
if (pidlHere != pidl)
{
// We can only get here if we allocated the pidlHere
ILFree((LPITEMIDLIST)pidlHere);
}
return hres;
}
//
// EnumShellFolder stuff
//
typedef struct
{
IEnumIDList eu;
int cRef;
int iCur;
DWORD grfFlags;
LPENUMIDLIST peuFolder;
CRegItemsSF * psfri;
HDKA hdka;
} RegItemsESF, *PRegItemsESF;
STDMETHODIMP CRegItems_ESF_QueryInterface(LPENUMIDLIST peunk, REFIID riid, LPVOID * ppvObj)
{
PRegItemsESF this = IToClass(RegItemsESF, eu, peunk);
if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IEnumIDList))
{
this->cRef++;
*ppvObj = &this->eu;
return NOERROR;
}
else
{
*ppvObj = NULL;
return E_NOINTERFACE;
}
}
STDMETHODIMP_(ULONG) CRegItems_ESF_AddRef(LPENUMIDLIST peunk)
{
PRegItemsESF this = IToClass(RegItemsESF, eu, peunk);
this->cRef++;
return this->cRef;
}
STDMETHODIMP_(ULONG) CRegItems_ESF_Release(LPENUMIDLIST peunk)
{
PRegItemsESF this = IToClass(RegItemsESF, eu, peunk);
this->cRef--;
if (this->cRef > 0)
{
return(this->cRef);
}
this->peuFolder->lpVtbl->Release(this->peuFolder);
this->psfri->sf.lpVtbl->Release(&this->psfri->sf);
if (this->hdka)
{
DKA_Destroy(this->hdka);
}
LocalFree((HLOCAL)this);
return(0);
}
STDMETHODIMP CRegItems_ESF_Next(LPENUMIDLIST peunk, ULONG celt,
LPITEMIDLIST * ppidlOut, ULONG * pceltFetched)
{
PRegItemsESF this = IToClass(RegItemsESF, eu, peunk);
IDLREGITEM idlRegItem;
HRESULT hres;
int iReqItems = this->psfri->rii.iReqItems;
CLSID clsid;
const CLSID * pclsid;
TryAgain:
if (this->iCur < iReqItems)
{
++this->iCur;
// feed the back in reverse order as they were given to us...
pclsid = this->psfri->sReqItems[iReqItems - this->iCur].pclsid;
goto FillAndRet;
}
if (this->hdka)
{
while ((this->iCur - iReqItems) < DKA_GetItemCount(this->hdka))
{
LPCTSTR pszKey = DKA_GetKey(this->hdka, this->iCur-iReqItems);
++this->iCur;
pclsid = &clsid;
if (FAILED(SHCLSIDFromString(pszKey, &clsid)))
{
continue;
}
// If this is one of the "required" items, then we have
// already enumerated it.
if (_RegItems_NReqItem(&this->psfri->rii, pclsid) >= 0)
{
continue;
}
FillAndRet:
// We're filling the regitem with class id pclsid. If this is a
// remote item, first invoke the class to see if it really wants
// to be enumerated for this remote computer.
if (this->psfri->pszMachine)
{
IUnknown* punk;
hres = SHCoCreateInstance(NULL, pclsid, NULL, &IID_IUnknown, &punk);
if (SUCCEEDED(hres))
{
// It's a remote registry item! Use IRemoteComputer
IRemoteComputer * premc;
hres = punk->lpVtbl->QueryInterface(punk, &IID_IRemoteComputer, &premc);
if (SUCCEEDED(hres))
{
hres = premc->lpVtbl->Initialize(premc, this->psfri->pszMachine, TRUE);
premc->lpVtbl->Release(premc);
}
#ifdef UNICODE
else
{
IRemoteComputerA * premca;
hres = punk->lpVtbl->QueryInterface(punk, &IID_IRemoteComputerA, &premca);
if (SUCCEEDED(hres))
{
CHAR szComputerA[MAX_PATH]; // BUGBUG: max_computername_len?
// Convert the computer name to ansi
WideCharToMultiByte(CP_ACP, 0, this->psfri->pszMachine, -1,
szComputerA, ARRAYSIZE(szComputerA),
NULL, NULL);
hres = premca->lpVtbl->Initialize(premca, szComputerA, TRUE);
premca->lpVtbl->Release(premca);
}
}
#endif // UNICODE
punk->lpVtbl->Release(punk);
}
if (FAILED(hres))
{
goto TryAgain;
}
}
// Ok, actually enumerate the item
_RegItems_FillID(&this->psfri->rii, (LPSHITEMID)&idlRegItem.idri, pclsid);
idlRegItem.cbNext = 0;
// The "normal" case would want both types, so we will
// special case that to not look in the Registry
if ((this->grfFlags & (SHCONTF_FOLDERS|SHCONTF_NONFOLDERS))
!= (SHCONTF_FOLDERS|SHCONTF_NONFOLDERS))
{
DWORD rgfInOut = SFGAO_FOLDER;
LPCITEMIDLIST pidl = (LPCITEMIDLIST)&idlRegItem;
if (FAILED(CRegItems_GetAttributesOf(
&this->psfri->sf, 1, &pidl, &rgfInOut)))
{
rgfInOut = 0;
}
if (rgfInOut & SFGAO_FOLDER)
{
if (!(this->grfFlags & SHCONTF_FOLDERS))
{
goto TryAgain;
}
}
else
{
if (!(this->grfFlags & SHCONTF_NONFOLDERS))
{
goto TryAgain;
}
}
}
hres = SHILClone((LPCITEMIDLIST)&idlRegItem, ppidlOut);
if (SUCCEEDED(hres) && pceltFetched)
{
*pceltFetched = 1;
}
return(hres);
}
}
// Either there is no DKA or we are done with it, so just pass along to
// to the folder
return(this->peuFolder->lpVtbl->Next(this->peuFolder, celt, ppidlOut,
pceltFetched));
}
STDMETHODIMP CRegItems_QueryInterface(IShellFolder *psf, REFIID riid, LPVOID * ppvObj)
{
CRegItemsSF * this = IToClass(CRegItemsSF, sf, psf);
if (IsEqualIID(riid, &IID_IUnknown)
|| IsEqualIID(riid, &IID_IShellFolder))
{
*ppvObj = psf;
psf->lpVtbl->AddRef(psf);
return NOERROR;
}
return(this->rii.psfInner->lpVtbl->QueryInterface(this->rii.psfInner, riid, ppvObj));
}
STDMETHODIMP_(ULONG) CRegItems_AddRef(IShellFolder *psf)
{
CRegItemsSF * this = IToClass(CRegItemsSF, sf, psf);
++this->cRef;
return(this->cRef);
}
extern IShellFolder *g_psfDrives;
STDMETHODIMP_(ULONG) CRegItems_Release(IShellFolder *psf)
{
CRegItemsSF * this = IToClass(CRegItemsSF, sf, psf);
--this->cRef;
if (this->cRef)
{
return(this->cRef);
}
if (&this->sf == g_psfDrives)
{
#ifdef DEBUG
DebugMsg(DM_TRACE, TEXT("********** WRONG! ********* Call Chee..."));
Assert(0);
#endif
g_psfDrives = NULL;
}
this->rii.psfInner->lpVtbl->Release(this->rii.psfInner);
if (this->pszMachine)
{
LocalFree(this->pszMachine);
}
LocalFree((HLOCAL)this);
return(0);
}
HRESULT ParseNextLevel(IShellFolder *psf, HWND hwndOwner, LPBC pbc,
LPCITEMIDLIST pidlNext, LPOLESTR pwzRest, LPITEMIDLIST *ppidlOut,
ULONG * pdwAttributes)
{
IShellFolder *psfNext;
ULONG chEaten;
LPITEMIDLIST pidlRest;
HRESULT hres;
if (!*pwzRest)
{
// pidlNext should be a simple pidl.
Assert(!ILIsEmpty(pidlNext) && ILIsEmpty(_ILNext(pidlNext)));
if (pdwAttributes)
{
CRegItems_GetAttributesOf(psf, 1, &pidlNext, pdwAttributes);
}
return(SHILClone(pidlNext, ppidlOut));
}
Assert(*pwzRest == TEXT('\\'));
++pwzRest;
hres = psf->lpVtbl->BindToObject(psf, pidlNext, pbc, &IID_IShellFolder,
&psfNext);
if (FAILED(hres))
{
return(hres);
}
hres = psfNext->lpVtbl->ParseDisplayName(psfNext, hwndOwner, pbc, pwzRest,
&chEaten, &pidlRest, pdwAttributes);
psfNext->lpVtbl->Release(psfNext);
if (FAILED(hres))
{
return(hres);
}
hres = SHILCombine(pidlNext, pidlRest, ppidlOut);
SHFree(pidlRest);
return(hres);
}
// This is a separate function so that the string is not on the stack
// of the calling function
HRESULT _RegItems_ParseRegName(CRegItemsSF * this,
HWND hwndOwner, LPBC pbc, LPOLESTR pwzDisplayName, LPITEMIDLIST * ppidlOut,
ULONG * pdwAttributes)
{
IDLREGITEM idlRegItem;
TCHAR szDisplayName[GUIDSTR_MAX+10];
HRESULT hres;
CLSID clsid;
LPOLESTR pwzNext;
// Note that we add 2 to skip the RegItem identifier characters
pwzDisplayName += 2;
for (pwzNext=pwzDisplayName; *pwzNext && *pwzNext!=TEXT('\\'); ++pwzNext)
{
// Skip to a '\\'
}
OleStrToStrN(szDisplayName, ARRAYSIZE(szDisplayName),
pwzDisplayName, pwzNext-pwzDisplayName);
// Note that szDisplayName is NOT NULL terminated, but SHCLSIDFromString
// doesn't seem to mind.
hres = SHCLSIDFromString(szDisplayName, &clsid);
if (FAILED(hres))
{
return(hres);
}
if (!_RegItems_IsSubObject(&this->rii, &clsid))
{
return E_INVALIDARG;
}
_RegItems_FillID(&this->rii, (LPSHITEMID)&idlRegItem.idri, &clsid);
idlRegItem.cbNext = 0;
return(ParseNextLevel(&this->sf, hwndOwner, pbc, (LPCITEMIDLIST)&idlRegItem, pwzNext,
ppidlOut, pdwAttributes));
}
STDMETHODIMP CRegItems_ParseDisplayName(IShellFolder *psf,
HWND hwndOwner, LPBC pbc, LPOLESTR lpszDisplayName,
ULONG * pchEaten, LPITEMIDLIST * ppidlOut, ULONG* pdwAttributes)
{
CRegItemsSF * this = IToClass(CRegItemsSF, sf, psf);
// ::{guid} lets you get the pidl for a reg item
if (lpszDisplayName[0] == this->rii.cRegItem &&
lpszDisplayName[1] == this->rii.cRegItem)
{
return _RegItems_ParseRegName(this, hwndOwner,
pbc, lpszDisplayName, ppidlOut, pdwAttributes);
}
return this->rii.psfInner->lpVtbl->ParseDisplayName(this->rii.psfInner,
hwndOwner, pbc, lpszDisplayName, pchEaten, ppidlOut, pdwAttributes);
}
extern IEnumIDListVtbl c_RegItemsESFVtbl; // forward
STDMETHODIMP CRegItems_EnumObjects(IShellFolder * psf, HWND hwndOwner, DWORD grfFlags, LPENUMIDLIST *ppenumOut)
{
CRegItemsSF * this = IToClass(CRegItemsSF, sf, psf);
HRESULT hres;
PRegItemsESF pesf = (void*)LocalAlloc(LPTR, SIZEOF(RegItemsESF));
if (!pesf)
{
*ppenumOut = NULL; // assume error
return E_OUTOFMEMORY;
}
hres = this->rii.psfInner->lpVtbl->EnumObjects(this->rii.psfInner, hwndOwner, grfFlags, &(pesf->peuFolder));
if (FAILED(hres))
{
LocalFree((HLOCAL)pesf);
return(hres);
}
// I don't really care that much if this fails
pesf->hdka = DKA_Create(this->rii.hkRegItems, NULL, NULL, NULL, FALSE);
// Note that hdka could be NULL if the hkey did not exist
psf->lpVtbl->AddRef(psf);
pesf->psfri = this;
pesf->eu.lpVtbl = &c_RegItemsESFVtbl;
pesf->cRef = 1;
pesf->iCur = 0;
pesf->grfFlags = grfFlags;
*ppenumOut = &pesf->eu;
return NOERROR;
}
// Vtable
#ifndef WINNT
#pragma data_seg(".text", "CODE")
#endif
IEnumIDListVtbl c_RegItemsESFVtbl =
{
CRegItems_ESF_QueryInterface,
CRegItems_ESF_AddRef,
CRegItems_ESF_Release,
CRegItems_ESF_Next,
CDefEnum_Skip,
CDefEnum_Reset,
CDefEnum_Clone,
};
#ifndef WINNT
#pragma data_seg()
#endif
STDMETHODIMP CRegItems_BindToObject(IShellFolder *psf, LPCITEMIDLIST pidl, LPBC pbc,
REFIID riid, LPVOID * ppvOut)
{
CRegItemsSF * this = IToClass(CRegItemsSF, sf, psf);
if (_RegItems_IsReg(psf, pidl))
{
return _RegItems_BindToObject(this->pszMachine, &this->rii, pidl, pbc, riid, ppvOut, FALSE);
}
else
{
return this->rii.psfInner->lpVtbl->BindToObject(this->rii.psfInner,
pidl, pbc, riid, ppvOut);
}
}
STDMETHODIMP CRegItems_CompareIDs(IShellFolder *psf, LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
{
CRegItemsSF * this = IToClass(CRegItemsSF, sf, psf);
LPCIDREGITEM pidri1 = (LPCIDREGITEM)pidl1;
LPCIDREGITEM pidri2 = (LPCIDREGITEM)pidl2;
LPCITEMIDLIST pidlNext1, pidlNext2;
IShellFolder *psfNext;
int iRes;
HRESULT hres;
// Put all RegItem's first if this->rii.iCmp==1, last if -1
if (_RegItems_IsReg(psf, pidl1))
{
if (_RegItems_IsReg(psf, pidl2))
{
// Both are RegItem's
STRRET StrRet1, StrRet2;
int nReqItem1, nReqItem2;
// All of the required items come first, in reverse
// order (to make this simpler)
nReqItem1 = _RegItems_NReqItem(&this->rii, &pidri1->clsid);
nReqItem2 = _RegItems_NReqItem(&this->rii, &pidri2->clsid);
if (nReqItem1==-1 && nReqItem2==-1)
{
#ifdef UNICODE
TCHAR szItemName1[MAX_PATH];
TCHAR szItemName2[MAX_PATH];
#endif
RegItems_GetName(&this->rii, pidl1, &StrRet1);
RegItems_GetName(&this->rii, pidl2, &StrRet2);
#ifdef UNICODE
StrRetToStrN(szItemName1,ARRAYSIZE(szItemName1),&StrRet1,pidl1);
StrRetToStrN(szItemName2,ARRAYSIZE(szItemName2),&StrRet2,pidl2);
iRes = lstrcmp(szItemName1,szItemName2);
#else
iRes = lstrcmp(StrRet1.cStr, StrRet2.cStr);
#endif
}
else
{
iRes = nReqItem2 - nReqItem1;
}
}
else
{
// Only pidl1 is a RegItem.
iRes = -this->rii.iCmp;
}
}
else if (_RegItems_IsReg(psf, pidl2))
{
// Only pidl2 is a RegItem
iRes = this->rii.iCmp;
}
else
{
return(this->rii.psfInner->lpVtbl->CompareIDs(this->rii.psfInner,
lParam, pidl1, pidl2));
}
if (iRes != 0)
{
return(ResultFromShort(iRes));
}
// The names are the same; make sure the CLSID's are the same
iRes = memcmp(&pidri1->clsid, &pidri2->clsid, SIZEOF(CLSID));
if (iRes != 0)
{
return(ResultFromShort(iRes));
}
// If the class ID's really are the same, we'd better check the next
// level
pidlNext1 = _ILNext(pidl1);
pidlNext2 = _ILNext(pidl2);
if (ILIsEmpty(pidlNext1))
{
if (ILIsEmpty(pidlNext2))
{
return(ResultFromShort(0));
}
return(ResultFromShort(-1));
}
else if (ILIsEmpty(pidlNext2))
{
return(ResultFromShort(1));
}
hres = _RegItems_BindToObject(this->pszMachine, &this->rii, pidl1, NULL, &IID_IShellFolder,
&psfNext, TRUE);
if (FAILED(hres))
{
return(hres);
}
hres = psfNext->lpVtbl->CompareIDs(psfNext, lParam, pidlNext1, pidlNext2);
psfNext->lpVtbl->Release(psfNext);
return(hres);
}
STDMETHODIMP CRegItems_CreateViewObject(IShellFolder *psf, HWND hwndOwner, REFIID riid, LPVOID * ppvOut)
{
CRegItemsSF * this = IToClass(CRegItemsSF, sf, psf);
return this->rii.psfInner->lpVtbl->CreateViewObject(this->rii.psfInner, hwndOwner, riid, ppvOut);
}
STDMETHODIMP CRegItems_GetAttributesOf(IShellFolder *psf, UINT cidl, LPCITEMIDLIST * apidl,
ULONG * prgfInOut)
{
CRegItemsSF * this = IToClass(CRegItemsSF, sf, psf);
UINT rgfThis, rgfOut = *prgfInOut;
LPCITEMIDLIST *ppidl, *ppidlEnd;
int i;
HRESULT hres;
if (!cidl)
{
// This is a special case for the folder as a whole, so I know
// nothing about it.
return(this->rii.psfInner->lpVtbl->GetAttributesOf(
this->rii.psfInner, cidl, apidl, prgfInOut));
}
// REVIEW: If this is too slow, we can cache this buffer
ppidl = (void*)LocalAlloc(LPTR, cidl*SIZEOF(LPCITEMIDLIST));
if (!ppidl)
{
return E_OUTOFMEMORY;
}
ppidlEnd = ppidl + cidl;
for (i=cidl-1; i>=0; --i)
{
LPIDREGITEM pidri = (LPIDREGITEM)apidl[i];
int nReqItem;
if (_RegItems_IsReg(psf, (LPCITEMIDLIST)pidri))
{
--cidl;
rgfThis = this->rii.rgfRegItems;
nReqItem = _RegItems_NReqItem(&this->rii, &pidri->clsid);
if (nReqItem >= 0)
{
rgfThis |= this->rii.pReqItems[nReqItem].dwAttributes;
}
else
{
rgfThis |= _RegItems_GetAttributesFromCLSID(&pidri->clsid);
}
rgfOut &= rgfThis;
}
else
{
--ppidlEnd;
*ppidlEnd = (LPCITEMIDLIST)pidri;
}
}
if (cidl)
{
rgfThis = rgfOut;
hres = this->rii.psfInner->lpVtbl->GetAttributesOf(this->rii.psfInner,
cidl, ppidlEnd, &rgfThis);
if (FAILED(hres))
{
return(hres);
}
rgfOut &= rgfThis;
}
LocalFree((HLOCAL)ppidl);
*prgfInOut = rgfOut;
return NOERROR;
}
//
// Returns: TRUE, if any of pidl points to a reg item.
//
BOOL CRegItem_AnyRegItem(IShellFolder * psf, UINT cidl, LPCITEMIDLIST apidl[])
{
UINT i;
for (i = 0; i < cidl; i++) {
if (_RegItems_IsReg(psf, apidl[i]))
return TRUE;
}
return FALSE;
}
STDMETHODIMP CRegItems_GetUIObjectOf(IShellFolder *psf, HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl,
REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
{
CRegItemsSF * this = IToClass(CRegItemsSF, sf, psf);
if ((IsEqualIID(riid, &IID_IExtractIcon)
#ifdef UNICODE
|| IsEqualIID(riid, &IID_IExtractIconA)
#endif
) && cidl == 1 && apidl && apidl[0] && _RegItems_IsReg(psf, apidl[0]))
{
HRESULT hres;
HKEY hkCLSID;
LPCTSTR pszIconFile;
int iDefIcon;
LPCIDREGITEM pidri = (LPCIDREGITEM)apidl[0];
int nReqItem = _RegItems_NReqItem(&this->rii, &pidri->clsid);
if (nReqItem >= 0)
{
pszIconFile = this->rii.pReqItems[nReqItem].pszIconFile;
iDefIcon = this->rii.pReqItems[nReqItem].iDefIcon;
}
else
{
pszIconFile = NULL;
iDefIcon = II_FOLDER;
}
*ppvOut = NULL;
hres = SHRegGetCLSIDKey(&((LPCIDREGITEM)apidl[0])->clsid, NULL, TRUE, &hkCLSID);
if (SUCCEEDED(hres))
{
LPEXTRACTICON pxicon;
hres = SHCreateDefExtIconKey(hkCLSID, pszIconFile, iDefIcon, iDefIcon, GIL_PERCLASS, &pxicon);
if (hres == NOERROR) // Normal good iextracticon guy
*ppvOut = pxicon;
else if (SUCCEEDED(hres)) // Probably S_FALSE guy
pxicon->lpVtbl->Release(pxicon); // Lose this bad guy
RegCloseKey(hkCLSID);
}
if (*ppvOut == NULL)
{
RegItems_GetClassKey(apidl[0], &hkCLSID);
hres = SHCreateDefExtIconKey(hkCLSID, pszIconFile, iDefIcon, iDefIcon, GIL_PERCLASS, (LPEXTRACTICON *)ppvOut);
RegCloseKey(hkCLSID);
}
#ifdef UNICODE
if (SUCCEEDED(hres) && IsEqualIID(riid, &IID_IExtractIconA))
{
LPEXTRACTICON pxicon = *ppvOut;
hres = pxicon->lpVtbl->QueryInterface(pxicon,riid,ppvOut);
pxicon->lpVtbl->Release(pxicon);
}
#endif
return hres;
}
else if (CRegItem_AnyRegItem(psf, cidl, apidl))
{
if (IsEqualIID(riid, &IID_IDataObject))
{
return CIDLData_CreateFromIDArray(this->rii.pidlThis, cidl, apidl, (LPDATAOBJECT *)ppvOut);
}
}
return this->rii.psfInner->lpVtbl->GetUIObjectOf(this->rii.psfInner, hwndOwner,
cidl, apidl, riid, prgfInOut, ppvOut);
}
STDMETHODIMP CRegItems_GetDisplayNameOf(IShellFolder *psf, LPCITEMIDLIST pidl,
DWORD uFlags, LPSTRRET lpName)
{
CRegItemsSF * this = IToClass(CRegItemsSF, sf, psf);
HRESULT hres;
if (_RegItems_IsReg(psf, pidl))
{
IShellFolder * psfNext;
LPCITEMIDLIST pidlNext = _ILNext(pidl);
if (ILIsEmpty(pidlNext))
{
if (this->pszMachine && (uFlags == SHGDN_NORMAL))
{
return RegItems_GetNameRemote(this->pszMachine, &this->rii, pidl, lpName);
}
else
{
return RegItems_GetName(&this->rii, pidl, lpName);
}
}
// Yes, it contains more than one ID
// REVIEW: Then again, maybe we are just supposed to show the
// name of the last guy in the list, and if it is a FS guy,
// then it may show the full path depending on the flags.
hres = _RegItems_BindToObject(this->pszMachine, &this->rii, pidl, NULL, &IID_IShellFolder, &psfNext, TRUE);
if (SUCCEEDED(hres))
{
hres = psfNext->lpVtbl->GetDisplayNameOf(psfNext, pidlNext, uFlags, lpName);
// If it returns an offset to the pidlNext, we should
// change the offset relative to pidl.
if (SUCCEEDED(hres) && lpName->uType==STRRET_OFFSET)
{
lpName->uOffset += (LPBYTE)pidlNext - (LPBYTE)pidl;
}
psfNext->lpVtbl->Release(psfNext);
}
return(hres);
}
else
{
return this->rii.psfInner->lpVtbl->GetDisplayNameOf(this->rii.psfInner, pidl, uFlags, lpName);
}
}
STDMETHODIMP CRegItems_SetNameOf(IShellFolder *psf, HWND hwndOwner,
LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD uFlags, LPITEMIDLIST * ppidlOut)
{
CRegItemsSF * this = IToClass(CRegItemsSF, sf, psf);
if (_RegItems_IsReg(psf, pidl))
{
HRESULT hres = E_INVALIDARG;
HKEY hkCLSID;
if (ppidlOut)
*ppidlOut = NULL;
hres = RegItems_GetClassKey(pidl, &hkCLSID);
if (SUCCEEDED(hres))
{
TCHAR szName[MAX_PATH];
OleStrToStr(szName, lpszName);
if (RegSetValue(hkCLSID, NULL, REG_SZ, szName, lstrlen(szName))
== ERROR_SUCCESS)
{
LPITEMIDLIST pidlAbs;
hres = NOERROR;
// Generate an UpdateItem notification to let the
// system know to regenerate the information...
pidlAbs = ILCombine(this->rii.pidlThis, pidl);
if (pidlAbs)
{
SHChangeNotify(SHCNE_RENAMEFOLDER, SHCNF_IDLIST, pidlAbs, pidlAbs);
ILFree(pidlAbs);
}
if (ppidlOut)
{
// The caller wanted a pidl returned, so clone it...
*ppidlOut = ILClone(pidl);
}
}
else
hres = E_FAIL;
}
return hres;
}
else
{
return this->rii.psfInner->lpVtbl->SetNameOf(this->rii.psfInner, hwndOwner, pidl, lpszName, uFlags, ppidlOut);
}
}
#ifndef WINNT
#pragma data_seg(".text", "CODE")
#endif
IShellFolderVtbl c_RegItemsSFVtbl =
{
CRegItems_QueryInterface,
CRegItems_AddRef,
CRegItems_Release,
CRegItems_ParseDisplayName,
CRegItems_EnumObjects,
CRegItems_BindToObject,
CDefShellFolder_BindToStorage,
CRegItems_CompareIDs,
CRegItems_CreateViewObject,
CRegItems_GetAttributesOf,
CRegItems_GetUIObjectOf,
CRegItems_GetDisplayNameOf,
CRegItems_SetNameOf,
};
#ifndef WINNT
#pragma data_seg()
#endif
// WARNING: Note that we copy the pointer to lpInfo->pidlThis.
//
HRESULT RegItems_AddToShellFolder(LPCREGITEMSINFO lpInfo, IShellFolder **ppsf)
{
int iReqItems = lpInfo->iReqItems;
CRegItemsSF * this = (void*)LocalAlloc(LPTR, SIZEOF(CRegItemsSF) + iReqItems * SIZEOF(REQREGITEM));
if (!this)
{
return E_OUTOFMEMORY;
}
lpInfo->psfInner->lpVtbl->AddRef(lpInfo->psfInner);
this->sf.lpVtbl = &c_RegItemsSFVtbl;
this->cRef = 1;
this->pszMachine = NULL;
this->rii = *lpInfo;
for (--iReqItems; iReqItems>=0; --iReqItems)
{
this->sReqItems[iReqItems] = lpInfo->pReqItems[iReqItems];
}
this->rii.pReqItems = &this->sReqItems[0];
*ppsf = &this->sf;
return NOERROR;
}
// WARNING: Note that we copy the pointer to lpInfo->pidlThis.
//
HRESULT RegItems_AddToShellFolderRemote(LPCREGITEMSINFO lpInfo, LPTSTR pszMachine, IShellFolder **ppsf)
{
CRegItemsSF * this;
HRESULT hres = RegItems_AddToShellFolder(lpInfo, ppsf);
if (FAILED(hres))
{
return hres;
}
this = IToClass(CRegItemsSF, sf, *ppsf);
if (NULL != pszMachine)
{
this->pszMachine = (LPTSTR)LocalAlloc(LPTR, (1 + lstrlen(pszMachine)) * sizeof(TCHAR));
if (!this->pszMachine)
{
CRegItems_Release(&this->sf);
return E_OUTOFMEMORY;
}
lstrcpy(this->pszMachine, pszMachine);
}
return NOERROR;
}
HRESULT RegItems_GetName(LPCREGITEMSINFO lpInfo, LPCITEMIDLIST pidl, LPSTRRET pStrRet)
{
LPCIDREGITEM pidri = (LPCIDREGITEM)pidl;
HRESULT hres = E_INVALIDARG;
HKEY hkCLSID;
LONG lLenBuff;
LONG lLen;
LPTSTR lpNameBuff;
#ifdef UNICODE
TCHAR szName[MAX_PATH];
pStrRet->uType = STRRET_OLESTR;
lpNameBuff = szName;
lLen = lLenBuff = ARRAYSIZE(szName);
#else
pStrRet->uType = STRRET_CSTR;
lpNameBuff = pStrRet->cStr;
lLen = lLenBuff = ARRAYSIZE(pStrRet->cStr);
#endif
*lpNameBuff = TEXT('\0');
hres = RegItems_GetClassKey(pidl, &hkCLSID);
if (SUCCEEDED(hres))
{
if (RegQueryValue(hkCLSID, NULL, lpNameBuff, &lLen)
!= ERROR_SUCCESS || *lpNameBuff==TEXT('\0'))
{
// Can this ever happen?
hres = E_FAIL;
}
SHRegCloseKey(hkCLSID);
}
//
// We need to be able to open/display controls and printers
// even though the registry is broken.
//
if (FAILED(hres))
{
int nReqItem = _RegItems_NReqItem(lpInfo, &pidri->clsid);
if (nReqItem >= 0)
{
lLen = lLenBuff;
LoadString(HINST_THISDLL, lpInfo->pReqItems[nReqItem].uNameID,
lpNameBuff, lLen);
hres = NOERROR;
}
else
{
// REVIEW: We have some Registry problem here, and I
// don't know what to do about it
Assert(FALSE);
}
}
#ifdef UNICODE
if (SUCCEEDED(hres))
{
pStrRet->pOleStr = SHAlloc((lstrlen(lpNameBuff)+1)*SIZEOF(TCHAR));
if (pStrRet->pOleStr == NULL)
{
hres = E_OUTOFMEMORY;
}
else
{
lstrcpy(pStrRet->pOleStr,lpNameBuff);
}
}
else
{
// We can't leave a NULL pOleStr in the failure case,
// so patch it up to be a blank CSTR
pStrRet->uType = STRRET_CSTR;
pStrRet->cStr[0] = TEXT('\0');
}
#endif
return(hres);
}
HRESULT RegItems_GetNameRemote(LPTSTR pszMachine, LPCREGITEMSINFO lpInfo, LPCITEMIDLIST pidl, LPSTRRET pStrRet)
{
LPCIDREGITEM pidri = (LPCIDREGITEM)pidl;
HRESULT hres = E_INVALIDARG;
HKEY hkCLSID;
TCHAR szName[MAX_PATH];
LPTSTR pszRet;
LONG lNameLen = ARRAYSIZE(szName);
if (NULL == pszMachine)
{
return E_INVALIDARG;
}
hres = RegItems_GetClassKey(pidl, &hkCLSID);
if (SUCCEEDED(hres))
{
if (RegQueryValue(hkCLSID, NULL, szName, &lNameLen)
!= ERROR_SUCCESS || *szName==TEXT('\0'))
{
// Can this ever happen?
hres = E_FAIL;
}
SHRegCloseKey(hkCLSID);
}
//
// We need to be able to open/display controls and printers
// even though the registry is broken.
//
if (FAILED(hres))
{
int nReqItem = _RegItems_NReqItem(lpInfo, &pidri->clsid);
if (nReqItem >= 0)
{
LoadString(HINST_THISDLL, lpInfo->pReqItems[nReqItem].uNameID,
szName, ARRAYSIZE(szName));
hres = NOERROR;
}
else
{
// REVIEW: We have some Registry problem here, and I
// don't know what to do about it
Assert(FALSE);
}
}
// szName now holds the item name, and pszMachine holds the machine.
// Note that pszMachine is in UNC form, i.e. "\\machine", so skip the first
// two characters. Be careful, just in case.
if (pszMachine[0] == TEXT('\\') && pszMachine[1] == TEXT('\\'))
{
pszMachine += 2;
}
pszRet = ShellConstructMessageString(HINST_THISDLL, MAKEINTRESOURCE(IDS_DSPTEMPLATE_WITH_ON), pszMachine, szName);
if (pszRet)
{
#ifdef UNICODE
pStrRet->uType = STRRET_OLESTR;
pStrRet->pOleStr = pszRet;
#else
pStrRet->uType = STRRET_CSTR;
lstrcpyn(pStrRet->cStr, pszRet, ARRAYSIZE(pStrRet->cStr));
SHFree(pszRet);
#endif
}
else
{
// Set failure to be a blank CSTR
pStrRet->uType = STRRET_CSTR;
pStrRet->cStr[0] = TEXT('\0');
}
return(hres);
}
LPITEMIDLIST RegItems_CreateRelID(LPCREGITEMSINFO lpInfo, const CLSID *pclsid)
{
IDLREGITEM idlRegItem;
_RegItems_FillID(lpInfo, (LPSHITEMID)&idlRegItem.idri, pclsid);
idlRegItem.cbNext = 0;
return ILClone((LPCITEMIDLIST)&idlRegItem);
}
const CLSID * RegItems_GetClassID(LPCITEMIDLIST pidl)
{
LPCIDREGITEM pidri = (LPCIDREGITEM)pidl;
return &pidri->clsid;
}
HRESULT RegItems_BindToObject(LPCREGITEMSINFO lpInfo, LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, LPVOID * ppvOut)
{
return _RegItems_BindToObject(NULL, lpInfo, pidl, pbc, riid, ppvOut, FALSE);
}
IShellFolder * RegItems_GetInnerShellFolder(IShellFolder *psf)
{
CRegItemsSF * this = IToClass(CRegItemsSF, sf, psf);
if (psf->lpVtbl == &c_RegItemsSFVtbl)
{
return(this->rii.psfInner);
}
else
{
return(psf);
}
}
HRESULT RegItems_GetClassKeys(IShellFolder *psf, LPCITEMIDLIST pidl,
HKEY *phkCLSID, HKEY *phkBase)
{
LPCIDREGITEM pidri = (LPCIDREGITEM)pidl;
TCHAR szThisCLSID[GUIDSTR_MAX];
TCHAR szPath[GUIDSTR_MAX + 20]; // Add room for "CLSID\\"
if (phkCLSID)
{
StringFromGUID2A(&pidri->clsid, szThisCLSID, ARRAYSIZE(szThisCLSID));
wsprintf(szPath, c_szSSlashS, c_szCLSID, szThisCLSID);
if (SHRegOpenKey(HKEY_CLASSES_ROOT, szPath, phkCLSID) != ERROR_SUCCESS)
{
// BUGBUG: We should probably look for more error codes
return E_INVALIDARG;
}
}
if (phkBase)
{
LONG rgfInOut = SFGAO_FOLDER;
if (FAILED(psf->lpVtbl->GetAttributesOf(psf, 1, &pidl, &rgfInOut)))
{
rgfInOut = 0;
}
_SHGetBaseKey(rgfInOut&SFGAO_FOLDER, phkBase);
}
return NOERROR;
}
HRESULT
_RegItems_DeleteRegItem(IShellFolder *psf, LPCITEMIDLIST pidl, BOOL fIgnoreAttrs)
{
CRegItemsSF *this;
const CLSID *pclsid;
HKEY hkParent;
TCHAR szClass[GUIDSTR_MAX];
LPITEMIDLIST pidlAbs;
//
// sanity
//
if (!_RegItems_IsReg(psf, pidl))
return E_INVALIDARG;
this = IToClass(CRegItemsSF, sf, psf);
pclsid = &((LPIDREGITEM)pidl)->clsid;
if (_RegItems_NReqItem(&this->rii, pclsid) >= 0)
{
// attempting to delete a 'required' item!!!
Assert(FALSE);
return E_ACCESSDENIED;
}
if (!fIgnoreAttrs &&
!(_RegItems_GetAttributesFromCLSID(pclsid) & SFGAO_CANDELETE))
{
return E_ACCESSDENIED;
}
//
// delete the item
//
StringFromGUID2A(pclsid, szClass, ARRAYSIZE(szClass));
hkParent = this->rii.hkRegItems;
if (!*szClass || !hkParent ||
(RegDeleteKey(hkParent, szClass) != ERROR_SUCCESS))
{
Assert(FALSE);
return E_FAIL;
}
//
// tell the world
//
pidlAbs = ILCombine(this->rii.pidlThis, pidl);
if (pidlAbs)
{
SHChangeNotify(SHCNE_DELETE, SHCNF_IDLIST, pidlAbs, NULL);
ILFree(pidlAbs);
}
return NOERROR;
}
BOOL
_RegItems_GetDeleteMessage(IShellFolder *psf, LPCITEMIDLIST pidl, LPTSTR buffer, int cchMax)
{
CRegItemsSF *this;
const CLSID *pclsid;
HKEY hkParent, hk;
TCHAR szClass[GUIDSTR_MAX];
LONG cbMax = cchMax * SIZEOF(TCHAR);
VDATEINPUTBUF(buffer, TCHAR, cchMax);
//
// sanity
//
if (cbMax > 0)
*buffer = 0;
else
return FALSE;
if (!_RegItems_IsReg(psf, pidl))
return FALSE;
this = IToClass(CRegItemsSF, sf, psf);
pclsid = &((LPIDREGITEM)pidl)->clsid;
if (_RegItems_NReqItem(&this->rii, pclsid) >= 0)
return FALSE;
//
// get the item key
//
StringFromGUID2A(pclsid, szClass, ARRAYSIZE(szClass));
hkParent = this->rii.hkRegItems;
if (!*szClass || !hkParent ||
(RegOpenKey(hkParent, szClass, &hk) != ERROR_SUCCESS))
{
Assert(FALSE);
return FALSE;
}
//
// get the message
//
if (RegQueryValueEx(hk, c_szRegValDeleteMessage, NULL, NULL, (LPBYTE)buffer, &cbMax)
!= ERROR_SUCCESS)
{
*buffer = 0;
}
RegCloseKey(hk);
return (*buffer != 0);
}
//----------------------------------------------------------------------------
//BUGBUG: this routine is a stack pig (but we have to ship)
#define MAX_REGITEM_WARNTEXT 1024
void RegItems_Delete(LPSHELLFOLDER psfReg, HWND hwndOwner, LPDATAOBJECT pdtobj)
{
STGMEDIUM medium;
LPIDA pida = DataObj_GetHIDA(pdtobj, &medium);
if (pida)
{
TCHAR szItemWarning[MAX_REGITEM_WARNTEXT];
UINT i, count = pida->cidl;
UINT nregfirst = (UINT)-1;
UINT creg = 0;
UINT cwarn = 0;
LPCITEMIDLIST pidl;
//
// calc number of regitems and index of first
//
for (i = 0; i < count; i++)
{
pidl = IDA_GetIDListPtr(pida, i);
Assert(pidl);
if (_RegItems_IsReg(psfReg, pidl))
{
creg++;
if (nregfirst == (UINT)-1)
nregfirst = i;
if ((cwarn < 2) && _RegItems_GetDeleteMessage(psfReg, pidl,
szItemWarning, ARRAYSIZE(szItemWarning)))
{
cwarn++;
}
}
}
//
// compose the confirmation message / ask the user / fry the items...
//
if (creg)
{
TCHAR szItemName[MAX_PATH];
TCHAR szWarnText[1024 + MAX_REGITEM_WARNTEXT];
TCHAR szWarnCaption[128];
TCHAR szTemp[256];
MSGBOXPARAMS mbp = {SIZEOF(MSGBOXPARAMS), hwndOwner,
HINST_THISDLL, szWarnText, szWarnCaption,
MB_YESNO | MB_USERICON, MAKEINTRESOURCE(IDI_NUKEFILE),
0, NULL, 0};
//
// so we can tell if we got these later
//
*szItemName = 0;
*szWarnText = 0;
//
// if there is only one, mention it by name
//
if (creg == 1)
{
TCHAR szTemp[256];
STRRET str;
pidl = IDA_GetIDListPtr(pida, nregfirst);
if (SUCCEEDED(psfReg->lpVtbl->GetDisplayNameOf(psfReg, pidl,
SHGDN_NORMAL, &str)))
{
int idString = (creg == count)?
IDS_CANTRECYCLEREGITEMS_NAME :
IDS_CANTRECYCLEREGITEMS_INCL_NAME;
StrRetToStrN(szItemName, MAX_PATH, &str, pidl);
LoadString(HINST_THISDLL, idString, szTemp,
ARRAYSIZE(szTemp));
wsprintf(szWarnText, szTemp, szItemName);
}
}
//
// otherwise, say "these items..." or "some of these items..."
//
if (!*szWarnText)
{
int idString = (creg == count)?
IDS_CANTRECYCLEREGITEMS_ALL : IDS_CANTRECYCLEREGITEMS_SOME;
LoadString(HINST_THISDLL, idString, szWarnText,
ARRAYSIZE(szWarnText));
//
// we just loaded a very vague message
// don't confuse the user any more by adding random text
// if these is a special warning, force it to show separately
//
if (cwarn == 1)
cwarn++;
}
lstrcat(szWarnText, c_szCrLfLf);
//
// if there is exactly one special warning message, add it in
//
if (cwarn == 1)
{
lstrcat(szWarnText, szItemWarning);
lstrcat(szWarnText, c_szCrLfLf);
}
//
// add the question "are you sure..."
//
if ((count == 1) && *szItemName)
{
TCHAR szTemp2[256];
LoadString(HINST_THISDLL, IDS_CONFIRMDELETEDESKTOPREGITEM,
szTemp2, ARRAYSIZE(szTemp2));
wsprintf(szTemp, szTemp2, szItemName);
}
else
{
LoadString(HINST_THISDLL, IDS_CONFIRMDELETEDESKTOPREGITEMS,
szTemp, ARRAYSIZE(szTemp));
}
lstrcat(szWarnText, szTemp);
//
// finally, the message box caption (also needed in loop below)
//
LoadString(HINST_THISDLL, IDS_CONFIRMDELETE_CAPTION, szWarnCaption,
ARRAYSIZE(szWarnCaption));
//
// make sure the user is cool with it
//
if (MessageBoxIndirect(&mbp) == IDYES)
{
LPCITEMIDLIST *ppidlFS, *apidlFS = NULL;
UINT nstart = nregfirst;
//
// if there are fs items, remember them so we can delete later
//
if (creg < count)
{
apidlFS = (LPCITEMIDLIST *)LocalAlloc(LPTR, (count - creg) *
SIZEOF(LPCITEMIDLIST));
if (apidlFS)
{
ppidlFS = apidlFS;
nstart = 0;
}
}
//
// go ahead and delete the reg items
//
for (i = nstart; i < count; i++)
{
pidl = IDA_GetIDListPtr(pida, i);
if (_RegItems_IsReg(psfReg, pidl))
{
if ((cwarn > 1) && _RegItems_GetDeleteMessage(psfReg,
pidl, szItemWarning, ARRAYSIZE(szItemWarning)))
{
STRRET str;
if (SUCCEEDED(psfReg->lpVtbl->GetDisplayNameOf(
psfReg, pidl, SHGDN_NORMAL, &str)))
{
StrRetToStrN(szItemName, MAX_PATH, &str, pidl);
}
else
lstrcpy(szItemName, szWarnCaption);
MessageBox(hwndOwner, szItemWarning, szItemName,
MB_OK | MB_ICONINFORMATION);
}
_RegItems_DeleteRegItem(psfReg, pidl, FALSE);
}
else if (apidlFS)
{
// remember this one
*ppidlFS++ = pidl;
}
}
//
// now delete the fs objects
//
if (apidlFS)
{
IContextMenu *pcm;
if (SUCCEEDED(psfReg->lpVtbl->GetUIObjectOf(psfReg,
hwndOwner, (ppidlFS - apidlFS), apidlFS,
&IID_IContextMenu, NULL, &pcm)))
{
// BUGBUG: everybody ignores CMIC_MASK_FLAG_NO_UI
CMINVOKECOMMANDINFOEX ici =
{
SIZEOF(CMINVOKECOMMANDINFOEX),
CMIC_MASK_FLAG_NO_UI,
hwndOwner,
NULL,
NULL,
NULL,
SW_NORMAL,
};
#ifdef UNICODE
CHAR szDeleteAnsi[MAX_PATH];
WideCharToMultiByte(CP_ACP, 0,
c_szDelete, -1,
szDeleteAnsi, ARRAYSIZE(szDeleteAnsi),
NULL, NULL);
ici.lpVerb = szDeleteAnsi;
ici.lpVerbW = c_szDelete;
ici.fMask |= CMIC_MASK_UNICODE;
#else
ici.lpVerb = c_szDelete;
#endif
pcm->lpVtbl->InvokeCommand(pcm,
(CMINVOKECOMMANDINFO*)&ici);
pcm->lpVtbl->Release(pcm);
}
LocalFree((HANDLE)apidlFS);
}
}
}
HIDA_ReleaseStgMedium(pida, &medium);
}
}