delfldr.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 39k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include "shellprv.h"
  2. #include "clsobj.h"
  3. #include "caggunk.h"
  4. #pragma hdrstop
  5. // Delegated IShellFolder object.  Takes an ISF inner and adds the list of
  6. // delegated shell folders to its namespace, wrapping the IDLISTs as required.
  7. class CDelegateFolder : public CAggregatedUnknown, IDelegateShellFolder, IShellFolder2, IPersistFreeThreadedObject
  8. {
  9. public:
  10.     // *** IUnknown ***
  11.     STDMETHODIMP QueryInterface(REFIID riid, void **ppv)
  12.                 { return CAggregatedUnknown::QueryInterface(riid, ppv); };
  13.     STDMETHODIMP_(ULONG) AddRef(void) 
  14.                 { return CAggregatedUnknown::AddRef(); };
  15.     STDMETHODIMP_(ULONG) Release(void) 
  16.                 { return CAggregatedUnknown::Release(); };
  17.     // IPersistFreeThreadedObject
  18.     STDMETHODIMP GetClassID(CLSID *pCLSID);
  19.     // *** IShellFolder methods ***
  20.     STDMETHODIMP ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR pszDisplayName,
  21.                                   ULONG *pchEaten, LPITEMIDLIST *ppidl, ULONG *pdwAttributes);
  22.     STDMETHODIMP EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList);
  23.     STDMETHODIMP BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppvOut);
  24.     STDMETHODIMP BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv);
  25.     STDMETHODIMP CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
  26.     STDMETHODIMP CreateViewObject (HWND hwnd, REFIID riid, void **ppvOut);
  27.     STDMETHODIMP GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, ULONG *rgfInOut);
  28.     STDMETHODIMP GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST * apidl,
  29.                                REFIID riid, UINT * prgfInOut, void **ppvOut);
  30.     STDMETHODIMP GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, STRRET *pName);
  31.     STDMETHODIMP SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR pszName, 
  32.                            DWORD uFlags, LPITEMIDLIST *ppidlOut);
  33.     // *** IShellFolder2 methods ***
  34.     STDMETHODIMP GetDefaultSearchGUID(LPGUID lpGuid);
  35.     STDMETHODIMP EnumSearches(LPENUMEXTRASEARCH *ppenum);
  36.     STDMETHODIMP GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay);
  37.     STDMETHODIMP GetDefaultColumnState(UINT iColumn, DWORD *pbState);
  38.     STDMETHODIMP GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv);
  39.     STDMETHODIMP GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pDetails);
  40.     STDMETHODIMP MapNameToSCID(LPCWSTR pwszName, SHCOLUMNID *pscid);
  41.     // *** IDelegateShellFolder ***
  42.     STDMETHODIMP Initialize(WORD id, IShellFolder2* psf);
  43.     STDMETHODIMP AddFolders(CLSID* aCLISD, INT count);
  44. protected:
  45.     CDelegateFolder(IUnknown *punkOuter);
  46.     ~CDelegateFolder();
  47.     // used by the CAggregatedUnknown stuff
  48.     HRESULT v_InternalQueryInterface(REFIID riid,void **ppv);
  49.     
  50.     LPCITEMIDLIST _GetFolderIDList();
  51.     PDELEGATEITEMID _IsDelegateObject(LPCITEMIDLIST pidl, LPCLSID pclsid);
  52.     HRESULT _InitFolder(IUnknown *punk);
  53.     HRESULT _GetDelegateFolder(LPCITEMIDLIST pidl, REFIID riid, void **ppv);
  54.     HRESULT _GetItemFolder(LPCITEMIDLIST pidl, IShellFolder **ppsf);
  55.     HRESULT _GetItemFolder2(LPCITEMIDLIST pidl, IShellFolder2 **ppsf);
  56. private:
  57.     HDCA            _dcaDelegates;              // array of CLSIDs we are using
  58.     IShellFolder2   *_psfOuter;                 // IShellFolder2 of the inner object
  59.     WORD            _id;                        // ID used for marking our IDLISTs
  60.     BOOL            _fFreeThread:1;             // supports the IPersistFreeThreadedObject iface
  61.     LPITEMIDLIST    _pidl;                      // IDLIST passed to our ::Initialize method
  62.     friend HRESULT CDelegateFolder_CreateInstance(IUnknown* punkOuter, REFIID riid, void **ppvOut);
  63. };  
  64. //-----------------------------------------------------------------------------
  65. // Stuff
  66. //-----------------------------------------------------------------------------
  67. // flow control helpers
  68. #define ExitGracefully(_hr, _r)             
  69.             { _hr = (_r); goto exit; }
  70. #define FailGracefully(_hr)                 
  71.             { if (FAILED(hr)) goto exit; }
  72.                 
  73. STDAPI CDelegateMalloc_Create(void *pv, UINT cbSize, WORD wOuter, IMalloc **ppmalloc);
  74. class CDelegateFolderEnum : public IEnumIDList
  75. {
  76. public:
  77.     CDelegateFolderEnum(HWND hwnd, DWORD grfFlags, HDPA dpaFolders);
  78.     ~CDelegateFolderEnum();
  79.     // *** IUnknown methods ***
  80.     STDMETHOD(QueryInterface) (REFIID riid, void **ppv);
  81.     STDMETHOD_(ULONG,AddRef) (THIS);
  82.     STDMETHOD_(ULONG,Release) (THIS);
  83.     // *** IEnumIDList methods ***
  84.     STDMETHOD(Next)  (ULONG celt,
  85.                       LPITEMIDLIST *rgelt,
  86.                       ULONG *pceltFetched);
  87.     STDMETHOD(Skip)  (ULONG celt);
  88.     STDMETHOD(Reset) (THIS);
  89.     STDMETHOD(Clone) (IEnumIDList **ppenum);
  90. private:
  91.     LONG _cRef;
  92.     HWND _hwnd;
  93.     DWORD _grfFlags;
  94.     HDPA _dpaFolders;
  95.     INT _index;
  96.     IEnumIDList* _pCurrentEnum;
  97. };
  98. //
  99. // get the clsid of the delegate from the pidl.
  100. //
  101. #define _GetDelegateCLSID(pdi)               
  102.             (*(UNALIGNED CLSID*)&(((PDELEGATEITEMID)(pdi))->rgb[((PDELEGATEITEMID)(pdi))->cbInner]))
  103. //
  104. // callback used to comapre two delegate item idlists CLSID
  105. //
  106. INT _CompareDelegateItem(void *pv1, void *pv2, LPARAM lParam)
  107. {
  108.     PDELEGATEITEMID pdi1 = (PDELEGATEITEMID)pv1;
  109.     PDELEGATEITEMID pdi2 = (PDELEGATEITEMID)pv2;
  110.     return memcmp((UNALIGNED CLSID*)&(pdi1->rgb[pdi1->cbInner]), 
  111.                   (UNALIGNED CLSID*)&(pdi2->rgb[pdi2->cbInner]),
  112.                   SIZEOF(CLSID));
  113.         
  114. }
  115. //
  116. // callback used to destroy the IUnkown DPA.
  117. //
  118. static INT _ReleaseCB(void *pItem, void *pData)
  119. {
  120.     IUnknown *pUnknown = (IUnknown *)pItem;
  121.     pUnknown->Release();
  122.     return 1;
  123. }
  124. //-----------------------------------------------------------------------------
  125. // Constructors etc
  126. //-----------------------------------------------------------------------------
  127. // Constructor
  128. CDelegateFolder::CDelegateFolder(IUnknown *punkOuter) : 
  129.     CAggregatedUnknown(punkOuter),
  130.     _dcaDelegates(NULL),
  131.     _psfOuter(NULL), 
  132.     _id(0),
  133.     _fFreeThread(FALSE),
  134.     _pidl(NULL)
  135. {
  136.     DllAddRef();
  137. }
  138. CDelegateFolder::~CDelegateFolder()
  139. {
  140.     if ( _dcaDelegates )
  141.         DCA_Destroy(_dcaDelegates);
  142.    
  143.     ILFree(_pidl);
  144.     DllRelease();
  145. }
  146. //
  147. // get the pidl used to initialize this namespace
  148. //
  149. LPCITEMIDLIST CDelegateFolder::_GetFolderIDList()
  150. {
  151.     if (!_pidl)
  152.         SHGetIDListFromUnk(_psfOuter, &_pidl);
  153.     return _pidl;
  154. }
  155. //
  156. // aggregated unknown handling
  157. //
  158. HRESULT CDelegateFolder::v_InternalQueryInterface(REFIID riid, void **ppv)
  159. {
  160.     static const QITAB qit[] = {
  161.         QITABENT(CDelegateFolder, IDelegateShellFolder),                // IID_IDelegateShellFolder
  162.         QITABENTMULTI(CDelegateFolder, IShellFolder, IShellFolder2),    // IID_IShellFolder
  163.         QITABENT(CDelegateFolder, IShellFolder2),                       // IID_IShellFolder2
  164.         QITABENT(CDelegateFolder, IPersistFreeThreadedObject),          // IID_IPersistFreeThreadedObject
  165.         { 0 },
  166.     };
  167.     if ( IsEqualIID(riid, IID_IPersistFreeThreadedObject) && !_fFreeThread )
  168.         return E_NOINTERFACE;
  169.     return QISearch(this, qit, riid, ppv);
  170. }
  171. //-----------------------------------------------------------------------------
  172. // IDelegateShellFolder
  173. //-----------------------------------------------------------------------------
  174. STDMETHODIMP CDelegateFolder::Initialize(WORD id, IShellFolder2* psf)
  175. {
  176.     // ensure we have the DCA for storing the delegate folders into, then lets grav the ISF
  177.     // we have been given.
  178.     
  179.     if ( !_dcaDelegates )
  180.     {
  181.         _dcaDelegates = DCA_Create();
  182.         if ( !_dcaDelegates )
  183.             return E_OUTOFMEMORY;
  184.     }
  185.     ASSERT(NULL != psf);
  186.     // NOTE: AddRef() is not called because psf is required to be an interface on the
  187.     // same aggregated object
  188.     _psfOuter = psf;
  189.     _id = id;
  190.     // use the CLSID (from our delegate) as the location in the registry
  191.     // where we look for the delegates to load
  192.     CLSID clsid;
  193.     if (SUCCEEDED(GetClassID(&clsid)))
  194.     {
  195.         HKEY hKey;
  196.         if (SUCCEEDED(SHRegGetCLSIDKey(clsid, NULL, FALSE, FALSE, &hKey)))
  197.         {
  198.             DCA_AddItemsFromKey(_dcaDelegates, hKey, TEXT("shellex\DelegateShellFolders"));
  199.             RegCloseKey(hKey);
  200.         }
  201.     }
  202.     // is the inner object free threaded?  if so we must honor this IID as the regitems
  203.     // code uses it to cache us.
  204.     IPersistFreeThreadedObject* ppfto;
  205.     if ( SUCCEEDED(_psfOuter->QueryInterface(IID_IPersistFreeThreadedObject, (void **)&ppfto)))
  206.     {        
  207.         _fFreeThread = TRUE;
  208.         ppfto->Release();
  209.     }
  210.     return S_OK;
  211. }
  212. //-----------------------------------------------------------------------------
  213. // given an array of CLISDs add them to the delegate object list
  214. STDMETHODIMP CDelegateFolder::AddFolders(CLSID* aCLISD, INT count)
  215. {
  216.     INT i;
  217.     // fail if either we don't have a delegate list to ad items to or, we have
  218.     // no array of CLSIDs to add.
  219.     if ( !aCLISD || !_dcaDelegates )
  220.         return E_INVALIDARG;
  221.     for ( i = 0 ; i < count ; i++ )
  222.     {
  223.         if ( !DCA_AddItem(_dcaDelegates, aCLISD[i]) )
  224.             return E_FAIL;
  225.     }    
  226.     return S_OK;
  227. }
  228. /*-----------------------------------------------------------------------------
  229. /   Crack the pidl and see if it looks like a delegate object, we return S_OK
  230. /   if it is, otherwise we hand back S_FALSE.
  231. /
  232. / In:
  233. /   pidl -> pidl to be cracked
  234. /   pclsid -> receives the CLSID for the object (if non-zero)
  235. /
  236. / Out:
  237. /   HRESULT
  238. /----------------------------------------------------------------------------*/
  239. PDELEGATEITEMID CDelegateFolder::_IsDelegateObject(LPCITEMIDLIST pidl, LPCLSID pclsid)
  240. {
  241.     PDELEGATEITEMID pdi = (PDELEGATEITEMID)pidl;
  242.     if ( pdi && (pdi->cbSize > SIZEOF(DELEGATEITEMID)-1) && (pdi->wOuter == _id) )
  243.     {
  244.         if ( pclsid )
  245.             *pclsid = *((UNALIGNED CLSID*)&(pdi->rgb[pdi->cbInner]));
  246.         return pdi;
  247.     }
  248.     return NULL;
  249. }
  250. HRESULT CDelegateFolder::_InitFolder(IUnknown *punk)
  251. {
  252.     HRESULT hr = S_OK;
  253.     IPersistFolder* ppf;
  254.     if ( SUCCEEDED(punk->QueryInterface(IID_IPersistFolder, (void **)&ppf)) )
  255.     {
  256.         hr = ppf->Initialize(_GetFolderIDList());
  257.         ppf->Release();
  258.     }
  259.     return hr;
  260. }
  261. /*-----------------------------------------------------------------------------
  262. /   Extract the delegate CLSID from the pidl we see, if the type is not a delegate
  263. /   item then return failure.  if ppv is non-NULL then create an object from that
  264. /   CLSID that maps to the thing we want.
  265. /
  266. / In:
  267. /   pidl = pidl to look into
  268. /   pCLSID = receives the clisd
  269. /   riid, ppv -> if you want an instance then pass the IID and a ppv
  270. /
  271. / Out:
  272. /   HRESULT
  273. /----------------------------------------------------------------------------*/
  274. HRESULT CDelegateFolder::_GetDelegateFolder(LPCITEMIDLIST pidl, REFIID riid, void **ppv)
  275. {
  276.     HRESULT hr;   
  277.     CLSID clsid;
  278.     PDELEGATEITEMID pdi = _IsDelegateObject(pidl, &clsid);
  279.     if (!pdi)
  280.         return E_FAIL;
  281.     // the caller wants an instance of this delegate folder, so lets co-create it and set
  282.     // its allocator as required.
  283.     IDelegateFolder* pDelegateFolder;
  284.     hr = SHCoCreateInstance(NULL, &clsid, NULL, IID_IDelegateFolder, (void **)&pDelegateFolder);
  285.     FailGracefully(hr);
  286.     IMalloc* pAlloc;
  287.     if ( SUCCEEDED(CDelegateMalloc_Create(&clsid, SIZEOF(CLSID), _id, &pAlloc)) )
  288.     {
  289.         pDelegateFolder->SetItemAlloc(pAlloc);
  290.         pAlloc->Release();
  291.     }
  292.     hr = pDelegateFolder->QueryInterface(riid, ppv);
  293.     pDelegateFolder->Release();
  294.     // the caller is requesting IShellFolder for this object, therefore we need to bind 
  295.     // and ensure that its parent is correctly initialized (by calling IPersistFolder),
  296.     // note that at this point just calling Initialize with our cached PIDL should be
  297.     // sufficent.
  298.     if ( SUCCEEDED(hr) && _GetFolderIDList() && 
  299.             (IsEqualIID(riid, IID_IShellFolder) || IsEqualIID(riid, IID_IShellFolder2)) )
  300.     {
  301.         _InitFolder((IUnknown *)*ppv);
  302.     }
  303.     hr = S_OK;          // success
  304. exit:
  305.     return hr;
  306. }
  307. HRESULT CDelegateFolder::_GetItemFolder(LPCITEMIDLIST pidl, IShellFolder **ppsf)
  308. {
  309.     HRESULT hr;
  310.     if (_IsDelegateObject(pidl, NULL))
  311.     {
  312.         hr = _GetDelegateFolder(pidl, IID_IShellFolder, (void **)ppsf);
  313.     }
  314.     else
  315.     {
  316.         *ppsf = _psfOuter;
  317.         _psfOuter->AddRef();
  318.         hr = S_OK;
  319.     }
  320.     return hr;
  321. }
  322. HRESULT CDelegateFolder::_GetItemFolder2(LPCITEMIDLIST pidl, IShellFolder2 **ppsf)
  323. {
  324.     HRESULT hr;
  325.     if (_IsDelegateObject(pidl, NULL))
  326.     {
  327.         hr = _GetDelegateFolder(pidl, IID_IShellFolder2, (void **)ppsf);
  328.     }
  329.     else
  330.     {
  331.         *ppsf = _psfOuter;
  332.         _psfOuter->AddRef();
  333.         hr = S_OK;
  334.     }
  335.     return hr;
  336. }
  337. // IPersist method
  338. STDMETHODIMP CDelegateFolder::GetClassID(CLSID *pCLSID)
  339. {
  340.     IPersist* pps;
  341.     HRESULT hr = _psfOuter->QueryInterface(IID_IPersist, (void **)&pps);
  342.     if ( SUCCEEDED(hr) )
  343.     {
  344.         hr = pps->GetClassID(pCLSID);
  345.         pps->Release();
  346.     }
  347.     return hr;
  348. }
  349. //-----------------------------------------------------------------------------
  350. // IShellFolder methods
  351. //-----------------------------------------------------------------------------
  352. STDMETHODIMP CDelegateFolder::ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR pszDisplayName,
  353.                                                ULONG *pchEaten, LPITEMIDLIST *ppidl, ULONG *pdwAttributes)
  354. {
  355.     // round robbin the delegate namespaces, seeing if any want to parse the string,
  356.     // if they don't they will return E_NOTIMPL or E_INVALIDARG.  If they return anything
  357.     // other than that then we return their result, otherwise we continue.
  358.     for (int i = 0 ; i < DCA_GetItemCount(_dcaDelegates) ; i++)
  359.     {
  360.         IShellFolder* psf;
  361.         if ( SUCCEEDED(DCA_CreateInstance(_dcaDelegates, i, IID_IShellFolder, (void**)&psf)) )
  362.         {   
  363.             IDelegateFolder* pdf;
  364.             if ( SUCCEEDED(psf->QueryInterface(IID_IDelegateFolder, (void**)&pdf)) )
  365.             {
  366.                 IMalloc* pAlloc;
  367.                 if ( SUCCEEDED(CDelegateMalloc_Create((LPVOID)DCA_GetItem(_dcaDelegates, i), SIZEOF(CLSID), _id, &pAlloc)) )
  368.                 {
  369.                     pdf->SetItemAlloc(pAlloc);
  370.                     pAlloc->Release();
  371.                 }
  372.                 pdf->Release();
  373.             }
  374.             HRESULT hr = psf->ParseDisplayName(hwnd, pbc, pszDisplayName, pchEaten, ppidl, pdwAttributes);
  375.             psf->Release();
  376.             if ( (hr != E_INVALIDARG) && (hr != E_NOTIMPL) )
  377.             {
  378.                 return hr;
  379.             }
  380.         }
  381.     }
  382.     // None of the delegates were interested so lets call the _psfOuter and let them have a crack at it!
  383.     return _psfOuter->ParseDisplayName(hwnd, pbc, pszDisplayName,
  384.                                        pchEaten, ppidl, pdwAttributes);
  385. }
  386. //-----------------------------------------------------------------------------
  387. STDMETHODIMP CDelegateFolder::EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList)
  388. {
  389.     CDelegateFolderEnum* pEnum;
  390.     IDelegateFolder* pDelegateFolder;
  391.     IMalloc* pAlloc;
  392.     HDPA dpaFolders = NULL;
  393.     INT i;
  394.     *ppenumIDList = NULL; // in case of failure
  395.     // to construct the enumerator we are going to give out to the oustside world we
  396.     // must fill a DPA with the IShellFolder iface's we want to use.  Therefore lets
  397.     // walk the list of delegate folders add those to the DPA (having both set their
  398.     // malloc and then initialized them).
  399.     dpaFolders = DPA_Create(4);
  400.     if ( !dpaFolders )
  401.         return E_OUTOFMEMORY;
  402.     for ( i = 0 ; i < DCA_GetItemCount(_dcaDelegates) ; i++ )
  403.     {
  404.         if ( SUCCEEDED(DCA_CreateInstance(_dcaDelegates, i, IID_IDelegateFolder, (void **)&pDelegateFolder)) )
  405.         {
  406.             if ( SUCCEEDED(CDelegateMalloc_Create((LPVOID)DCA_GetItem(_dcaDelegates, i), SIZEOF(CLSID), _id, &pAlloc)) )
  407.             {
  408.                 pDelegateFolder->SetItemAlloc(pAlloc);
  409.                 pAlloc->Release();
  410.                 _InitFolder((IUnknown *)pDelegateFolder);
  411.                 IShellFolder* psf;
  412.                 if ( SUCCEEDED(pDelegateFolder->QueryInterface(IID_IShellFolder, (void **)&psf)) )
  413.                 {
  414.                     if ( -1 == DPA_AppendPtr(dpaFolders, psf) )
  415.                     {
  416.                         psf->Release();            // failed to place into the DPA.
  417.                     }
  418.                 }
  419.             }
  420.             pDelegateFolder->Release();
  421.         }
  422.     }
  423.     _psfOuter->AddRef();
  424.     DPA_AppendPtr(dpaFolders, _psfOuter);           // BUGBUG: what about failure
  425.     pEnum = new CDelegateFolderEnum(hwnd, grfFlags, dpaFolders);
  426.     if ( !pEnum )
  427.     {
  428.         DPA_DestroyCallback(dpaFolders, _ReleaseCB, NULL);
  429.         return E_OUTOFMEMORY;
  430.     }
  431.     *ppenumIDList = SAFECAST(pEnum, IEnumIDList*);      // pass out the enumerator
  432.     return S_OK;
  433. }
  434. //-----------------------------------------------------------------------------
  435. STDMETHODIMP CDelegateFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbc,
  436.                                            REFIID riid, void **ppvOut)
  437. {
  438.     IShellFolder* psfItem;
  439.     HRESULT hr = _GetItemFolder(pidl, &psfItem);
  440.     if (SUCCEEDED(hr))
  441.     {
  442.         hr = psfItem->BindToObject(pidl, pbc, riid, ppvOut);
  443.         psfItem->Release();
  444.     }
  445.     return hr;
  446. }
  447. //-----------------------------------------------------------------------------
  448. STDMETHODIMP CDelegateFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbc,
  449.                                             REFIID riid, void **ppv)
  450. {
  451.     IShellFolder* psfItem;
  452.     HRESULT hr = _GetItemFolder(pidl, &psfItem);
  453.     if (SUCCEEDED(hr))
  454.     {
  455.         hr = psfItem->BindToStorage(pidl, pbc, riid, ppv);
  456.         psfItem->Release();
  457.     }
  458.     return hr;
  459. }
  460. //-----------------------------------------------------------------------------
  461. STDMETHODIMP CDelegateFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  462. {
  463.     HRESULT hr;
  464.     LPCITEMIDLIST pidlNext1 = _ILNext(pidl1);
  465.     LPCITEMIDLIST pidlNext2 = _ILNext(pidl2);
  466.     PDELEGATEITEMID pdi1 = _IsDelegateObject(pidl1, NULL);
  467.     PDELEGATEITEMID pdi2 = _IsDelegateObject(pidl2, NULL);
  468.     IShellFolder* psfItem1 = NULL;
  469.     IShellFolder* psfItem2 = NULL;
  470.     
  471.     // if we have two delegate objects then attempt to compare, if we have a single then
  472.     // the delegate comes first.  if neither of the items are delegates then lets pass
  473.     // them onto the innerISF.
  474.     if ( pdi1 )
  475.     {
  476.         INT iResult = 0;
  477.         if ( pdi2 )
  478.         {
  479.             STRRET StrRet1, StrRet2;
  480.             TCHAR szItemName1[MAX_PATH];
  481.             TCHAR szItemName2[MAX_PATH];
  482.             hr = _GetDelegateFolder(pidl1, IID_IShellFolder, (void **)&psfItem1);
  483.             FailGracefully(hr);
  484.         
  485.             hr = _GetDelegateFolder(pidl2, IID_IShellFolder, (void **)&psfItem2);
  486.             FailGracefully(hr);
  487.             
  488.             if ( FAILED(psfItem1->GetDisplayNameOf(pidl1, SHGDN_NORMAL, &StrRet1)) ||
  489.                    FAILED(psfItem2->GetDisplayNameOf(pidl2, SHGDN_NORMAL, &StrRet2)) )
  490.             {
  491.                 ExitGracefully(hr, E_FAIL);
  492.             }
  493.             StrRetToStrN(szItemName1, ARRAYSIZE(szItemName1), &StrRet1, pidl1);
  494.             StrRetToStrN(szItemName2, ARRAYSIZE(szItemName2), &StrRet2, pidl2);
  495.             iResult = lstrcmp(szItemName1,szItemName2);
  496.         }
  497.         else
  498.         {
  499.             iResult = 1;        
  500.         }
  501.         // their names match so lets check out the rest of the  data, starting with the CLSIDs, 
  502.         // if they match then we must continue the binding process and let them be compared.
  503.         if ( !iResult )
  504.             iResult = memcmp(&pdi1->rgb[pdi1->cbInner], &pdi2->rgb[pdi2->cbInner], SIZEOF(CLSID));
  505.         if ( iResult )
  506.             ExitGracefully(hr, ResultFromShort(iResult));
  507.         if ( ILIsEmpty(pidlNext1) )
  508.         {
  509.             if ( ILIsEmpty(pidlNext2) )
  510.                 ExitGracefully(hr, ResultFromShort(0));     // they are the same size
  511.                 
  512.             ExitGracefully(hr, ResultFromShort(-1));        // pidl1 is shorter
  513.         }
  514.         else if ( ILIsEmpty(pidlNext2) )
  515.             ExitGracefully(hr, ResultFromShort(1));         // pidl2 is shorter
  516.         // call into the delegate namespace that owns these IDLISTs and let it compare
  517.         if ( psfItem1 )
  518.         {
  519.             hr = _GetDelegateFolder(pidl1, IID_IShellFolder, (void **)&psfItem1);
  520.             FailGracefully(hr);
  521.         }
  522.         hr = psfItem1->CompareIDs(lParam, pidl1, pidl2);        // done
  523.     }
  524.     else if ( pdi2 )
  525.     {
  526.         hr = ResultFromShort(-1);       // only pidl2 was a delegate
  527.     }
  528.     else 
  529.     {
  530.         // both items belong to the inner ISF, so lets pass them to that so they can be compared,
  531.         // having done that we can just return the result from there.
  532.         hr = _psfOuter->CompareIDs(lParam, pidl1, pidl2);
  533.     }
  534. exit:
  535.     if ( psfItem1 )
  536.         psfItem1->Release();
  537.     if ( psfItem2 )
  538.         psfItem2->Release();
  539.     return hr;
  540. }
  541. //-----------------------------------------------------------------------------
  542. STDMETHODIMP CDelegateFolder::CreateViewObject(HWND hwnd, REFIID riid, void **ppvOut)
  543. {
  544.     return _psfOuter->CreateViewObject(hwnd, riid, ppvOut);
  545. }
  546. //-----------------------------------------------------------------------------
  547. STDMETHODIMP CDelegateFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl, ULONG * rgfInOut)
  548. {
  549.     HRESULT hr = E_FAIL;
  550.     IShellFolder* psfItem;
  551.     LPCITEMIDLIST* apidl2 = NULL;
  552.     HDPA dpa = NULL;
  553.     CLSID clsid;
  554.     ULONG i, cidl2;
  555.     if ( cidl == 1 )
  556.     {
  557.         // pass real IDLs through, otherwise get the delegate folder that
  558.         // this idlist maps to and get attributes from it.
  559.         IShellFolder* psfItem;
  560.         hr = _GetItemFolder(*apidl, &psfItem);
  561.         if (SUCCEEDED(hr))
  562.         {
  563.             hr = psfItem->GetAttributesOf(cidl, apidl, rgfInOut);
  564.             psfItem->Release();
  565.         }
  566.     }
  567.     else if ( cidl > 1 )
  568.     {
  569.         // the selection is large, so we build two lists, the first contains the items that
  570.         // relate to the inner ISF, the second is a list of the delegate items.  the items 
  571.         // destined for the inner ISF are stored in a LocalAlloc, the delegates are in a 
  572.         // DPA.
  573.         dpa = DPA_Create(4);
  574.         apidl2 = (LPCITEMIDLIST*)LocalAlloc(LPTR, SIZEOF(LPCITEMIDLIST)*cidl);
  575.         if ( !apidl2 || !dpa )
  576.             ExitGracefully(hr, E_OUTOFMEMORY);
  577.         for ( cidl2 = 0, i = 0 ; i != cidl ; i++ )
  578.         {        
  579.             if ( !_IsDelegateObject(apidl[i], NULL) )
  580.             {
  581.                 apidl2[cidl2++] = apidl[i];
  582.             }
  583.             else
  584.             {
  585.                 if ( -1 == DPA_AppendPtr(dpa, (LPVOID)apidl[i]) )
  586.                     ExitGracefully(hr, E_OUTOFMEMORY);
  587.             }
  588.         }
  589.         // call the innerISF with the items it is interested in.
  590.         if ( cidl2 )
  591.         {
  592.             hr = _psfOuter->GetAttributesOf(cidl2, apidl2, rgfInOut);
  593.             FailGracefully(hr);
  594.         }
  595.         // if we have any destined for the delegate namespace then lets
  596.         // first sort that list (basedon the CLSID) and bind to the
  597.         // namespace as required.  the initial sort avoids us having
  598.         // to CoCreate the delegate object multiple times.
  599.         if ( DPA_GetPtrCount(dpa) )
  600.         {
  601.             DPA_Sort(dpa, _CompareDelegateItem, NULL);
  602.             for ( cidl2 = 0, i = 0 ; i != (ULONG)DPA_GetPtrCount(dpa) ; i++ )
  603.             {
  604.                 // if we are no longer in the same CLSID and the list
  605.                 // is long we pass them onto the namespace
  606.                 if ( cidl2 &&
  607.                        !IsEqualCLSID(clsid, _GetDelegateCLSID((PDELEGATEITEMID)DPA_GetPtr(dpa, i))) )
  608.                 {
  609.                     hr = _GetDelegateFolder(apidl2[0], IID_IShellFolder, (void **)&psfItem);
  610.                     FailGracefully(hr);
  611.                     hr = psfItem->GetAttributesOf(cidl2, apidl2, rgfInOut);
  612.                     psfItem->Release();
  613.                     cidl2 = 0;      // no new items in the dpa copy yet!
  614.                 }
  615.                 // add this item to the list, if we have none
  616.                 // then take a snapshot of the GUID
  617.                 if ( !cidl2 )
  618.                     clsid = _GetDelegateCLSID((PDELEGATEITEMID)DPA_GetPtr(dpa, i));
  619.                 apidl2[cidl2++] = (LPCITEMIDLIST)DPA_GetPtr(dpa, i);
  620.             }
  621.             if ( cidl2 )
  622.             {
  623.                 // on exit ensure that we have passed out the remainng items.
  624.                 hr = _GetDelegateFolder(apidl2[0], IID_IShellFolder, (void **)&psfItem);
  625.                 FailGracefully(hr);
  626.                 hr = psfItem->GetAttributesOf(cidl2, apidl2, rgfInOut);
  627.                 psfItem->Release();
  628.             }
  629.         }
  630.     }
  631. exit:
  632.     if ( dpa )
  633.         DPA_Destroy(dpa);
  634.     if ( apidl2 )
  635.         LocalFree((HLOCAL)apidl2);
  636.     return hr;
  637. }
  638. //-----------------------------------------------------------------------------
  639. STDMETHODIMP CDelegateFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, STRRET *pName)
  640. {
  641.     IShellFolder* psfItem;
  642.     HRESULT hr = _GetItemFolder(pidl, &psfItem);
  643.     if (SUCCEEDED(hr))
  644.     {
  645.         hr = psfItem->GetDisplayNameOf(pidl, uFlags, pName);
  646.         psfItem->Release();
  647.     }
  648.     return hr;
  649. }
  650. //-----------------------------------------------------------------------------
  651. STDMETHODIMP CDelegateFolder::SetNameOf(HWND hwnd, LPCITEMIDLIST pidl,
  652.                                         LPCOLESTR pszName, DWORD uFlags, LPITEMIDLIST *ppidlOut)
  653. {
  654.     IShellFolder* psfItem;
  655.     HRESULT hr = _GetItemFolder(pidl, &psfItem);
  656.     if (SUCCEEDED(hr))
  657.     {
  658.         hr = psfItem->SetNameOf(hwnd, pidl, pszName, uFlags, ppidlOut);
  659.         psfItem->Release();
  660.     }
  661.     return hr;
  662. }
  663. //-----------------------------------------------------------------------------
  664. STDMETHODIMP CDelegateFolder::GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST *apidl,
  665.                                           REFIID riid, UINT *prgfInOut, void **ppvOut)
  666. {
  667.     HRESULT hr = E_FAIL;
  668.     IShellFolder* psfItem;
  669.     BOOL fDelegate = FALSE;
  670.     UINT i, cidl2;
  671.     LPCITEMIDLIST* apidl2 = NULL;
  672.     if ( cidl == 1 )
  673.     {
  674.         // single selection is simple, we must just pass that down to the 
  675.         // correct owner.
  676.         fDelegate = (_IsDelegateObject(*apidl, NULL) != NULL);
  677.         if ( fDelegate )
  678.         {
  679.             hr = _GetDelegateFolder(*apidl, IID_IShellFolder, (void **)&psfItem);
  680.             FailGracefully(hr);
  681.             hr = psfItem->GetUIObjectOf(hwnd, cidl, apidl, riid, prgfInOut, ppvOut);
  682.             psfItem->Release();
  683.         }
  684.     }
  685.     else if ( cidl > 1 )
  686.     {
  687.         // walk the list of IDLISTs and see what items we have, if there are any delegate
  688.         // items then this complicates things, if not then we can just pass to the 
  689.         // inner ISF to get the information from that.
  690.         for ( i = 0 ; (i != cidl) && !fDelegate ; i++ )
  691.             fDelegate = (_IsDelegateObject(apidl[i], NULL) != NULL);
  692.         if ( fDelegate )
  693.         {
  694.             if ( IsEqualIID(riid, IID_IDataObject) )
  695.             {
  696.                 hr = CIDLData_CreateFromIDArray(_GetFolderIDList(), cidl, apidl, (IDataObject **)ppvOut);
  697.             }
  698.             else if ( IsEqualIID(riid, IID_IContextMenu) )
  699.             {
  700.                 // the selection is large, there is at least one delegate item in it
  701.                 // so lets build an alternate list where all the items match the
  702.                 // first (clsid and delegate-ness).
  703.                 apidl2 = (LPCITEMIDLIST*)LocalAlloc(LPTR, SIZEOF(LPCITEMIDLIST)*cidl);
  704.                 if ( !apidl2 )  
  705.                     ExitGracefully(hr, E_OUTOFMEMORY);
  706.                 for ( cidl2 = 0, i = 0 ; i != cidl ; i++ )
  707.                 {
  708.                     if ( (_IsDelegateObject(apidl[0], NULL) == _IsDelegateObject(apidl[i], NULL)) &&
  709.                             ( !_IsDelegateObject(apidl[0], NULL) || 
  710.                                  IsEqualCLSID(_GetDelegateCLSID(apidl[0]), _GetDelegateCLSID(apidl[i]))) )
  711.                     {
  712.                         apidl2[cidl2++] = apidl[i];
  713.                     }
  714.                 }
  715.                 // if there is a delegate in the first the bind to it and call it, otherwise
  716.                 // just call the innerISF.
  717.                 if ( !_IsDelegateObject(apidl2[0], NULL) )
  718.                 {
  719.                     hr = _psfOuter->GetUIObjectOf(hwnd, cidl2, apidl2, riid, prgfInOut, ppvOut);
  720.                 }
  721.                 else
  722.                 {
  723.                     hr = _GetDelegateFolder(apidl2[0], IID_IShellFolder, (void **)&psfItem);
  724.                     FailGracefully(hr);
  725.                     hr = psfItem->GetUIObjectOf(hwnd, cidl2, apidl2, riid, prgfInOut, ppvOut);
  726.                     psfItem->Release();
  727.                 }
  728.                 fDelegate = TRUE;           // already handled
  729.             }
  730.             else
  731.             {
  732.                 ExitGracefully(hr, E_NOTIMPL);          // BUGBUG: we must expand on this guy!
  733.             }
  734.         }            
  735.     }
  736.     // handled yet?  if not then pass onto the inner ISF
  737.     if ( !fDelegate )
  738.         hr = _psfOuter->GetUIObjectOf(hwnd, cidl, apidl, riid, prgfInOut, ppvOut);
  739. exit:
  740.     if ( apidl2 )
  741.         LocalFree(apidl2);
  742.     return hr;
  743. }
  744. //-----------------------------------------------------------------------------
  745. STDMETHODIMP CDelegateFolder::GetDefaultSearchGUID(LPGUID lpGUID)
  746. {
  747.     return _psfOuter->GetDefaultSearchGUID(lpGUID);
  748. }
  749. STDMETHODIMP CDelegateFolder::EnumSearches(LPENUMEXTRASEARCH *ppenum)
  750. {
  751.     return _psfOuter->EnumSearches(ppenum);
  752. }
  753. STDMETHODIMP CDelegateFolder::GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay)
  754. {
  755.     return _psfOuter->GetDefaultColumn(dwRes, pSort, pDisplay);
  756. }
  757. STDMETHODIMP CDelegateFolder::GetDefaultColumnState(UINT iColumn, DWORD *pbState)
  758. {
  759.     return _psfOuter->GetDefaultColumnState(iColumn, pbState);
  760. }
  761. STDMETHODIMP CDelegateFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv)
  762. {
  763.     IShellFolder2* psfItem;
  764.     HRESULT hr = _GetItemFolder2(pidl, &psfItem);
  765.     if (SUCCEEDED(hr))
  766.     {
  767.         hr = psfItem->GetDetailsEx(pidl, pscid, pv);
  768.         psfItem->Release();
  769.     }
  770.     return hr;
  771. }
  772. STDMETHODIMP CDelegateFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pDetails)
  773. {
  774.     IShellFolder2* psfItem;
  775.     HRESULT hr = _GetItemFolder2(pidl, &psfItem);
  776.     if (SUCCEEDED(hr))
  777.     {
  778.         hr = psfItem->GetDetailsOf(pidl, iColumn, pDetails);
  779.         psfItem->Release();
  780.     }
  781.     return hr;
  782. }
  783. STDMETHODIMP CDelegateFolder::MapNameToSCID(LPCWSTR pwszName, SHCOLUMNID *pscid)
  784. {
  785.     return _psfOuter->MapNameToSCID(pwszName, pscid);
  786. }
  787. /*-----------------------------------------------------------------------------
  788. / Instance creation 
  789. /----------------------------------------------------------------------------*/
  790. STDAPI CDelegateFolder_CreateInstance(IUnknown* punkOuter, REFIID riid, void **ppvOut)
  791. {
  792.     // we only suport being created as an agregate
  793.     if ( !punkOuter || !IsEqualIID(riid, IID_IUnknown))
  794.     {
  795.         ASSERT(0);
  796.         return E_FAIL;
  797.     }
  798.     CDelegateFolder *pdelisf = new CDelegateFolder(punkOuter);
  799.     if ( !pdelisf )
  800.         return E_OUTOFMEMORY;
  801.     *ppvOut = pdelisf->_GetInner();
  802.     return S_OK;
  803. }
  804. //-----------------------------------------------------------------------------
  805. // Enumerator, this handles enumerating the IF and bringing in the delegate
  806. // folder objects.
  807. //-----------------------------------------------------------------------------
  808. CDelegateFolderEnum::CDelegateFolderEnum(HWND hwnd, DWORD grfFlags, HDPA dpaFolders) :
  809.     _cRef(1),
  810.     _hwnd(hwnd),
  811.     _grfFlags(grfFlags),
  812.     _dpaFolders(dpaFolders),
  813.     _index(0),
  814.     _pCurrentEnum(NULL)
  815. {   
  816.     DllAddRef();
  817. }
  818. CDelegateFolderEnum::~CDelegateFolderEnum()
  819. {
  820.     if ( _dpaFolders )
  821.         DPA_DestroyCallback(_dpaFolders, _ReleaseCB, NULL);
  822.     if ( _pCurrentEnum )
  823.         _pCurrentEnum->Release();
  824.     DllRelease();
  825. }
  826. // IUnknown goop
  827. STDMETHODIMP CDelegateFolderEnum::QueryInterface(REFIID riid, void **ppv)
  828. {
  829.     static const QITAB qit[] = {
  830.         QITABENT(CDelegateFolderEnum, IEnumIDList),
  831.         { 0 },
  832.     };
  833.     return QISearch(this, qit, riid, ppv);
  834. }
  835. STDMETHODIMP_(ULONG) CDelegateFolderEnum::AddRef()
  836. {
  837.     return InterlockedIncrement(&_cRef);
  838. }
  839. STDMETHODIMP_(ULONG) CDelegateFolderEnum::Release()
  840. {
  841.     if (InterlockedDecrement(&_cRef))
  842.         return _cRef;
  843.     delete this;
  844.     return 0;
  845. }
  846. //-----------------------------------------------------------------------------
  847. // IEnumIDList
  848. //-----------------------------------------------------------------------------
  849. STDMETHODIMP CDelegateFolderEnum::Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched)
  850. {
  851.     HRESULT hr = S_FALSE;
  852.     ULONG ulDummy;
  853.     if (pceltFetched == NULL)
  854.         pceltFetched = &ulDummy;
  855.     *pceltFetched = 0;             // nothing has been returned yet
  856.     // whilst we have an enumerator and there have been no items returned
  857.     // lets go around to see how many objects we should be removing.
  858.     while ( !*pceltFetched )
  859.     {
  860.         // no enumerator, lets see if we can get an instance of the next
  861.         // one to enumerate from.
  862.         if ( !_pCurrentEnum )
  863.         {
  864.             while ( _index < DPA_GetPtrCount(_dpaFolders) )
  865.             {
  866.                 IShellFolder* pShellFolder = (IShellFolder*)DPA_GetPtr(_dpaFolders, _index++);
  867.                 ASSERT(pShellFolder);
  868.                 if ( SUCCEEDED(pShellFolder->EnumObjects(_hwnd, _grfFlags, &_pCurrentEnum)) )
  869.                     break;
  870.             }
  871.             if ( !_pCurrentEnum )
  872.                 break;
  873.         }
  874.         // do we have an enumerator now? if so then lets call it and return the items back
  875.         // to the caller.
  876.         if ( _pCurrentEnum )
  877.         {
  878.             hr = _pCurrentEnum->Next(celt, rgelt, pceltFetched);
  879.             if ( hr == S_FALSE )
  880.             {
  881.                 _pCurrentEnum->Release();
  882.                 _pCurrentEnum = NULL;
  883.                 if ( !*pceltFetched )
  884.                     continue;
  885.             }
  886.             break;
  887.         }
  888.     }
  889.     return hr;
  890. }
  891. //-----------------------------------------------------------------------------
  892. STDMETHODIMP CDelegateFolderEnum::Skip(ULONG celt)
  893. {
  894.     return E_NOTIMPL;
  895. }
  896. //-----------------------------------------------------------------------------
  897. STDMETHODIMP CDelegateFolderEnum::Reset(THIS)
  898. {
  899.     // lets start the enumeration process again, so set the index back to the head
  900.     // and release the enumerator we are currently using.
  901.     _index = 0;
  902.     ATOMICRELEASE(_pCurrentEnum);
  903.     return S_OK;
  904. }
  905. //-----------------------------------------------------------------------------
  906. STDMETHODIMP CDelegateFolderEnum::Clone(IEnumIDList **ppenum)
  907. {
  908.     return E_NOTIMPL;
  909. }
  910. //-----------------------------------------------------------------------------
  911. // This code used to be in shdocvw, it is the implementation of a IMalloc for handling
  912. // delegate folder items
  913. //-----------------------------------------------------------------------------
  914. class CDelagateMalloc : public IMalloc
  915. {
  916. public:
  917.     // IUnknown
  918.     virtual STDMETHODIMP QueryInterface(REFIID,void **);
  919.     virtual STDMETHODIMP_(ULONG) AddRef(void);
  920.     virtual STDMETHODIMP_(ULONG) Release(void);
  921.     // IMalloc
  922.     virtual STDMETHODIMP_(LPVOID)   Alloc(ULONG cb);
  923.     virtual STDMETHODIMP_(LPVOID)   Realloc(void *pv, ULONG cb);
  924.     virtual STDMETHODIMP_(void)     Free(void *pv);
  925.     virtual STDMETHODIMP_(ULONG)    GetSize(void *pv);
  926.     virtual STDMETHODIMP_(int)      DidAlloc(void *pv);
  927.     virtual STDMETHODIMP_(void)     HeapMinimize();
  928. private:
  929.     CDelagateMalloc(void *pv, UINT cbSize, WORD wOuter);
  930.     ~CDelagateMalloc();
  931.     void* operator new(size_t cbClass, UINT cbSize);
  932.     friend HRESULT CDelegateMalloc_Create(void *pv, UINT cbSize, WORD wOuter, IMalloc **ppmalloc);
  933. protected:
  934.     LONG _cRef;
  935.     WORD _wOuter;           // delegate item outer signature
  936.     WORD _wUnused;          // to allign
  937. #ifdef DEBUG
  938.     UINT _cAllocs;
  939. #endif
  940.     UINT _cb;
  941.     BYTE _data[];
  942. };
  943. void* CDelagateMalloc::operator new(size_t cbClass, UINT cbSize)
  944. {
  945.     return ::operator new(cbClass + cbSize);
  946. }
  947. CDelagateMalloc::CDelagateMalloc(void *pv, UINT cbSize, WORD wOuter)
  948. {
  949.     _cRef = 1;
  950.     _wOuter = wOuter;
  951.     _cb = cbSize;
  952.     memcpy(_data, pv, _cb);
  953. }
  954. CDelagateMalloc::~CDelagateMalloc()
  955. {
  956.     DEBUG_CODE( TraceMsg(DM_TRACE, "DelegateMalloc destroyed with %d allocs performed", _cAllocs); )
  957. }
  958. HRESULT CDelagateMalloc::QueryInterface(REFIID riid, void **ppv)
  959. {
  960.     static const QITAB qit[] = {
  961.         QITABENT(CDelagateMalloc, IMalloc), // IID_IMalloc
  962.         { 0 },
  963.     };
  964.     return QISearch(this, qit, riid, ppv);
  965. }
  966. ULONG CDelagateMalloc::AddRef()
  967. {
  968.     return InterlockedIncrement(&_cRef);
  969. }
  970. ULONG CDelagateMalloc::Release()
  971. {
  972.     if (InterlockedDecrement(&_cRef))
  973.         return _cRef;
  974.     delete this;
  975.     return 0;
  976. }
  977. void *CDelagateMalloc::Alloc(ULONG cb)
  978. {
  979.     WORD cbActualSize = (WORD)(
  980.                         SIZEOF(DELEGATEITEMID) - 1 +    // header (-1 sizeof(rgb[0])
  981.                         cb +                            // inner
  982.                         _cb);                           // outer data
  983.     PDELEGATEITEMID pidl = (PDELEGATEITEMID)SHAlloc(cbActualSize + 2);  // +2 for pidl term
  984.     if (pidl)
  985.     {
  986.         pidl->cbSize = cbActualSize;
  987.         pidl->wOuter = _wOuter;
  988.         pidl->cbInner = (WORD)cb;
  989.         memcpy(&pidl->rgb[cb], _data, _cb);
  990.         *(WORD *)&(((BYTE *)pidl)[cbActualSize]) = 0;
  991. #ifdef DEBUG
  992.         _cAllocs++;
  993. #endif
  994.     }
  995.     return pidl;
  996. }
  997. void *CDelagateMalloc::Realloc(void *pv, ULONG cb)
  998. {
  999.     return NULL;
  1000. }
  1001. void CDelagateMalloc::Free(void *pv)
  1002. {
  1003.     SHFree(pv);
  1004. }
  1005. ULONG CDelagateMalloc::GetSize(void *pv)
  1006. {
  1007.     return (ULONG)-1;
  1008. }
  1009. int CDelagateMalloc::DidAlloc(void *pv)
  1010. {
  1011.     return -1;
  1012. }
  1013. void CDelagateMalloc::HeapMinimize()
  1014. {
  1015. }
  1016. STDAPI CDelegateMalloc_Create(void *pv, UINT cbSize, WORD wOuter, IMalloc **ppmalloc)
  1017. {
  1018.     CDelagateMalloc *pdm = new(cbSize) CDelagateMalloc(pv, cbSize, wOuter);
  1019.     if (pdm)
  1020.     {
  1021.         HRESULT hres = pdm->QueryInterface(IID_IMalloc, (void **)ppmalloc);
  1022.         pdm->Release();
  1023.         return hres;
  1024.     }
  1025.     return E_OUTOFMEMORY;
  1026. }