shdocfl.cpp.1488
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 89k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include "priv.h"
  2. #include "dochost.h"
  3. #include "basesb.h"
  4. HRESULT LoadDefaultSiteMap(LPCITEMIDLIST pidl);
  5. #define NO_IE_NAMESPACE
  6. #define DM_STARTUP          0
  7. extern "C" {
  8. #include "..shell32shitemid.h" // for SHID_XX
  9. }
  10. extern LPCITEMIDLIST g_pidlRootClass;
  11. HRESULT CDocObjectView_Create(IShellView** ppv, IShellFolder* psf, LPCITEMIDLIST pidl, REFCLSID rclsid, Site *pSite);
  12. #define CSTMSG(psz) DebugMsg(0, TEXT("shd TR-CDOF::%s called"), psz)
  13. #define IPFMSG(psz) DebugMsg(0, TEXT("shd TR-IPF::%s called"), psz)
  14. #define URLMSG(psz) DebugMsg(0, "shd TR-DOF::%s", psz)
  15. #define URLMSG2(psz, x) DebugMsg(0, "shd TR-DOF::%s %x", psz, x)
  16. #define URLMSG3(psz, x, y) DebugMsg(0, "shd TR-DOF::%s %x %x", psz, x, y)
  17. typedef HRESULT (*DATACOMPLETECB)(LPCSTR lpszLocalFileName, IUnknown *pUnk);
  18. HRESULT URLDataToFile(LPSTR lpURL, LPSTR lpFileName, DATACOMPLETECB fnDataCompleteCallback);
  19. #define DEFAULT_SITEMAP_NAME   TEXT("sitemap.smp")
  20. HRESULT Sitemap_OnDataComplete(LPCSTR  lpszLocalFileName, IUnknown *pUnk);
  21. HRESULT _GetStdLocation(LPTSTR szPath, DWORD cbSize, UINT id);
  22. typedef struct tagURLID {
  23.     ITEMIDLIST idl;
  24.     BYTE bType;
  25.     TCHAR ach[MAX_URL_STRING];
  26.     WORD wNullTerminate;
  27. } URLID, *PURLID;
  28. #define _URLPidlType(pidl)      ((BYTE)((pidl)->bType))
  29. #define _PidlToUrlPtr(pidl)     ((LPSTR)((PCURLID)(pidl))->ach)
  30. #define _URLDelegateID(pidl)    (((PURLID)(pidl))->idl.mkid.abID[0])
  31. #define ProtocolIdlOuterData(pidl)  (((LPVOID)&((PDELEGATEITEMID)(pidl))->rgb[((PDELEGATEITEMID)(pidl))->cbInner]))
  32. #define PDID_SIG                    MAKEWORD(SHID_INTERNET_SITE, URLID_PROTOCOL)
  33. #define _IsPidlProtocol(pidl)       ((((PDELEGATEITEMID)(pidl))->cbSize >= (SIZEOF(PDELEGATEITEMID)-1)) && 
  34.                                      (((PDELEGATEITEMID)(pidl))->wOuter == PDID_SIG))
  35. #define _PidlToProtocol(pidl)       ((CHAR *)(ProtocolIdlOuterData(pidl)))
  36. IShellFolder* g_psfInternet = NULL;
  37. LPWSTR g_szStartPageTitle = NULL;  //stores title of start page (global)
  38. class CDocObjectFolder :
  39.     public IShellFolder, public IPersistFolder, public IShellIcon
  40. {
  41. public:
  42.     CDocObjectFolder(REFCLSID rclsid, LPCITEMIDLIST pidl = NULL, LPCITEMIDLIST pidlRoot = NULL,
  43.                      Site *psite = NULL);
  44.     // IUnknown
  45.     virtual STDMETHODIMP QueryInterface(REFIID,void **);
  46.     virtual STDMETHODIMP_(ULONG) AddRef(void);
  47.     virtual STDMETHODIMP_(ULONG) Release(void);
  48.     // IShellFolder
  49.     virtual STDMETHODIMP ParseDisplayName(HWND hwndOwner,
  50.         LPBC pbcReserved, LPOLESTR lpszDisplayName,
  51.         ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes);
  52.     virtual STDMETHODIMP EnumObjects( THIS_ HWND hwndOwner, DWORD grfFlags, LPENUMIDLIST * ppenumIDList);
  53.     virtual STDMETHODIMP BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved,
  54.                                  REFIID riid, LPVOID * ppvOut);
  55.     virtual STDMETHODIMP BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved,
  56.                                  REFIID riid, LPVOID * ppvObj);
  57.     virtual STDMETHODIMP CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
  58.     virtual STDMETHODIMP CreateViewObject (HWND hwndOwner, REFIID riid, LPVOID * ppvOut);
  59.     virtual STDMETHODIMP GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl,
  60.                                     ULONG * rgfInOut);
  61.     virtual STDMETHODIMP GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl,
  62.                                  REFIID riid, UINT * prgfInOut, LPVOID * ppvOut);
  63.     virtual STDMETHODIMP GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName);
  64.     virtual STDMETHODIMP SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl,
  65.                                  LPCOLESTR lpszName, DWORD uFlags,
  66.                                  LPITEMIDLIST * ppidlOut);
  67.     // IPersistFolder
  68.     virtual STDMETHODIMP GetClassID(LPCLSID lpClassID);
  69.     virtual STDMETHODIMP Initialize(LPCITEMIDLIST pidl);
  70.     // IShellIcon (yes, we are cheating here!)
  71.     virtual STDMETHODIMP GetIconOf(LPCITEMIDLIST pidl, UINT flags,
  72. LPINT lpIconIndex);
  73. protected:
  74.     ~CDocObjectFolder();
  75.     UINT            _cRef;
  76.     LPITEMIDLIST    _pidlRoot;
  77.     LPITEMIDLIST    _pidlItem;
  78.     REFCLSID     _rclsid;
  79.     Site*           _psite;
  80.     BOOL _IsInternetFolder() { return IsEqualGUID(_rclsid, CLSID_CURLFolder); };
  81.     BOOL _IsInternetRoot() { return !_psite; }; // this returns true if it's Desktop/Internet (not a child of it)
  82.     BOOL _ValidateSite();
  83.     BOOL _GetProtocolHandler(LPCSTR szProtocol, IShellFolder **ppsfHandler);
  84.     BOOL _GetProtocolHandlerFromPidl(LPCITEMIDLIST pidl, IShellFolder **ppsfHandler);
  85.     HRESULT _GetAttributesOfProtocol(LPCSTR pszProtocol, LPCITEMIDLIST *apidl, UINT cpidl, ULONG *rgfInOut);
  86. };
  87. class CMallocItem : public IMalloc
  88. {
  89. public:
  90.     CMallocItem(LPCSTR szProtocol);
  91.     ~CMallocItem();
  92.     // IUnknown
  93.     virtual STDMETHODIMP QueryInterface(REFIID,void **);
  94.     virtual STDMETHODIMP_(ULONG) AddRef(void);
  95.     virtual STDMETHODIMP_(ULONG) Release(void);
  96.     // IMalloc
  97.     virtual STDMETHODIMP_(LPVOID)   Alloc(ULONG cb);
  98.     virtual STDMETHODIMP_(LPVOID)   Realloc(LPVOID pv, ULONG cb);
  99.     virtual STDMETHODIMP_(void)     Free(LPVOID pv);
  100.     virtual STDMETHODIMP_(ULONG)    GetSize(LPVOID pv);
  101.     virtual STDMETHODIMP_(int)      DidAlloc(LPVOID pv);
  102.     virtual STDMETHODIMP_(void)     HeapMinimize();
  103. protected:
  104.     UINT _cRef;
  105.     LPSTR _pszProtocol;  // protocol for the allocator
  106. };
  107. class CInetEnum : public IEnumIDList
  108. {
  109. public:
  110.     // *** IUnknown methods ***
  111.     STDMETHOD(QueryInterface) (REFIID riid, LPVOID * ppvObj);
  112.     STDMETHOD_(ULONG,AddRef) () ;
  113.     STDMETHOD_(ULONG,Release) ();
  114.     // *** IEnumIDList methods ***
  115.     STDMETHOD(Next)  (ULONG celt,
  116.                       LPITEMIDLIST *rgelt,
  117.                       ULONG *pceltFetched);
  118.     STDMETHOD(Skip)  (ULONG celt);
  119.     STDMETHOD(Reset) ();
  120.     STDMETHOD(Clone) (IEnumIDList **ppenum);
  121.     CInetEnum(Site *psite);
  122.     ~CInetEnum();
  123. protected:
  124.     UINT  _cRef;
  125.     UINT  _iCur;
  126.     Site *_psite; // what's our base site  (NULL means top level)
  127. };
  128. class CDocIcon : public IExtractIcon
  129. {
  130. public:
  131.     // *** IUnknown methods ***
  132.     STDMETHOD(QueryInterface) (REFIID riid, LPVOID * ppvObj);
  133.     STDMETHOD_(ULONG,AddRef) () ;
  134.     STDMETHOD_(ULONG,Release) ();
  135.     // *** IExtractIcon methods ***
  136.     STDMETHOD(GetIconLocation)(
  137.                          UINT   uFlags,
  138.                          LPSTR  szIconFile,
  139.                          UINT   cchMax,
  140.                          int   * piIndex,
  141.                          UINT  * pwFlags);
  142.     STDMETHOD(Extract)(
  143.                            LPCSTR pszFile,
  144.                            UINT   nIconIndex,
  145.                            HICON   *phiconLarge,
  146.                            HICON   *phiconSmall,
  147.                            UINT    nIconSize);
  148.     CDocIcon(LPCITEMIDLIST pidl);
  149.     virtual ~CDocIcon();
  150. protected:
  151.     HRESULT CDocIcon::_GetIconLocationForFile(LPSTR pszFile,
  152.                          UINT   uFlags,
  153.                          LPSTR  szIconFile,
  154.                          UINT   cchMax,
  155.                          int   * piIndex,
  156.                          UINT  * pwFlags);
  157.     UINT  _cRef;
  158.     LPITEMIDLIST  _pidl;
  159. };
  160. class CInternetIcon : public CDocIcon
  161. {
  162. public:
  163.     CInternetIcon(LPCITEMIDLIST pidl, Site* site);
  164.     ~CInternetIcon();
  165.     // *** IUnknown methods ***
  166.     STDMETHOD(GetIconLocation)(
  167.                          UINT   uFlags,
  168.                          LPSTR  szIconFile,
  169.                          UINT   cchMax,
  170.                          int   * piIndex,
  171.                          UINT  * pwFlags);
  172. protected:
  173.     Site*               _psite;
  174. };
  175. class CDocMenu : public IContextMenu
  176. {
  177. public:
  178.     // *** IUnknown methods ***
  179.     STDMETHOD(QueryInterface) (REFIID riid, LPVOID * ppvObj);
  180.     STDMETHOD_(ULONG,AddRef) () ;
  181.     STDMETHOD_(ULONG,Release) ();
  182.     // IContextMenu
  183.     STDMETHOD(QueryContextMenu)(HMENU hmenu,
  184.                                 UINT indexMenu,
  185.                                 UINT idCmdFirst,
  186.                                 UINT idCmdLast,
  187.                                 UINT uFlags);
  188.     STDMETHOD(InvokeCommand)(LPCMINVOKECOMMANDINFO lpici);
  189.     STDMETHOD(GetCommandString)(UINT        idCmd,
  190.                                 UINT        uType,
  191.                                 UINT      * pwReserved,
  192.                                 LPSTR       pszName,
  193.                                 UINT        cchMax);
  194.     CDocMenu(LPCITEMIDLIST pidlRoot, LPCITEMIDLIST pidlItem);
  195.     virtual ~CDocMenu();
  196. protected:
  197.     UINT  _cRef;
  198.     LPITEMIDLIST  _pidl;
  199. };
  200. //========================================================================
  201. //
  202. //========================================================================
  203. //#define FAKE_SITEMAP
  204. #ifdef FAKE_SITEMAP
  205. BOOL _ValidateURL(LPTSTR pszName);
  206. void LoadFakeSiteMap(LPCITEMIDLIST pidl)
  207. {
  208.     TCHAR szUrl[MAX_URL_STRING];
  209.     TCHAR szSiteMapFile[MAX_URL_STRING];
  210.     LPTSTR pszEnd;
  211.     LPTSTR pszStart;
  212.     PidlToUrl(pidl, szUrl);
  213.     if (szUrl[0] && _ValidateURL(szUrl))  {
  214.         pszStart = szUrl + 7; // skip over http://
  215.         pszEnd = StrChr(pszStart, '/');
  216.         if (!pszEnd)
  217.             pszEnd = StrChr(pszStart, '\');
  218.         if (!pszEnd)
  219.             pszEnd = pszStart + lstrlen(pszStart) + 1;
  220.         lstrcpy(szSiteMapFile, TEXT("c:\"));
  221.         lstrcpyn(szSiteMapFile + 3, pszStart, pszEnd - pszStart);
  222.         lstrcat(szSiteMapFile, TEXT(".smp"));
  223.         SL_AddNewSiteMap(szSiteMapFile);
  224.     }
  225. }
  226. #else
  227. #define LoadFakeSiteMap(pidl) 0
  228. #endif
  229. #ifdef DEBUG
  230. HRESULT WINAPI URLQualifyA(PCSTR pcszURL, DWORD dwInFlags,
  231.                            PSTR *ppszTranslatedURL);
  232. void TryOneURLQualify(PCSTR pszUrl)
  233. {
  234.     HRESULT hres;
  235.     LPSTR pszUrlFull;
  236.     hres = URLQualifyA(pszUrl, TRANSLATEURL_FL_GUESS_PROTOCOL | TRANSLATEURL_FL_USE_DEFAULT_PROTOCOL,
  237.                        &pszUrlFull);
  238.     DebugMsg(DM_TRACE, "Translate %s returned %d n(%s)", pszUrl, hres, pszUrlFull ? pszUrlFull : pszUrl);
  239.     if (pszUrlFull) {
  240.         LocalFree(pszUrlFull);
  241.     }
  242. }
  243. void TestURLQualify()
  244. {
  245.     TryOneURLQualify("www.mit.edu");
  246.     TryOneURLQualify("http://msw");
  247.     TryOneURLQualify("msw");
  248. }
  249. #endif
  250. //========================================================================
  251. // CDocObjectFolder members
  252. //========================================================================
  253. CDocObjectFolder::CDocObjectFolder(REFCLSID rclsid, LPCITEMIDLIST pidl, LPCITEMIDLIST pidlRoot, Site* psite)
  254. : _cRef(1), _rclsid(rclsid), _pidlItem(NULL), _pidlRoot(NULL), _psite(psite)
  255. {
  256.     DebugMsg(TF_SHDLIFE, TEXT("ctor CDocObjectFolder %x"), this);
  257.     //
  258.     // WARNING: See comments above OleUninitialize (which is also commented out).
  259.     //
  260.     // OleInitialize(NULL);
  261.     DllAddRef();
  262. #if 0
  263.     TestURLQualify();
  264. #endif
  265.     if (_psite)
  266.         _psite->AddRef();
  267.     if (pidl) {
  268.         _pidlItem = ILClone(pidl);
  269.     }
  270.     if (pidlRoot) {
  271.         _pidlRoot = ILClone(pidlRoot);
  272.     }
  273. }
  274. CDocObjectFolder::~CDocObjectFolder()
  275. {
  276.     DebugMsg(TF_SHDLIFE, TEXT("dtor CDocObjectFolder %x"), this);
  277.     if (_pidlItem) {
  278.         ILFree(_pidlItem);
  279.         _pidlItem = NULL;
  280.     }
  281.     if (_pidlRoot) {
  282.         ILFree(_pidlRoot);
  283.         _pidlRoot = NULL;
  284.     }
  285.     if (_psite)
  286.         _psite->Release();
  287.     //
  288.     // WARNING: We can't call OLE here because this destructor will be
  289.     //  called from within the ThreadDetach. At this point, OLE might
  290.     //  have already done the clean-up. I believe it is quite safe
  291.     //  to remove OleInitialize/OleUninitialize pair from this instance.
  292.     //  (SatoNa)
  293.     //
  294.     // OleUninitialize();
  295.     DllRelease();
  296. }
  297. HRESULT CDocObjectFolder::QueryInterface(REFIID riid, LPVOID * ppvObj)
  298. {
  299.     if (IsEqualIID(riid, IID_IShellFolder) || IsEqualIID(riid, IID_IUnknown))
  300.     {
  301.         *ppvObj = (IShellFolder*)this;
  302.     }
  303.     else if (IsEqualIID(riid, IID_IPersistFolder))
  304.     {
  305.         *ppvObj = (IPersistFolder*)this;
  306.     }
  307.     else if (IsEqualIID(riid, IID_IShellIcon))
  308.     {
  309.         *ppvObj = (IShellIcon*)this;
  310.     }
  311.     else
  312.     {
  313.         *ppvObj = NULL;
  314.         return E_NOINTERFACE;
  315.     }
  316.     AddRef();
  317.     return S_OK;
  318. }
  319. ULONG CDocObjectFolder::AddRef()
  320. {
  321.     _cRef++;
  322.     return _cRef;
  323. }
  324. ULONG CDocObjectFolder::Release()
  325. {
  326.     _cRef--;
  327.     if (_cRef > 0)
  328.         return _cRef;
  329.     delete this;
  330.     return 0;
  331. }
  332. HRESULT CDocObjectFolder_CreateInstance(IUnknown* pUnkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
  333. {
  334.     // aggregation checking is handled in class factory
  335.     CSTMSG(TEXT("CreateInstance"));
  336.     CDocObjectFolder* ptfld = new CDocObjectFolder(*poi->pclsid);
  337.     if (ptfld) {
  338. #ifdef DEBUG
  339.         //
  340.         // HACK:
  341.         //
  342.         //   SHELL32 caches c_sfInetRoot in a static DATA section
  343.         //  and never release it. It caches an instance of CDocobjectFolder
  344.         //  and never release it. Therefore, we are removing this object
  345.         //  from the to-be-memleak-detected list to avoid a false alarm
  346.         //  assuming that we don't realy leak this object.
  347.         //   Please don't copy it to another place unless you are really
  348.         //  sure that it's OK not to detect leaks in that scenario.
  349.         //  (SatoNa)
  350.         //
  351.         extern void remove_from_memlist(void *pv);
  352.         remove_from_memlist(ptfld);
  353. #endif
  354.         *ppunk = SAFECAST(ptfld, IShellFolder *);
  355.         return S_OK;
  356.     }
  357.     return E_OUTOFMEMORY;
  358. }
  359. //
  360. // this might modify pszName if it's not a fully qualified url!
  361. BOOL _ValidateURL(LPTSTR pszName)
  362. {
  363.     //
  364.     // WARNING: In order to allow URL extensions, we assume all strings
  365.     //  which contains ":" in it is a valid string.
  366.     // Assumptions are:
  367.     //
  368.     // (1) CDesktop::ParseDisplayName parse file system strings first.
  369.     // (2) URL moniker will return an error correctly if URL is not valid.
  370.     //
  371.     if (SUCCEEDED(IURLQualify(pszName, TRANSLATEURL_FL_GUESS_PROTOCOL | TRANSLATEURL_FL_USE_DEFAULT_PROTOCOL, pszName))
  372.         && -1 != GetUrlScheme(pszName))
  373.             return TRUE;
  374.     else
  375.         return FALSE;
  376. }
  377. #define LOC_IsLocation(pidl) (((((LPIDFILELOCATION)pidl)->bFlags) & SHID_LOC) == SHID_LOC)
  378. #define LOC_Type(pidl)  ((((LPIDFILELOCATION)pidl)->bFlags) & SHID_LOC_TYPEMASK)
  379. #define LOC_GetLocation(pidl) (((LPIDFILELOCATION)pidl)->cLocation)
  380. // this gives a good guess as to whether something could be a location spec.
  381. // it can give a false positive, but not a false negative.
  382. // this allows us to blow off work if we get a negative.
  383. //
  384. // if it finds something it suspects to be a location spec, it returns a pointer
  385. // to it.  otherwise returns NULL;
  386. LPIDFILELOCATION IEMaybeHasLocationSpec(LPCITEMIDLIST pidl)
  387. {
  388.     LPITEMIDLIST pidlLast = ILFindLastID(pidl);
  389.     // the SHID_LOC bits aren't valid for filesys pidls
  390.     if (!(pidlLast && pidlLast != pidl && LOC_IsLocation(pidlLast))) {
  391.         pidlLast = NULL;
  392.     }
  393.     return (LPIDFILELOCATION)pidlLast;
  394. }
  395. // BUGBUG: this might get deceived on junction points.
  396. // we should add another check on filesys
  397. // fills in the location and removes the location pidl if it was such a thing
  398. BOOL ILRemoveLocation(LPITEMIDLIST pidl, LPWSTR pszLocation)
  399. {
  400.     WORD cbOld;
  401.     LPIDFILELOCATION pidlLast;
  402.     BOOL fRet = FALSE;
  403.     if (pszLocation)
  404.         pszLocation[0] = 0;
  405.     pidlLast = IEMaybeHasLocationSpec(pidl);
  406.     if (pidlLast) {
  407.         char szBuffer[MAX_PATH];
  408.         cbOld = pidlLast->cb;
  409.         pidlLast->cb = 0;
  410.         // one last check...  after stripping it off, we should
  411.         // be able to get a path from the pidl
  412.         if (SHGetPathFromIDList(pidl, szBuffer)) {
  413.             // yes, we did have the location
  414.             if (pszLocation)
  415.                 ualstrcpyW(pszLocation, pidlLast->cLocation);
  416.             fRet = TRUE;
  417.         } else {
  418.             // nope!
  419.             pidlLast->cb = cbOld;
  420.         }
  421.     }
  422.     return fRet;
  423. }
  424. void ILAppendLocation(LPITEMIDLIST *ppidl, LPWSTR pszLocation)
  425. {
  426.     if (pszLocation) {
  427.         LPITEMIDLIST pidl;
  428.         IDFILELOCATION id;
  429.         ZeroMemory(&id, sizeof(id));
  430.         id.bFlags = SHID_LOC;
  431.         ualstrcpyW(id.cLocation, pszLocation);
  432.         id.cb = (((LPBYTE)(&id.cLocation[0])) + (ualstrlenW(id.cLocation) + 1) * SIZEOF(WCHAR)) - ((LPBYTE)&id);
  433.         pidl = ILCombine(*ppidl, (LPITEMIDLIST)&id);
  434.         if (pidl) {
  435.             ILFree(*ppidl);
  436.             *ppidl = pidl;
  437.         }
  438.     }
  439. }
  440. void PidlToUrl(LPCITEMIDLIST pidl, LPTSTR pszUrl)
  441. {
  442.     lstrcpy(pszUrl, _PidlToUrlPtr(pidl));
  443. }
  444. void UrlToID(LPSTR psz, BYTE bType, PURLID pidlUrl)
  445. {
  446.     ZeroMemory(pidlUrl, sizeof(URLID));
  447.     lstrcpyn(_PidlToUrlPtr(pidlUrl), psz, MAX_URL_STRING);
  448. #ifdef DEBUG
  449.     if (lstrlen(psz) < lstrlen(_PidlToUrlPtr(pidlUrl))) {
  450.      DebugMsg(TF_WARNING, "UrlToID string trancated (%d->%d)",
  451.      lstrlen(_PidlToUrlPtr(pidlUrl)), lstrlen(psz) );
  452.     }
  453. #endif
  454.     // assuming the string is the end of the pidl, get the length
  455.     // by subtracting the idl address from the end of the string (null)
  456.     pidlUrl->idl.mkid.cb = ((lstrlen(_PidlToUrlPtr(pidlUrl)) + 1 +
  457.         (LPBYTE)_PidlToUrlPtr(pidlUrl)) - ((LPBYTE)pidlUrl));
  458.     _URLDelegateID(pidlUrl) = SHID_INTERNET_SITE;
  459.     _URLPidlType(pidlUrl) = bType;
  460. }
  461. LPITEMIDLIST UrlToPidl(LPTSTR pszUrl, LPWSTR pszLocation, LPTSTR pszFrameName,
  462.     LPTSTR pszHeaders, LPBYTE pPostData, int cbPostData)
  463. {
  464.     LPITEMIDLIST pidlRet = NULL;
  465.     URLID idl;
  466.     URLID idlLocation;
  467.     PURLID pidlFree = NULL;
  468.     PURLID pidlUrl = &idl;
  469.     BOOL fEnhancedURL = pszUrl && (pszFrameName || pszHeaders || pPostData);
  470.     char szSize[10];
  471.     if (fEnhancedURL)
  472.     {
  473.         int cbEURL = lstrlen(pszUrl)+ 1;
  474.         LPBYTE pb;
  475.         if (pszFrameName)
  476.             cbEURL += lstrlen(pszFrameName) + 2;
  477.         if (pszHeaders)
  478.             cbEURL += lstrlen(pszHeaders) + 2;
  479.         if (pPostData)
  480.         {
  481.             wsprintf(szSize, "%i", cbPostData);
  482.             cbEURL += cbPostData + lstrlen(szSize) + 2;
  483.         }
  484.         if (cbEURL > 0xFFFF-FIELD_OFFSET(URLID,ach)) goto exitPoint;
  485.         // NOTE: include an extra 2 0 bytes at end to Terminate (cb of following
  486.         // id)
  487.         pidlUrl = (PURLID) LocalAlloc(LPTR, FIELD_OFFSET(URLID,ach)+cbEURL+2);
  488.         if (pidlUrl == NULL) goto exitPoint;
  489.         pidlFree = pidlUrl;
  490.         ZeroMemory(pidlUrl, FIELD_OFFSET(URLID,ach)+cbEURL+2);
  491.         pb = (LPBYTE)_PidlToUrlPtr(pidlUrl);
  492.         lstrcpy((LPSTR)pb, pszUrl);
  493.         pb += lstrlen(pszUrl) + 1;
  494.         if (pszFrameName)
  495.         {
  496.             *pb++ = EURL_FRAMENAME;
  497.             lstrcpy((LPSTR)pb, pszFrameName);
  498.             pb += lstrlen(pszFrameName) + 1;
  499.             ASSERT(pb <= ((LPBYTE) pidlUrl)+FIELD_OFFSET(URLID,ach)+cbEURL);
  500.         }
  501.         if (pszHeaders)
  502.         {
  503.             *pb++ = EURL_HEADERS;
  504.             lstrcpy((LPSTR)pb, pszHeaders);
  505.             pb += lstrlen(pszHeaders) + 1;
  506.             ASSERT(pb <= ((LPBYTE) pidlUrl)+FIELD_OFFSET(URLID,ach)+cbEURL);
  507.         }
  508.         if (pPostData)
  509.         {
  510.             *pb++ = EURL_POSTDATA;
  511.             lstrcpy((LPSTR)pb, szSize);
  512.             pb += lstrlen(szSize) + 1;
  513.             memcpy(pb, pPostData, cbPostData);
  514.             ASSERT(pb+cbPostData <= ((LPBYTE) pidlUrl)+FIELD_OFFSET(URLID,ach)+cbEURL);
  515.         }
  516.         // assuming the string is the end of the pidl, get the length
  517.         // by subtracting the idl address from the end of the EURL
  518.         pidlUrl->idl.mkid.cb = (cbEURL + (LPBYTE)_PidlToUrlPtr(pidlUrl))
  519.                        - ((LPBYTE)pidlUrl);
  520.         _URLDelegateID(pidlUrl) = SHID_INTERNET_SITE;
  521.         _URLPidlType(pidlUrl) = URLID_URLBASE;
  522.     }
  523.     else
  524.     {
  525.         if (pszUrl)
  526.             UrlToID(pszUrl, URLID_URLBASE, &idl);
  527.     }
  528.     if (pszLocation && pszLocation[0]) {
  529.         char szLocation[MAX_URL_STRING];
  530.         WideCharToMultiByte(CP_ACP, 0, pszLocation, -1, szLocation,
  531.             ARRAYSIZE(szLocation), NULL, NULL);
  532.         UrlToID(szLocation, URLID_LOCATION, &idlLocation);
  533.     } else {
  534.         pszLocation = NULL;
  535.     }
  536.     if (pszUrl && pszLocation ) {
  537.         pidlRet = ILCombine((LPITEMIDLIST)pidlUrl, (LPITEMIDLIST)&idlLocation);
  538.     } else if (pszUrl) {
  539.         pidlRet = ILClone((LPITEMIDLIST)pidlUrl);
  540.     } else if (pszLocation) {
  541.         pidlRet = ILClone((LPITEMIDLIST)&idlLocation);
  542.     }
  543. exitPoint:
  544.     if (pidlFree) LocalFree(pidlFree);
  545.     return pidlRet;
  546. }
  547. LPITEMIDLIST UrlToPidl2(LPCITEMIDLIST pidlParent, LPTSTR pszURL, BYTE bType)
  548. {
  549.     URLID idl;
  550.     UrlToID(pszURL, bType, &idl);
  551.     if (pidlParent) {
  552.         return ILCombine(pidlParent, (LPITEMIDLIST)&idl);
  553.     }
  554.     return ILClone((LPITEMIDLIST)&idl);
  555. }
  556. BOOL CDocObjectFolder::_GetProtocolHandler(LPCSTR pszProtocol, IShellFolder **ppsfHandler)
  557. {
  558.     BOOL fRet = FALSE;
  559.     char szCLSID[GUIDSTR_MAX];
  560.     DWORD cbSize;
  561.     TraceMsg(TF_PIDLWRAP, "GetProtocolHandler(%s)", pszProtocol);
  562.     *ppsfHandler = NULL;
  563.     cbSize = SIZEOF(szCLSID);
  564.     if (pszProtocol && pszProtocol[0] &&
  565.         SHGetValue(HKEY_CLASSES_ROOT, pszProtocol, TEXT("ShellFolder"),
  566.                    NULL, &szCLSID, &cbSize) == ERROR_SUCCESS)
  567.     {
  568.         IDelegateFolder *pdf;
  569.         //
  570.         // Get his IDelegateFolder.
  571.         //
  572.         // BUGBUG if we already have a psf initialized with the same
  573.         // pidl, can we just reuse it instead of CoCreateInstancing another?
  574.         if (SUCCEEDED(SHCoCreateInstance(szCLSID, NULL, NULL, IID_IDelegateFolder, (LPVOID *)&pdf)))
  575.         {
  576.             //
  577.             // Get his IShellFolder.
  578.             //
  579.             if (SUCCEEDED(pdf->QueryInterface(IID_IShellFolder, (LPVOID *)ppsfHandler)))
  580.             {
  581.                 IPersistFolder *ppf;
  582.                 //
  583.                 // Get his IPersistFolder.
  584.                 //
  585.                 if (SUCCEEDED(pdf->QueryInterface(IID_IPersistFolder, (LPVOID *)&ppf)))
  586.                 {
  587.                     CMallocItem *pmi;
  588.                     //
  589.                     // Get an allocator.
  590.                     //
  591.                     // BUGBUG - if we already have an IMalloc around
  592.                     // for this protocol, just find & addref it, instead
  593.                     // of creating a new one each time.
  594.                     pmi = new CMallocItem(pszProtocol);
  595.                     if (pmi)
  596.                     {
  597.                         //
  598.                         // Tell his IDelegateFolder to use my allocator.
  599.                         //
  600.                         if (SUCCEEDED(pdf->SetItemAlloc(pmi)))
  601.                         {
  602.                             fRet = TRUE;
  603.                         }
  604.                         //
  605.                         // I don't need my allocator any more.
  606.                         // We assume here that the pdf AddRef()ed the
  607.                         // pmi (unless he didn't need it either).
  608.                         //
  609.                         pmi->Release();
  610.                     }
  611.                     //
  612.                     // Don't need the ppf any more.
  613.                     //
  614.                     ppf->Release();
  615.                 }
  616.                 if (fRet)
  617.                 {
  618.                     //
  619.                     // On success, initialize him with the root pidl.
  620.                     //
  621.                     ppf->Initialize(_pidlRoot);
  622.                 }
  623.                 else
  624.                 {
  625.                     //
  626.                     // On failure, don't return an IShellFolder.
  627.                     //
  628.                     (*ppsfHandler)->Release();
  629.                     *ppsfHandler = NULL;
  630.                 }
  631.             }
  632.             //
  633.             // Don't need the pdf any more.
  634.             //
  635.             pdf->Release();
  636.         }
  637.     }
  638.     TraceMsg(TF_PIDLWRAP, "GetProtocolHandler=%d", fRet);
  639.     return fRet;
  640. }
  641. BOOL CDocObjectFolder::_GetProtocolHandlerFromPidl(LPCITEMIDLIST pidl, IShellFolder **ppsfHandler)
  642. {
  643.     BOOL fRet = FALSE;
  644.     TraceMsg(TF_PIDLWRAP, "GetProtocolHandlerFromPidl(pidl=%08X)", pidl);
  645.     *ppsfHandler = NULL;
  646.     if (_IsPidlProtocol(pidl))
  647.     {
  648.         fRet = _GetProtocolHandler(_PidlToProtocol(pidl), ppsfHandler);
  649.     }
  650.     TraceMsg(TF_PIDLWRAP, "GetProtocolHandlerFromPidl=%d", fRet);
  651.     return fRet;
  652. }
  653. BOOL _GetUrlProtocol(LPCTSTR szURL, LPTSTR pszProtocol, DWORD cchBufferSize)
  654. {
  655.     PARSEDURL pu;
  656.     pu.cbSize = SIZEOF(PARSEDURL);
  657.     if (SUCCEEDED(ParseURL(szURL, &pu)) && cchBufferSize > pu.cchProtocol)
  658.     {
  659.         StrCpyN(pszProtocol, pu.pszProtocol, pu.cchProtocol +1);
  660.         return TRUE;
  661.     }
  662.     return FALSE;
  663. }
  664.     
  665. HRESULT CDocObjectFolder::ParseDisplayName(HWND hwndOwner,
  666.         LPBC pbcReserved, LPOLESTR pwszDisplayName,
  667.         ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes)
  668. {
  669.     HRESULT hres = E_FAIL;
  670.     // BUGBUG: We'd better use separate C++ class!
  671.     if (_IsInternetFolder() && !_pidlItem)
  672.     {
  673.         char szName[MAX_URL_STRING];
  674.         WideCharToMultiByte(CP_ACP, 0, pwszDisplayName, -1, szName, ARRAYSIZE(szName), NULL, NULL);
  675.         if (!PathIsFilePath(szName))  {
  676.             if (_ValidateURL(szName) || ShouldShellExecURL( szName ))  {
  677.                 char szEncoded[MAX_URL_STRING];
  678.                 char szProtocol[MAX_PATH];
  679.                 LPSTR pszName = szName;
  680.                 DWORD dwSize = ARRAYSIZE(szEncoded);
  681.                 IShellFolder *psfHandler;
  682.                 // if we're down here, then the szName was really a url so try to encode it.
  683.                 // turn spaces to %20
  684.                 if (SUCCEEDED(UrlEscape(szName, szEncoded, &dwSize, 0)))
  685.                     pszName = szEncoded;
  686.                 if (_GetUrlProtocol(pszName, szProtocol, ARRAYSIZE(szProtocol)) &&
  687.                     _GetProtocolHandler(szProtocol, &psfHandler))
  688.                 {
  689.                     TraceMsg(TF_PIDLWRAP, "Asking "%s" handler to parse %s (%08X) into a pidl", szProtocol, szName, szName);
  690.                     hres = psfHandler->ParseDisplayName(hwndOwner, pbcReserved,
  691.                                                         pwszDisplayName, pchEaten,
  692.                                                         ppidl, pdwAttributes);
  693.                     TraceMsg(TF_PIDLWRAP, "the result is %08X, the pidl is %08X", hres, *ppidl);
  694.                     psfHandler->Release();
  695.                     DebugMsg(TF_URLNAMESPACE, TEXT("CODF::PDN(%s) called psfHandler and returning %x"),
  696.                              szName, hres);
  697.                 }
  698.                 else
  699.                 {
  700.                     *ppidl = UrlToPidl(pszName, NULL, NULL, NULL, NULL, 0);
  701.                     hres = (*ppidl ? S_OK : E_OUTOFMEMORY);
  702.                     DebugMsg(TF_URLNAMESPACE, TEXT("CODF::PDN(%s) called UrlToPidl and returning %x"),
  703.                              szName, hres);
  704.                 }
  705.             } else {
  706.                 DebugMsg(DM_ERROR, TEXT("CDOF::PDN(%s) returning E_FAIL because of (%s) is FALSE"),
  707.                     szName,
  708.                     TEXT("(_ValidateURL(szName) || ShouldShellExecURL( szName ))"));
  709.             }
  710.         } else {
  711.             DebugMsg(DM_ERROR, TEXT("CDOF::PDN(%s) returning E_FAIL because of (%s) is FALSE"),
  712.                 szName,
  713.                 TEXT("(!PathIsFilePath(szName))"));
  714.         }
  715.     } else {
  716.         DebugMsg(DM_ERROR, TEXT("CDOF::PDN returning E_FAIL because of (%s) is FALSE"),
  717.                 TEXT("if (_IsInternetFolder() && !_pidlItem)"));
  718.     }
  719.     return hres;
  720. }
  721. HRESULT CDocObjectFolder::EnumObjects(HWND hwndOwner, DWORD grfFlags, LPENUMIDLIST * ppenumIDList)
  722. {
  723.     DebugMsg(0, TEXT("sdv DOF:EnumObjects called"));
  724.     if (!_ValidateSite())
  725.         return E_FAIL;
  726.     *ppenumIDList = new CInetEnum(_psite);
  727.     return *ppenumIDList ? S_OK : E_OUTOFMEMORY;
  728. }
  729. BOOL CDocObjectFolder::_ValidateSite()
  730. {
  731.     BOOL fRet = TRUE;
  732.     if (_psite) {
  733.         Site* psiteParent = _psite->GetParent();
  734.         if (psiteParent->IsInternetRoot()) {
  735.             Site* psiteNew;
  736.             // if this was a top level item site, it could have been replaced
  737.             psiteNew = psiteParent->FindSite(_psite->GetUrl(), FALSE);
  738.             if (psiteNew != _psite) {
  739.                 if (psiteNew) {
  740.                     // if we found one swap us
  741.                     _psite->Release();
  742.                     _psite = psiteNew;
  743.                     psiteNew->AddRef();
  744.                 } else {
  745.                     // if we didn't, we really failed... bail out
  746.                     fRet = FALSE;
  747.                 }
  748.             }
  749.             psiteNew->Release();  //Earlier FindSite() did one Addref.
  750.         }
  751.         //Eariler GetParent() did one AddRef()...
  752.         if(psiteParent != INVALID_SITE)
  753.             psiteParent->Release(); //...And this is the corresponding Release()
  754.     }
  755.     return fRet;
  756. }
  757. HRESULT CDocObjectFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbcReserved,
  758.                                        REFIID riid, LPVOID * ppvOut)
  759. {
  760.     HRESULT hres = E_OUTOFMEMORY;
  761.     *ppvOut = NULL;
  762.     Site* psiteNew = NULL;
  763.     if (_IsInternetFolder()) {
  764.         if (_IsPidlProtocol(pidl))
  765.         {
  766.             IShellFolder *psfHandler;
  767.             if (_GetProtocolHandlerFromPidl(pidl, &psfHandler))
  768.             {
  769.                 TraceMsg(TF_PIDLWRAP, "Calling "%s" handler to bind to object", _PidlToProtocol(pidl));
  770.                 HRESULT hres = psfHandler->BindToObject(pidl, pbcReserved, riid, ppvOut);
  771.                 TraceMsg(TF_PIDLWRAP, "Hander hres=%08X, ppvOut=%08X", hres, ppvOut);
  772.                 if (SUCCEEDED(hres))
  773.                 {
  774.                     // TraceMsg(TF_PIDLWRAP, "Adding to site list too!");
  775.                     // SL_AddExplicitLocation(pidl);
  776.                 }
  777.                 psfHandler->Release();
  778.                 return hres;
  779.             }
  780.             ASSERT(FALSE);
  781.             // BUGBUG -
  782.             // where do we want to fall into if we don't have the protocol?
  783.             // let's try to fall through into the old code.
  784.             return E_FAIL;
  785.         }
  786.         if (!_ValidateSite())
  787.             return E_FAIL;
  788.         psiteNew = PidlToSite(pidl, _psite);
  789.         // if we couldn't find the site and we are a top level site
  790.         if(psiteNew == INVALID_SITE) {
  791.             if (_IsInternetRoot()) {
  792.                 // BUGBUG just set a flag here and actually add to
  793.                 // sitelist at end of function if/when EVERYTHING succeeds.
  794.                 SL_AddExplicitLocation(pidl);
  795.              // This breaks IE's Form submission stuff. So, backed out
  796.              // temporarily
  797.              // This break's BharatS's offline reading stuff. So, backed out
  798.              // temporarily.
  799.              //   if(WhichPlatform() == PLATFORM_NASH)
  800.              //       LoadDefaultSiteMap(pidl);
  801.                 psiteNew = PidlToSite(pidl, _psite);
  802.                 if (psiteNew == INVALID_SITE)
  803.                     return E_OUTOFMEMORY;
  804. #ifdef FAKE_SITEMAP
  805.                 LoadFakeSiteMap(pidl);
  806. #endif
  807.             } else {
  808.                 // not one of our kids
  809.                 return E_FAIL;
  810.             }
  811.         }
  812.     }
  813.     CDocObjectFolder* ptfld = new CDocObjectFolder(_rclsid, pidl, _pidlRoot,
  814.                                                    psiteNew);
  815.     if (ptfld) {
  816.         hres = ptfld->QueryInterface(riid, ppvOut);
  817.         ptfld->Release();
  818.     } else {
  819.         ASSERT(hres == E_OUTOFMEMORY);
  820.     }
  821.     psiteNew->Release();
  822.     return hres;
  823. }
  824. HRESULT CDocObjectFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbcReserved,
  825.                                  REFIID riid, LPVOID * ppvObj)
  826. {
  827.     if (_IsPidlProtocol(pidl))
  828.     {
  829.         IShellFolder *psfHandler;
  830.         if (_GetProtocolHandlerFromPidl(pidl, &psfHandler))
  831.         {
  832.             HRESULT hres = psfHandler->BindToStorage(pidl, pbcReserved, riid, ppvObj);
  833.             psfHandler->Release();
  834.             return hres;
  835.         }
  836.     }
  837.     return E_NOTIMPL;
  838. }
  839. HRESULT CDocObjectFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  840. {
  841.     int iRet;
  842.     //
  843.     // Check for empty pidls.
  844.     //
  845.     if (ILIsEmpty(pidl1) && ILIsEmpty(pidl2))
  846.     {
  847.         return ResultFromShort(0);
  848.     }
  849.     else if (ILIsEmpty(pidl1))
  850.     {
  851.         return ResultFromShort(-1);
  852.     }
  853.     else if (ILIsEmpty(pidl2))
  854.     {
  855.         return ResultFromShort(1);
  856.     }
  857.     //
  858.     // Check for location pidls.
  859.     //
  860.     if (LOC_IsLocation(pidl1) && LOC_IsLocation(pidl2))
  861.     {
  862.         // they're both locations... strcmp them.
  863.         return ResultFromShort(ualstrcmpW(LOC_GetLocation(pidl1), LOC_GetLocation(pidl2)));
  864.     }
  865.     else if (LOC_IsLocation(pidl1))
  866.     {
  867.         return ResultFromShort(1);
  868.     }
  869.     else if (LOC_IsLocation(pidl2))
  870.     {
  871.         return ResultFromShort(-1);
  872.     }
  873.     //
  874.     // Check for protocol pidls.
  875.     //
  876.     if (_IsPidlProtocol(pidl1) && _IsPidlProtocol(pidl2))
  877.     {
  878.         //
  879.         // They are both protocol pidls, compare their protocols
  880.         //
  881.         iRet = lstrcmpA(_PidlToProtocol(pidl1), _PidlToProtocol(pidl2));
  882.         if (iRet == 0)
  883.         {
  884.             //
  885.             // Wow, the same protocol too.  Call their handler to compare.
  886.             //
  887.             IShellFolder *psfHandler;
  888.             if (_GetProtocolHandler(_PidlToProtocol(pidl1), &psfHandler))
  889.             {
  890.                 iRet = psfHandler->CompareIDs(lParam, pidl1, pidl2);
  891.                 psfHandler->Release();
  892.             }
  893.         }
  894.         return ResultFromShort(iRet);
  895.     }
  896.     else if (_IsPidlProtocol(pidl1))
  897.     {
  898.         return ResultFromShort(1);
  899.     }
  900.     else if (_IsPidlProtocol(pidl2))
  901.     {
  902.         return ResultFromShort(-1);
  903.     }
  904.     //
  905.     // whack off the last / so that http://foo/  == http://foo
  906.     //
  907.     iRet = lstrcmp(_PidlToUrlPtr(pidl1), _PidlToUrlPtr(pidl2));
  908.     if (iRet) {
  909.         return ResultFromShort(iRet);
  910.     }
  911.     return CompareIDs(lParam, _ILNext(pidl1), _ILNext(pidl2));
  912. }
  913. HRESULT CDocObjectFolder::CreateViewObject(HWND hwndOwner, REFIID riid,
  914.     LPVOID *ppvOut)
  915. {
  916.     HRESULT hres = E_NOINTERFACE;
  917.     *ppvOut = NULL;
  918.     if (IsEqualIID(riid, IID_IShellView))
  919.     {
  920.         LPITEMIDLIST pidlFull;
  921.         if (_pidlRoot && _pidlItem) {
  922.             pidlFull = ILCombine(_pidlRoot, _pidlItem);
  923.         } else {
  924.             pidlFull = _pidlRoot;
  925.         }
  926.         hres = CDocObjectView_Create((IShellView**)ppvOut, this, pidlFull,
  927.                                      _rclsid, _psite);
  928.         if (pidlFull && pidlFull!=_pidlRoot) {
  929.             ILFree(pidlFull);
  930.         }
  931.     }
  932.     return hres;
  933. }
  934. HRESULT CDocObjectFolder::_GetAttributesOfProtocol(LPCSTR pszProtocol,
  935.                                                    LPCITEMIDLIST *apidl,
  936.                                                    UINT cpidl, ULONG *rgfInOut)
  937. {
  938.     HRESULT hres = S_OK;
  939.     if (cpidl)
  940.     {
  941.         if (pszProtocol)
  942.         {
  943.             //
  944.             // We have a protocol.  Find the protocol handler
  945.             // and pass it the bundle of pidls.
  946.             //
  947.             IShellFolder *psfHandler;
  948.             if (_GetProtocolHandler(pszProtocol, &psfHandler))
  949.             {
  950.                 hres = psfHandler->GetAttributesOf(cpidl, apidl, rgfInOut);
  951.                 psfHandler->Release();
  952.             }
  953.             else
  954.             {
  955.                 hres = E_FAIL;
  956.             }
  957.         }
  958.         else
  959.         {
  960.             //
  961.             // These pidls are normal children of the Internet folder.
  962.             //
  963.             ULONG uOut = SFGAO_FOLDER | SFGAO_CANLINK;
  964.             if ((*rgfInOut) & SFGAO_HASSUBFOLDER)
  965.             {
  966.                 _ValidateSite();
  967.                 if (cpidl == 1)
  968.                 {
  969.                     Site *psite;
  970.                     psite = PidlToSite(apidl[0], _psite);
  971.                     if (psite != INVALID_SITE)
  972.                     {
  973.                         if (psite->GetCount())
  974.                         {
  975.                             uOut |= SFGAO_HASSUBFOLDER;
  976.                         }
  977.                         psite->Release();
  978.                     }
  979.                 }
  980.             }
  981.             *rgfInOut &= uOut;
  982.         }
  983.     }
  984.     return hres;
  985. }
  986. int CALLBACK ComparePidl(LPVOID pv1, LPVOID pv2, LPARAM lParam)
  987. {
  988.     LPCITEMIDLIST pidl1=(LPCITEMIDLIST)pv1;
  989.     LPCITEMIDLIST pidl2=(LPCITEMIDLIST)pv2;
  990.     if (_IsPidlProtocol(pidl1) && _IsPidlProtocol(pidl2))
  991.     {
  992.         return lstrcmpA(_PidlToProtocol(pidl1), _PidlToProtocol(pidl2));
  993.     }
  994.     else if (_IsPidlProtocol(pidl1))
  995.     {
  996.         return 1;
  997.     }
  998.     else if (_IsPidlProtocol(pidl2))
  999.     {
  1000.         return -1;
  1001.     }
  1002.     else
  1003.     {
  1004.         return 0;
  1005.     }
  1006. }
  1007. HRESULT CDocObjectFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST * apidl,
  1008.                                     ULONG * rgfInOut)
  1009. {
  1010.     if (*rgfInOut == 0)
  1011.     {
  1012.         //
  1013.         // Nothing to do.
  1014.         //
  1015.     }
  1016.     else if (!_IsInternetFolder())
  1017.     {
  1018.         //
  1019.         // Asking about a docobject file or some of its children.
  1020.         //
  1021.         *rgfInOut &= SFGAO_BROWSABLE | SFGAO_CANLINK;
  1022.     }
  1023.     else
  1024.     {
  1025.         //
  1026.         // Internet folder case.
  1027.         //
  1028.         LPCSTR pszProtocol;
  1029.         if (cidl == 0)
  1030.         {
  1031.             //
  1032.             // They are asking about the Internet Folder itself.
  1033.             //
  1034.             *rgfInOut &= SFGAO_FOLDER | SFGAO_CANLINK | SFGAO_HASSUBFOLDER;
  1035.             if ((*rgfInOut) & SFGAO_HASSUBFOLDER)
  1036.             {
  1037.                 _ValidateSite();
  1038.                 if (_psite->GetCount() == 0)
  1039.                 {
  1040.                     *rgfInOut &= ~SFGAO_HASSUBFOLDER;
  1041.                 }
  1042.             }
  1043.         }
  1044.         else if (cidl == 1)
  1045.         {
  1046.             //
  1047.             // Often we are asked about only one child,
  1048.             // so we optimize that case.
  1049.             //
  1050.             pszProtocol = _IsPidlProtocol(apidl[0]) ?
  1051.                             _PidlToProtocol(apidl[0]) :
  1052.                             NULL;
  1053.             _GetAttributesOfProtocol(pszProtocol, apidl, cidl, rgfInOut);
  1054.         }
  1055.         else
  1056.         {
  1057.             //
  1058.             // They are asking about multiple internet children.
  1059.             // These children may have different protocols,
  1060.             // so we have to find the GetAttributesOf handler for
  1061.             // each group of protocols in the list.
  1062.             //
  1063.             HDPA hdpa;
  1064.             LPCITEMIDLIST pidlBase;
  1065.             UINT i, cpidlGroup;
  1066.             //
  1067.             // Create a list of pidls sorted by protocol.
  1068.             //
  1069.             hdpa = DPA_Create(100);
  1070.             if (!hdpa)
  1071.             {
  1072.                 return E_OUTOFMEMORY;
  1073.             }
  1074.             for (i=0; i<cidl; i++)
  1075.             {
  1076.                 DPA_AppendPtr(hdpa, (LPVOID)apidl[i]);
  1077.             }
  1078.             DPA_Sort(hdpa, ComparePidl, NULL);
  1079.             //
  1080.             // Call GetAttributesOf on each protocol group.
  1081.             // A group
  1082.             //   starts at pidlBase
  1083.             //   contains cpidlGroup pidls
  1084.             //   has a protocol of pszProtocol
  1085.             //
  1086.             pidlBase = (LPCITEMIDLIST)DPA_FastGetPtr(hdpa, 0);
  1087.             pszProtocol = NULL;
  1088.             cpidlGroup = 0;
  1089.             for (i=0; *rgfInOut && (i<cidl); i++)
  1090.             {
  1091.                 LPCITEMIDLIST pidlNew;
  1092.                 pidlNew = (LPCITEMIDLIST)DPA_FastGetPtr(hdpa, i);
  1093.                 if (_IsPidlProtocol(pidlNew))
  1094.                 {
  1095.                     LPCSTR pszProtocolNew;
  1096.                     pszProtocolNew = _PidlToProtocol(pidlNew);
  1097.                     //
  1098.                     // See if we have a new protocol.
  1099.                     //
  1100.                     if (!pszProtocol ||
  1101.                         (lstrcmpA(pszProtocol, pszProtocolNew) != 0))
  1102.                     {
  1103.                         //
  1104.                         // We have a new protocol, time to process
  1105.                         // the last batch pidls.
  1106.                         //
  1107.                         _GetAttributesOfProtocol(pszProtocol,
  1108.                                                  &pidlBase, cpidlGroup,
  1109.                                                  rgfInOut);
  1110.                         pidlBase = pidlNew;
  1111.                         pszProtocol = pszProtocolNew;
  1112.                         cpidlGroup = 0;
  1113.                     }
  1114.                 }
  1115.                 cpidlGroup++;
  1116.             }
  1117.             if (*rgfInOut)
  1118.             {
  1119.                 ASSERT(cpidlGroup);
  1120.                 _GetAttributesOfProtocol(pszProtocol, &pidlBase,
  1121.                                          cpidlGroup, rgfInOut);
  1122.             }
  1123.             DPA_Destroy(hdpa);
  1124.         }
  1125.     }
  1126.     return S_OK;
  1127. }
  1128. BOOL GetCommonProtocol(LPCITEMIDLIST *apidl, UINT cpidl, LPSTR *ppszProtocol)
  1129. {
  1130.     UINT ipidl;
  1131.     LPSTR pszProtocol;
  1132.     LPSTR pszProtocolNext;
  1133.     *ppszProtocol = NULL;
  1134.     if (cpidl == 0)
  1135.     {
  1136.         //
  1137.         // No pidls - no protocols, but they do all match!
  1138.         //
  1139.         return TRUE;
  1140.     }
  1141.     //
  1142.     // Grab the protocol of the first pidl, and use it to compare
  1143.     // against the rest of the pidls.
  1144.     //
  1145.     pszProtocol = _IsPidlProtocol(apidl[0]) ?
  1146.                     _PidlToProtocol(apidl[0]) : NULL;
  1147.     for (ipidl=1; ipidl<cpidl; ipidl++)
  1148.     {
  1149.         pszProtocolNext = _IsPidlProtocol(apidl[ipidl]) ?
  1150.                             _PidlToProtocol(apidl[ipidl]) : NULL;
  1151.         //
  1152.         // Check if the protocols are different.
  1153.         //
  1154.         if ((pszProtocol != pszProtocolNext) &&
  1155.             ((pszProtocol == NULL) ||
  1156.              (pszProtocolNext == NULL) ||
  1157.              (lstrcmpA(pszProtocol, pszProtocolNext) != 0)))
  1158.         {
  1159.             return FALSE;
  1160.         }
  1161.     }
  1162.     *ppszProtocol = pszProtocol;
  1163.     return TRUE;
  1164. }
  1165. HRESULT CDocObjectFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST * apidl,
  1166.                                  REFIID riid, UINT * prgfInOut, LPVOID * ppvOut)
  1167. {
  1168.     HRESULT hres = E_FAIL;
  1169.     *ppvOut = NULL;
  1170.     if (IsEqualIID(riid, IID_IExtractIcon)) 
  1171.     {
  1172.         if (_IsInternetFolder()) 
  1173.         {
  1174.             Site* psiteChild;
  1175.             ASSERT(cidl == 1);
  1176.             if (apidl[0]) 
  1177.             {
  1178.                 if (_IsPidlProtocol(apidl[0]))
  1179.                 {
  1180.                     IShellFolder *psfHandler;
  1181.                     if (_GetProtocolHandlerFromPidl(apidl[0], &psfHandler))
  1182.                     {
  1183.                         hres = psfHandler->GetUIObjectOf(hwndOwner, 1, apidl, riid, prgfInOut, ppvOut);
  1184.                         psfHandler->Release();
  1185.                         return hres;
  1186.                     }
  1187.                     return E_INVALIDARG;
  1188.                 }
  1189.                 psiteChild = PidlToSite(apidl[0], _psite);
  1190.                 if (psiteChild == INVALID_SITE)
  1191.                 {
  1192.                     psiteChild = NULL;
  1193.                 }
  1194.             } 
  1195.             else 
  1196.             {
  1197.                 psiteChild = _psite;
  1198.                 _psite->AddRef();
  1199.             }
  1200.             *ppvOut = (IExtractIcon*)new CInternetIcon(apidl[0], psiteChild);
  1201.             psiteChild->Release();
  1202.         } 
  1203.         else 
  1204.         {
  1205.             LPITEMIDLIST pidl = NULL;
  1206.             if (apidl[0] && LOC_IsLocation(apidl[0])) 
  1207.             {
  1208.                 // if it's a location thing, pass in us
  1209.                 pidl = _pidlRoot;
  1210.             } 
  1211.             else 
  1212.             {
  1213.                 // this should never happen... the only sub item you
  1214.                 // can bind to and get info for is a location
  1215.                 ASSERT(0);
  1216.                 //pidl = apidl[0];
  1217.             }
  1218.             *ppvOut = (IExtractIcon*)new CDocIcon(pidl);
  1219.         }
  1220.         hres = (*ppvOut) ? S_OK : E_OUTOFMEMORY;
  1221.     }
  1222.     else if (IsEqualIID(riid, IID_IContextMenu)) 
  1223.     {
  1224.         LPSTR pszProtocol;
  1225.         if (GetCommonProtocol(apidl, cidl, &pszProtocol))
  1226.         {
  1227.             //
  1228.             // Whew, at least all the pidls are of the same protocol,
  1229.             // so we only need to call one handler.
  1230.             //
  1231.             if (pszProtocol)
  1232.             {
  1233.                 IShellFolder *psfHandler;
  1234.                 if (_GetProtocolHandler(pszProtocol, &psfHandler))
  1235.                 {
  1236.                     hres = psfHandler->GetUIObjectOf(hwndOwner, cidl, apidl, riid, prgfInOut, ppvOut);
  1237.                     psfHandler->Release();
  1238.                     return hres;
  1239.                 }
  1240.                 ASSERT(FAILED(hres));
  1241.             }
  1242.             else
  1243.             {
  1244.                 *ppvOut = (IContextMenu*)new CDocMenu(_pidlRoot, apidl[0]);
  1245.                 hres = (*ppvOut) ? S_OK : E_OUTOFMEMORY;
  1246.             }
  1247.         }
  1248.         else
  1249.         {
  1250.             //
  1251.             // BUGBUG in the multiple pidl case, should we get
  1252.             // the menu of the first item and use it?  If we do
  1253.             // it that way, we need to be sure that all possible
  1254.             // IContextMenus (including our CDocMenu) must be
  1255.             // able to identify their pidls and process only them.
  1256.             //
  1257.             ASSERT(FAILED(hres));
  1258.         }
  1259.     }
  1260.     else if (IsEqualIID(riid, IID_IDataObject))
  1261.     {
  1262.         if (cidl == 1)
  1263.         {
  1264.             LPSTR pszURL = _PidlToUrlPtr(apidl[0]);
  1265.             if (pszURL)
  1266.             {
  1267.                 IUniformResourceLocator *purl;
  1268.                 hres = CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER,
  1269.                         IID_IUniformResourceLocator, (void **)&purl);
  1270.                 if (SUCCEEDED(hres))
  1271.                 {
  1272.                     hres = purl->SetURL(pszURL, 0);
  1273.                     
  1274.                     if (SUCCEEDED(hres))
  1275.                     {
  1276.                         IShellLink * psl;
  1277.                         if (SUCCEEDED(purl->QueryInterface(IID_IShellLink, (LPVOID *)&psl)))
  1278.                         {
  1279.                             STRRET srName;
  1280.                             TCHAR szName[MAX_PATH];
  1281.                             if (SUCCEEDED(GetDisplayNameOf(apidl[0], SHGDN_INFOLDER, &srName)))
  1282.                             {
  1283.                                 StrRetToStrN(szName, ARRAYSIZE(szName), &srName, apidl[0]);
  1284.                                 PathRenameExtension(szName, TEXT(".url"));
  1285.                                 psl->SetDescription(szName);
  1286.                             }
  1287.                             psl->Release();
  1288.                         }
  1289.                         
  1290.                         hres = purl->QueryInterface(IID_IDataObject, ppvOut);
  1291.                     }
  1292.                     purl->Release();
  1293.                 }
  1294.             }       
  1295.         }
  1296.         else
  1297.             ASSERT(FAILED(hres));
  1298.     }
  1299.     else
  1300.         ASSERT(FAILED(hres));
  1301.     return hres;
  1302. }
  1303. HRESULT CDocObjectFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName)
  1304. {
  1305.     HRESULT hres = S_OK;    // assume success
  1306.     // Special case for IE 3.0 frame.
  1307.     if (_IsInternetFolder())
  1308.     {
  1309.         //
  1310.         // Check for wrapped pidl.
  1311.         //
  1312.         if (_IsPidlProtocol(pidl))
  1313.         {
  1314.             IShellFolder *psfHandler;
  1315.             if (_GetProtocolHandlerFromPidl(pidl, &psfHandler))
  1316.             {
  1317.                 hres = psfHandler->GetDisplayNameOf(pidl, uFlags, lpName);
  1318.                 psfHandler->Release();
  1319.             }
  1320.             else
  1321.             {
  1322.                 hres = E_FAIL;
  1323.             }
  1324.             return hres;
  1325.         }
  1326.         Site* psite = PidlToSite(pidl, _psite);
  1327.         if (psite != INVALID_SITE) {
  1328.             CHAR szBuf[MAX_URL_STRING];
  1329.             szBuf[0] = 0;
  1330.             if (psite->IsInternetRoot()) {
  1331.                 ENTERCRITICAL;
  1332.                 if ((uFlags & (SHGDN_FORPARSING | SHGDN_FORADDRESSBAR)) ||
  1333.                     !g_szStartPageTitle) {
  1334.                     LEAVECRITICAL;
  1335.                     DWORD  cbSize = ARRAYSIZE(szBuf);
  1336.                     hres = _GetStdLocation(szBuf, ARRAYSIZE(szBuf), IDM_GOHOME);
  1337.                     // We treat URLs from the registry like they were typed on
  1338.                     // the address bar.
  1339.                     if SUCCEEDED(hres) {
  1340.                         ParseURLFromOutsideSource (szBuf, szBuf, &cbSize);
  1341.                     }
  1342.                 } else {
  1343.                     //it's the start page: if we have the title stored in g_szStartPageTitle,
  1344.                     //use it; otherwise, go thru _GetStdLocation.  This is a special case.
  1345.                     WideCharToMultiByte(CP_ACP,0,g_szStartPageTitle,-1,
  1346.                         szBuf,ARRAYSIZE(szBuf),NULL,NULL);
  1347.                     LEAVECRITICAL;
  1348.                 }
  1349.             } else {
  1350.                 Site* psiteLocation = NULL;
  1351.                 LPSTR pszName = NULL;
  1352.                 // default
  1353.                 if (uFlags & (SHGDN_FORPARSING | SHGDN_FORADDRESSBAR)) {
  1354.                     if (psite->GetType() == URLID_LOCATION) {
  1355.                         psiteLocation = psite;
  1356.                         psite = psiteLocation->GetParent();
  1357.                     }
  1358.                     pszName = psite->GetUrl();
  1359.                     if (pszName) {
  1360.                         DWORD dwSize = ARRAYSIZE(szBuf);
  1361.                         UrlCanonicalize(pszName, szBuf, &dwSize, 0);
  1362.                     }
  1363.                 } else {
  1364.                     pszName = psite->GetName();
  1365.                     lstrcpyn(szBuf, pszName, ARRAYSIZE(szBuf));
  1366.                 }
  1367.                 if (psiteLocation) {
  1368.                     if (uFlags & (SHGDN_FORPARSING | SHGDN_FORADDRESSBAR) &&
  1369.                         (lstrlen(szBuf) + lstrlen(psiteLocation->GetUrl())) < ARRAYSIZE(szBuf)) {
  1370.                         lstrcat(szBuf, psiteLocation->GetUrl());
  1371.                     }
  1372.                     psiteLocation->Release();
  1373.                 }
  1374.                 psite->Release();
  1375.             }
  1376.             if (SUCCEEDED(hres)) {
  1377.                 if (lstrlen(szBuf) < ARRAYSIZE(lpName->cStr)) {
  1378.                     lpName->uType = STRRET_CSTR;
  1379.                     lstrcpy(lpName->cStr, szBuf);
  1380.                     ASSERT(hres==S_OK);
  1381.                 } else {
  1382.                     lpName->uType = STRRET_OLESTR;
  1383.                     lpName->pOleStr = MakeWideStrFromAnsi(szBuf, STR_OLESTR);
  1384.                     hres = lpName->pOleStr ? S_OK : E_OUTOFMEMORY;
  1385.                 }
  1386.             }
  1387.             return hres;
  1388.         }
  1389.         else //INVALID_SITE: this case happens when no Site exists yet for this pidl
  1390.         {
  1391.             //if you're passed a pidl that has no associated site
  1392.             LPITEMIDLIST pidlLast = ILFindLastID(pidl);
  1393.             if (pidlLast && !ILIsEmpty(pidlLast) && ((PURLID)pidlLast)->bType == URLID_LOCATION &&
  1394.                 pidl != pidlLast)
  1395.             {
  1396.                 LPITEMIDLIST pidl2;
  1397.                 CHAR szUrl[MAX_URL_STRING];
  1398.                 lpName->uType = STRRET_WSTR;
  1399.                 pidl2 = (LPITEMIDLIST)pidl;
  1400.                 while (pidl != pidlLast)
  1401.                 {
  1402.                     pidl2 = (LPITEMIDLIST)pidl;
  1403.                     pidl = _ILNext(pidl);
  1404.                 }
  1405.                 if ((lstrlen(PidlToUrlPtr(pidl2))+lstrlen(PidlToUrlPtr(pidlLast)) < ARRAYSIZE(szUrl)))
  1406.                 {
  1407.                     wsprintf(szUrl, TEXT("%s%s"), PidlToUrlPtr(pidl2), PidlToUrlPtr(pidlLast));
  1408.                     lpName->pOleStr = MakeWideStrFromAnsi(szUrl,STR_OLESTR);
  1409.                     return lpName->pOleStr ? S_OK : E_OUTOFMEMORY;
  1410.                 }
  1411.             }
  1412.             // fall through
  1413.         }
  1414.     } else {
  1415.         // BUGBUG: for the location, we probably want to return something better that
  1416.         // #location...  at least for the address bar
  1417.         if (LOC_IsLocation(pidl)) {
  1418.             LPIDFILELOCATION pidlLoc = (LPIDFILELOCATION)pidl;
  1419.             lpName->uType = STRRET_OLESTR;
  1420.             lpName->pOleStr = (LPWSTR)OleAlloc(sizeof(WCHAR) * (1+ualstrlenW(LOC_GetLocation(pidlLoc))));
  1421.             if (lpName->pOleStr) {
  1422.                 ualstrcpyW(lpName->pOleStr, pidlLoc->cLocation);
  1423.                 ASSERT(hres == S_OK);
  1424.             } else {
  1425.                 hres = E_OUTOFMEMORY;
  1426.             }
  1427.             return hres;
  1428.         }
  1429.     }
  1430.     lpName->uType = STRRET_OFFSET;
  1431.     lpName->uOffset = (LPBYTE)(_PidlToUrlPtr(pidl)) - (LPBYTE)pidl;
  1432.     return S_OK;
  1433. }
  1434. HRESULT CDocObjectFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl,
  1435.                                  LPCOLESTR lpszName, DWORD uFlags,
  1436.                                  LPITEMIDLIST * ppidlOut)
  1437. {
  1438.     HRESULT hres = E_FAIL;
  1439.     Site* psite;
  1440.     //
  1441.     // Check for wrapped pidl.
  1442.     //
  1443.     if (_IsPidlProtocol(pidl))
  1444.     {
  1445.         IShellFolder *psfHandler;
  1446.         if (_GetProtocolHandlerFromPidl(pidl, &psfHandler))
  1447.         {
  1448.             hres = psfHandler->SetNameOf(hwndOwner, pidl, lpszName, uFlags, ppidlOut);
  1449.             psfHandler->Release();
  1450.         }
  1451.         else
  1452.         {
  1453.             hres = E_FAIL;
  1454.         }
  1455.         return hres;
  1456.     }
  1457.     if (!ILIsEmpty(pidl)) {
  1458.         psite = PidlToSite(pidl, _psite);
  1459.     } else {
  1460.         psite = _psite;
  1461.         _psite->AddRef();
  1462.     }
  1463.     if (psite) {
  1464.         TCHAR szTitle[256];
  1465.         OleStrToStrN(szTitle, ARRAYSIZE(szTitle), lpszName, (UINT)-1);
  1466.         if (psite->SetName(szTitle))
  1467.             hres = NOERROR;
  1468.         psite->Release();
  1469.     } else {
  1470.         // then we're setting the name for the start page...
  1471.         if (g_szStartPageTitle)
  1472.             LocalFree(g_szStartPageTitle);
  1473.         g_szStartPageTitle = StrDupW(lpszName);
  1474.     }
  1475.     return E_FAIL;
  1476. }
  1477. HRESULT CDocObjectFolder::GetClassID(LPCLSID lpClassID)
  1478. {
  1479.     *lpClassID = _rclsid;
  1480.     return S_OK;
  1481. }
  1482. HRESULT CDocObjectFolder::Initialize(LPCITEMIDLIST pidl)
  1483. {
  1484.     IPFMSG(TEXT("Initialize"));
  1485.     if (_pidlRoot) {
  1486.         ILFree(_pidlRoot);
  1487.         _pidlRoot = NULL;
  1488.     }
  1489.     if (pidl) {
  1490.         _pidlRoot = ILClone(pidl);
  1491.     }
  1492.     return S_OK;
  1493. }
  1494. HRESULT CDocObjectFolder::GetIconOf(LPCITEMIDLIST pidl, UINT flags,
  1495. LPINT lpIconIndex)
  1496. {
  1497.     SHFILEINFO sfi;
  1498.     LPCSTR psz;
  1499.     sfi.iIcon = 0;
  1500.     char szLocation[MAX_URL_STRING];
  1501.     //
  1502.     // Check for wrapped pidl.
  1503.     //
  1504.     if (_IsPidlProtocol(pidl))
  1505.     {
  1506.         HRESULT hres = S_FALSE;
  1507.         IShellFolder *psfHandler;
  1508.         if (_GetProtocolHandlerFromPidl(pidl, &psfHandler))
  1509.         {
  1510.             IShellIcon *psi;
  1511.             if (SUCCEEDED(psfHandler->QueryInterface(IID_IShellIcon, (LPVOID *)&psi)))
  1512.             {
  1513.                 hres = psi->GetIconOf(pidl, flags, lpIconIndex);
  1514.                 psi->Release();
  1515.             }
  1516.             psfHandler->Release();
  1517.         }
  1518.         return hres;
  1519.     }
  1520.     if (!_IsInternetFolder() && LOC_IsLocation(pidl)) {
  1521.         // if it's a location, the icon is the same as for the "this" icon
  1522.         SHGetPathFromIDList(_pidlRoot, szLocation);
  1523.         psz = szLocation;
  1524.     } else {
  1525.         psz = _PidlToUrlPtr(pidl);
  1526.     }
  1527.     DWORD ret = SHGetFileInfo(psz,
  1528.                               FILE_ATTRIBUTE_NORMAL,
  1529.                               &sfi,
  1530.                               sizeof(sfi),
  1531.                               SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES);
  1532.     DebugMsg(0, TEXT("sdv DOF::GetIconOf returns %d with iIcon=%d"), ret, sfi.iIcon);
  1533.     *lpIconIndex = sfi.iIcon;
  1534.     return S_OK;
  1535. }
  1536. HRESULT CMallocItem::QueryInterface(REFIID riid, LPVOID *ppvObj)
  1537. {
  1538.     if (IsEqualIID(riid, IID_IMalloc) || IsEqualIID(riid, IID_IUnknown))
  1539.     {
  1540.         *ppvObj = (IMalloc *)this;
  1541.     }
  1542.     else
  1543.     {
  1544.         *ppvObj = NULL;
  1545.         return E_NOINTERFACE;
  1546.     }
  1547.     AddRef();
  1548.     return S_OK;
  1549. }
  1550. ULONG CMallocItem::AddRef()
  1551. {
  1552.     return ++_cRef;
  1553. }
  1554. ULONG CMallocItem::Release()
  1555. {
  1556.     if (--_cRef > 0) {
  1557.         return _cRef;
  1558.     }
  1559.     delete this;
  1560.     return 0;
  1561. }
  1562. LPVOID CMallocItem::Alloc(ULONG cb)
  1563. {
  1564.     WORD cbActualSize;
  1565.     PDELEGATEITEMID pidl;
  1566.     cbActualSize = SIZEOF(DELEGATEITEMID) - 1 +     // header
  1567.                    cb +                             // inner
  1568.                    lstrlenA(_pszProtocol) + 1;      // outer + sz terminator
  1569.     pidl = (PDELEGATEITEMID)SHAlloc(cbActualSize + 2);  // +2 for pidl term
  1570.     if (pidl)
  1571.     {
  1572.         pidl->cbSize = cbActualSize;
  1573.         pidl->wOuter = PDID_SIG;
  1574.         pidl->cbInner = (WORD)cb;
  1575.         lstrcpyA((CHAR *)&(pidl->rgb[cb]), _pszProtocol);
  1576.         *(WORD *)&(((BYTE *)pidl)[cbActualSize])=0;
  1577.     }
  1578.     return pidl;
  1579. }
  1580. LPVOID CMallocItem::Realloc(LPVOID pv, ULONG cb)
  1581. {
  1582.     return NULL;
  1583. }
  1584. void CMallocItem::Free(LPVOID pv)
  1585. {
  1586.     SHFree(pv);
  1587. }
  1588. ULONG CMallocItem::GetSize(LPVOID pv)
  1589. {
  1590.     return (ULONG)-1;
  1591. }
  1592. int CMallocItem::DidAlloc(LPVOID pv)
  1593. {
  1594.     return -1;
  1595. }
  1596. void CMallocItem::HeapMinimize()
  1597. {
  1598. }
  1599. CMallocItem::CMallocItem(LPCSTR szProtocol) : _cRef(1)
  1600. {
  1601.     DebugMsg(TF_SHDLIFE, TEXT("ctor CMallocItem %x"), this);
  1602.     int cbSize = lstrlenA(szProtocol) + 1;
  1603.     _pszProtocol = (LPSTR)SHAlloc(cbSize);
  1604.     if (_pszProtocol)
  1605.     {
  1606.         lstrcpyA(_pszProtocol, szProtocol);
  1607.     }
  1608. }
  1609. CMallocItem::~CMallocItem()
  1610. {
  1611.     DebugMsg(TF_SHDLIFE, TEXT("dtor CMallocItem %x"), this);
  1612.     if (_pszProtocol)
  1613.     {
  1614.         SHFree(_pszProtocol);
  1615.         _pszProtocol = NULL;
  1616.     }
  1617. }
  1618. HRESULT CDocIcon::QueryInterface(REFIID riid, LPVOID * ppvObj)
  1619. {
  1620.     if (IsEqualIID(riid, IID_IExtractIcon) || IsEqualIID(riid, IID_IUnknown))
  1621.     {
  1622.         *ppvObj = (IExtractIcon*)this;
  1623.     }
  1624.     else
  1625.     {
  1626.         *ppvObj = NULL;
  1627.         return E_NOINTERFACE;
  1628.     }
  1629.     AddRef();
  1630.     return S_OK;
  1631. }
  1632. ULONG CDocIcon::AddRef()
  1633. {
  1634.     return ++_cRef;
  1635. }
  1636. ULONG CDocIcon::Release()
  1637. {
  1638.     if (--_cRef > 0) {
  1639.         return _cRef;
  1640.     }
  1641.     delete this;
  1642.     return 0;
  1643. }
  1644. HRESULT CDocIcon::_GetIconLocationForFile(LPSTR pszFile,
  1645.                          UINT   uFlags,
  1646.                          LPSTR  szIconFile,
  1647.                          UINT   cchMax,
  1648.                          int   * piIndex,
  1649.                          UINT  * pwFlags)
  1650. {
  1651.     *pwFlags = GIL_NOTFILENAME;
  1652.     szIconFile[0] = '*';
  1653.     szIconFile[1] = '';
  1654.     SHFILEINFO sfi;
  1655.     sfi.iIcon = 0;
  1656.     DWORD ret = SHGetFileInfo(pszFile,
  1657.                               FILE_ATTRIBUTE_NORMAL,
  1658.                               &sfi,
  1659.                               sizeof(sfi),
  1660.                               SHGFI_SYSICONINDEX|SHGFI_USEFILEATTRIBUTES);
  1661.     DebugMsg(0, TEXT("sdv DOF::GetIconLocation returns %d with iIcon=%d"), ret, sfi.iIcon);
  1662.     // "*" as the file name means iIndex is already a system icon index.
  1663.     *piIndex = sfi.iIcon;
  1664.     return S_OK;
  1665. }
  1666. HRESULT CDocIcon::GetIconLocation(
  1667.                          UINT   uFlags,
  1668.                          LPSTR  szIconFile,
  1669.                          UINT   cchMax,
  1670.                          int   * piIndex,
  1671.                          UINT  * pwFlags)
  1672. {
  1673.     if (_pidl==NULL) {
  1674. return E_FAIL;
  1675.     }
  1676.     char szFile[MAX_PATH];
  1677.     SHGetPathFromIDList(_pidl, szFile);
  1678.     return _GetIconLocationForFile(szFile, uFlags, szIconFile, cchMax, piIndex, pwFlags);
  1679. }
  1680. HRESULT CDocIcon::Extract(
  1681.                            LPCSTR pszFile,
  1682.                            UINT   nIconIndex,
  1683.                            HICON   *phiconLarge,
  1684.                            HICON   *phiconSmall,
  1685.                            UINT    nIconSize)
  1686. {
  1687.     DebugMsg(0, TEXT("sdv ER DOF::Extract called (shouldn't be called!)"));
  1688.     return E_FAIL;
  1689. }
  1690. CDocIcon::CDocIcon(LPCITEMIDLIST pidl) : _cRef(1)
  1691. {
  1692.     DebugMsg(TF_SHDLIFE, TEXT("ctor CDocIcon %x"), this);
  1693.     if (pidl) {
  1694.         _pidl = ILClone(pidl);
  1695.     }
  1696. }
  1697. CDocIcon::~CDocIcon()
  1698. {
  1699.     DebugMsg(TF_SHDLIFE, TEXT("dtor CDocIcon %x"), this);
  1700.     if (_pidl) {
  1701. ILFree(_pidl);
  1702.     }
  1703. }
  1704. /// Internet IExtractIcon impl.
  1705. CInternetIcon::CInternetIcon(LPCITEMIDLIST pidl, Site* psite) :
  1706.     CDocIcon(pidl),
  1707.     _psite(psite)
  1708. {
  1709.     DebugMsg(TF_SHDLIFE, TEXT("ctor CInternetIcon %x"), this);
  1710.     if (_psite)
  1711.         _psite->AddRef();
  1712. }
  1713. CInternetIcon::~CInternetIcon()
  1714. {
  1715.     DebugMsg(TF_SHDLIFE, TEXT("dtor CInternetIcon %x"), this);
  1716.     if (_psite)
  1717.         _psite->Release();
  1718. }
  1719. HRESULT CInternetIcon::GetIconLocation(
  1720.                          UINT   uFlags,
  1721.                          LPSTR  szIconFile,
  1722.                          UINT   cchMax,
  1723.                          int   * piIndex,
  1724.                          UINT  * pwFlags)
  1725. {
  1726.     if (_pidl==NULL) {
  1727. return E_FAIL;
  1728.     }
  1729.     *pwFlags = GIL_NOTFILENAME;
  1730.     szIconFile[0] = '*';
  1731.     szIconFile[1] = '';
  1732.     if(_psite) {
  1733.         *piIndex = _psite->SysIconIndex();
  1734.     }
  1735.     if (*piIndex == -1) {
  1736.         return _GetIconLocationForFile(_PidlToUrlPtr(_pidl), uFlags,
  1737.             szIconFile, cchMax, piIndex, pwFlags);
  1738.     }
  1739.     return S_OK;
  1740. }
  1741. HRESULT CDocMenu::QueryInterface(REFIID riid, LPVOID * ppvObj)
  1742. {
  1743.     if (IsEqualIID(riid, IID_IContextMenu) || IsEqualIID(riid, IID_IUnknown))
  1744.     {
  1745.         *ppvObj = SAFECAST(this, IContextMenu*);
  1746.     }
  1747.     else
  1748.     {
  1749.         *ppvObj = NULL;
  1750.         return E_NOINTERFACE;
  1751.     }
  1752.     AddRef();
  1753.     return S_OK;
  1754. }
  1755. ULONG CDocMenu::AddRef()
  1756. {
  1757.     return ++_cRef;
  1758. }
  1759. ULONG CDocMenu::Release()
  1760. {
  1761.     if (--_cRef > 0) {
  1762.         return _cRef;
  1763.     }
  1764.     delete this;
  1765.     return 0;
  1766. }
  1767. CDocMenu::CDocMenu(LPCITEMIDLIST pidlRoot, LPCITEMIDLIST pidlItem) : _cRef(1)
  1768. {
  1769.     DebugMsg(TF_SHDLIFE, TEXT("ctor CDocMenu %x"), this);
  1770.     if (pidlRoot && pidlItem) {
  1771. _pidl = ILCombine(pidlRoot, pidlItem);
  1772.     }
  1773. }
  1774. CDocMenu::~CDocMenu()
  1775. {
  1776.     DebugMsg(TF_SHDLIFE, TEXT("dtor CDocMenu %x"), this);
  1777.     if (_pidl) {
  1778. ILFree(_pidl);
  1779.     }
  1780. }
  1781. HRESULT CDocMenu::QueryContextMenu(HMENU hmenu,
  1782.                                 UINT indexMenu,
  1783.                                 UINT idCmdFirst,
  1784.                                 UINT idCmdLast,
  1785.                                 UINT uFlags)
  1786. {
  1787.     TCHAR szOpen[64];
  1788.     LoadString(HINST_THISDLL, IDS_OPEN, szOpen, ARRAYSIZE(szOpen));
  1789.     
  1790.     InsertMenu(hmenu, indexMenu, MF_BYPOSITION, idCmdFirst, szOpen);
  1791.     return ResultFromShort(1);
  1792. }
  1793. //
  1794. //
  1795. // typedef struct _CMINVOKECOMMANDINFO {
  1796. //     DWORD cbSize;        // sizeof(CMINVOKECOMMANDINFO)
  1797. //     DWORD fMask;         // any combination of CMIC_MASK_*
  1798. //     HWND hwnd;           // might be NULL (indicating no owner window)
  1799. //     LPCSTR lpVerb;       // either a string or MAKEINTRESOURCE(idOffset)
  1800. //     LPCSTR lpParameters; // might be NULL (indicating no parameter)
  1801. //     LPCSTR lpDirectory;  // might be NULL (indicating no specific directory)
  1802. //     int nShow;           // one of SW_ values for ShowWindow() API
  1803. //
  1804. //     DWORD dwHotKey;
  1805. //     HANDLE hIcon;
  1806. // } CMINVOKECOMMANDINFO,  *LPCMINVOKECOMMANDINFO;
  1807. //
  1808. HRESULT CDocMenu::InvokeCommand(LPCMINVOKECOMMANDINFO lpici)
  1809. {
  1810.     if (HIWORD(lpici->lpVerb)) {
  1811. if (lstrcmp(lpici->lpVerb, TEXT("open"))) {
  1812.     return E_INVALIDARG;
  1813. }
  1814.     }
  1815.     SHELLEXECUTEINFO sei = {
  1816. sizeof(SHELLEXECUTEINFO),
  1817. SEE_MASK_IDLIST | SEE_MASK_CLASSNAME,
  1818. lpici->hwnd,
  1819. TEXT("open"),
  1820. NULL,
  1821. NULL,
  1822. NULL,
  1823. SW_NORMAL,
  1824. NULL,
  1825. (LPVOID)_pidl,
  1826. TEXT("Folder"),
  1827. NULL,
  1828. 0,
  1829. NULL,
  1830. NULL
  1831.     };
  1832.     BOOL fRet=ShellExecuteEx(&sei);
  1833.     DebugMsg(0, TEXT("sdv TR ::InvokeCommand ShellEx returned %d"), fRet);
  1834.     return S_OK;
  1835. }
  1836. HRESULT CDocMenu::GetCommandString(UINT        idCmd,
  1837.                                 UINT        uType,
  1838.                                 UINT      * pwReserved,
  1839.                                 LPSTR       pszName,
  1840.                                 UINT        cchMax)
  1841. {
  1842.     HRESULT hres = E_INVALIDARG;
  1843.     if (idCmd==0)
  1844.     {
  1845. if (uType == GCS_VERB) {
  1846.     lstrcpy(pszName, TEXT("open"));
  1847.     hres = S_OK;
  1848. }
  1849. else if ((uType & GCS_HELPTEXT) != 0)
  1850. {
  1851.     // BUGBUG: NLS
  1852.     lstrcpy(pszName, TEXT("Open"));
  1853.     hres = S_OK;
  1854. }
  1855.     }
  1856.     return S_OK;
  1857. }
  1858. class CDocObjMenuExt : public CDocMenu, public IShellExtInit
  1859. {
  1860. public:
  1861.     // *** IUnknown methods ***
  1862.     STDMETHOD(QueryInterface) (REFIID riid, LPVOID * ppvObj);
  1863.     STDMETHOD_(ULONG,AddRef) () { return CDocMenu::AddRef(); }
  1864.     STDMETHOD_(ULONG,Release) () { return CDocMenu::Release(); }
  1865.     // IContextMenu
  1866.     STDMETHOD(QueryContextMenu)(HMENU hmenu,
  1867.                                 UINT indexMenu,
  1868.                                 UINT idCmdFirst,
  1869.                                 UINT idCmdLast,
  1870.                                 UINT uFlags);
  1871.     // *** IShellExtInit methods ***
  1872.     STDMETHOD(Initialize)(LPCITEMIDLIST pidlFolder,
  1873.                           IDataObject *lpdobj, HKEY hkeyProgID);
  1874.     CDocObjMenuExt() : CDocMenu(NULL, NULL) {}
  1875. protected:
  1876.     DWORD _dwAttrib;
  1877. };
  1878. HRESULT CDocObjMenuExt::QueryInterface(REFIID riid, void ** ppvObj)
  1879. {
  1880.     if (IsEqualIID(riid, IID_IShellExtInit))
  1881.     {
  1882.         *ppvObj = (IShellExtInit*)this;
  1883.         _cRef++;
  1884.         return S_OK;
  1885.     }
  1886.     return CDocMenu::QueryInterface(riid, ppvObj);
  1887. }
  1888. HRESULT CDocObjMenuExt::QueryContextMenu(HMENU hmenu,
  1889.                                 UINT indexMenu,
  1890.                                 UINT idCmdFirst,
  1891.                                 UINT idCmdLast,
  1892.                                 UINT uFlags)
  1893. {
  1894.     HRESULT hres = ResultFromShort(0);
  1895.     if (_pidl && (_dwAttrib & SFGAO_FOLDER))
  1896.     {
  1897. // BUGBUG: NLS
  1898. InsertMenu(hmenu, indexMenu, MF_BYPOSITION, idCmdFirst, TEXT("Open in &Explorer"));
  1899. hres = ResultFromShort(1);
  1900.     }
  1901.     return hres;
  1902. }
  1903. HRESULT CDocObjMenuExt::Initialize(LPCITEMIDLIST pidlFolder,
  1904.                           IDataObject *pdtobj, HKEY hkeyProgID)
  1905. {
  1906.     HRESULT hres = S_OK;
  1907.     if (_pidl) {
  1908. ILFree(_pidl);
  1909. _pidl = NULL;
  1910.     }
  1911.     STGMEDIUM medium;
  1912.     FORMATETC fmte = {CF_HDROP, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  1913.     hres = pdtobj->GetData(&fmte, &medium);
  1914.     if (SUCCEEDED(hres))
  1915.     {
  1916. TCHAR szPath[MAX_PATH];
  1917. if (DragQueryFile((HDROP)medium.hGlobal, 0, szPath, ARRAYSIZE(szPath)))
  1918. {
  1919.     _dwAttrib = SFGAO_FOLDER;
  1920.     hres = SHILCreateFromPath(szPath, &_pidl, &_dwAttrib);
  1921.     if (FAILED(hres)) {
  1922. _dwAttrib = 0;
  1923.     }
  1924. }
  1925. ReleaseStgMedium(&medium);
  1926.     }
  1927.     return hres;
  1928. }
  1929. HRESULT CDocObjMenuExt_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  1930. {
  1931.     *ppunk = NULL;
  1932.     if (pUnkOuter)
  1933.         return CLASS_E_NOAGGREGATION;
  1934.     DebugMsg(0, TEXT("shd - TR CDocObjmenuExt_CreateInstance called"));
  1935.     CDocObjMenuExt* pdomx = new CDocObjMenuExt();
  1936.     if (pdomx) {
  1937. *ppunk = (IContextMenu*)pdomx;
  1938. return S_OK;
  1939.     }
  1940.     return E_OUTOFMEMORY;
  1941. }
  1942. //// CInetEnum
  1943. HRESULT CInetEnum::QueryInterface(REFIID riid, LPVOID * ppvObj)
  1944. {
  1945.     if (IsEqualIID(riid, IID_IEnumIDList) || IsEqualIID(riid, IID_IUnknown))
  1946.     {
  1947.         *ppvObj = SAFECAST(this, IEnumIDList *);
  1948.     }
  1949.     else
  1950.     {
  1951.         *ppvObj = NULL;
  1952.         return E_NOINTERFACE;
  1953.     }
  1954.     AddRef();
  1955.     return S_OK;
  1956. }
  1957. ULONG CInetEnum::AddRef()
  1958. {
  1959.     return ++_cRef;
  1960. }
  1961. ULONG CInetEnum::Release()
  1962. {
  1963.     if (--_cRef > 0) {
  1964. return _cRef;
  1965.     }
  1966.     delete this;
  1967.     return 0;
  1968. }
  1969. HRESULT CInetEnum::Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched)
  1970. {
  1971.     UINT celtFetched = 0;
  1972.     HRESULT hres = S_FALSE;
  1973.     //
  1974.     // WARNING: Never return from within this critical section!
  1975.     //
  1976.     DebugMsg(0, TEXT("sdv TR INE::Next called when _iCur is %d and DPA has %d items"),
  1977.              _iCur, _psite->GetCount());
  1978.     // it's ok if _psite is NULL....
  1979.     Site* psite = _psite->Enum(_iCur);
  1980.     if (psite) {
  1981.         _iCur++;
  1982.         rgelt[0] = psite->CloneID();
  1983.         if (rgelt[0]) {
  1984.             celtFetched = 1;
  1985.             hres = S_OK;
  1986.         } else {
  1987.             hres = E_OUTOFMEMORY;
  1988.         }
  1989.     }
  1990.     if (pceltFetched) {
  1991.         *pceltFetched = celtFetched;
  1992.     }
  1993.     return hres;
  1994. }
  1995. HRESULT CInetEnum::Skip(ULONG celt)
  1996. {
  1997.     return E_NOTIMPL;
  1998. }
  1999. HRESULT CInetEnum::Reset()
  2000. {
  2001.     _iCur = 0;
  2002.     return S_OK;
  2003. }
  2004. HRESULT CInetEnum::Clone(IEnumIDList **ppenum)
  2005. {
  2006.     *ppenum = NULL;
  2007.     return E_NOTIMPL;
  2008. }
  2009. CInetEnum::~CInetEnum()
  2010. {
  2011.     DebugMsg(TF_SHDLIFE, TEXT("dtor CInetEnum %x"), this);
  2012.     if (_psite)
  2013.         _psite->Release();
  2014. }
  2015. CInetEnum::CInetEnum(Site* psite) :
  2016.     _cRef(1),
  2017.     _iCur(0),
  2018.     _psite(psite)
  2019. {
  2020.     DebugMsg(TF_SHDLIFE, TEXT("ctor CInetEnum %x"), this);
  2021.     if (_psite)
  2022.         _psite->AddRef();
  2023. }
  2024. STDAPI MonikerFromURL(LPCWSTR wszPath, IMoniker** ppmk)
  2025. {
  2026.     HRESULT hres = CreateURLMoniker(NULL, wszPath, ppmk);
  2027.     if (FAILED(hres)) 
  2028.     {
  2029.         IBindCtx* pbc;
  2030.         hres = CreateBindCtx(0, &pbc);
  2031.         if (SUCCEEDED(hres)) 
  2032.         {
  2033.             // Fall back to a system (file) moniker
  2034.             ULONG cchEaten = 0;
  2035.             hres = MkParseDisplayName(pbc, wszPath, &cchEaten, ppmk);
  2036.             pbc->Release();
  2037.         }
  2038.     }
  2039.     return hres;
  2040. }
  2041. STDAPI MonikerFromString(LPCTSTR szPath, IMoniker** ppmk)
  2042. {
  2043.     WCHAR wszPath[MAX_URL_STRING];
  2044.     MultiByteToWideChar(CP_ACP, 0, szPath, -1, wszPath, ARRAYSIZE(wszPath));
  2045.     return MonikerFromURL(wszPath, ppmk);
  2046. }
  2047. HRESULT InitPSFInternet()
  2048. {
  2049.     HRESULT hres = S_OK;
  2050.     if (!g_psfInternet) 
  2051.     {
  2052.         hres = SHCoCreateInstance(NULL, &CLSID_CURLFolder, NULL, 
  2053.             IID_IShellFolder, (void **)&g_psfInternet);
  2054.         ASSERT(SUCCEEDED(hres));
  2055.     }
  2056.     return hres;
  2057. }
  2058. LPCSTR PidlToUrlPtr(LPCITEMIDLIST pidl)
  2059. {
  2060.     return _PidlToUrlPtr((PURLID)pidl);
  2061. }
  2062. BYTE   URLPidlType(LPCITEMIDLIST pidl)
  2063. {
  2064.     return _URLPidlType((PURLID)pidl);
  2065. }
  2066. LPCSTR PidlToEURLPtr(LPCITEMIDLIST pidl, BYTE eurlID)
  2067. {
  2068.     LPCSTR pstr = _PidlToUrlPtr((PURLID)pidl);
  2069.     LPCSTR plast = pstr + (pidl->mkid.cb - FIELD_OFFSET(URLID, ach));
  2070.     //  advance past URL
  2071.     pstr += lstrlen(pstr)+1;
  2072.     while (pstr+1 < plast)
  2073.     {
  2074.         if ((BYTE)*pstr == eurlID) return ++pstr;
  2075.         //  PostData has cbBytes as first string followed by
  2076.         //  cbBytes BINARY data
  2077.         if ((BYTE)*pstr == EURL_POSTDATA)
  2078.         {
  2079.             int cbPostData;
  2080.             pstr++;
  2081.             cbPostData = StrToInt(pstr);
  2082.             pstr += lstrlen(pstr) + 1 + cbPostData;
  2083.         }
  2084.         else
  2085.         {
  2086.             pstr++;
  2087.             pstr += lstrlen(pstr) + 1;
  2088.         }
  2089.     }
  2090.     return NULL;
  2091. }
  2092. LPCSTR PidlToFrameNamePtr(LPCITEMIDLIST pidl)
  2093. {
  2094.     return PidlToEURLPtr(pidl, EURL_FRAMENAME);
  2095. }
  2096. LPCSTR PidlToHeadersPtr(LPCITEMIDLIST pidl)
  2097. {
  2098.     return PidlToEURLPtr(pidl, EURL_HEADERS);
  2099. }
  2100. void PidlToPostData(LPCITEMIDLIST pidl, LPCBYTE *pcb, int *cbPostData)
  2101. {
  2102.     LPCSTR psSize;
  2103.     psSize = PidlToEURLPtr(pidl, EURL_POSTDATA);
  2104.     if (!psSize)
  2105.     {
  2106.         *pcb = NULL;
  2107.     }
  2108.     else
  2109.     {
  2110.         *cbPostData = StrToInt(psSize);
  2111.         *pcb = (LPCBYTE) (psSize + lstrlen(psSize) + 1);
  2112.     }
  2113. }
  2114. BOOL IsEURLPidl(LPCITEMIDLIST pidl)
  2115. {
  2116.     BOOL bResult = FALSE;
  2117.     if (IsURLChild(pidl, TRUE))
  2118.     {
  2119.         LPCITEMIDLIST pidlURL = ILGetNext(pidl);
  2120.         if (pidlURL && URLPidlType(pidlURL) == URLID_URLBASE)
  2121.         {
  2122.             bResult = PidlToEURLPtr(pidlURL, EURL_FRAMENAME) ||
  2123.                       PidlToEURLPtr(pidlURL, EURL_HEADERS) ||
  2124.                       PidlToEURLPtr(pidlURL, EURL_POSTDATA);
  2125.         }
  2126.     }
  2127.     return bResult;
  2128. }
  2129. STDAPI_(BOOL) IEILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  2130. {
  2131.     UINT cb = ILGetSize(pidl1);
  2132.     if (cb == ILGetSize(pidl2) && memcmp(pidl1, pidl2, cb)==0) {
  2133.         return TRUE;
  2134.     }
  2135. #ifdef NO_IE_NAMESPACE
  2136.     if (IsURLChild(pidl1, TRUE)) {
  2137. if (IsURLChild(pidl2, TRUE)) {
  2138.             if (SUCCEEDED(InitPSFInternet())) {
  2139.         return g_psfInternet->CompareIDs(0, _ILNext(pidl1), _ILNext(pidl2)) == ResultFromShort(0);
  2140.             } else {
  2141.                 ASSERT(0);
  2142.                 return FALSE;   // We are not supposed to hit this code.
  2143.             }
  2144. } else {
  2145.     return FALSE;
  2146. }
  2147.     } else if (IsURLChild(pidl2, TRUE)) {
  2148. return FALSE;
  2149.     }
  2150. #endif
  2151.     LPIDFILELOCATION pid1Loc = IEMaybeHasLocationSpec(pidl1);
  2152.     LPIDFILELOCATION pid2Loc = IEMaybeHasLocationSpec(pidl2);
  2153.     if (pid1Loc && pid2Loc) {
  2154.         BOOL fRet = FALSE;;
  2155.         LPITEMIDLIST pidl1Clone = ILClone(pidl2);
  2156.         LPITEMIDLIST pidl2Clone = ILClone(pidl1);
  2157.         // they both have a location..  whack them off, and compare.
  2158.         if (pidl1Clone && pidl2Clone &&
  2159.             ILRemoveLocation(pidl1Clone, NULL) && ILRemoveLocation(pidl2Clone, NULL)) {
  2160.             if (ILIsEqual(pidl1Clone, pidl2Clone)) {
  2161.                 if (!ualstrcmpW(pid1Loc->cLocation, pid2Loc->cLocation))
  2162.                     fRet = TRUE;
  2163.             }
  2164.         }
  2165.         if (pidl1Clone)
  2166.             ILFree(pidl1Clone);
  2167.         if (pidl2Clone)
  2168.             ILFree(pidl2Clone);
  2169.         return fRet;
  2170.     } else if (pid1Loc || pid2Loc){
  2171.         // if either of them have it but they don't both have it,
  2172.         // they aren't equal
  2173.         return FALSE;
  2174.     }
  2175. #undef ILIsEqual
  2176.     return ILIsEqual(pidl1, pidl2);
  2177. #define ILIsEqual g_pfnILIsEqual
  2178. }
  2179. PFNILISEQUAL g_pfnILIsEqual  = NULL;
  2180. //
  2181. // HACK: Copied from regitems.c
  2182. //
  2183. #pragma pack(1)
  2184. typedef struct
  2185. {
  2186.     WORD    cb;
  2187.     BYTE    bFlags;
  2188.     BYTE    bReserved;      // This is to get DWORD alignment
  2189.     CLSID   clsid;
  2190. } IDREGITEM;
  2191. typedef struct
  2192. {
  2193.     IDREGITEM       idri;
  2194.     USHORT          cbNext;
  2195. //    operator LPCITEMIDLIST () const { return (LPCITEMIDLIST)&idri; };
  2196. } IDLREGITEM;
  2197. #pragma pack()
  2198. IDLREGITEM c_idlURLRoot =
  2199. {
  2200.     {
  2201.         SIZEOF(IDREGITEM),
  2202.         SHID_ROOT_REGITEM,
  2203.         0,
  2204.         // CLSID_ShellInetRoot goes here
  2205.     },
  2206.     0
  2207. };
  2208. LPCITEMIDLIST c_pidlURLRoot = (LPCITEMIDLIST)&c_idlURLRoot;
  2209. STDAPI_(BOOL) IsURLChild(LPCITEMIDLIST pidl, BOOL fIncludeHome)
  2210. {
  2211.     // if we're a rooted explorer, this is always false
  2212.     // this means we're definitely in nashville, so we shouldn't have a split
  2213.     // world
  2214.     if (IsRooted())
  2215.         return FALSE;
  2216.     //
  2217.     // it must be an absolute pidl with a root regitem id at the front
  2218.     //
  2219.     if ((pidl->mkid.cb != sizeof(IDREGITEM)) ||
  2220.         (pidl->mkid.abID[0] != SHID_ROOT_REGITEM))
  2221.     {
  2222.         return FALSE;
  2223.     }
  2224.     //
  2225.     // the clsid in the pidl must be our internet folder's
  2226.     //
  2227.     if (!IsEqualGUID(((IDREGITEM*)pidl)->clsid, c_idlURLRoot.idri.clsid))
  2228.     {
  2229.         //
  2230.         // this should never happen, find francish to debug it immediately
  2231.         //
  2232.         ASSERT(!IsEqualGUID(((IDREGITEM*)pidl)->clsid, CLSID_CURLFolder));
  2233.         return FALSE;
  2234.     }
  2235.     //
  2236.     // if it is a pidl to the internet root then it is the IE3 Home Page
  2237.     //
  2238.     if (ILIsEmpty(_ILNext(pidl))) 
  2239.         return fIncludeHome;
  2240.     //
  2241.     // otherwise it is our child if it is a site object
  2242.     //
  2243.     return (_URLDelegateID(_ILNext(pidl)) == SHID_INTERNET_SITE);
  2244. }
  2245. STDAPI_(void) InitURLIDs(UINT uPlatform)
  2246. {
  2247.     c_idlURLRoot.idri.clsid = CLSID_ShellInetRoot;
  2248.     switch (uPlatform)
  2249.     {
  2250.     case PLATFORM_NASH:
  2251. #undef ILIsEqual
  2252.         g_pfnILIsEqual = ILIsEqual;
  2253. #define ILIsEqual g_pfnILIsEqual
  2254.         break;
  2255.     default:
  2256.         ASSERT(FALSE);
  2257.         //
  2258.         // fall through
  2259.         //
  2260.     case PLATFORM_IE3:
  2261.         g_pfnILIsEqual = IEILIsEqual;
  2262.         break;
  2263.     }
  2264. }
  2265. #ifdef DEBUG
  2266. void DumpValue(LPSTR lpName, LPSTR lpStr, DWORD dwLen)
  2267. {
  2268.   char Name[256];
  2269.   if(lpStr)
  2270.       lstrcpyn(Name, lpStr, (int)dwLen+1);
  2271.   else
  2272.       lstrcpy(Name, "");
  2273.   DebugMsg(TF_SITEMAP, TEXT("%s = %s, Length=%dnr"),lpName, Name, dwLen);
  2274. }
  2275. #else
  2276. #define DumpValue(x,y,z) 0
  2277. #endif
  2278. #ifdef FEATURE_SITEMAP
  2279. //#define TESTING  1
  2280. #ifdef TESTING
  2281. HRESULT LoadDefaultSiteMap(LPCITEMIDLIST pidl)
  2282. {
  2283.   return(URLDataToFile("http://batcave", DEFAULT_SITEMAP_NAME, Sitemap_OnDataComplete));
  2284. }
  2285. #else
  2286. HRESULT LoadDefaultSiteMap(LPCITEMIDLIST pidl)
  2287. {
  2288.   URL_COMPONENTS  uc;
  2289.   CHAR  szHomeUrl[MAX_URL_STRING];
  2290.   CHAR  szUrl[MAX_URL_STRING];
  2291.   //Let's crack the URL to determine various parts of it.
  2292.   ZeroMemory(&uc, sizeof(uc));
  2293.   //Initialize the fields with non-zero to indicate that we need the ptrs back.
  2294. #ifdef DEBUG
  2295.   uc.dwUserNameLength = uc.dwPasswordLength =
  2296.   uc.dwUrlPathLength =
  2297. #endif
  2298.   uc.dwSchemeLength = uc.dwHostNameLength =
  2299.   uc.dwExtraInfoLength = 1;
  2300.   uc.dwStructSize = sizeof(uc);
  2301.   // Make a copy of the string so that InternetCrackUrl doesn't overwrite
  2302.   // the string in the pidl!
  2303.   PidlToUrl(pidl, szUrl);
  2304.   if (!InternetCrackUrl(szUrl, 0, 0, &uc))
  2305.   {
  2306.       DebugMsg(TF_SITEMAP, TEXT("InternetCrackUrl failed:Error=%d"), GetLastError());
  2307.       return(E_FAIL);
  2308.   }
  2309.   DumpValue("lpszScheme", uc.lpszScheme, uc.dwSchemeLength);
  2310.   DumpValue("lpszHostName", uc.lpszHostName, uc.dwHostNameLength);
  2311.   DumpValue("lpszUserName", uc.lpszUserName, uc.dwUserNameLength);
  2312.   DumpValue("lpszPassword", uc.lpszPassword, uc.dwPasswordLength);
  2313.   DumpValue("lpszUrlPath", uc.lpszUrlPath, uc.dwUrlPathLength);
  2314.   DumpValue("lpszExtraInfo", uc.lpszExtraInfo, uc.dwExtraInfoLength);
  2315.   DumpValue("nScheme", NULL, uc.nScheme);
  2316.   DumpValue("nPort", NULL, uc.nPort);
  2317.   //Check if this is a form based request.
  2318.   if (uc.lpszExtraInfo)
  2319.       return(E_FAIL);  //If so, do not try to download sitemap for it.
  2320.   //We need to copy the "://" too. So add 3 to the scheme length.
  2321.   lstrcpyn(szHomeUrl, uc.lpszScheme, uc.dwSchemeLength+3+uc.dwHostNameLength+1);
  2322.   return URLDataToFile(szHomeUrl, DEFAULT_SITEMAP_NAME, Sitemap_OnDataComplete);
  2323. }
  2324. #endif
  2325. //
  2326. // When we boot up, this function is called just once by explorer. Explorer
  2327. // looks at the specific location in the registry to see
  2328. // if there is an "Intranet Home" Page specified. If so, it calls this function.
  2329. // This function tries to download the default sitemap from this location,
  2330. // increment the sitemap's viewcount sothat it is kept around all the time.
  2331. //
  2332. //  Note: This is called from RunStartupApps() in explorer.exe.
  2333. //
  2334. HRESULT WINAPI LoadIntranetSitemap(LPSTR szIntranetHomePage)
  2335. {
  2336.   DWORD dwBuffLen = SIZEOF(szIntranetHomePage);
  2337.   LPITEMIDLIST pidlFull, pidlIntranetHome;
  2338.   Site *pSiteNew;
  2339.   HRESULT hres = E_FAIL;
  2340.   //Let's create a pidl for the URL for Intranet Home page.
  2341.   if(pidlFull = ILCreateFromPath(szIntranetHomePage))
  2342.   {
  2343.       // Is there a way to create the pidl just for an URL instead of
  2344.       // getting the full pidl and then to skip to the URL part of it?
  2345.       if(pidlIntranetHome = ILFindChild(c_pidlURLRoot, pidlFull))  //Skip to the URL part of it!
  2346.       {
  2347.           // If this site is already there, bail out!
  2348.           if((pSiteNew = PidlToSite(pidlIntranetHome, NULL)) != INVALID_SITE)
  2349.           {
  2350.               DebugMsg(TF_SITEMAP, TEXT("Site for %s already there!"), szIntranetHomePage);
  2351.               pSiteNew->Release();
  2352.           }
  2353.           else
  2354.           {
  2355.               // Add an explicit location first. This is needed to increment the ViewCount
  2356.               // immediately because the actual sitemap gets downloaded asynchronously
  2357.               // later.
  2358.               SL_AddExplicitLocation(pidlIntranetHome);
  2359.               pSiteNew = PidlToSite(pidlIntranetHome, NULL);
  2360.               ASSERT(pSiteNew != INVALID_SITE);  //This must be valid because we already added an
  2361.                      // explicit location.
  2362.               if(pSiteNew != INVALID_SITE)
  2363.               {
  2364.                   // This ensures that the sitemap will stick around for ever.
  2365.                   pSiteNew->IncrementViewCount();
  2366.                   pSiteNew->Release();
  2367.                   //Load the default sitemap asynchronously.
  2368.                   hres = LoadDefaultSiteMap(pidlIntranetHome);
  2369.               }
  2370.           }
  2371.       }
  2372.       ILFree(pidlFull);
  2373.   }
  2374.   return(hres);
  2375. }
  2376. #endif //FEATURE_SITEMAP
  2377. //  this function requires MAX_URL_STRING
  2378. HRESULT IEGetDisplayName(LPCITEMIDLIST pidl, LPTSTR pszName, UINT uFlags)
  2379. {
  2380.     HRESULT hres;
  2381.     BOOL    fNeedRelease = FALSE;
  2382. #ifdef NO_IE_NAMESPACE
  2383.     if (IsURLChild(pidl, TRUE)) {
  2384.         hres = InitPSFInternet();
  2385. if (SUCCEEDED(hres))
  2386.         {
  2387.             STRRET srName;
  2388.             hres = g_psfInternet->GetDisplayNameOf(_ILNext(pidl), uFlags, &srName);
  2389.             if (SUCCEEDED(hres))
  2390.             {
  2391.                 StrRetToStrN(pszName, MAX_URL_STRING, &srName, _ILNext(pidl));
  2392.                 DebugMsg(0, TEXT("ief TR IEGDN psfI->GDNO returned %s"), pszName);
  2393.             }
  2394.             else
  2395.             {
  2396.                 DebugMsg(0, TEXT("ief TR IEGDN psfI->GDNO failed %x"), hres);
  2397.             }
  2398.         }
  2399.     } else {
  2400. #endif
  2401.         DWORD dwGDNFlags;
  2402.         switch (uFlags) {
  2403.         case SHGDN_NORMAL:
  2404.         case SHGDN_FORADDRESSBAR:
  2405.             dwGDNFlags = ILGDN_ITEMONLY;
  2406.             break;
  2407.         case SHGDN_INFOLDER:
  2408.             dwGDNFlags = ILGDN_INFOLDER;
  2409.             break;
  2410.         case SHGDN_FORPARSING:
  2411.         default:
  2412.             dwGDNFlags = ILGDN_FULLNAME;
  2413.             break;
  2414.         }
  2415.         
  2416.         IShellFolder* psfDesktop = g_psfDesktop;
  2417.         if (g_pidlRootClass && ILIsEmpty(pidl)) {
  2418.             hres = SHGetDesktopFolder(&psfDesktop);
  2419.             fNeedRelease = TRUE; // Remember that we will need to Release psfDesktop when we are don't because we didn't just make a copy.
  2420.             if (FAILED(hres))
  2421.                 return hres;
  2422.             pidl = g_pidlRootClass;
  2423.         } else if (!psfDesktop) {
  2424.             SHGetDesktopFolder(&psfDesktop);
  2425.         }
  2426.         
  2427.         hres = ILGetDisplayNameEx(psfDesktop, pidl, pszName, dwGDNFlags) ? S_OK : E_FAIL;
  2428. #if 0
  2429.         if (FAILED(hres)) {
  2430.             // this was a bug in win95 that ILGetDisplayName for \server
  2431.             // failed because it wasn't a filesys  \servershare succeeds...
  2432.             // instead we need to use SHGetDataFromIDList.
  2433.             IShellFolder *psfDesktop;
  2434.             SHGetDesktopFolder(&psfDesktop);
  2435.             if (psfDesktop)  {
  2436.                 LPITEMIDLIST pidlParent = ILClone(pidl);
  2437.                 if (pidlParent) {
  2438.                     IShellFolder *psf;
  2439.                     ILRemoveLastID(pidlParent);
  2440.                     if (!ILIsEmpty(pidlParent) && SUCCEEDED(psfDesktop->BindToObject(pidlParent, NULL, IID_IShellFolder, (void **)&psf))) {
  2441.                         BYTE bBuffer[1024];
  2442.                         hres = SHGetDataFromIDList(psf, ILFindLastID(pidl), SHGDFIL_NETRESOURCE,
  2443.                                                    (LPNETRESOURCE)bBuffer, SIZEOF(bBuffer));
  2444.                         if (SUCCEEDED(hres)) {
  2445.                             LPNETRESOURCE pnr = (LPNETRESOURCE)bBuffer;
  2446.                             lstrcpy(pszName, pnr->lpRemoteName);
  2447.                         }
  2448.                         psf->Release();
  2449.                     }
  2450.                     ILFree(pidlParent);
  2451.                 }
  2452.                 psfDesktop->Release();
  2453.             }
  2454.         }
  2455. #endif
  2456.         if (fNeedRelease)
  2457.             psfDesktop->Release();
  2458.         if (FAILED(hres))
  2459.             pszName[0] = 0;
  2460. #ifdef NO_IE_NAMESPACE
  2461.     }
  2462. #endif
  2463.     DebugMsg(TF_URLNAMESPACE, TEXT("IEGDN(%s) returning %x"), pszName, hres);
  2464.     return hres;
  2465. }
  2466. #ifndef UNICODE
  2467. HRESULT IEGetDisplayNameW(LPCITEMIDLIST pidl, LPWSTR pwszName, UINT uFlags)
  2468. {
  2469.     TCHAR szName[MAX_URL_STRING];
  2470.     HRESULT hres = IEGetDisplayName(pidl, szName, uFlags);
  2471.         
  2472.     if (SUCCEEDED(hres))
  2473.         StrToOleStrN(pwszName, MAX_URL_STRING, szName, -1);
  2474.     return hres;
  2475. }
  2476. #endif
  2477. HRESULT IEGetAttributesOf(LPCITEMIDLIST pidl, DWORD* pdwAttribs)
  2478. {
  2479.     HRESULT hres = E_OUTOFMEMORY;
  2480.     LPCITEMIDLIST pidlLast = ILFindLastID(pidl);
  2481.     if (FAILED(InitPSFDesktop(NULL, NULL)))
  2482.         return E_FAIL;
  2483.     if (pidlLast == pidl) {
  2484.         hres = g_psfDesktop->GetAttributesOf(1, &pidlLast, pdwAttribs);
  2485.         if (FAILED(hres)) {
  2486.             DebugMsg(DM_ERROR, TEXT("CSB::_GetAttributesOf g_psfDesktop->GetAttr failed %x"), hres);
  2487.         }
  2488.     } else {
  2489.         IShellFolder* psfParent = NULL;
  2490.         LPITEMIDLIST pidlCopy = ILClone(pidl);
  2491.         if (pidlCopy) {
  2492.             // remove the location info if any...
  2493.             // we do this because we tacked it on ourselves, and the binding
  2494.             // might not know about it.
  2495.             ILRemoveLocation(pidlCopy, NULL);
  2496.             // find last again because ILRemoveLocation may have whacked it off
  2497.             LPITEMIDLIST pidlLast = ILFindLastID(pidlCopy);
  2498.             WORD cbOld = pidlLast->mkid.cb;
  2499.             pidlLast->mkid.cb = 0;
  2500.             hres = g_psfDesktop->BindToObject(pidlCopy, NULL, IID_IShellFolder, (void **)&psfParent);
  2501.             pidlLast->mkid.cb = cbOld;
  2502.             if (SUCCEEDED(hres)) {
  2503.                 hres = psfParent->GetAttributesOf(1, (LPCITEMIDLIST*)&pidlLast, pdwAttribs);
  2504.                 if (FAILED(hres)) {
  2505.                     DebugMsg(DM_ERROR, TEXT("CSB::_GetAttributesOf psfParent->GetAttr failed %x"), hres);
  2506.                 }
  2507.                 psfParent->Release();
  2508.             } else {
  2509.                 DebugMsg(DM_ERROR, TEXT("CSB::_GetAttributesOf g_psfDesktop->Bind failed %x"), hres);
  2510.             }
  2511.             ILFree(pidlCopy);
  2512.         }
  2513.     }
  2514.     DebugMsg(TF_URLNAMESPACE, TEXT("IEGAO(%x) returning %x (hres=%x)"),
  2515.              pidl, *pdwAttribs, hres);
  2516.     return hres;
  2517. }
  2518. HRESULT IEBindToObject(LPCITEMIDLIST pidl, IShellFolder **ppsfOut)
  2519. {
  2520.     HRESULT hres = NOERROR;
  2521.     *ppsfOut = NULL;
  2522.     if (FAILED(InitPSFDesktop(NULL, NULL)))
  2523.         return E_FAIL;
  2524.     // Special case:  If we have the pidl for the "Desktop" then just use the Desktop folder itself
  2525.     if(ILIsEmpty(pidl))
  2526.     {
  2527.         *ppsfOut = g_psfDesktop;
  2528.         g_psfDesktop->AddRef();
  2529.         hres = NOERROR;
  2530.         
  2531. #ifdef NO_IE_NAMESPACE
  2532.         // we need this else clause if The Internet is NOT in the namespace (ie3)
  2533.     } else if (IsURLChild(pidl, TRUE)) {
  2534.         DebugMsg(DM_STARTUP, TEXT("_CreateNewShellViewPidl IsURLChild is true"));
  2535. hres = InitPSFInternet();
  2536.         if (SUCCEEDED(hres))
  2537.         {
  2538.     hres = g_psfInternet->BindToObject(_ILNext(pidl), NULL, IID_IShellFolder, (void **)ppsfOut);
  2539.             AssertMsg(SUCCEEDED(hres), TEXT("_CreateNewShellViewPidl g_psfINet->Bind failed %x"), hres);
  2540.         }
  2541. #endif
  2542.         
  2543.     } else {
  2544. DWORD dwAttribs = SFGAO_FOLDER | SFGAO_BROWSABLE | SFGAO_FILESYSTEM;
  2545.         if (SUCCEEDED(hres)) {
  2546.             hres = IEGetAttributesOf(pidl, &dwAttribs);
  2547.             if (SUCCEEDED(hres)) {
  2548.                 DebugMsg(DM_STARTUP, TEXT("CSB::_CreateNSVP GetAttributesOf returned %x (%x, %x)"),
  2549.                          dwAttribs, dwAttribs & SFGAO_FOLDER, dwAttribs & SFGAO_BROWSABLE);
  2550.                 //
  2551.                 // Check if desktop can help us binding to it.
  2552.                 //  case 1: pidl is a folder
  2553.                 //  case 2: pidl is a doc-object and this is Win96
  2554.                 //
  2555.                 if (dwAttribs & (SFGAO_FOLDER | SFGAO_BROWSABLE)) {
  2556.                     //
  2557.                     // Yes, just call psfDesktop->BindToObjec
  2558.                     //
  2559.                     if (SUCCEEDED(hres)) {
  2560.                         // Special case:  If we have the pidl for the "Desktop" then just use the Desktop folder itself
  2561.                         if(ILIsEmpty(pidl)) {
  2562.                             *ppsfOut = g_psfDesktop;
  2563.                             g_psfDesktop->AddRef();
  2564.                             hres = NOERROR;
  2565.                         } else {
  2566.                             DebugMsg(DM_STARTUP, TEXT("CSB::_CreateNSVP calling psdDesktop->BindToObject"));
  2567.                             hres = g_psfDesktop->BindToObject(pidl, NULL, IID_IShellFolder, (void **)ppsfOut);
  2568.                             DebugMsg(DM_STARTUP, TEXT("CSB::_CreateNSVP called psdDesktop->BindToObject %x %x"), hres, *ppsfOut);
  2569.                         }
  2570.                     }
  2571.                 } else {
  2572.                     DebugMsg(DM_WARNING, TEXT("IEBindToObject dwAttribs has no folder/browser bit"));
  2573.                     //
  2574.                     //  This code forces a fake binding to CDocObjectFolder for
  2575.                     // files which are not DocObject. Without this code, file:
  2576.                     // to non-Docobject files (such as multi-media files)
  2577.                     // won't do anything.
  2578.                     //
  2579.                     //  We also have this code in case we change our mind to
  2580.                     // release a stand-alone IE browser which does not require
  2581.                     // new SHELL32.DLL. 
  2582.                     //
  2583.                     if (dwAttribs & SFGAO_FILESYSTEM) {
  2584.                         //
  2585.                         // No, we need to fake BindToObject.
  2586.                         //
  2587.                         DebugMsg(DM_STARTUP, TEXT("CSB::_CreateNSVP calling SHCoCreateInstance"));
  2588.                         IPersistFolder *ppsf;
  2589.                         hres = SHCoCreateInstance(NULL, &CLSID_CDocObjectFolder, NULL,
  2590.                                                   IID_IPersistFolder, (void **)&ppsf);
  2591.                         if (SUCCEEDED(hres)) {
  2592.                             hres = ppsf->Initialize(pidl);
  2593.                             if (SUCCEEDED(hres)) {
  2594.                                 hres = ppsf->QueryInterface(IID_IShellFolder, (void **)ppsfOut);
  2595.                             }
  2596.                             ppsf->Release();
  2597.                         }
  2598.                     } else {
  2599.                         hres = E_FAIL;
  2600.                     }
  2601.                 }
  2602.             } else {
  2603.                 DebugMsg(DM_ERROR, TEXT("CBS::_CreateNSVP _GetAttributesOf failed %x"), hres);
  2604.             }
  2605.         }
  2606. DebugMsg(DM_STARTUP, TEXT("CSB::_CreateNSVP got %x %x"), hres, *ppsfOut);
  2607.     }
  2608.     DebugMsg(TF_URLNAMESPACE, TEXT("IEBTO(%x) returning %x"), pidl, hres);
  2609.     return hres;
  2610. }