windows-nt/Source/XPSP1/NT/net/config/common/ncbase/pidlutil.cpp
2020-09-26 16:20:57 +08:00

677 lines
14 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1997.
//
// File: P I D L . C P P
//
// Contents: PIDL utility routines. This stuff is mainly copied from the
// existing Namespace extension samples and real code, since
// everyone and their gramma uses this stuff.
//
// Notes:
//
// Author: jeffspr 1 Oct 1997
//
//----------------------------------------------------------------------------
#include "pch.h"
#pragma hdrstop
#include "shlobj.h"
#include "shlobjp.h"
#include "pidlutil.h"
#if DBG
//+---------------------------------------------------------------------------
//
// Function: ILNext
//
// Purpose: Return the next PIDL in the list
//
// Arguments:
// pidl []
//
// Returns:
//
// Author: jeffspr 1 Oct 1997 (from brianwen)
//
// Notes:
//
LPITEMIDLIST ILNext(LPCITEMIDLIST pidl)
{
if (pidl)
{
pidl = (LPITEMIDLIST) ((BYTE *)pidl + pidl->mkid.cb);
}
return (LPITEMIDLIST)pidl;
}
//+---------------------------------------------------------------------------
//
// Function: ILIsEmpty
//
// Purpose: Is this PIDL empty
//
// Arguments:
// pidl []
//
// Returns:
//
// Author: jeffspr 1 Oct 1997 (from brianwen)
//
// Notes:
//
BOOL ILIsEmpty(LPCITEMIDLIST pidl)
{
return (!pidl || !pidl->mkid.cb);
}
#endif // #if DBG
//+---------------------------------------------------------------------------
//
// Function: ILGetSizePriv
//
// Purpose: Return the size of a pidl.
//
// Arguments:
// pidl []
//
// Returns:
//
// Author: jeffspr 1 Oct 1997 (from brianwen)
//
// Notes:
//
UINT ILGetSizePriv(LPCITEMIDLIST pidl)
{
UINT cbTotal = 0;
if (pidl)
{
cbTotal += sizeof(pidl->mkid.cb); // Null terminator
while (pidl->mkid.cb)
{
cbTotal += pidl->mkid.cb;
pidl = ILNext(pidl);
}
}
return cbTotal;
}
//+---------------------------------------------------------------------------
//
// Function: ILCreate
//
// Purpose: Create a PIDL
//
// Arguments:
// cbSize []
//
// Returns:
//
// Author: jeffspr 1 Oct 1997 (from brianwen)
//
// Notes:
//
LPITEMIDLIST ILCreate(DWORD dwSize)
{
LPITEMIDLIST pidl = (LPITEMIDLIST) SHAlloc(dwSize);
return pidl;
}
VOID FreeIDL(LPITEMIDLIST pidl)
{
Assert(pidl);
SHFree(pidl);
}
//+---------------------------------------------------------------------------
//
// Function: ILIsSingleID
//
// Purpose: Returns TRUE if the idlist has just one ID in it.
//
// Arguments:
// pidl []
//
// Returns:
//
// Author: jeffspr 1 Oct 1997 (from brianwen)
//
// Notes:
//
BOOL ILIsSingleID(LPCITEMIDLIST pidl)
{
if (pidl == NULL)
return FALSE;
return (pidl->mkid.cb == 0 || ILNext(pidl)->mkid.cb == 0);
}
//+---------------------------------------------------------------------------
//
// Function: ILGetCID
//
// Purpose: Returns the number of ID's in the list.
//
// Arguments:
// pidl []
//
// Returns:
//
// Author: jeffspr 1 Oct 1997 (from brianwen)
//
// Notes:
//
UINT ILGetCID(LPCITEMIDLIST pidl)
{
UINT cid = 0;
while (!ILIsEmpty(pidl))
{
++ cid;
pidl = ILNext(pidl);
}
return cid;
}
//+---------------------------------------------------------------------------
//
// Function: ILGetSizeCID
//
// Purpose: Get the length of the first cid items in a pidl.
//
// Arguments:
// pidl []
// cid []
//
// Returns:
//
// Author: jeffspr 1 Oct 1997 (from brianwen)
//
// Notes:
//
UINT ILGetSizeCID(LPCITEMIDLIST pidl, UINT cid)
{
UINT cbTotal = 0;
if (pidl)
{
cbTotal += sizeof(pidl->mkid.cb); // Null terminator
while (cid && !ILIsEmpty(pidl))
{
cbTotal += pidl->mkid.cb;
pidl = ILNext(pidl);
-- cid;
}
}
return cbTotal;
}
//+---------------------------------------------------------------------------
//
// Function: CloneIDLFirstCID
//
// Purpose: Make a new list consisting of only the first cid items on
// an existing list.
//
// Arguments:
// pidl []
// cid []
//
// Returns:
//
// Author: jeffspr 1 Oct 1997 (from brianwen)
//
// Notes:
//
LPITEMIDLIST CloneIDLFirstCID(LPCITEMIDLIST pidl, UINT cid)
{
Assert((INT)cid >= 0);
UINT cb = ILGetSizeCID(pidl, cid);
LPITEMIDLIST pidlRet = (LPITEMIDLIST) SHAlloc(cb);
if (pidlRet)
{
// Notes: no need to zero-init.
// Also, do not copy the NULL terminator.
memcpy (pidlRet, pidl, cb - sizeof(pidl->mkid.cb));
LPITEMIDLIST pidlTerm = pidlRet;
// Cannot test for NULL terminator, we have not terminated
// the list yet.
//
while (cid)
{
pidlTerm = ILNext(pidlTerm);
-- cid;
}
pidlTerm->mkid.cb = 0;
}
return pidlRet;
}
//+---------------------------------------------------------------------------
//
// Function: ILSkipCID
//
// Purpose: Skips the first cid items in a pidl.
//
// Arguments:
// pidl []
// cid []
//
// Returns:
//
// Author: jeffspr 1 Oct 1997 (from brianwen)
//
// Notes:
//
LPITEMIDLIST ILSkipCID(LPCITEMIDLIST pidl, UINT cid)
{
Assert((INT)cid >= 0);
while (cid && !ILIsEmpty(pidl))
{
pidl = ILNext(pidl);
-- cid;
}
return (LPITEMIDLIST)pidl;
}
//+---------------------------------------------------------------------------
//
// Function: ILCombinePriv
//
// Purpose: Combine two PIDLs
//
// Arguments:
// pidl1 []
// pidl2 []
//
// Returns:
//
// Author: jeffspr 1 Oct 1997 (from brianwen)
//
// Notes:
//
LPITEMIDLIST ILCombinePriv(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
{
LPITEMIDLIST pidlNew = NULL;
// Let me pass in NULL pointers
if (!pidl1)
{
if (!pidl2)
{
pidlNew = NULL;
}
else
{
pidlNew = CloneIDL(pidl2);
}
}
else
{
if (!pidl2)
{
pidlNew = CloneIDL(pidl1);
}
else
{
UINT cb1 = ILGetSizePriv(pidl1) - sizeof(pidl1->mkid.cb);
UINT cb2 = ILGetSizePriv(pidl2);
pidlNew = ILCreate(cb1 + cb2);
if (pidlNew)
{
memcpy(pidlNew, pidl1, cb1);
memcpy((PWSTR)(((LPBYTE)pidlNew) + cb1), pidl2, cb2);
Assert (ILGetSizePriv(pidlNew) == cb1+cb2);
}
}
}
return pidlNew;
}
#if 0
BOOL ILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
{
if (FSetupGlobalShellFolders())
{
LPSHELLFOLDER psfDesktop = (LPSHELLFOLDER) PvGlobGet (ipsfDesktop);
if (psfDesktop)
{
VERIFYPTR(pidl1, FALSE);
VERIFYPTR(pidl2, FALSE);
return psfDesktop->CompareIDs(0, pidl1, pidl2) == ResultFromShort(0);
}
}
return FALSE;
}
#endif
//+---------------------------------------------------------------------------
//
// Function: CloneIDL
//
// Purpose: Clone an IDL (return a duplicate)
//
// Arguments:
// pidl []
//
// Returns:
//
// Author: jeffspr 1 Oct 1997 (from brianwen)
//
// Notes:
//
LPITEMIDLIST CloneIDL(LPCITEMIDLIST pidl)
{
UINT cb = 0;
LPITEMIDLIST pidlRet = NULL;
if (pidl)
{
cb = ILGetSizePriv(pidl);
pidlRet = (LPITEMIDLIST) SHAlloc(cb);
if (pidlRet)
{
memcpy(pidlRet, pidl, cb);
}
}
return pidlRet;
}
//+---------------------------------------------------------------------------
//
// Function: ILFindLastIDPriv
//
// Purpose: Find the last ID in an IDL
//
// Arguments:
// pidl []
//
// Returns:
//
// Author: jeffspr 1 Oct 1997 (from brianwen)
//
// Notes:
//
LPITEMIDLIST ILFindLastIDPriv(LPCITEMIDLIST pidl)
{
LPCITEMIDLIST pidlLast = pidl;
LPCITEMIDLIST pidlNext = pidl;
Assert(pidl);
// Find the last one in the list
//
while (pidlNext->mkid.cb)
{
pidlLast = pidlNext;
pidlNext = ILNext(pidlLast);
}
return (LPITEMIDLIST)pidlLast;
}
//+---------------------------------------------------------------------------
//
// Function: ILRemoveLastIDPriv
//
// Purpose: Remove the last ID from an IDL
//
// Arguments:
// pidl []
//
// Returns:
//
// Author: jeffspr 1 Oct 1997
//
// Notes:
//
BOOL ILRemoveLastIDPriv(LPITEMIDLIST pidl)
{
BOOL fRemoved = FALSE;
Assert(pidl);
if (pidl->mkid.cb)
{
LPITEMIDLIST pidlLast = (LPITEMIDLIST)ILFindLastIDPriv(pidl);
Assert(pidlLast->mkid.cb);
Assert(ILNext(pidlLast)->mkid.cb==0);
// Remove the last one
pidlLast->mkid.cb = 0; // null-terminator
fRemoved = TRUE;
}
return fRemoved;
}
//+---------------------------------------------------------------------------
//
// Function: CloneRgIDL
//
// Purpose: Clone a pidl array
//
// Arguments:
// rgpidl [in] PIDL array to clone
// cidl [in] Count of the pidl array
// fUseCache [in] If TRUE, generate the returned IDL from the cache
// fAllowNonCacheItems [in] Use old version of pidl if cached version non available
// pppidl [out] Return pointer for pidl array
//
// Returns:
//
// Author: jeffspr 22 Oct 1997
//
// Notes:
//
/*
HRESULT HrCloneRgIDL(
LPCITEMIDLIST * rgpidl,
ULONG cidl,
BOOL fUseCache,
BOOL fAllowNonCacheItems,
LPITEMIDLIST ** pppidl,
ULONG * pcidl)
{
HRESULT hr = NOERROR;
LPITEMIDLIST * rgpidlReturn = NULL;
ULONG irg = 0;
ULONG cidlCopied = 0;
Assert(pppidl);
Assert(pcidl);
Assert(rgpidl);
if (!rgpidl || !cidl)
{
hr = E_INVALIDARG;
goto Exit;
}
else
{
// Alloc the return buffer
//
rgpidlReturn = (LPITEMIDLIST *) SHAlloc(cidl * sizeof(LPITEMIDLIST));
if (!rgpidlReturn)
{
hr = E_OUTOFMEMORY;
goto Exit;
}
else
{
// Clone all elements within the passed in PIDL array
//
for (irg = 0; irg < cidl; irg++)
{
if (rgpidl[irg])
{
if (fUseCache)
{
PCONNLISTENTRY pcle = NULL;
PCONFOLDPIDL pcfp = (PCONFOLDPIDL) rgpidl[irg];
hr = g_ccl.HrFindConnectionByGuid(&(pcfp->guidId), &pcle);
if (hr == S_OK)
{
Assert(pcle);
Assert(pcle->pccfe);
// Copy to the return pidl array.
hr = HrConFoldEntryToPidl(pcle->pccfe, &(rgpidlReturn[cidlCopied++]));
if (FAILED(hr))
goto Exit;
}
else
{
TraceTag(ttidShellFolder, "HrCloneRgIDL: Connection find returned: 0x%08x", hr);
if (hr == S_FALSE)
{
if (fAllowNonCacheItems)
{
TraceTag(ttidShellFolder, "HrCloneRgIDL: Connection not found in cache, "
"using non-cache item");
rgpidlReturn[cidlCopied++] = CloneIDL((LPITEMIDLIST)rgpidl[irg]);
if (!rgpidlReturn[irg])
{
hr = E_OUTOFMEMORY;
goto Exit;
}
}
else
{
TraceTag(ttidShellFolder, "HrCloneRgIDL: Connection not found in cache. "
"Dropping item from array");
}
}
else
{
AssertSz(FALSE, "HrCloneRgIDL: Connection find HR_FAILED");
}
}
}
else
{
// Clone this element in the PIDL array
//
rgpidlReturn[cidlCopied++] = CloneIDL ((LPITEMIDLIST) rgpidl[irg]);
if (!rgpidlReturn[irg])
{
hr = E_OUTOFMEMORY;
goto Exit;
}
}
}
else
{
// Make sure that we don't try to delete bogus data later.
//
rgpidlReturn[cidlCopied++] = NULL;
AssertSz(FALSE, "Bogus element in the rgpidl in HrCloneRgIDL");
hr = E_INVALIDARG;
goto Exit;
}
}
}
}
Exit:
if (FAILED(hr))
{
// Free the already-allocated IDLISTs
//
ULONG irgT = 0;
for (irgT = 0; irgT < irg; irgT++)
{
if (rgpidlReturn[irgT])
{
FreeIDL(rgpidlReturn[irgT]);
}
}
SHFree(rgpidlReturn);
*pppidl = NULL;
}
else
{
// Fill in the return var.
//
*pppidl = rgpidlReturn;
*pcidl = cidlCopied;
}
TraceHr(ttidError, FAL, hr, FALSE, "HrCloneRgIDL");
return hr;
} // CloneRgIDL
*/
//+---------------------------------------------------------------------------
//
// Function: FreeRgIDL
//
// Purpose: Free a PIDL array
//
// Arguments:
// cidl [in] Size of PIDL array
// apidl [in] Pointer to the array itself.
//
// Returns:
//
// Author: jeffspr 27 Oct 1997
//
// Notes:
//
VOID FreeRgIDL(
UINT cidl,
LPITEMIDLIST * apidl)
{
if (apidl)
{
for (UINT i = 0; i < cidl; i++)
{
FreeIDL(apidl[i]);
}
SHFree(apidl);
}
}