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

Windows Kernel

Development Platform:

Visual C++

  1. #include "pch.h"
  2. #include "iids.h"
  3. #pragma hdrstop
  4. /*-----------------------------------------------------------------------------
  5. / Column information used by the shell to Detail view mode.
  6. /----------------------------------------------------------------------------*/
  7. //
  8. // column information
  9. //
  10. const struct
  11. {
  12.     UINT idString;              // resource ID for the column title
  13.     INT  fmt;                   // formatting flags of the column
  14.     INT  cxChar;                // average char with of this column
  15. }
  16. columns[] =
  17. {
  18.     IDS_OBJECTNAME, LVCFMT_LEFT, 64,                // DSVMID_ARRANGEBYNAME
  19.     IDS_TYPE,       LVCFMT_LEFT, 32,                // DSVMID_ARRANGEBYCLASS
  20. };
  21. //
  22. // CDsFolder
  23. //
  24. #define NAMESPACE_ATTRIBUTES (SFGAO_FOLDER|SFGAO_FILESYSANCESTOR|SFGAO_HASSUBFOLDER|SFGAO_CANLINK)
  25. class CDsFolder : public IDsFolderInternalAPI, IPersistFolder2, IDelegateFolder, IShellFolder, CUnknown
  26. {
  27.     friend HRESULT _GetDetailsOf(CDsFolder *pdf, PDETAILSINFO pDetails, UINT iColumn);
  28.     friend HRESULT _MergeArrangeMenu(CDsFolder *pdf, LPARAM arrangeParam, LPQCMINFO pInfo);
  29.     private:
  30.         CLSID             _clsidNamespace;          // where in the registry to look for our configuration
  31.         LPITEMIDLIST      _pidl;                    // absolute IDLIST to our object
  32.         INT               _cbOffset;                // offset to start of ds elements
  33.         LPTSTR            _pPrettyPath;             // prettified version of the folder path
  34.         LPWSTR            _pAttribPrefix;           // attribute prefix (set via internal API)
  35.         DWORD             _dwProviderAND;           // extra AND for the provider flags
  36.         DWORD             _dwProviderXOR;           // extra XOR for the provider flags
  37.         LPWSTR            _pServer;                 // server
  38.         LPWSTR            _pUserName;               // user name 
  39.         LPWSTR            _pPassword;               // password
  40.         HRESULT           _hresCoInit;              // did we do a CoInitialize?
  41.         IADsPathname      *_padp;                   // IADsPathname iface for name cracking
  42.         IDsDisplaySpecifier *_pdds;                 // IDsDisplaySpecifier for DsXXX APIs
  43.         IMalloc           *_pm;                     // IMalloc used for delegate folder support
  44.     private:
  45.         HRESULT _RealInitialize(LPCITEMIDLIST pidlRoot, LPCITEMIDLIST pidlBindTo, INT cbOffset);
  46.         BOOL    _InitCOM(void);
  47.         HRESULT _GetPathname(void);
  48.         HRESULT _GetDsDisplaySpecifier(void);
  49.         HRESULT _GetJunction(LPITEMIDLIST pidl, LPITEMIDLIST *ppidlRight, IDLISTDATA *pData);
  50.         HRESULT _GetJunctionSF(LPITEMIDLIST pidlFull, IBindCtx *pbc, IDLISTDATA *pData, LPITEMIDLIST *ppidlRight, IShellFolder **ppsf);
  51.         HRESULT _TryToParsePath(LPITEMIDLIST* ppidl, IADsPathname *padp, LPWSTR pObjectClass, LPDOMAINTREE pDomainTree);
  52.         HRESULT _SetDispSpecOptions(IDataObject *pdo);
  53.     public:
  54.         CDsFolder();
  55.         ~CDsFolder();
  56.         // IUnknown
  57.         STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
  58.         STDMETHOD_(ULONG, AddRef)();
  59.         STDMETHOD_(ULONG, Release)();
  60.         // IDsFolderInternalAPI
  61.         STDMETHOD(SetAttributePrefix)(LPWSTR pAttributePrefix);
  62.         STDMETHOD(SetProviderFlags)(DWORD dwAND, DWORD dwXOR);
  63.         STDMETHOD(SetComputer)(LPCWSTR pszComputerName, LPCWSTR pszUserName, LPCWSTR pszPassword);
  64.         // IPersistFolder
  65.         STDMETHOD(GetClassID)(LPCLSID pClassID);
  66.         STDMETHOD(Initialize)(LPCITEMIDLIST pidl);
  67.         // IPersistFolder2
  68.         STDMETHOD(GetCurFolder)(LPITEMIDLIST *ppidl);
  69.         // IDelegateFolder
  70.         STDMETHOD(SetItemAlloc)(IMalloc *pm);
  71.         // IShellFolder
  72.         STDMETHOD(ParseDisplayName)(HWND hwndOwner, LPBC pbc, LPOLESTR pDisplayName, 
  73.                                       ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes);
  74.         STDMETHOD(EnumObjects)(HWND hwndOwner, DWORD grfFlags, LPENUMIDLIST * ppEnumIDList);
  75.         STDMETHOD(BindToObject)(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, void **ppv);
  76.         STDMETHOD(BindToStorage)(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, void **ppv);
  77.         STDMETHOD(CompareIDs)(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
  78.         STDMETHOD(CreateViewObject)(HWND hwndOwner, REFIID riid, void **ppv);
  79.         STDMETHOD(GetAttributesOf)(UINT cidl, LPCITEMIDLIST * apidl, ULONG * rgfInOut);
  80.         STDMETHOD(GetUIObjectOf)(HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl, REFIID riid, UINT * prgfInOut, void **ppv);
  81.         STDMETHOD(GetDisplayNameOf)(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET pName);
  82.         STDMETHOD(SetNameOf)(HWND hwndOwner, LPCITEMIDLIST pidl, LPCOLESTR pszName, DWORD uFlags, LPITEMIDLIST* ppidlOut);
  83. };
  84. //
  85. // CDsExtractIcon 
  86. //
  87. class CDsExtractIcon : public IExtractIcon, CUnknown
  88. {
  89.     private:
  90.         LPITEMIDLIST _pidl;     
  91.         IDsDisplaySpecifier *_pdds;
  92.     public:
  93.         CDsExtractIcon(IDsDisplaySpecifier *pdds, LPCITEMIDLIST pidl);
  94.         ~CDsExtractIcon();
  95.         // IUnknown
  96.         STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
  97.         STDMETHOD_(ULONG, AddRef)();
  98.         STDMETHOD_(ULONG, Release)();
  99.         // IExtractIcon
  100.         STDMETHOD(GetIconLocation)(UINT uFlags, LPTSTR szIconFile, UINT cchMax, int* pIndex, UINT* pwFlags);
  101.         STDMETHOD(Extract)(LPCTSTR pszFile, UINT nIconIndex, HICON* pLargeIcon, HICON* pSmallIcon, UINT nIconSize);
  102. };
  103. //
  104. // CDsFolderProperties
  105. //
  106. class CDsFolderProperties : public IDsFolderProperties, CUnknown
  107. {
  108.     public:
  109.         // IUnknown
  110.         STDMETHOD(QueryInterface)(REFIID riid, void **ppv);
  111.         STDMETHOD_(ULONG, AddRef)();
  112.         STDMETHOD_(ULONG, Release)();
  113.         // IDsFolderProperties
  114.         STDMETHOD(ShowProperties)(HWND hwndParent, IDataObject *pDataObject);
  115. };
  116. /*-----------------------------------------------------------------------------
  117. / Callback functions used by this IShellFolder implementation
  118. /----------------------------------------------------------------------------*/
  119. /*-----------------------------------------------------------------------------
  120. / _StrRetFromString
  121. / -----------------
  122. /   Package a WIDE string into a LPSTRRET structure.
  123. /
  124. / In:
  125. /   pStrRet -> receieves the newly allocate string
  126. /   pString -> string to be copied.
  127. /
  128. / Out:
  129. /   -
  130. /----------------------------------------------------------------------------*/
  131. HRESULT _StrRetFromString(LPSTRRET lpStrRet, LPCTSTR pString)
  132. {
  133.     HRESULT hres;
  134.     TraceEnter(TRACE_FOLDER, "_StrRetFromString");
  135.     Trace(TEXT("pStrRet %08x, lpszString -%s-"), lpStrRet, pString);
  136.     TraceAssert(lpStrRet);
  137.     TraceAssert(pString);
  138. #ifdef UNICODE
  139.     lpStrRet->pOleStr = (LPWSTR)SHAlloc(StringByteSize(pString));
  140.     if ( !lpStrRet->pOleStr )
  141.         ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate buffer for string");
  142.     lpStrRet->uType = STRRET_OLESTR;
  143.     StrCpy(lpStrRet->pOleStr, pString);                
  144. #else
  145.     if ( lstrlen(pString) > (MAX_PATH-1) )
  146.         ExitGracefully(hres, E_OUTOFMEMORY, "Buffer too small for string");
  147.     lpStrRet->uType = STRRET_CSTR;
  148.     StrCpy(lpStrRet->cStr, pString);
  149. #endif
  150.     hres = S_OK;                              // success
  151. exit_gracefully:
  152.     TraceLeaveResult(hres);
  153. }
  154. /*-----------------------------------------------------------------------------
  155. / _GetDetailsOf
  156. / -------------
  157. /   Handle the GetDetailsOf call back for this view.  If PIDL is NULL on
  158. /   entry then just return the column heading, otherwise get that information
  159. /   for the IDLIST and column combination.
  160. /
  161. / In:
  162. /   pDetails -> structure to fill
  163. /   iColumn -> column being invoked on
  164. /
  165. / Out:
  166. /   HRESULT
  167. /----------------------------------------------------------------------------*/
  168. HRESULT _GetDetailsOf(CDsFolder *pdf, PDETAILSINFO pDetails, UINT iColumn)
  169. {
  170.     HRESULT hres;
  171.     IDLISTDATA data;
  172.     USES_CONVERSION;
  173.     TraceEnter(TRACE_FOLDER, "_GetDetailsOf");
  174.     TraceAssert(pdf != NULL);
  175.     if ( iColumn > ARRAYSIZE(columns) )
  176.         ExitGracefully(hres, E_INVALIDARG, "Bad column index");
  177.     // Fill out the structure with the formatting information,
  178.     // and a dummy string incase we fail.
  179.     pDetails->fmt = columns[iColumn].fmt;
  180.     pDetails->cxChar = columns[iColumn].cxChar;
  181.     pDetails->str.uType = STRRET_CSTR;
  182.     pDetails->str.cStr[0] = TEXT('');
  183.     if ( !pDetails->pidl )
  184.     {
  185.         TCHAR szBuffer[MAX_PATH];
  186.         if ( !LoadString(GLOBAL_HINSTANCE, columns[iColumn].idString, szBuffer, ARRAYSIZE(szBuffer)) )
  187.             ExitGracefully(hres, E_FAIL, "Failed to load column heading");
  188.         hres = _StrRetFromString(&pDetails->str, szBuffer);
  189.         FailGracefully(hres, "Failed making a StrRet from the column heading");
  190.     }
  191.     else
  192.     {
  193.         hres = UnpackIdList(pDetails->pidl, DSIDL_HASCLASS, &data);
  194.         FailGracefully(hres, "Failed to unpack the IDLIST");
  195.         if ( iColumn == DSVMID_ARRANGEBYCLASS )
  196.         {
  197.             WCHAR szBuffer[MAX_PATH];
  198.             if ( SUCCEEDED(pdf->_GetDsDisplaySpecifier()) )
  199.                 pdf->_pdds->GetFriendlyClassName(data.pObjectClass, szBuffer, ARRAYSIZE(szBuffer));
  200.             else
  201.                 StrCpyW(szBuffer, data.pObjectClass);
  202.             hres = _StrRetFromString(&pDetails->str, W2CT(szBuffer));
  203.             FailGracefully(hres, "Failed to make StrRet from class name");
  204.         }
  205.         else
  206.         {
  207.             TraceAssert(FALSE);
  208.             ExitGracefully(hres, E_FAIL, "Bad column specified");
  209.         }
  210.     }
  211.     // hres = S_OK;
  212. exit_gracefully:
  213.     TraceLeaveResult(hres);
  214. }
  215. /*-----------------------------------------------------------------------------
  216. / _MergeArrangeMenu
  217. / -----------------
  218. /   Merge our verbs into the view menu
  219. /
  220. / In:
  221. /   arrangeParam = current sort parameter
  222. /   pInfo -> QCMINFO structure
  223. /
  224. / Out:
  225. /   HRESULT
  226. /----------------------------------------------------------------------------*/
  227. HRESULT _MergeArrangeMenu(CDsFolder *pdf, LPARAM arrangeParam, LPQCMINFO pInfo)
  228. {
  229.     HRESULT hres;
  230.     MENUITEMINFO mii = { SIZEOF(MENUITEMINFO), MIIM_SUBMENU };
  231.     UINT idCmdFirst = pInfo->idCmdFirst;
  232.     HMENU hMyArrangeMenu;
  233.     TraceEnter(TRACE_FOLDER, "_MergeArrangeMenu");
  234.     TraceAssert(pdf != NULL);
  235.     Trace(TEXT("arrangeParam %08x, pInfo->idCmdFirst %08x"), arrangeParam, pInfo->idCmdFirst);
  236.     if ( GetMenuItemInfo(pInfo->hmenu, SFVIDM_MENU_ARRANGE, FALSE, &mii) )
  237.     {
  238.         hMyArrangeMenu = LoadMenu(GLOBAL_HINSTANCE, MAKEINTRESOURCE(IDR_ARRANGE));
  239.         if ( hMyArrangeMenu )
  240.         {
  241.             pInfo->idCmdFirst = Shell_MergeMenus(mii.hSubMenu,
  242.                                                  GetSubMenu(hMyArrangeMenu, 0), 
  243.                                                  0, 
  244.                                                  pInfo->idCmdFirst, pInfo->idCmdLast,
  245.                                                  0);                    
  246.             DestroyMenu(hMyArrangeMenu);
  247.         }
  248.     } 
  249.     TraceLeaveResult(S_OK);
  250. }
  251. /*-----------------------------------------------------------------------------
  252. / _FolderCallBack
  253. / ---------------
  254. /   Handles callbacks from the shell for the view object we are the parent of.
  255. /
  256. / In:
  257. /   psvView -> view object
  258. /   psf -> shell folder (our object)
  259. /   hwndMain = window handle for a dialog parent
  260. /   uMsg, wParam, lParam = message specific information
  261. /
  262. / Out:
  263. /   -
  264. /----------------------------------------------------------------------------*/
  265. HRESULT CALLBACK _FolderCallBack(LPSHELLVIEW psvOuter, LPSHELLFOLDER psf, HWND hwndView, UINT uMsg, WPARAM wParam, LPARAM lParam)
  266. {
  267.     HRESULT hres = NOERROR;
  268.     CDsFolder *pdf;
  269.     psf->QueryInterface(CLSID_DsFolderSF, (void **)&pdf);
  270.     switch (uMsg)
  271.     {
  272.         case SFVM_INITMENUPOPUP:
  273.             break;
  274.         case SFVM_MERGEMENU:
  275.             hres = _MergeArrangeMenu(pdf, ShellFolderView_GetArrangeParam(hwndView), (LPQCMINFO)lParam);
  276.             break;
  277.         case SFVM_INVOKECOMMAND:
  278.         {
  279.             UINT idCmd = (UINT)wParam;
  280.             switch ( idCmd )
  281.             {
  282.                 case DSVMID_ARRANGEBYNAME:
  283.                 case DSVMID_ARRANGEBYCLASS:
  284.                     ShellFolderView_ReArrange(hwndView, idCmd);
  285.                     break;
  286.                 default:
  287.                     hres = S_FALSE;
  288.                     break;
  289.             }
  290.             break;
  291.         }
  292.         case SFVM_GETHELPTEXT:
  293.         {
  294.             hres = S_OK;
  295.         
  296.             switch ( LOWORD(wParam) )
  297.             {
  298.                 case DSVMID_ARRANGEBYNAME:
  299.                     LoadString(GLOBAL_HINSTANCE, IDS_BYOBJECTNAME, (LPTSTR)lParam, HIWORD(wParam));
  300.                     break;
  301.                 case DSVMID_ARRANGEBYCLASS:
  302.                     LoadString(GLOBAL_HINSTANCE, IDS_BYTYPE, (LPTSTR)lParam, HIWORD(wParam));
  303.                     break;
  304.                 default:
  305.                     hres = S_FALSE;
  306.                     break;
  307.             }
  308.         }
  309.         case SFVM_GETDETAILSOF:
  310.             hres = _GetDetailsOf(pdf, (PDETAILSINFO)lParam, (UINT)wParam);
  311.             break;
  312.         case SFVM_COLUMNCLICK:
  313.             ShellFolderView_ReArrange(hwndView, (UINT)wParam);
  314.             break;
  315.         case SFVM_BACKGROUNDENUM:
  316.             hres = S_OK;
  317.             break;
  318.         default:
  319.             hres = E_NOTIMPL;
  320.             break;
  321.     }
  322.     return hres;
  323. }
  324. /*-----------------------------------------------------------------------------
  325. / _FolderCFMCallBack
  326. / ------------------
  327. /   Handles callbacks for the context menu which is displayed when the user
  328. /   right clicks on objects within the view.
  329. /
  330. / In:
  331. /   psf -> shell folder (our object)
  332. /   hwndView = window handle for a dialog parent
  333. /   pDataObject -> data object for the menu
  334. /   uMsg, wParam, lParam = message specific information
  335. /
  336. / Out:
  337. /   -
  338. /----------------------------------------------------------------------------*/
  339. HRESULT CALLBACK _FolderCFMCallback(LPSHELLFOLDER psf, HWND hwndView, LPDATAOBJECT pDataObject, UINT uMsg, WPARAM wParam, LPARAM lParam)
  340. {
  341.     HRESULT hres = NOERROR;
  342.     CDsFolder* pdf;
  343.     TraceEnter(TRACE_FOLDER, "_FolderCFMCallback");
  344.     Trace(TEXT("psf %08x, hwndView %08x, pDataObject %08x"), psf, hwndView, pDataObject);
  345.     Trace(TEXT("uMsg %08x, wParam %08x, lParam %08x"), uMsg, wParam, lParam);
  346.     psf->QueryInterface(CLSID_DsFolderSF, (void **)&pdf);
  347.     switch ( uMsg )
  348.     {
  349.         case DFM_MERGECONTEXTMENU:
  350.             hres = _MergeArrangeMenu(pdf, ShellFolderView_GetArrangeParam(hwndView), (LPQCMINFO)lParam);
  351.             break;
  352.         case DFM_GETHELPTEXTW:
  353.         {
  354.             hres = S_OK;
  355.         
  356.             switch ( LOWORD(wParam) )
  357.             {
  358.                 case DSVMID_ARRANGEBYNAME:
  359.                     LoadString(GLOBAL_HINSTANCE, IDS_BYOBJECTNAME, (LPTSTR)lParam, HIWORD(wParam));
  360.                     break;
  361.                 case DSVMID_ARRANGEBYCLASS:
  362.                     LoadString(GLOBAL_HINSTANCE, IDS_BYTYPE, (LPTSTR)lParam, HIWORD(wParam));
  363.                     break;
  364.                 default:
  365.                     hres = S_FALSE;
  366.                     break;
  367.             }
  368.         }
  369.         case DFM_INVOKECOMMAND:
  370.         {
  371.             UINT idCmd = (UINT)wParam;
  372.             switch ( idCmd )
  373.             {
  374.                 case (UINT)DFM_CMD_PROPERTIES:
  375.                     hres = ShowObjectProperties(hwndView, pDataObject);
  376.                     break;
  377.                 case DSVMID_ARRANGEBYNAME:
  378.                 case DSVMID_ARRANGEBYCLASS:
  379.                     ShellFolderView_ReArrange(hwndView, idCmd);
  380.                     break;
  381.                 default:
  382.                     hres = S_FALSE;
  383.                     break;
  384.             }
  385.             break;
  386.         }
  387.         case DFM_GETDEFSTATICID:
  388.         {
  389.             *((UINT*)lParam) = (UINT)DFM_CMD_PROPERTIES;
  390.             break;
  391.         }
  392.         default:
  393.             hres = E_NOTIMPL;
  394.             break;
  395.     }
  396.     TraceLeaveResult(hres);
  397. }
  398. /*-----------------------------------------------------------------------------
  399. / CDsFolder
  400. /   This is our DS IShellFolder implementation, it provides a mapping from
  401. /   the shell namespace down to Active Directory.
  402. /----------------------------------------------------------------------------*/
  403. CDsFolder::CDsFolder() :
  404.     _dwProviderAND(0xffffffff),
  405.     _hresCoInit(E_FAIL)
  406. {
  407. }
  408. CDsFolder::~CDsFolder()
  409. {
  410.     DoILFree(_pidl);
  411.     LocalFreeString(&_pPrettyPath);
  412.     LocalFreeStringW(&_pAttribPrefix);
  413.     LocalFreeStringW(&_pServer);
  414.     LocalFreeStringW(&_pUserName);
  415.     LocalFreeStringW(&_pPassword);
  416.     DoRelease(_padp);
  417.     DoRelease(_pdds);
  418.     DoRelease(_pm);
  419. }
  420. #undef CLASS_NAME
  421. #define CLASS_NAME CDsFolder
  422. #include "unknown.inc"
  423. STDMETHODIMP CDsFolder::QueryInterface( REFIID riid, void **ppv)
  424. {
  425.     INTERFACES iface[] =
  426.     {
  427.         &IID_IDsFolderInternalAPI, (IDsFolderInternalAPI*)this,
  428.         &IID_IShellFolder, (LPSHELLFOLDER)this,
  429.         &IID_IPersistFolder, (LPPERSISTFOLDER)this,
  430.         &IID_IPersistFolder2, (IPersistFolder2*)this,
  431.         &IID_IDelegateFolder, (IDelegateFolder*)this,
  432.     };
  433.     // requesting CLSID_DsFolder gets the CDsFolder object without a reference
  434.     // count.
  435.     if ( IsEqualIID(CLSID_DsFolderSF, riid) )
  436.     {
  437.         *ppv = this;
  438.         return S_OK;
  439.     }
  440.    return HandleQueryInterface(riid, ppv, iface, ARRAYSIZE(iface));
  441. }
  442. //
  443. // handle create instance of the CDsFolder object
  444. //
  445. STDAPI CDsFolder_CreateInstance(IUnknown* punkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  446. {
  447.     CDsFolder *pdf = new CDsFolder();
  448.     if ( !pdf )
  449.         return E_OUTOFMEMORY;
  450.     HRESULT hres = pdf->QueryInterface(IID_IUnknown, (void **)ppunk);
  451.     pdf->Release();
  452.     return hres;
  453. }
  454. //-----------------------------------------------------------------------------
  455. // Helper functions
  456. //-----------------------------------------------------------------------------
  457. //
  458. // ensure we have COM alive...
  459. //
  460. BOOL CDsFolder::_InitCOM(void)
  461. {
  462.     TraceEnter(TRACE_FOLDER, "CDsFolder::_InitCOM");
  463.     if ( FAILED(_hresCoInit) )
  464.     {
  465.         TraceMsg("Calling CoInitialize");
  466.         _hresCoInit = CoInitialize(NULL);
  467.     }
  468.     TraceLeaveValue(SUCCEEDED(_hresCoInit));
  469. }
  470. //
  471. // ensure we have the IADsPathname object
  472. //
  473. HRESULT CDsFolder::_GetPathname(void)
  474. {
  475.     HRESULT hres;
  476.     TraceEnter(TRACE_FOLDER, "CDsFolder::_GetPathname");
  477.     if ( _InitCOM() && !_padp )
  478.     {
  479.         hres = CoCreateInstance(CLSID_Pathname, NULL, CLSCTX_INPROC_SERVER, IID_IADsPathname, (void **)&_padp);
  480.         FailGracefully(hres, "Failed to get the IADsPathname interface");
  481.     }
  482.     hres = S_OK;
  483. exit_gracefully:
  484.     if ( SUCCEEDED(hres) )
  485.         _padp->SetDisplayType(ADS_DISPLAY_FULL);
  486.     TraceLeaveResult(hres);
  487. }
  488. //
  489. // ensure we have the IDsDisplaySpecifier object
  490. //
  491. HRESULT CDsFolder::_GetDsDisplaySpecifier(void)
  492. {
  493.     HRESULT hres = S_OK;
  494.     TraceEnter(TRACE_FOLDER, "CDsFolder::_GetDsDisplaySpecifier");
  495.     if ( _InitCOM() && !_pdds )
  496.     {
  497.         hres = CoCreateInstance(CLSID_DsDisplaySpecifier, NULL, CLSCTX_INPROC_SERVER, IID_IDsDisplaySpecifier, (void **)&_pdds);
  498.         if ( SUCCEEDED(hres) )
  499.             _pdds->SetServer(_pServer, _pUserName, _pPassword, 0x0);
  500.     }
  501.     TraceLeaveResult(hres);
  502. }
  503. /*-----------------------------------------------------------------------------
  504. / IDsFolderInternalAPI
  505. /----------------------------------------------------------------------------*/
  506. STDMETHODIMP CDsFolder::SetAttributePrefix(LPWSTR pAttributePrefix)
  507. {
  508.     HRESULT hres;
  509.     USES_CONVERSION;
  510.         
  511.     TraceEnter(TRACE_FOLDER, "CDsFolder::SetAttributePrefix");
  512.     LocalFreeStringW(&_pAttribPrefix);
  513.     hres = LocalAllocStringW(&_pAttribPrefix, pAttributePrefix);
  514.     FailGracefully(hres, "Failed to store attribute prefix");
  515.     Trace(TEXT("Setting attribute prefix to: %s"), W2T(pAttributePrefix));
  516.     
  517. exit_gracefully:
  518.     TraceLeaveResult(hres);
  519. }
  520. //-----------------------------------------------------------------------------
  521. STDMETHODIMP CDsFolder::SetProviderFlags(DWORD dwAND, DWORD dwXOR)
  522. {
  523.     TraceEnter(TRACE_FOLDER, "CDsFolder::SetProviderFlags");
  524.     Trace(TEXT("dwAND %08x, dwXOR %08x"), dwAND, dwXOR);
  525.     _dwProviderAND = dwAND;
  526.     _dwProviderXOR = dwXOR;
  527.     TraceLeaveResult(S_OK);
  528. }
  529. STDMETHODIMP CDsFolder::SetComputer(LPCWSTR pszComputerName, LPCWSTR pszUserName, LPCWSTR pszPassword)
  530. {
  531.     HRESULT hres;
  532.     TraceEnter(TRACE_FOLDER, "CDsFolder::SetComputer");
  533.     LocalFreeStringW(&_pServer);
  534.     LocalFreeStringW(&_pUserName);
  535.     LocalFreeStringW(&_pPassword);
  536.     hres = LocalAllocStringW(&_pServer, pszComputerName);
  537.     if ( SUCCEEDED(hres) )
  538.         hres = LocalAllocStringW(&_pUserName, pszUserName);
  539.     if ( SUCCEEDED(hres) )
  540.         hres = LocalAllocStringW(&_pPassword, pszPassword);
  541.     if ( FAILED(hres) )
  542.     {
  543.         LocalFreeStringW(&_pServer);
  544.         LocalFreeStringW(&_pUserName);
  545.         LocalFreeStringW(&_pPassword);
  546.     }
  547.     TraceLeaveResult(hres);
  548. }
  549. /*-----------------------------------------------------------------------------
  550. / IPersistFolder methods
  551. /----------------------------------------------------------------------------*/
  552. STDMETHODIMP CDsFolder::GetClassID(LPCLSID pClassID)
  553. {
  554.     TraceEnter(TRACE_FOLDER, "CDsFolder::GetClassID");
  555.     TraceAssert(pClassID);
  556.     *pClassID = CLSID_MicrosoftDS;
  557.     TraceLeaveResult(S_OK);
  558. }
  559. /*---------------------------------------------------------------------------*/
  560. // Initialization we handle in two ways.  We assume that IPersistFolder::Initialize
  561. // is called with an absolute IDLIST to the start of our name space, further to
  562. // that (eg. when we bind to an object) we call an internal version.
  563. //
  564. // We assume this because we need to have an idea of how much to skip to get
  565. // to the DS specific parts of an absolute IDLIST.
  566. STDMETHODIMP CDsFolder::Initialize(LPCITEMIDLIST pidl)
  567. {
  568.     HRESULT hres;
  569.     TraceEnter(TRACE_FOLDER, "CDsFolder::Initialize");
  570.     hres = _RealInitialize(pidl, NULL, ILGetSize(pidl)-SIZEOF(SHORT));
  571.     FailGracefully(hres, "Failed when calling CDsFolder::_RealInitialize");
  572. exit_gracefully:
  573.     TraceLeaveResult(hres);
  574. }
  575. HRESULT CDsFolder::_RealInitialize(LPCITEMIDLIST pidlRoot, LPCITEMIDLIST pidlBindTo, INT cbOffset)
  576. {
  577.     HRESULT hres;
  578.     LPITEMIDLIST pidl;
  579.     TraceEnter(TRACE_FOLDER, "CDsFolder::_RealInitialize");
  580.     if ( !pidlRoot )
  581.         ExitGracefully(hres, E_FAIL, "Failed due to no pidlRoot");
  582.     _cbOffset = cbOffset;
  583.     if ( !pidlBindTo )
  584.     {
  585.         _pidl = ILClone(pidlRoot);
  586.     }
  587.     else
  588.     {
  589.         _pidl = ILCombine(pidlRoot, pidlBindTo);
  590.     }
  591.     if ( !_pidl )
  592.         ExitGracefully(hres, E_OUTOFMEMORY, "Failed to create root IDLIST");
  593.     hres = S_OK;                  // success
  594. exit_gracefully:
  595.     TraceLeaveResult(hres);
  596. }
  597. /*-----------------------------------------------------------------------------
  598. / IPersistFolder2 methods
  599. /----------------------------------------------------------------------------*/
  600. STDMETHODIMP CDsFolder::GetCurFolder(LPITEMIDLIST *ppidl)
  601. {
  602.     HRESULT hres;
  603.     TraceEnter(TRACE_FOLDER, "CDsFolder::GetCurFolder");
  604.     if ( !ppidl || !_pidl )
  605.         ExitGracefully(hres, E_INVALIDARG, "Bad ppidl pointer, or perhaps no PIDL");
  606.     *ppidl = ILClone(_pidl);
  607.     TraceAssert(*ppidl);
  608.     if ( !*ppidl )
  609.         ExitGracefully(hres, E_OUTOFMEMORY, "Failed to clone our current folder pidl");
  610.     hres = S_OK;
  611. exit_gracefully:
  612.     TraceLeaveResult(hres);
  613. }
  614. /*-----------------------------------------------------------------------------
  615. / IDelegateFolder methods
  616. /----------------------------------------------------------------------------*/
  617. STDMETHODIMP CDsFolder::SetItemAlloc(IMalloc *pm)
  618. {
  619.     TraceEnter(TRACE_FOLDER, "CDsFolder::SetItemAlloc");
  620.     DoRelease(_pm);
  621.     
  622.     if ( pm )
  623.     {
  624.         pm->AddRef();
  625.         _pm = pm;
  626.     }
  627.     TraceLeaveResult(S_OK);
  628. }
  629. /*-----------------------------------------------------------------------------
  630. / IShellFolder methods
  631. /----------------------------------------------------------------------------*/
  632. #define SKIP_PREFIX 7 // 'LDAP://'
  633. HRESULT CDsFolder::_TryToParsePath(LPITEMIDLIST* ppidl, IADsPathname *padp, LPWSTR pObjectClass, LPDOMAINTREE pDomainTree)
  634. {
  635.     HRESULT hres;
  636.     LPDOMAINDESC pDomainDesc;
  637.     BSTR bstrPath = NULL;
  638.     BSTR bstrPathWithServer = NULL;
  639.     LONG lElements;
  640.     BOOL fDomainRoot = FALSE;
  641.     LPITEMIDLIST pidl = NULL;
  642.     LPITEMIDLIST pidlCombined = NULL;
  643.     DWORD i;
  644.     USES_CONVERSION;
  645.     TraceEnter(TRACE_PARSE, "_TryToParsePath");
  646.     hres = padp->Retrieve(ADS_FORMAT_X500_NO_SERVER, &bstrPath);
  647.     FailGracefully(hres, "Failed to retrieve the path (without server reference)");
  648.     hres = padp->Retrieve(ADS_FORMAT_X500, &bstrPathWithServer);
  649.     FailGracefully(hres, "Failed to retrieve the path");
  650.     // Get the path we are parsing, is it a domain root, if so then we
  651.     // don't want to look any deeper.  
  652.     Trace(TEXT("Path is %s"), W2T(bstrPath+SKIP_PREFIX));
  653.     for ( pDomainDesc = pDomainTree->aDomains ; pDomainDesc ; pDomainDesc = pDomainDesc->pdNextSibling )
  654.     {
  655.         Trace(TEXT("Comparing to domain %s"), W2T(pDomainDesc->pszNCName));
  656.         if ( !StrCmpIW(bstrPath+SKIP_PREFIX, pDomainDesc->pszNCName) )
  657.         {
  658.             TraceMsg("Found root domain object");
  659.             fDomainRoot = TRUE;
  660.             break;
  661.         }
  662.     }
  663.     // if this is the domain root then lets pack the PIDL for it.
  664.     if ( !fDomainRoot ) 
  665.     {
  666.         hres = padp->RemoveLeafElement();                                     // remove the leaf element
  667.         FailGracefully(hres, "Failed to remove the leaf element");
  668.         padp->GetNumElements(&lElements);
  669.         Trace(TEXT("lElements %08x"), lElements);
  670.         if ( !lElements )        
  671.             ExitGracefully(hres, E_INVALIDARG, "Bad pathname passed");
  672.         hres = _TryToParsePath(ppidl, padp, NULL, pDomainTree);     // we don't know the class
  673.         FailGracefully(hres, "Failed recursing into the names");
  674.     }
  675.     // now convert this into an IDLIST and append it to the one we 
  676.     // already have to return to the caller.
  677.     hres = _GetDsDisplaySpecifier();
  678.     FailGracefully(hres, "Failed to get the IDsDisplaySpecifier object");
  679.     hres = CreateIdListFromPath(&pidl, NULL, bstrPathWithServer, pObjectClass, NULL, _pm, _pdds);
  680.     FailGracefully(hres, "Failed to create an IDLIST");
  681.     if ( *ppidl )
  682.     {
  683.         pidlCombined = ILCombine(*ppidl, pidl);
  684.         TraceAssert(pidlCombined);
  685.         if ( !pidlCombined )
  686.             ExitGracefully(hres, E_OUTOFMEMORY, "Failed to combine the pidl");
  687.         *ppidl = pidlCombined;
  688.         pidlCombined = NULL;
  689.     }
  690.     else
  691.     {
  692.         *ppidl = pidl;
  693.         pidl = NULL;
  694.     }
  695.     
  696.     hres = S_OK;    
  697. exit_gracefully:
  698.     SysFreeString(bstrPath);
  699.     SysFreeString(bstrPathWithServer);
  700.     DoILFree(pidl);
  701.     DoILFree(pidlCombined);
  702.     TraceLeaveResult(hres);
  703. }
  704. //
  705. // parse display name for IShellFolder 
  706. // BUGBUG: fix to cope with the NTDS scheme
  707. //
  708. STDMETHODIMP CDsFolder::ParseDisplayName(HWND hwndOwner, 
  709.                                          LPBC pbc, 
  710.                                          LPOLESTR pDisplayName,
  711.                                          ULONG* pchEaten, 
  712.                                          LPITEMIDLIST* ppidl, 
  713.                                          ULONG *pdwAttributes)
  714. {
  715.     HRESULT hres = E_INVALIDARG;
  716.     BSTR bstrObjectClass = NULL;
  717.     IPropertyBag* pPropertyBag = NULL;
  718.     IDsBrowseDomainTree* pdbdt = NULL;
  719.     LPDOMAINTREE pDomainTree = NULL;
  720.     VARIANT variant;    
  721.     USES_CONVERSION;
  722.     TraceEnter(TRACE_FOLDER, "CDsFolder::ParseDisplayName");
  723.     Trace(TEXT("pDisplayName: %s"), W2T(pDisplayName));
  724.     *ppidl = NULL;
  725.     VariantInit(&variant);
  726.     if ( !*pDisplayName )
  727.         ExitGracefully(hres, S_OK, "Name is NULL, nothing to parse");
  728.     // Look and see if we have the DS property bag, if we do then
  729.     // we can check to see if we have an object class property
  730.     // within that.
  731.     if ( pbc && SUCCEEDED(pbc->GetObjectParam(DS_PDN_PROPERTYBAG, (IUnknown**)&pPropertyBag)) )
  732.     {
  733.         hres = pPropertyBag->Read(DS_PDN_OBJECTLCASS, &variant, NULL);
  734.         if ( SUCCEEDED(hres) )
  735.         {
  736.             if ( V_VT(&variant) != VT_BSTR )
  737.                 ExitGracefully(hres, E_UNEXPECTED, "Failed to get the object class");
  738.             bstrObjectClass = V_BSTR(&variant);
  739.             Trace(TEXT("ObjectClass from property bag is: %s"), W2T(bstrObjectClass));
  740.         }
  741.    }
  742.     // ensure we have the IADsPathname interface then lets call the parser,
  743.     // this can be quite a quick process although it does eat quite alot
  744.     // of stack.  The resulting IDLIST is allocated using the malloc
  745.     // interface to we give.
  746.     hres = _GetPathname();        
  747.     FailGracefully(hres, "Failed to get the IADsPathname object");
  748.     hres = _padp->Set(pDisplayName, ADS_SETTYPE_FULL);
  749.     FailGracefully(hres, "Failed to set the path of the name");
  750.     _padp->SetDisplayType(ADS_DISPLAY_FULL);
  751.     // get the domain list, we use this to determine the domain root and
  752.     // therefore the point where parsing is no long needed.
  753.     if ( !_InitCOM() )
  754.         TraceMsg("Failed to initialize COM");
  755.     hres = CoCreateInstance(CLSID_DsDomainTreeBrowser, NULL, CLSCTX_INPROC_SERVER, IID_IDsBrowseDomainTree, (void **)&pdbdt);
  756.     FailGracefully(hres, "Failed to get the domain tree interface");
  757.     hres = pdbdt->SetComputer(_pServer, _pUserName, _pPassword);
  758.     FailGracefully(hres, "Failed to set browsing attributes");
  759.     hres = pdbdt->GetDomains(&pDomainTree, DBDTF_RETURNFQDN);
  760.     FailGracefully(hres, "Failed when getting domain tree information");  
  761.     // now build a set of IDLISTs using this information, the pPathname contains a structure
  762.     hres = _TryToParsePath(ppidl, _padp, bstrObjectClass, pDomainTree);
  763.     FailGracefully(hres, "Failed when calling recursive parser");
  764.     hres = S_OK;          // successs
  765. exit_gracefully:        
  766.     if ( pdbdt )
  767.         pdbdt->FreeDomains(&pDomainTree);
  768.     DoRelease(pPropertyBag);
  769.     DoRelease(pdbdt);
  770.     VariantClear(&variant);
  771.     if ( hres == E_ADS_BAD_PATHNAME )
  772.     {
  773.         TraceMsg("Name was not an ADSI one, therefore making the result E_INVALIDARG");
  774.         hres = E_INVALIDARG;
  775.     }
  776.     TraceLeaveResult(hres);
  777. }
  778. /*---------------------------------------------------------------------------*/
  779. STDMETHODIMP CDsFolder::EnumObjects(HWND hwndOwner, DWORD grfFlags, LPENUMIDLIST* ppEnumIdList)
  780. {
  781.     if ( !_InitCOM() )
  782.         return E_FAIL;
  783.     return CDsEnum_CreateInstance(_ILSkip(_pidl, _cbOffset), hwndOwner, grfFlags, _pm, ppEnumIdList);
  784. }
  785. /*---------------------------------------------------------------------------*/
  786. HRESULT CDsFolder::_GetJunction(LPITEMIDLIST pidl, LPITEMIDLIST *ppidlRight, IDLISTDATA *pData)
  787. {
  788.     HRESULT hres;
  789.     TraceEnter(TRACE_FOLDER, "CDsFolder::_GetJunction");
  790.     // walk the pidl attempting to find the junction point, if we find one then we return both
  791.     // the pidl data to the right and the main pidl.
  792.     *ppidlRight = NULL;
  793.     if (ILIsEmpty(pidl))
  794.     {
  795.         ExitGracefully(hres, E_INVALIDARG, "pidl is empty");
  796.     }
  797.     while ( !ILIsEmpty(pidl) )
  798.     {
  799.         hres = UnpackIdList(pidl, 0x0, pData);
  800.         FailGracefully(hres, "Failed to unpack pidl");
  801.         pidl = _ILNext(pidl);
  802.         if ( pData->pUNC )
  803.         {
  804.             if ( !ILIsEmpty(pidl) )
  805.             {
  806.                 *ppidlRight = ILClone(pidl);
  807.                 TraceAssert(*ppidlRight);
  808.                 if ( !*ppidlRight )
  809.                     ExitGracefully(hres, E_OUTOFMEMORY, "Failed to clone the rest of the pidl");
  810.             }
  811.             pidl->mkid.cb = 0;       // truncate the pidl we have
  812.             break;
  813.         }
  814.     }
  815.     hres = S_OK;
  816. exit_gracefully:
  817.     TraceLeaveResult(hres);
  818. }
  819. HRESULT CDsFolder::_GetJunctionSF(LPITEMIDLIST pidlFull, IBindCtx *pbc, 
  820.                                     IDLISTDATA *pData, LPITEMIDLIST *ppidlRight, IShellFolder **ppsf)
  821. {
  822.     HRESULT hres;
  823.     IShellFolder *psf = NULL;
  824.     IPersistFolder3 *ppf3 = NULL;
  825.     IShellFolder* psfDesktop = NULL;
  826.     IDLISTDATA data = { 0 };
  827.     PERSIST_FOLDER_TARGET_INFO pfti = {0};
  828.     LPITEMIDLIST pidl = NULL;
  829.     TraceEnter(TRACE_FOLDER, "CDsFolder::_GetJunctionSF");
  830.     if ( !pData )
  831.         pData = &data;
  832.     //
  833.     // get the junction information from the object, if we have a UNC then we must
  834.     // create the IShellFolder that represents it.
  835.     //
  836.     hres = _GetJunction(_ILSkip(pidlFull, _cbOffset), ppidlRight, pData);
  837.     FailGracefully(hres, "Failed to bind to junction object");
  838.     if ( !pData->pUNC )
  839.         ExitGracefully(hres, S_FALSE, "Object is not a junction");
  840.     if ( !_InitCOM() )
  841.         TraceMsg("Failed to initialize COM");
  842.     hres = CoCreateInstance(CLSID_ShellDesktop, NULL, CLSCTX_INPROC_SERVER, IID_IShellFolder, (LPVOID*)&psfDesktop);
  843.     FailGracefully(hres, "Failed to get IShellFolder for the desktop object");
  844.     hres = psfDesktop->ParseDisplayName(NULL, NULL, pData->pUNC, NULL, &pidl, NULL);
  845.     FailGracefully(hres, "Failed to parse the UNC to a PIDL");
  846.     
  847.     //
  848.     // In this case lets create the FS folder and initializeit accordingly with a PIDL.
  849.     //
  850.     hres = CoCreateInstance(CLSID_ShellFSFolder, NULL, CLSCTX_INPROC_SERVER, IID_IShellFolder, (void **)&psf);
  851.     FailGracefully(hres, "Failed to get ShellFsFolder");
  852.     hres = psf->QueryInterface(IID_IPersistFolder3, (void **)&ppf3);
  853.     FailGracefully(hres, "Failed to get the IPersistFolderAlias");
  854.     pfti.pidlTargetFolder = pidl;            
  855.     pfti.dwAttributes = -1;        
  856.     pfti.csidl = -1;
  857.     hres = ppf3->InitializeEx(pbc, pidlFull, &pfti);
  858.     if ( SUCCEEDED(hres) )
  859.         psf->QueryInterface(IID_IShellFolder, (void **)ppsf);
  860. exit_gracefully:
  861.     DoRelease(psf);
  862.     DoRelease(ppf3);
  863.     DoRelease(psfDesktop);
  864.     if ( pidl )
  865.         ILFree(pidl);
  866.     TraceLeaveResult(hres);
  867. }
  868. STDMETHODIMP CDsFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  869. {
  870.     HRESULT hres = E_FAIL;
  871.     IShellFolder *psf = NULL;
  872.     LPITEMIDLIST pidlFull = NULL;
  873.     LPITEMIDLIST pidlRight = NULL;
  874.     USES_CONVERSION;
  875.     TraceEnter(TRACE_FOLDER, "CDsFolder::BindToObject");
  876.     Trace(TEXT("Entry IDLIST is %08x"), pidl);
  877.     TraceGUID("Interface being requested", riid);
  878.     pidlFull = ILCombine(_pidl, pidl);
  879.     if ( !pidlFull )
  880.         ExitGracefully(hres, E_OUTOFMEMORY, "Failed to alloc temporary pidl");
  881.     // attempt to get the sf that has junction.  this call can return S_FALSE
  882.     // indicating there is no junction, therefore we create a new instance
  883.     // of CDsFolder.
  884.     //
  885.     // if it was a junction then continue the bind process through the
  886.     // junction to the real namespace.
  887.     hres = _GetJunctionSF(pidlFull, pbc, NULL, &pidlRight, &psf);
  888.     if ( SUCCEEDED(hres) )
  889.     {
  890.         if ( hres == S_FALSE )
  891.         {
  892.             // Create a new CDsFolder object, pass on the IMalloc interface we have
  893.             // etc.
  894.             CDsFolder *pDsFolder = new CDsFolder();
  895.             TraceAssert(pDsFolder);
  896.             if ( !pDsFolder )
  897.                 ExitGracefully(hres, E_OUTOFMEMORY, "Failed to allocate new CDsFolder");
  898.             hres = pDsFolder->_RealInitialize(_pidl, pidl, _cbOffset);     
  899.             if ( SUCCEEDED(hres) )
  900.                 hres = pDsFolder->SetItemAlloc(_pm);
  901.             if ( SUCCEEDED(hres) )
  902.                 hres = pDsFolder->QueryInterface(riid, ppv);
  903.             pDsFolder->Release();
  904.         }
  905.         else
  906.         {
  907.             // pidlRight?  if not then we are at the right point in the namespace,
  908.             // otherwise we must continue the bind.
  909.             if ( pidlRight )
  910.                 hres = psf->BindToObject(pidlRight, pbc, riid, ppv);
  911.             else
  912.                 hres = psf->QueryInterface(riid, ppv);
  913.         }
  914.     }
  915. exit_gracefully:
  916.     DoILFree(pidlFull);
  917.     DoILFree(pidlRight);
  918.     DoRelease(psf);
  919.     TraceLeaveResult(hres);
  920. }
  921. /*---------------------------------------------------------------------------*/
  922. STDMETHODIMP CDsFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved, REFIID riid, void **ppv)
  923. {
  924.     TraceEnter(TRACE_FOLDER, "CDsFolder::BindToStorage");
  925.     TraceLeaveResult(E_NOTIMPL);
  926. }
  927. /*---------------------------------------------------------------------------*/
  928. STDMETHODIMP CDsFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  929. {
  930.     IDLISTDATA data1, data2;
  931.     HRESULT hres = E_INVALIDARG;
  932.     INT iResult = 0;
  933.     LPITEMIDLIST pidlT1, pidlT2;
  934.     LPITEMIDLIST pidlT = NULL;
  935.     WCHAR szName1[MAX_PATH];
  936.     WCHAR szName2[MAX_PATH];
  937.     IShellFolder *pShellFolder = NULL;
  938.     USES_CONVERSION;
  939.     TraceEnter(TRACE_COMPARE, "CDsFolder::CompareIDs");
  940.     hres = UnpackIdList(pidl1, DSIDL_HASCLASS, &data1);
  941.     FailGracefully(hres, "Failed to unpack pidl1");
  942.     hres = UnpackIdList(pidl2, DSIDL_HASCLASS, &data2);
  943.     FailGracefully(hres, "Failed to unpack pidl2");
  944.     // Ensure that containers end up at the top of the list
  945.     if ( (data1.dwFlags & DSIDL_ISCONTAINER) != (data2.dwFlags & DSIDL_ISCONTAINER) )
  946.     {
  947.         iResult = (data1.dwFlags & DSIDL_ISCONTAINER) ? -1:+1;
  948.         goto exit_result;
  949.     }
  950.     // lParam indicates which column we are sorting on, therefore using that compare
  951.     // the values we have just unpacked from IDLISTs.
  952.     switch ( lParam & SHCIDS_COLUMNMASK )
  953.     {
  954.         case DSVMID_ARRANGEBYNAME:
  955.         {
  956.             _GetPathname();
  957.             if ( SUCCEEDED(NameFromIdList(pidl1, _ILSkip(_pidl, _cbOffset), szName1, ARRAYSIZE(szName1), _padp)) &&
  958.                     SUCCEEDED(NameFromIdList(pidl2, _ILSkip(_pidl, _cbOffset), szName2, ARRAYSIZE(szName2), _padp)) )
  959.             {
  960.                 Trace(TEXT("Comparing -%s-, -%s-"), W2T(szName1), W2T(szName2));
  961.                 iResult = StrCmpIW(szName1, szName2);
  962.             }
  963.             break;
  964.         }
  965.         case DSVMID_ARRANGEBYCLASS:
  966.             Trace(TEXT("Classes -%s-, -%s-"), W2T(data1.pObjectClass), W2T(data2.pObjectClass));
  967.             iResult = StrCmpIW(data1.pObjectClass, data2.pObjectClass);
  968.             break;
  969.         default:
  970.             TraceAssert(FALSE);
  971.             ExitGracefully(hres, E_INVALIDARG, "Bad sort column");
  972.             break;
  973.     }
  974.     // If they match then check that they are absolutely identical, if that is
  975.     // the case then continue down the IDLISTs if more elements present.
  976.    
  977.     if ( iResult == 0 )
  978.     {
  979.         iResult = memcmp(pidl1, pidl2, ILGetSize(pidl1));
  980.         Trace(TEXT("memcmp of pidl1, pidl2 yeilds %d"), iResult);
  981.         if ( iResult != 0 )
  982.             goto exit_result;
  983.         pidlT1 = _ILNext(pidl1);
  984.         pidlT2 = _ILNext(pidl2);
  985.         if ( ILIsEmpty(pidlT1) )
  986.         {
  987.             if ( ILIsEmpty(pidlT2) )
  988.             {
  989.                 iResult = 0;
  990.             }
  991.             else
  992.             {
  993.                 iResult = -1;
  994.             }
  995.             goto exit_result;
  996.         }
  997.         else if ( ILIsEmpty(pidlT2) )
  998.         {
  999.             iResult = 1;
  1000.             goto exit_result;
  1001.         }
  1002.         // Both IDLISTs have more elements, therefore continue down them
  1003.         // binding to the next element in 1st IDLIST and then calling its
  1004.         // compare method.
  1005.         pidlT = ILClone(pidl1);
  1006.         if ( !pidlT )
  1007.             ExitGracefully(hres, E_OUTOFMEMORY, "Failed to clone IDLIST for binding");
  1008.         _ILNext(pidlT)->mkid.cb = 0;
  1009.         hres = BindToObject(pidlT, NULL, IID_IShellFolder, (void **)&pShellFolder);
  1010.         FailGracefully(hres, "Failed to get the IShellFolder implementation from pidl1");
  1011.         hres = pShellFolder->CompareIDs(lParam, pidlT1, pidlT2);
  1012.         Trace(TEXT("CompareIDs returned %08x"), ShortFromResult(hres));
  1013.         goto exit_gracefully;
  1014.     }
  1015. exit_result:
  1016.     Trace(TEXT("Exiting with iResult %d"), iResult);
  1017.     hres = ResultFromShort(iResult);
  1018. exit_gracefully:
  1019.     DoRelease(pShellFolder);
  1020.     DoILFree(pidlT);
  1021.     TraceLeaveResult(hres);
  1022. }
  1023. /*---------------------------------------------------------------------------*/
  1024. STDMETHODIMP CDsFolder::CreateViewObject(HWND hwndOwner, REFIID riid, void **ppv)
  1025. {
  1026.     HRESULT hres;
  1027.     TraceEnter(TRACE_FOLDER, "CDsFolder::CreateViewObject");
  1028.     TraceGUID("View object requested", riid);
  1029.     TraceAssert(ppv);
  1030.     if ( IsEqualIID(riid, IID_IShellView) )
  1031.     {
  1032.         CSFV csfv;
  1033.         csfv.cbSize = SIZEOF(csfv);
  1034.         csfv.pshf = (LPSHELLFOLDER)this;
  1035.         csfv.psvOuter = NULL;
  1036.         csfv.pidl = _pidl;
  1037.         csfv.lEvents = 0;
  1038.         csfv.pfnCallback = _FolderCallBack;
  1039.         csfv.fvm = FVM_ICON;
  1040.         hres = SHCreateShellFolderViewEx(&csfv, (LPSHELLVIEW*)ppv);
  1041.         FailGracefully(hres, "SHCreateShellFolderViewEx failed");
  1042.     }
  1043.     else if ( IsEqualIID(riid, IID_IContextMenu) )
  1044.     {
  1045.         hres = CDefFolderMenu_Create2(_pidl, 
  1046.                                     hwndOwner,
  1047.                                     NULL, 0,
  1048.                                     (LPSHELLFOLDER)this,
  1049.                                     _FolderCFMCallback,
  1050.                                     NULL, 
  1051.                                     0, 
  1052.                                     (LPCONTEXTMENU*)ppv);        
  1053.     }
  1054.     else
  1055.     {
  1056.         ExitGracefully(hres, E_NOINTERFACE, "View object not supported");
  1057.     }
  1058. exit_gracefully:
  1059.     TraceLeaveResult(hres);
  1060. }
  1061. /*---------------------------------------------------------------------------*/
  1062. STDMETHODIMP CDsFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST* apidl, ULONG* rgfInOut)
  1063. {
  1064.     HRESULT hres;
  1065.     IDLISTDATA data;
  1066.     UINT i;
  1067.     TraceEnter(TRACE_FOLDER, "CDsFolder::GetAttributesOf");
  1068.     Trace(TEXT("cidl = %d"), cidl);
  1069.     if ( !rgfInOut )
  1070.         ExitGracefully(hres, E_INVALIDARG, "Bad rgfInOut value");
  1071.     *rgfInOut = 0;
  1072.     if ( cidl == 0 )
  1073.     {
  1074.         // get the namespace attributes we want to invoke for this namespace
  1075.         // checking the policy to see if we should be hiding this object
  1076.         *rgfInOut = NAMESPACE_ATTRIBUTES;
  1077.         if ( CheckDsPolicy(NULL, c_szHideNamespace) || !ShowDirectoryUI() )
  1078.         {
  1079.             TraceMsg("Namespace being marked as hidden");
  1080.             *rgfInOut |= SFGAO_NONENUMERATED;
  1081.         }           
  1082.     }
  1083.     else if ( cidl >= 1 )
  1084.     {
  1085.         // cidl > 1 && rgfInOut != NULL
  1086.         //  - walk all the IDLISTs we were given and get their attributes, and compose
  1087.         //    a mask containing the bits
  1088.         TraceAssert(apidl);
  1089.         TraceAssert(rgfInOut);
  1090.         for ( i = 0; i != cidl; i++ )
  1091.         {
  1092.             hres = UnpackIdList(apidl[i], DSIDL_HASCLASS, &data);
  1093.             FailGracefully(hres, "Failed to unpack IDLIST");
  1094.             *rgfInOut |= AttributesFromIdList(&data);
  1095.         }
  1096.     }
  1097.     hres = S_OK;
  1098. exit_gracefully:
  1099.     TraceLeaveResult(hres);
  1100. }
  1101. /*---------------------------------------------------------------------------*/
  1102. HRESULT CDsFolder::_SetDispSpecOptions(IDataObject *pdo)
  1103. {
  1104.     HRESULT hres;
  1105.     CLIPFORMAT cfDsDispSpecOptions = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_DSDISPLAYSPECOPTIONS);
  1106.     FORMATETC fmte = {cfDsDispSpecOptions, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  1107.     STGMEDIUM medium = { TYMED_NULL, NULL, NULL };
  1108.     DSDISPLAYSPECOPTIONS *pddso = NULL;;
  1109.     DWORD cbStruct = SIZEOF(DSDISPLAYSPECOPTIONS);
  1110.     DWORD offsetStrings = SIZEOF(DSDISPLAYSPECOPTIONS);
  1111.     LPWSTR pAttribPrefix = _pAttribPrefix;
  1112.     TraceEnter(TRACE_FOLDER, "CDsFolder::_SetAttribPrefix");
  1113.     if ( !pAttribPrefix )
  1114.         pAttribPrefix = DS_PROP_SHELL_PREFIX;        
  1115.     cbStruct += StringByteSizeW(pAttribPrefix);
  1116.     cbStruct += StringByteSizeW(_pUserName);
  1117.     cbStruct += StringByteSizeW(_pPassword);
  1118.     cbStruct += StringByteSizeW(_pServer);
  1119.     // allocate and fill the structure
  1120.     hres = AllocStorageMedium(&fmte, &medium, cbStruct, (void **)&pddso);
  1121.     FailGracefully(hres, "Failed to allocate STGMEDIUM for data");
  1122.     pddso->dwSize = SIZEOF(DSDISPLAYSPECOPTIONS);
  1123.     pddso->dwFlags = DSDSOF_HASUSERANDSERVERINFO|DSDSOF_DSAVAILABLE;
  1124.     //pddso->offsetAttribPrefix = 0x0;
  1125.     //pddso->offsetUserName = 0x0;
  1126.     //pddso->offsetPassword = 0x0;
  1127.     //pddso->offsetServer = 0x0;
  1128.     //pddso->offsetServerConfigPath = 0x0;
  1129.     pddso->offsetAttribPrefix = offsetStrings;
  1130.     StringByteCopyW(pddso, offsetStrings, pAttribPrefix);
  1131.     offsetStrings += StringByteSizeW(pAttribPrefix);
  1132.     if ( _pUserName )
  1133.     {
  1134.         pddso->offsetUserName = offsetStrings;
  1135.         StringByteCopyW(pddso, offsetStrings, _pUserName);
  1136.         offsetStrings += StringByteSizeW(_pUserName);
  1137.     }
  1138.     if ( _pPassword )
  1139.     {
  1140.         pddso->offsetPassword = offsetStrings;
  1141.         StringByteCopyW(pddso, offsetStrings, _pPassword);
  1142.         offsetStrings += StringByteSizeW(_pPassword);
  1143.     }
  1144.     if ( _pServer )
  1145.     {
  1146.         pddso->offsetServer = offsetStrings;
  1147.         StringByteCopyW(pddso, offsetStrings, _pServer);
  1148.         offsetStrings += StringByteSizeW(_pServer);
  1149.     }
  1150.     // lets set into the IDataObject
  1151.     TraceMsg("Setting CF_DSDISPLAYSPECOPTIONS into the IDataObject");
  1152.     hres = pdo->SetData(&fmte, &medium, TRUE);
  1153.     FailGracefully(hres, "Failed to set the DSDISPLAYSPECOPTIONS into the IDataObject");
  1154. exit_gracefully:
  1155.     ReleaseStgMedium(&medium);
  1156.     TraceLeaveResult(hres);
  1157. }
  1158. STDMETHODIMP CDsFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST* aidl, REFIID riid, UINT* prgfReserved, void **ppv)
  1159. {
  1160.     HRESULT hres;
  1161.     LPITEMIDLIST pidlAbs = NULL;
  1162.     HKEY aKeys[UIKEY_MAX];
  1163.     LPITEMIDLIST pidl = NULL;
  1164.     INT i;
  1165.     TraceEnter(TRACE_FOLDER, "CDsFolder::GetUIObjectOf");
  1166.     TraceGUID("UI object requested", riid);
  1167.     TraceAssert(cidl > 0);
  1168.     TraceAssert(aidl);
  1169.     TraceAssert(ppv);
  1170.     ZeroMemory(aKeys, SIZEOF(aKeys));
  1171.     if ( IsEqualIID(riid, IID_IContextMenu) )
  1172.     {
  1173.         // IContextMenu requested, therefore lets use the shell to construct one for us,
  1174.         // then we can provide verbs on the namespace
  1175.         if ( cidl )
  1176.         {
  1177.             hres = GetKeysForIdList(*aidl, NULL, ARRAYSIZE(aKeys), aKeys);
  1178.             FailGracefully(hres, "Failed to get object keys");
  1179.         }
  1180.         hres = CDefFolderMenu_Create2(_pidl, hwndOwner,
  1181.                                     cidl, aidl,
  1182.                                     this,
  1183.                                     _FolderCFMCallback,
  1184.                                     ARRAYSIZE(aKeys), aKeys,
  1185.                                     (LPCONTEXTMENU*)ppv);
  1186.         FailGracefully(hres, "Failed to create context menu");
  1187.     }
  1188.     else if ( IsEqualIID(riid, IID_IDataObject) )
  1189.     {
  1190.         DSDATAOBJINIT ddoi = { 0 };
  1191.         IDataObject *pdo = NULL;
  1192.         ddoi.hwnd = hwndOwner;
  1193.         ddoi.pidlRoot = _pidl;
  1194.         ddoi.cbOffset = _cbOffset;
  1195.         ddoi.cidl = cidl;
  1196.         ddoi.aidl = aidl;
  1197.         ddoi.dwProviderAND = _dwProviderAND;
  1198.         ddoi.dwProviderXOR = _dwProviderXOR;
  1199.         hres = CDsDataObject_CreateInstance(&ddoi, IID_IDataObject, (void **)&pdo);
  1200.         FailGracefully(hres, "Failed to create the IDataObject");
  1201.         hres = _SetDispSpecOptions(pdo);
  1202.         FailGracefully(hres, "Failed to set the display spec options");
  1203.         hres = pdo->QueryInterface(riid, ppv);
  1204.         pdo->Release();
  1205.     }
  1206.     else if ( IsEqualIID(riid, IID_IExtractIcon) )
  1207.     {
  1208.         // IExtractIcon is used to support our object extraction, we can only cope
  1209.         // with extracting a single object at a time.  First however we must
  1210.         // build an IDLIST that represents the object we want to extract
  1211.         // and get the icon for it.
  1212.         if ( cidl != 1 )
  1213.             ExitGracefully(hres, E_FAIL, "Bad number of objects to get icon from");
  1214.         pidl = ILCombine(_pidl, *aidl);
  1215.         TraceAssert(pidl);
  1216.         Trace(TEXT("_pidl %08x, *aidl %08x, _cbOffset %d"), _pidl, *aidl, _cbOffset);
  1217.         if ( !pidl )
  1218.             ExitGracefully(hres, E_OUTOFMEMORY, "Failed to combine the IDLISTs");
  1219.         hres = _GetDsDisplaySpecifier();
  1220.         FailGracefully(hres, "Failed to get the IDsDisplaySpecifier object");
  1221.         CDsExtractIcon* pExtractIcon = new CDsExtractIcon(_pdds, _ILSkip(pidl, _cbOffset));
  1222.         TraceAssert(pExtractIcon);
  1223.         if ( !pExtractIcon )
  1224.             ExitGracefully(hres, E_OUTOFMEMORY, "Failed to create CDsExtractIcon");
  1225.         hres = pExtractIcon->QueryInterface(riid, ppv);
  1226.         pExtractIcon->Release();
  1227.     }
  1228.     else
  1229.     {
  1230.         ExitGracefully(hres, E_NOINTERFACE, "UI object not supported");
  1231.     }
  1232. exit_gracefully:
  1233.     TidyKeys(ARRAYSIZE(aKeys), aKeys);
  1234.     DoILFree(pidl);
  1235.         
  1236.     TraceLeaveResult(hres);
  1237. }
  1238. /*---------------------------------------------------------------------------*/
  1239. STDMETHODIMP CDsFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET pName)
  1240. {
  1241.     HRESULT hres = E_FAIL;
  1242.     LPITEMIDLIST pidlFull = NULL;
  1243.     LPITEMIDLIST pidlRight = NULL;
  1244.     IDLISTDATA data =  {0};
  1245.     IShellFolder *psf = NULL;
  1246.     LPWSTR pPath = NULL;
  1247.     BSTR bstrName = NULL;
  1248.     USES_CONVERSION;
  1249.     DECLAREWAITCURSOR = GetCursor();
  1250.     TraceEnter(TRACE_FOLDER, "CDsFolder::GetDisplayName");
  1251.     pidlFull = ILCombine(_pidl, pidl);
  1252.     TraceAssert(pidlFull);
  1253.          
  1254.     if ( !pidlFull )
  1255.         ExitGracefully(hres, E_OUTOFMEMORY, "Failed to combine PIDLs");
  1256.     // attempt to get the junction namespace, if not then we must convert the name,
  1257.     // if it is a junction the handle accordingly.
  1258.     hres = _GetJunctionSF(pidlFull, NULL, &data, &pidlRight, &psf);
  1259.     if ( SUCCEEDED(hres))
  1260.     {
  1261.         hres = _GetPathname();
  1262.         FailGracefully(hres, "Failed to get the IADsPathname interface");
  1263.         if ( (hres == S_FALSE) || !pidlRight || ILIsEmpty(pidlRight) )
  1264.         {
  1265.             TraceMsg("We don't have a trailing pidl, and its not a junction");
  1266.             // check to see if the name is the junction, and if we are requesting the 
  1267.             // for parsing && !in folder.  if that is valid then return the
  1268.             // junction name.
  1269.             if ( data.pUNC && (uFlags & SHGDN_FORPARSING) && !(uFlags & SHGDN_INFOLDER) )
  1270.             {
  1271.                 TraceMsg("Return the full parsing name of the junction");
  1272.                 // the junction is hit, pidlRight is NULL but the caller wants
  1273.                 // the for parsing version of the name which is not-infolder (phew).
  1274.                 hres = _StrRetFromString(pName, W2T(data.pUNC));
  1275.                 FailGracefully(hres, "Failed to get parsing juntion name");
  1276.             }
  1277.             else
  1278.             {
  1279.                 TraceMsg("Return path/name of DS object");
  1280.                 // pre-populate the IADsPathname object with a path to be
  1281.                 // worked on.
  1282.                 hres = PathFromIdList(_ILSkip(pidlFull, _cbOffset), &pPath, _padp);
  1283.                 FailGracefully(hres, "Failed to get the DS path");
  1284.                 hres = _padp->Set(pPath, ADS_SETTYPE_FULL);
  1285.                 FailGracefully(hres, "Failed to set the path of the name");
  1286.                 if ( uFlags & SHGDN_INFOLDER )
  1287.                 {
  1288.                     //
  1289.                     // get the in folder name, including removing all the crap if we can
  1290.                     //
  1291.                     if ( !(uFlags & SHGDN_FORPARSING) && data.pName )
  1292.                     {
  1293.                         hres = _StrRetFromString(pName, W2T(data.pName));
  1294.                     }
  1295.                     else
  1296.                     {
  1297.                         if ( !(uFlags & SHGDN_FORPARSING) )
  1298.                             _padp->SetDisplayType(ADS_DISPLAY_VALUE_ONLY);
  1299.                         hres = _padp->Retrieve(ADS_FORMAT_LEAF, &bstrName);
  1300.                         FailGracefully(hres, "Failed to get the pretty name");
  1301.                         hres = _StrRetFromString(pName, W2T(bstrName));
  1302.                     }
  1303.                 }
  1304.                 else
  1305.                 {
  1306.                     //
  1307.                     // get the display name from the ADsPath we have - convert to conanical format
  1308.                     // for displaying in the title / wbe view
  1309.                     //
  1310.                     WCHAR szBuffer[MAX_PATH];
  1311.                     hres = GetDisplayNameFromADsPath(NULL, szBuffer, ARRAYSIZE(szBuffer), _padp, TRUE);
  1312.                     FailGracefully(hres, "Failed to get display name from ADsPath");
  1313.                     hres = _StrRetFromString(pName, W2T(szBuffer));
  1314.                 }
  1315.                 FailGracefully(hres, "Failed to convert to BSTR");
  1316.             }
  1317.         }
  1318.         else
  1319.         {
  1320.             TraceMsg("Requesting name from junction object");
  1321.             // the pidlRight is non-null (therefore we must delegate) so 
  1322.             // lets call the psf we have to get the DisplayName of the object.
  1323.             hres = psf->GetDisplayNameOf(pidlRight, uFlags, pName);
  1324.         }
  1325.     }
  1326. exit_gracefully:
  1327.     DoRelease(psf);
  1328.     DoILFree(pidlFull);
  1329.     DoILFree(pidlRight);
  1330.     LocalFreeStringW(&pPath);
  1331.     SysFreeString(bstrName);
  1332.     ResetWaitCursor();
  1333.     TraceLeaveResult(hres);
  1334. }
  1335. /*---------------------------------------------------------------------------*/
  1336. STDMETHODIMP CDsFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, LPCOLESTR pName, DWORD uFlags, LPITEMIDLIST * ppidlOut)
  1337. {
  1338.     TraceEnter(TRACE_FOLDER, "CDsFolder::SetDisplayNameOf");
  1339.     TraceLeaveResult(E_NOTIMPL);
  1340. }
  1341. /*-----------------------------------------------------------------------------
  1342. / CDsExtractIcon
  1343. /----------------------------------------------------------------------------*/
  1344. CDsExtractIcon::CDsExtractIcon(IDsDisplaySpecifier *pdds, LPCITEMIDLIST pidl) :
  1345.     _pdds(pdds)
  1346. {
  1347.     TraceEnter(TRACE_UI, "CDsExtractIcon::CDsExtractIcon");
  1348.     
  1349.     _pidl = ILClone(pidl);
  1350.     _pdds->AddRef();
  1351.     
  1352.     TraceLeaveVoid();
  1353. }
  1354. CDsExtractIcon::~CDsExtractIcon()
  1355. {
  1356.     TraceEnter(TRACE_UI, "CDsExtractIcon::~CDsExtractIcon");
  1357.     DoILFree(_pidl);
  1358.     DoRelease(_pdds);
  1359.     TraceLeaveVoid();
  1360. }
  1361. // IUnknown bits
  1362. #undef CLASS_NAME
  1363. #define CLASS_NAME CDsExtractIcon
  1364. #include "unknown.inc"
  1365. STDMETHODIMP CDsExtractIcon::QueryInterface(REFIID riid, void **ppv)
  1366. {
  1367.     INTERFACES iface[] =
  1368.     {
  1369.         &IID_IExtractIcon, (LPEXTRACTICON)this,
  1370.     };
  1371.     return HandleQueryInterface(riid, ppv, iface, ARRAYSIZE(iface));
  1372. }
  1373. /*-----------------------------------------------------------------------------
  1374. / IExtractIcon methods
  1375. /----------------------------------------------------------------------------*/
  1376. STDMETHODIMP CDsExtractIcon::GetIconLocation(UINT uFlags, LPTSTR szIconFile, UINT cchMax, INT* pIndex, UINT* pwFlags)
  1377. {
  1378.     HRESULT hres;
  1379.     LPTSTR pLocation = NULL;
  1380.     IDLISTDATA data;
  1381.     DWORD dwFlags = 0;
  1382. #ifndef UNICODE
  1383.     WCHAR szIconLocation[MAX_PATH];
  1384. #endif
  1385.     USES_CONVERSION;
  1386.     TraceEnter(TRACE_UI, "CDsExtractIcon::GetIconLocation");
  1387.     if ( !_pidl || ILIsEmpty(_pidl) )
  1388.         ExitGracefully(hres, E_INVALIDARG, "No IDLIST to extract icon from");
  1389.     // If we have an empty IDLIST then lets ensure that we get the the icon location
  1390.     // for the namespace root.  Otherwise unpack the IDLIST and get the icon location
  1391.     // from the cache.
  1392.     hres = UnpackIdList(ILFindLastID(_pidl), DSIDL_HASCLASS, &data);
  1393.     FailGracefully(hres, "Failed to unpack IDLIST");
  1394.     dwFlags |= (uFlags & GIL_OPENICON) ?  DSGIF_ISOPEN:DSGIF_ISNORMAL;
  1395. #ifdef UNICODE
  1396.     hres = _pdds->GetIconLocation(data.pObjectClass, dwFlags, szIconFile, cchMax, pIndex);
  1397.     FailGracefully(hres, "Failed to get the icon location");            
  1398. #else
  1399.     // when building ANSI we must call the DsGetIcon location to get the icon
  1400.     // we are interested in, this API is ANSI only and therefore we must
  1401.     // thunk the call back as required.
  1402.     hres = _pdds->GetIconLocation(data.pObjectClass, dwFlags, szIconLocation, ARRAYSIZE(szIconLocation), pIndex);
  1403.     FailGracefully(hres, "Failed to get the icon location");            
  1404.     if ( hres != S_FALSE )
  1405.     {
  1406.         WideCharToMultiByte(CP_ACP, 0, szIconLocation, -1, szIconFile, cchMax, 0, FALSE);
  1407.         Trace(TEXT("Thunked icon location: %s"), szIconFile);
  1408.     }
  1409. #endif    
  1410. exit_gracefully:
  1411.     LocalFreeString(&pLocation);
  1412.     TraceLeaveResult(hres);
  1413. }
  1414. /*---------------------------------------------------------------------------*/
  1415. STDMETHODIMP CDsExtractIcon::Extract(LPCTSTR pszIconFile, UINT nIconIndex, HICON* pLargeIcon, HICON* pSmallIcon, UINT nIconSize)
  1416. {
  1417.     return S_FALSE;         // let the shell extract the image
  1418. }
  1419. /*----------------------------------------------------------------------------
  1420. / PropertyUI iface for the query UI to invoke use with
  1421. /----------------------------------------------------------------------------*/
  1422. // IUnknown handlers
  1423. #undef CLASS_NAME
  1424. #define CLASS_NAME CDsFolderProperties
  1425. #include "unknown.inc"
  1426. STDMETHODIMP CDsFolderProperties::QueryInterface( REFIID riid, void **ppv)
  1427. {
  1428.     INTERFACES iface[] =
  1429.     {
  1430.         &IID_IDsFolderProperties, (IDsFolderProperties*)this,
  1431.     };
  1432.    return HandleQueryInterface(riid, ppv, iface, ARRAYSIZE(iface));
  1433. }
  1434. //
  1435. // handle create instance of the CDsFolder object
  1436. //
  1437. STDAPI CDsFolderProperties_CreateInstance(IUnknown* punkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  1438. {
  1439.     CDsFolderProperties *pdfp = new CDsFolderProperties();
  1440.     if ( !pdfp )
  1441.         return E_OUTOFMEMORY;
  1442.     HRESULT hres = pdfp->QueryInterface(IID_IUnknown, (void **)ppunk);
  1443.     pdfp->Release();
  1444.     return hres;
  1445. }
  1446. /*----------------------------------------------------------------------------
  1447. / IDsFolderProperties
  1448. /----------------------------------------------------------------------------*/
  1449. /*-----------------------------------------------------------------------------
  1450. / IDsFolderProperties::ShowProperties
  1451. / -----------------------------------
  1452. /   Display the property page set that relates to the given IDataObject, it is
  1453. /   assumed that the caller is passing a IDataObject containing a valid DS
  1454. /   clipboard data blob.
  1455. /
  1456. / In:
  1457. /   hwndParent = parent window for the dialog
  1458. /   pDataObject -> data object containing the sleection data
  1459. /
  1460. / Out:
  1461. /   HRESULT
  1462. /----------------------------------------------------------------------------*/
  1463. STDMETHODIMP CDsFolderProperties::ShowProperties(HWND hwndParent, IDataObject *pDataObject)
  1464. {
  1465.     HRESULT hres;
  1466.     TraceEnter(TRACE_API, "CDsFolderProperties::ShowProperties");
  1467.     if ( !pDataObject )  
  1468.         ExitGracefully(hres, E_INVALIDARG, "No pDataObject given");
  1469.     CoInitialize(NULL);            // ensure we have COM
  1470.     hres = ShowObjectProperties(hwndParent, pDataObject);
  1471.     FailGracefully(hres, "Failed to open property pages");
  1472.     // hres = S_OK;               // success
  1473. exit_gracefully:
  1474.     TraceLeaveResult(hres);        
  1475. }