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

Windows Kernel

Development Platform:

Visual C++

  1. #include "shellprv.h"
  2. #include "caggunk.h"
  3. #include "views.h"
  4. #include "ids.h"
  5. #include "shitemid.h"
  6. #include "dbgmem.h"
  7. #include "idmk.h"
  8. #include "fstreex.h"
  9. #include "shobjprv.h"
  10. #include "datautil.h"
  11. #include "sfviewp.h"
  12. #include "winnetp.h"    // RESOURCE_SHAREABLE
  13. #include "prop.h"
  14. #include "infotip.h"
  15. extern "C"
  16. {
  17. #include "netview.h"
  18. #ifdef DEBUG // For leak detection
  19. extern void GetAndRegisterLeakDetection(void);
  20. extern BOOL g_fInitTable;
  21. extern LEAKDETECTFUNCS LeakDetFunctionTable;
  22. #endif
  23. // {22BEB58B-0794-11d2-A4AA-00C04F8EEB3E}
  24. const GUID CLSID_CNetFldr = { 0x22beb58b, 0x794, 0x11d2, 0xa4, 0xaa, 0x0, 0xc0, 0x4f, 0x8e, 0xeb, 0x3e };
  25. // idlist.c
  26. void StrRetFormat(LPSTRRET pStrRet, LPCITEMIDLIST pidlRel, LPCTSTR pszTemplate, LPCTSTR pszAppend);
  27. // in stdenum.cpp
  28. void* CStandardEnum_CreateInstance(REFIID riid, BOOL bInterfaces, int cElement, int cbElement, void *rgElements,
  29.                  void (WINAPI * pfnCopyElement)(void *, const void *, DWORD));
  30. // Where WNet stores its policy
  31. #define WNET_POLICY_KEY  TEXT("Software\Microsoft\Windows\CurrentVersion\Policies\Network")
  32. // netviewx.c
  33. extern const IDataObjectVtbl c_CNETIDLDataVtbl;
  34. extern const IDropTargetVtbl c_CPrintDropTargetVtbl;
  35. extern const IDropTargetVtbl c_CNetRootTargetVtbl;
  36. // fstreex.c
  37. extern TCHAR const c_szDirectoryClass[];
  38. }
  39. // is a \serverprinter object
  40. BOOL _IsPrintShare(LPCIDNETRESOURCE pidn)
  41. {
  42.     return NET_GetDisplayType(pidn) == RESOURCEDISPLAYTYPE_SHARE && 
  43.            NET_GetType(pidn) == RESOURCETYPE_PRINT;
  44. }
  45. STDAPI CNetFldr_CreateInstance(LPCITEMIDLIST pidlAbs, LPCITEMIDLIST pidlTarget, UINT uDisplayType, 
  46.                                LPCIDNETRESOURCE pidnForProvider, LPCTSTR pszResName, 
  47.                                REFIID riid, void **ppvOut);
  48. STDAPI_(BOOL) CreateNetHoodShortcuts();
  49. class CNetFolder : public CAggregatedUnknown, 
  50.                    public IShellFolder2, 
  51.                    public IPersistFolder3,
  52.                    public IShellIconOverlay
  53. {
  54. public:
  55.     // *** IUnknown ***
  56.     STDMETHODIMP QueryInterface(REFIID riid, void ** ppvObj)
  57.                 { return CAggregatedUnknown::QueryInterface(riid, ppvObj); };
  58.     STDMETHODIMP_(ULONG) AddRef(void) 
  59.                 { return CAggregatedUnknown::AddRef(); };
  60.     STDMETHODIMP_(ULONG) Release(void) 
  61.                 { return CAggregatedUnknown::Release(); };
  62.     // *** IShellFolder methods ***
  63.     STDMETHODIMP ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR lpszDisplayName,
  64.                                   ULONG* pchEaten, LPITEMIDLIST* ppidl, ULONG* pdwAttributes);
  65.     STDMETHODIMP EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList ** ppenumIDList);
  66.     STDMETHODIMP BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void** ppvOut);
  67.     STDMETHODIMP BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void** ppvObj);
  68.     STDMETHODIMP CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
  69.     STDMETHODIMP CreateViewObject (HWND hwndOwner, REFIID riid, void** ppvOut);
  70.     STDMETHODIMP GetAttributesOf(UINT cidl, LPCITEMIDLIST* apidl, ULONG* rgfInOut);
  71.     STDMETHODIMP GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST* apidl,
  72.                                REFIID riid, UINT* prgfInOut, void** ppvOut);
  73.     STDMETHODIMP GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName);
  74.     STDMETHODIMP SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD uFlags,
  75.                            LPITEMIDLIST* ppidlOut);
  76.     // *** IShellFolder2 methods ***
  77.     STDMETHODIMP GetDefaultSearchGUID(LPGUID lpGuid);
  78.     STDMETHODIMP EnumSearches(LPENUMEXTRASEARCH* ppenum);
  79.     STDMETHODIMP GetDefaultColumn(DWORD dwRes, ULONG* pSort, ULONG* pDisplay);
  80.     STDMETHODIMP GetDefaultColumnState(UINT iColumn, DWORD* pbState);
  81.     STDMETHODIMP GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID* pscid, VARIANT* pv);
  82.     STDMETHODIMP GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS* pDetails);
  83.     STDMETHODIMP MapColumnToSCID(UINT iColumn, SHCOLUMNID* pscid);
  84.     // *** IPersist methods ***
  85.     STDMETHODIMP GetClassID(CLSID* pClassID);
  86.     // *** IPersistFolder methods ***
  87.     STDMETHODIMP Initialize(LPCITEMIDLIST pidl);
  88.     // *** IPersistFolder2 methods ***
  89.     STDMETHODIMP GetCurFolder(LPITEMIDLIST* ppidl);
  90.     // *** IPersistFolderAlias methods ***
  91.     STDMETHOD(InitializeEx)(IBindCtx *pbc, LPCITEMIDLIST pidlRoot, const PERSIST_FOLDER_TARGET_INFO *ppfai);
  92.     STDMETHOD(GetFolderTargetInfo)(PERSIST_FOLDER_TARGET_INFO *ppfai);
  93.     // *** IShellIconOverlay methods***
  94.     STDMETHOD(GetOverlayIndex)(LPCITEMIDLIST pidl, int * pIndex);
  95.     STDMETHOD(GetOverlayIconIndex)(LPCITEMIDLIST pidl, int * pIconIndex);
  96. protected:
  97.     CNetFolder(IUnknown* punkOuter);
  98.     ~CNetFolder();
  99.     virtual HRESULT v_GetFileFolder(IShellFolder2 **ppsfFiles) 
  100.                 { *ppsfFiles = NULL; return E_NOTIMPL; };
  101.     // used by the CAggregatedUnknown stuff
  102.     HRESULT v_InternalQueryInterface(REFIID riid, void** ppvObj);
  103.     static HRESULT CALLBACK EnumCallBack(LPARAM lParam, void* pvData, UINT ecid, UINT index);
  104.     HRESULT _OpenKeys(LPCIDNETRESOURCE pidn, HKEY ahkeys[]);
  105.     LPCTSTR _GetProvider(LPCIDNETRESOURCE pidn, LPTSTR pszProvider, UINT cchProvider);
  106.     DWORD _OpenEnum(HWND hwnd, DWORD grfFlags, LPNETRESOURCE pnr, HANDLE *phEnum);
  107.     static HRESULT _CreateNetIDList(LPIDNETRESOURCE pidnIn, 
  108.                                     LPCTSTR pszName, LPCTSTR pszProvider, LPCTSTR pszComment,
  109.                                     LPITEMIDLIST *ppidl);
  110.     static HRESULT _NetResToIDList(NETRESOURCE *pnr, 
  111.                                    BOOL fAllowNull, BOOL fKeepProviderName, BOOL fKeepComment, 
  112.                                    LPITEMIDLIST *ppidl, LPARAM lParam);
  113.     static HRESULT _CreateEntireNetwork(LPITEMIDLIST *ppidl, LPARAM lParam);
  114.     LPTSTR _GetNameForParsing(LPCWSTR pwszName, LPTSTR pszBuffer, INT cchBuffer, LPTSTR *ppszRegItem);
  115.     HRESULT _ParseRest(LPBC pbc, LPCWSTR pszRest, LPITEMIDLIST* ppidl, DWORD* pdwAttributes);
  116.     HRESULT _AddUnknownIDList(DWORD dwDisplayType, LPITEMIDLIST *ppidl);
  117.     HRESULT _ParseSimple(LPBC pbc, LPWSTR pszName, LPITEMIDLIST* ppidl, DWORD* pdwAttributes);
  118.     HRESULT _NetResToIDLists(NETRESOURCE *pnr, DWORD dwbuf, LPITEMIDLIST *ppidl);
  119.     HRESULT _ParseNetName(HWND hwnd, LPBC pbc, LPCWSTR pwszName, ULONG* pchEaten, 
  120.                               LPITEMIDLIST* ppidl, DWORD* pdwAttributes);
  121.     LONG _GetFilePIDLType(LPCITEMIDLIST pidl);
  122.     LPITEMIDLIST _AddProviderToPidl(LPITEMIDLIST pidl, LPCTSTR lpProvider);
  123.     BOOL _MakeStripToLikeKinds(UINT *pcidl, LPCITEMIDLIST **papidl, BOOL fNetObjects);
  124.     LPFNDFMCALLBACK _GetCallbackType(LPCIDNETRESOURCE pidn)
  125.                         { return _IsPrintShare(pidn) ? &PrinterDFMCallBack : &DFMCallBack; };
  126.     static HRESULT CALLBACK GAOCallbackNetRoot(IShellFolder2* psf, LPCITEMIDLIST pidl, ULONG* prgfInOut);
  127.     LPITEMIDLIST _pidl;
  128.     LPITEMIDLIST _pidlTarget; // pidl of where the folder is in the namespace
  129.     LPCIDNETRESOURCE _pidnForProvider; // optional provider for this container...
  130.     LPTSTR _pszResName;      // optional resource name of this container
  131.     UINT _uDisplayType;      // display type of the folder
  132.     IShellFolder2* _psfFiles;
  133.     IUnknown* _punkInner;
  134.     
  135. private:
  136.     friend HRESULT CNetFldr_CreateInstance(LPCITEMIDLIST pidlAbs, LPCITEMIDLIST pidlTarget,
  137.                                            UINT uDisplayType,                                            
  138.                                            LPCIDNETRESOURCE pidnForProvider, LPCTSTR pszResName, 
  139.                                            REFIID riid, void** ppvOut);
  140.     friend HRESULT CNetwork_DFMCallBackBG(IShellFolder *psf, HWND hwnd,
  141.                                           IDataObject *pdtobj, UINT uMsg, 
  142.                                           WPARAM wParam, LPARAM lParam);
  143.     static DWORD CALLBACK _PropertiesThreadProc(void *pv);
  144.     friend BOOL NET_GetProviderKeyName(IShellFolder* psf, LPTSTR pszName, UINT uNameLen);
  145.     static HRESULT DFMCallBack(IShellFolder* psf, HWND hwnd,
  146.                                IDataObject* pdtobj, UINT uMsg, 
  147.                                WPARAM wParam, LPARAM lParam);
  148.     static HRESULT PrinterDFMCallBack(IShellFolder* psf, HWND hwnd,
  149.                                       IDataObject* pdtobj, UINT uMsg, 
  150.                                       WPARAM wParam, LPARAM lParam);
  151.     static HRESULT CALLBACK GAOCallbackNet(IShellFolder2* psf, LPCITEMIDLIST pidl, ULONG* prgfInOut);
  152.     BOOL _GetPathForShare(LPCIDNETRESOURCE pidn, LPTSTR pszPath);
  153.     HRESULT _GetPathForItem(LPCIDNETRESOURCE pidn, LPTSTR pszPath);
  154.     HRESULT _GetPathForItemW(LPCIDNETRESOURCE pidn, LPWSTR pszPath);
  155.     HRESULT _CreateFolderForItem(LPCITEMIDLIST pidl, LPCITEMIDLIST pidlTarget, LPCIDNETRESOURCE pidnForProvider, REFIID riid, void** ppv);
  156.     HRESULT _GetFormatName(LPCIDNETRESOURCE pidn, STRRET* pStrRet);
  157.     HRESULT _GetIconOverlayInfo(LPCIDNETRESOURCE pidn, int *pIndex, DWORD dwFlags);
  158. #ifdef WINNT
  159.     HKEY _OpenProviderTypeKey(LPCIDNETRESOURCE pidn);
  160. #endif // WINNT
  161.     HKEY _OpenProviderKey(LPCIDNETRESOURCE pidn);
  162.     static void WINAPI _CopyEnumElement(void* pDest, const void* pSource, DWORD dwSize);
  163.     HRESULT _GetNetResource(LPCIDNETRESOURCE pidn, NETRESOURCEW* pnr, int cb);
  164. };  
  165. class CNetRootFolder : public CNetFolder
  166. {
  167. public:
  168.     // *** IUnknown ***
  169.     STDMETHODIMP QueryInterface(REFIID riid, void ** ppvObj)
  170.                 { return CNetFolder::QueryInterface(riid, ppvObj); };
  171.     STDMETHODIMP_(ULONG) AddRef(void)
  172.                 { return CNetFolder::AddRef(); };
  173.     STDMETHODIMP_(ULONG) Release(void)
  174.                 { return CNetFolder::Release(); };
  175.     // *** IShellFolder methods ***
  176.     STDMETHODIMP ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR lpszDisplayName,
  177.                                   ULONG* pchEaten, LPITEMIDLIST* ppidl, ULONG* pdwAttributes);
  178.     STDMETHODIMP EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList ** ppenumIDList);
  179.     STDMETHODIMP BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void** ppvOut);
  180.     STDMETHODIMP BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void** ppvObj)
  181.         { return CNetFolder::BindToStorage(pidl, pbc, riid, ppvObj); };
  182.     STDMETHODIMP CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
  183.     STDMETHODIMP CreateViewObject (HWND hwndOwner, REFIID riid, void** ppvOut);
  184.     STDMETHODIMP GetAttributesOf(UINT cidl, LPCITEMIDLIST* apidl, ULONG* rgfInOut);
  185.     STDMETHODIMP GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST* apidl,
  186.                                REFIID riid, UINT* prgfInOut, void** ppvOut);
  187.     STDMETHODIMP GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName);
  188.     STDMETHODIMP SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD uFlags,
  189.                            LPITEMIDLIST* ppidlOut);
  190.     // *** IShellFolder2 methods ***
  191.     STDMETHODIMP GetDefaultSearchGUID(LPGUID lpGuid)
  192.         { return CNetFolder::GetDefaultSearchGUID(lpGuid); };
  193.     STDMETHODIMP EnumSearches(LPENUMEXTRASEARCH* ppenum)
  194.         { return CNetFolder::EnumSearches(ppenum); };
  195.     STDMETHODIMP GetDefaultColumn(DWORD dwRes, ULONG* pSort, ULONG* pDisplay)
  196.         { return CNetFolder::GetDefaultColumn(dwRes, pSort, pDisplay); };
  197.     STDMETHODIMP GetDefaultColumnState(UINT iColumn, DWORD* pbState)
  198.         { return CNetFolder::GetDefaultColumnState(iColumn, pbState); };
  199.     STDMETHODIMP GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID* pscid, VARIANT* pv)
  200.         { return CNetFolder::GetDetailsEx(pidl, pscid, pv); };
  201.     STDMETHODIMP GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS* pDetails)
  202.         { return CNetFolder::GetDetailsOf(pidl, iColumn, pDetails); };
  203.     STDMETHODIMP MapColumnToSCID(UINT iColumn, SHCOLUMNID* pscid)
  204.         { return CNetFolder::MapColumnToSCID(iColumn, pscid); };
  205.     // *** IPersist methods ***
  206.     STDMETHODIMP GetClassID(CLSID* pClassID);
  207.     // *** IPersistFolder methods ***
  208.     STDMETHODIMP Initialize(LPCITEMIDLIST pidl);
  209.     // *** IPersistFolder2 methods ***
  210.     STDMETHODIMP GetCurFolder(LPITEMIDLIST* ppidl)
  211.         { return CNetFolder::GetCurFolder(ppidl); };
  212.     // *** IPersistFolderAlias methods ***
  213.     STDMETHOD(InitializeEx)(IBindCtx *pbc, LPCITEMIDLIST pidlRoot, const PERSIST_FOLDER_TARGET_INFO *ppfai)
  214.         { return CNetFolder::InitializeEx(pbc, pidlRoot, ppfai); };
  215.     STDMETHOD(GetFolderTargetInfo)(PERSIST_FOLDER_TARGET_INFO *ppfai)
  216.         { return CNetFolder::GetFolderTargetInfo(ppfai); };
  217. protected:
  218.     CNetRootFolder(IUnknown* punkOuter) : CNetFolder(punkOuter) { };
  219.     ~CNetRootFolder() { ASSERT(NULL != _spThis); _spThis = NULL; };
  220.     BOOL v_HandleDelete(PLONG pcRef);
  221.     HRESULT v_GetFileFolder(IShellFolder2 **ppsfFiles);
  222. private:
  223.     HRESULT _TryParseEntireNet(HWND hwnd, LPBC pbc, WCHAR *pwszName, LPITEMIDLIST *ppidl, DWORD *pdwAttributes);
  224.     friend HRESULT CNetwork_CreateInstance(IUnknown* punkOuter, REFIID riid, void** ppv);
  225.     static CNetRootFolder* _spThis;
  226. };  
  227. class CNetSFVCB : public CBaseShellFolderViewCB
  228. {
  229. public:
  230.     CNetSFVCB(IShellFolder* psf, UINT uNetResType, LPCITEMIDLIST pidlMonitor, LONG lEvents) : 
  231.     CBaseShellFolderViewCB(psf, pidlMonitor, lEvents), _uNetResType(uNetResType) {}
  232.     ~CNetSFVCB() {}
  233.     STDMETHODIMP RealMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
  234. private:
  235.     UINT _uNetResType;
  236. private:
  237.     HRESULT OnMERGEMENU(DWORD pv, QCMINFO*lP)
  238.     {
  239.         CDefFolderMenu_MergeMenu(HINST_THISDLL, 0, POPUP_NETWORK_POPUPMERGE, lP);
  240.         return S_OK;
  241.     }                                                                                                                 
  242.     HRESULT OnINVOKECOMMAND(DWORD pv, UINT wP)
  243.     {
  244.         return CNetwork_DFMCallBackBG(m_pshf, m_hwndMain, NULL, DFM_INVOKECOMMAND, wP, 0);
  245.     }
  246.     HRESULT OnGETHELPTEXT(DWORD pv, UINT wPl, UINT wPh, LPTSTR lP)
  247.     {
  248. #ifdef UNICODE
  249.         return CNetwork_DFMCallBackBG(m_pshf, m_hwndMain, NULL, DFM_GETHELPTEXTW, MAKEWPARAM(wPl, wPh), (LPARAM)lP);
  250. #else
  251.         return CNetwork_DFMCallBackBG(m_pshf, m_hwndMain, NULL, DFM_GETHELPTEXT, MAKEWPARAM(wPl, wPh), (LPARAM)lP);
  252. #endif
  253.     }
  254.     HRESULT OnBACKGROUNDENUM(DWORD pv)
  255.     {
  256.         return S_OK;
  257.     }
  258.     HRESULT OnGETCOLSAVESTREAM(DWORD pv, WPARAM wP, IStream **pps)
  259.     {
  260.         LPCTSTR pszValName;
  261.         switch (_uNetResType) {
  262.         case RESOURCEDISPLAYTYPE_DOMAIN:
  263.             pszValName = TEXT("NetDomainColsX");
  264.             break;
  265.         case RESOURCEDISPLAYTYPE_SERVER:
  266.             pszValName = TEXT("NetServerColsX");
  267.             break;
  268.         default:
  269.             return E_FAIL;
  270.         }
  271.         *pps = OpenRegStream(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER, pszValName, (DWORD) wP);
  272.         return *pps ? S_OK : E_FAIL;
  273.     }
  274.     HRESULT OnDEFITEMCOUNT(DWORD pv, UINT *pnItems)
  275.     {
  276.         // if we time out enuming items make a guess at how many items there
  277.         // will be to make sure we get large icon mode and a reasonable window size
  278.         switch (_uNetResType) {
  279.         case RESOURCEDISPLAYTYPE_GENERIC:   // MyNetPlaces now has only a few items typically
  280.         case RESOURCEDISPLAYTYPE_SERVER:    // printers & shares, usually only a few
  281.             *pnItems = 10;   
  282.             break;
  283.         case RESOURCEDISPLAYTYPE_ROOT:    // usually only one or two items
  284.             *pnItems = 5;
  285.             break;
  286.         }
  287.         return S_OK;
  288.     }
  289.     HRESULT OnGetViews(DWORD pv, SHELLVIEWID *pvid, IEnumSFVViews **ppObj);
  290.     HRESULT OnGetZone(DWORD pv, DWORD * pdwZone);
  291.     HRESULT OnDefViewMode(DWORD pv, FOLDERVIEWMODE* pvm)
  292.     {
  293.         //
  294.         // force large icons for My Network Places.
  295.         //
  296.         if ( pvm && (_uNetResType == RESOURCEDISPLAYTYPE_GENERIC) )
  297.             *pvm = FVM_ICON;
  298.         return NOERROR;
  299.     }
  300. };
  301. HRESULT CNetSFVCB::OnGetZone(DWORD pv, DWORD * pdwZone)
  302. {
  303.     if (pdwZone)
  304.         *pdwZone = URLZONE_INTRANET; // default is "Local Intranet"
  305.     return S_OK;    
  306. }
  307. HRESULT CNetSFVCB::OnGetViews(DWORD pv, SHELLVIEWID *pvid, IEnumSFVViews **ppObj)
  308. {
  309.     *ppObj = NULL;
  310.     CViewsList cViews;
  311.     TCHAR szTemp[MAX_PATH];
  312.     // Add base class stuff
  313.     cViews.AddReg(HKEY_CLASSES_ROOT, TEXT("folder"));
  314.     switch (_uNetResType)
  315.     {
  316.     case RESOURCEDISPLAYTYPE_NETWORK:
  317.         if (NET_GetProviderKeyName(m_pshf, szTemp, ARRAYSIZE(szTemp)))
  318.         {
  319.             cViews.AddReg(HKEY_CLASSES_ROOT, szTemp);
  320.         }
  321.         break;
  322.     case RESOURCEDISPLAYTYPE_DOMAIN:
  323.         cViews.AddReg(HKEY_CLASSES_ROOT, TEXT("NetDomain"));
  324.         if (NET_GetProviderKeyName(m_pshf, szTemp, ARRAYSIZE(szTemp)))
  325.         {
  326.             lstrcat(szTemp, TEXT("\Domain"));
  327.             cViews.AddReg(HKEY_CLASSES_ROOT, szTemp);
  328.         }
  329.         break;
  330.     case RESOURCEDISPLAYTYPE_SERVER:
  331.         cViews.AddReg(HKEY_CLASSES_ROOT, TEXT("NetServer"));
  332.         if (NET_GetProviderKeyName(m_pshf, szTemp, ARRAYSIZE(szTemp)))
  333.         {
  334.             lstrcat(szTemp, TEXT("\Server"));
  335.             cViews.AddReg(HKEY_CLASSES_ROOT, szTemp);
  336.         }
  337.         break;
  338.     case RESOURCEDISPLAYTYPE_ROOT:
  339.         cViews.AddReg(HKEY_CLASSES_ROOT, TEXT("Network"));
  340.         break;
  341.     case RESOURCEDISPLAYTYPE_GENERIC:
  342.         // This is the "My Network Places" (net root)
  343.         cViews.AddCLSID(&CLSID_NetworkPlaces);
  344.         break;
  345.     }
  346.     cViews.GetDef(pvid);
  347.     return CreateEnumCViewList(&cViews, ppObj);
  348.     // Note the automatic destructor will free any views still left
  349. }
  350. STDMETHODIMP CNetSFVCB::RealMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
  351. {
  352.     switch (uMsg)
  353.     {
  354.     HANDLE_MSG(0, SFVM_MERGEMENU, OnMERGEMENU);
  355.     HANDLE_MSG(0, SFVM_INVOKECOMMAND, OnINVOKECOMMAND);
  356.     HANDLE_MSG(0, SFVM_GETHELPTEXT, OnGETHELPTEXT);
  357.     HANDLE_MSG(0, SFVM_BACKGROUNDENUM, OnBACKGROUNDENUM);
  358.     HANDLE_MSG(0, SFVM_GETCOLSAVESTREAM, OnGETCOLSAVESTREAM);
  359.     HANDLE_MSG(0, SFVM_GETVIEWS, OnGetViews);
  360.     HANDLE_MSG(0, SFVM_DEFITEMCOUNT, OnDEFITEMCOUNT);
  361.     HANDLE_MSG(0, SFVM_GETZONE, OnGetZone);
  362.     HANDLE_MSG(0, SFVM_DEFVIEWMODE, OnDefViewMode);
  363.     default:
  364.         return E_FAIL;
  365.     }
  366.     return NOERROR;
  367. }
  368. STDAPI_(IShellFolderViewCB*) Net_CreateSFVCB(IShellFolder* psf, 
  369.                                              UINT uNetResType, 
  370.                                              LPCITEMIDLIST pidlMonitor, 
  371.                                              LONG lEvents)
  372. {
  373.     return new CNetSFVCB(psf, uNetResType, pidlMonitor, lEvents);
  374. }
  375. // Define a collate order for the hood object types
  376. #define _HOOD_COL_RON    0
  377. #define _HOOD_COL_REMOTE 1
  378. #define _HOOD_COL_FILE   2
  379. #define _HOOD_COL_NET    3
  380. typedef struct
  381. {
  382.     CNetFolder *pnf;     // CNetFolder object (this)
  383.     HANDLE hEnum;
  384.     DWORD grfFlags;
  385.     LONG cItems;   // Count of items in buffer
  386.     LONG iItem;    // Current index of the item in the buffer
  387.     DWORD dwRemote;
  388.     union {
  389.         NETRESOURCE anr[0];
  390.         BYTE szBuffer[8192];
  391.     };
  392.     IEnumIDList *peunk;  // used for enumerating file system items (links)
  393. } ENUM_DATA;
  394. // Flags for the dwRemote field
  395. #define RMF_CONTEXT         0x00000001  // Entire network is being enumerated
  396. #define RMF_SHOWREMOTE      0x00000002  // Return Remote Services for next enumeration
  397. #define RMF_STOP_ENUM       0x00000004  // Stop enumeration
  398. #define RMF_GETLINKENUM     0x00000008  // Hoodlinks enum needs to be fetched
  399. #define RMF_SHOWLINKS       0x00000010  // Hoodlinks need to be shown
  400. #define RMF_FAKENETROOT     0x00000020  // Don't enumerate the workgroup items
  401. #define RMF_ENTIRENETSHOWN  0x40000000  // Entire network object shown
  402. #define RMF_REMOTESHOWN     0x80000000  // Return Remote Services for next enumeration
  403. const static ICONMAP c_aicmpNet[] = {
  404.     { SHID_NET_NETWORK     , II_NETWORK      },
  405.     { SHID_NET_DOMAIN      , II_GROUP        },
  406.     { SHID_NET_SERVER      , II_SERVER       },
  407.     { SHID_NET_SHARE       , (UINT)EIRESID(IDI_SERVERSHARE)  },
  408.     { SHID_NET_DIRECTORY   , II_FOLDER       },
  409.     { SHID_NET_PRINTER     , II_PRINTER      },
  410.     { SHID_NET_RESTOFNET   , II_WORLD        },
  411.     { SHID_NET_SHAREADMIN  , II_DRIVEFIXED   },
  412.     { SHID_NET_TREE        , II_TREE         },
  413. #ifdef WINNT
  414.     { SHID_NET_NDSCONTAINER, (UINT)EIRESID(IDI_NDSCONTAINER) },
  415. #endif
  416. };
  417. enum
  418. {
  419.     NKID_PROVIDERTYPE = 0,
  420.     NKID_PROVIDER,
  421.     NKID_NETCLASS,
  422.     NKID_NETWORK,
  423.     NKID_DIRECTORY,
  424.     NKID_FOLDER
  425. };
  426. #define NKID_COUNT 6
  427. enum
  428. {
  429.     ICOL_NAME = 0,
  430.     ICOL_COMMENT,
  431. };
  432. #define ICOL_FIRST      ICOL_NAME
  433. const COL_DATA s_net_cols[] = {
  434.     {ICOL_NAME,     IDS_NAME_COL,       30, LVCFMT_LEFT,    &SCID_NAME},
  435.     {ICOL_COMMENT,  IDS_COMMENT_COL,    30, LVCFMT_LEFT,    &SCID_Comment}
  436. };
  437. // This is one-entry cache for remote junctions resolution
  438. TCHAR g_szLastAttemptedJunctionName[MAX_PATH] = {0};
  439. TCHAR g_szLastResolvedJunctionName[MAX_PATH] = {0};
  440. REGITEMSINFO g_riiNetRoot =
  441. {
  442.     REGSTR_PATH_EXPLORER TEXT("\NetworkNeighborhood\NameSpace"),
  443.     NULL,
  444.     TEXT(':'),
  445.     SHID_NET_REGITEM,
  446.     1,
  447.     SFGAO_CANLINK,
  448.     0,
  449.     NULL,
  450.     RIISA_ORIGINAL,
  451.     NULL,
  452.     0,
  453.     0,
  454. };
  455. CNetRootFolder* CNetRootFolder::_spThis = NULL;
  456. HRESULT CNetFldr_CreateInstance(LPCITEMIDLIST pidlAbs, LPCITEMIDLIST pidlTarget, UINT uDisplayType, 
  457.                                 LPCIDNETRESOURCE pidnForProvider, LPCTSTR pszResName, 
  458.                                 REFIID riid, void **ppvOut)
  459. {
  460.     HRESULT hres = E_OUTOFMEMORY;
  461.     *ppvOut = NULL;
  462.     if (!ILIsEmpty(pidlAbs))
  463.     {
  464.         CNetFolder* pNetF = new CNetFolder(NULL);
  465.         if (NULL != pNetF)
  466.         {
  467.             pNetF->_uDisplayType = uDisplayType;
  468.             if ( pidnForProvider )
  469.             {
  470.                 //Make sure that the pidnProvider has provider information.
  471.                 ASSERT(NET_FHasProvider(pidnForProvider))
  472.                 //We are interested only in the provider informarion which is contained in the first entry.
  473.                 //Its enought if we clone only the first item in the pidl.
  474.                 pNetF->_pidnForProvider = (LPCIDNETRESOURCE)ILCloneFirst((LPCITEMIDLIST)pidnForProvider);                
  475.             }
  476.             if (pszResName && *pszResName)
  477.                 pNetF->_pszResName = StrDup(pszResName);
  478.            
  479.             pNetF->_pidl = ILClone(pidlAbs);
  480.             pNetF->_pidlTarget = ILClone(pidlTarget);
  481.             if ( pNetF->_pidl && (!pidlTarget || (pidlTarget && pNetF->_pidlTarget)) )
  482.             {
  483.                 if (uDisplayType == RESOURCEDISPLAYTYPE_SERVER)
  484.                 {
  485.                     // This is a remote computer. See if there are any remote
  486.                     // computer registry items. If so, aggregate with the registry
  487.                     // class.
  488.                     REGITEMSINFO riiComputer =
  489.                     {
  490.                         REGSTR_PATH_EXPLORER TEXT("\RemoteComputer\NameSpace"),
  491.                         NULL,
  492.                         TEXT(':'),
  493.                         SHID_NET_REMOTEREGITEM,
  494.                         -1,
  495.                         SFGAO_FOLDER | SFGAO_CANLINK,
  496.                         0,      // no required reg items
  497.                         NULL,
  498.                         RIISA_ORIGINAL,
  499.                         pszResName,
  500.                         0,
  501.                         0,
  502.                     };
  503.                     CRegFolder_CreateInstance(&riiComputer,
  504.                                               (IUnknown*) (IShellFolder*) pNetF,
  505.                                               IID_IUnknown,
  506.                                               (void**) &pNetF->_punkInner);
  507.                 }
  508.                 else if ( uDisplayType == RESOURCEDISPLAYTYPE_ROOT )
  509.                 {
  510.                     //
  511.                     // this is the entire net icon, so lets create an instance of the regitem folder
  512.                     // so we can merge in the items from there.
  513.                     //
  514.                     REGITEMSINFO riiEntireNet =
  515.                     {
  516.                         REGSTR_PATH_EXPLORER TEXT("\NetworkNeighborhood\EntireNetwork\NameSpace"),
  517.                         NULL,
  518.                         TEXT(':'),
  519.                         SHID_NET_REGITEM,
  520.                         -1,
  521.                         SFGAO_CANLINK,
  522.                         0,      // no required reg items
  523.                         NULL,
  524.                         RIISA_ORIGINAL,
  525.                         NULL,
  526.                         0,
  527.                         0,
  528.                     };
  529.                     CRegFolder_CreateInstance(&riiEntireNet,
  530.                                               (IUnknown*) (IShellFolder*) pNetF,
  531.                                               IID_IUnknown,
  532.                                               (void**) &pNetF->_punkInner);
  533.                 }
  534.                 else
  535.                 {
  536.                     ASSERT(hres == E_OUTOFMEMORY);
  537.                 }
  538.                 hres = pNetF->QueryInterface(riid, ppvOut);
  539.             }
  540.             pNetF->Release();
  541.         }
  542.         else
  543.         {
  544.             ASSERT(hres == E_OUTOFMEMORY);
  545.         }
  546.     }
  547.     else
  548.     {
  549.         ASSERT(0);
  550.         hres = E_INVALIDARG;
  551.     }
  552.     return hres;
  553. }
  554. HRESULT CNetwork_CreateInstance(IUnknown* punkOuter, REFIID riid, void** ppv)
  555. {
  556.     HRESULT hres = S_OK;
  557.     ASSERT(NULL != ppv);
  558.     // Must enter critical section to avoid racing against v_HandleDelete
  559.     ENTERCRITICAL;
  560.     if (NULL != CNetRootFolder::_spThis)
  561.     {
  562.         hres = CNetRootFolder::_spThis->QueryInterface(riid, ppv);
  563.     }
  564.     else
  565.     {
  566.         CNetRootFolder* pNetRootF = new CNetRootFolder(punkOuter);
  567.         if (NULL != pNetRootF)
  568.         {
  569.             pNetRootF->_uDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  570.             ASSERT(NULL == pNetRootF->_punkInner);
  571.             if (SHRestricted(REST_NOSETFOLDERS))
  572.                 g_riiNetRoot.iReqItems = 0;
  573.             // create the regitems object, he has the NetRoot object as his outer guy.
  574.             hres = CRegFolder_CreateInstance(&g_riiNetRoot,
  575.                                              (IUnknown*) (IShellFolder2*) pNetRootF, 
  576.                                              IID_IUnknown,
  577.                                              (void**) &pNetRootF->_punkInner);
  578.             // NOTE: not using SHInterlockedCompareExchange() because we have the critsec
  579.             CNetRootFolder::_spThis = pNetRootF;
  580.             hres = pNetRootF->QueryInterface(riid, ppv);
  581. #ifdef DEBUG
  582.             // these objects are created on the background thread, so to avoid
  583.             // fake leak swhen that thread terminates we have to remove them from its memlist.
  584.             // TO DO: transfer these pointers to main thread's memlist so that it shows up in the leak detection
  585.             // because we DO leak them (only at process detach time). here's why:
  586.             // we can't release _spThis at DLL detatch time since it calls other DLLs
  587.             // that may be unloaded now. we just leak instead of crash
  588.             GetAndRegisterLeakDetection();
  589.             if (g_fInitTable)
  590.             {
  591.                 // Remove the class pointer:
  592.                 LeakDetFunctionTable.pfnremove_from_memlist(pNetRootF);
  593.                 if ( NULL != pNetRootF->_punkInner )
  594.                 {
  595.                     // Remove the _punkInner if it isn't the regfolder pointer
  596.                     // (which means it is a delegate pointer - which may be allocated
  597.                     // on our heap)
  598.                     LeakDetFunctionTable.pfnremove_from_memlist(pNetRootF->_punkInner);
  599.                 }
  600.             }
  601. #endif
  602.             // Release the self-reference, but keep the the _spThis pointer intact
  603.             // (it will be reset to NULL in the destructor)
  604.             pNetRootF->Release();
  605.         }
  606.         else
  607.         {
  608.             hres = E_OUTOFMEMORY;
  609.             *ppv = NULL;
  610.         }
  611.     }
  612.     LEAVECRITICAL;
  613.     return hres;
  614. }
  615. CNetFolder::CNetFolder(IUnknown* punkOuter) : 
  616.     CAggregatedUnknown (punkOuter)
  617. {
  618.     // Assert that we're still using a zero-init flag inside the new operator
  619.     ASSERT(NULL == _pidl);
  620.     ASSERT(NULL == _pidlTarget);
  621.     ASSERT(NULL == _pidnForProvider);
  622.     ASSERT(NULL == _pszResName);
  623.     ASSERT(0 == _uDisplayType);
  624.     ASSERT(NULL == _psfFiles);
  625.     ASSERT(NULL == _punkInner);
  626.     DllAddRef();
  627. }
  628. CNetFolder::~CNetFolder()
  629. {
  630.     ILFree(_pidl);
  631.     ILFree(_pidlTarget);
  632.     ILFree((LPITEMIDLIST)_pidnForProvider);
  633.     
  634.     if (NULL != _pszResName)
  635.     {
  636.         LocalFree(_pszResName);
  637.     }
  638.     SHReleaseInnerInterface(SAFECAST(this, IShellFolder *), &_punkInner);
  639.     DllRelease();
  640. }
  641. HRESULT CNetFolder::v_InternalQueryInterface(REFIID riid, void** ppv)
  642. {
  643.     static const QITAB qit[] = {
  644.         QITABENT(CNetFolder, IShellFolder2),                                    // IID_IShellFolder2
  645.         QITABENTMULTI(CNetFolder, IShellFolder, IShellFolder2),                 // IID_IShellFolder
  646.         QITABENT(CNetFolder, IPersistFolder3),                              // IID_IPersistFolderAlias
  647.         QITABENT(CNetFolder, IShellIconOverlay),                            // IID_IShellIconOverlay
  648.         QITABENTMULTI(CNetFolder, IPersistFolder2, IPersistFolder3),        // IID_IPersistFolder2
  649.         QITABENTMULTI(CNetFolder, IPersistFolder, IPersistFolder3),         // IID_IPersistFolder
  650.         QITABENTMULTI(CNetFolder, IPersist, IPersistFolder3),               // IID_IPersist
  651.         QITABENTMULTI2(CNetFolder, IID_IPersistFreeThreadedObject, IPersist),   // IID_IPersistFreeThreadedObject
  652.         { 0 },
  653.     };
  654.     if (_punkInner && (IsEqualIID(riid, IID_IShellFolder) || IsEqualIID(riid, IID_IShellFolder2)))
  655.     {
  656.         return _punkInner->QueryInterface(riid, ppv);
  657.     }
  658.     else if (IsEqualIID(riid, CLSID_CNetFldr))
  659.     {
  660.         *ppv = this;        // get class pointer (unrefed!)
  661.         return S_OK;
  662.     }
  663.     else
  664.     {
  665.         HRESULT hr = QISearch(this, qit, riid, ppv);
  666.         if ((E_NOINTERFACE == hr) && (NULL != _punkInner))
  667.         {
  668.             return _punkInner->QueryInterface(riid, ppv);
  669.         }
  670.         else
  671.         {
  672.             return hr;
  673.         }
  674.     }
  675. }
  676. BOOL CNetRootFolder::v_HandleDelete(PLONG pcRef)
  677. {
  678.     ASSERT(NULL != pcRef);
  679.     ENTERCRITICAL;
  680.     // Once inside the critical section things are slightly more stable.
  681.     // CNetwork_CreateInstance won't be able to rescue the cached reference
  682.     // (and bump the refcount from 0 to 1).  And we don't have to worry
  683.     // about somebody Release()ing us down to zero a second time, since
  684.     // no new references can show up.
  685.     //
  686.     // HOWEVER!  All those scary things could've happened WHILE WE WERE
  687.     // WAITING TO ENTER THE CRITICAL SECTION.
  688.     //
  689.     // While we were waiting, somebody could've called CNetwork_CreateInstance,
  690.     // which bumps the reference count back up.  So don't destroy ourselves
  691.     // if our object got "rescued".
  692.     //
  693.     // What's more, while we were waiting, that somebody could've then
  694.     // Release()d us back down to zero, causing us to be called on that
  695.     // other thread, notice that the refcount is indeed zero, and destroy
  696.     // the object, all on that other thread.  So if we are not the cached
  697.     // instance, then don't destroy ourselves since that other thread did
  698.     // it already.
  699.     //
  700.     // And even more, somebody might call CNetwork_CreateInstance again
  701.     // and create a brand new object, which might COINCIDENTALLY happen
  702.     // to have the same address as the old object we are trying to destroy
  703.     // here.  But in that case, it's okay to destroy the new object because
  704.     // it is indeed the case that the object's reference count is zero and
  705.     // deserves to be destroyed.
  706.     if (this == _spThis && 0 == *pcRef)
  707.     {
  708.         *pcRef = 1000; // protect against cached pointers bumping us up then down
  709.         delete this;
  710.     }
  711.     LEAVECRITICAL;
  712.     // return TRUE to indicate that we've implemented this function
  713.     // (regardless of whether or not this object was actually deleted)
  714.     return TRUE;
  715. }
  716. STDMETHODIMP CNetFolder::ParseDisplayName(HWND hwnd, LPBC pbc, WCHAR* pszName, ULONG* pchEaten,
  717.                                           LPITEMIDLIST* ppidl, DWORD* pdwAttributes)
  718. {
  719.     return E_NOTIMPL;
  720. }
  721. // new for Win2K, this enables enuming the hidden admin shares
  722. #ifndef RESOURCE_SHAREABLE
  723. #define RESOURCE_SHAREABLE      0x00000006
  724. #endif
  725. //
  726. //  in:
  727. //      hwnd        NULL indicates no UI.
  728. //      grfFlags     IShellFolder::EnumObjects() SHCONTF_ flags
  729. //      pnr          in/out params
  730. //
  731. //
  732. DWORD CNetFolder::_OpenEnum(HWND hwnd, DWORD grfFlags, LPNETRESOURCE pnr, HANDLE *phEnum)
  733. {
  734.     DWORD dwType = (grfFlags & SHCONTF_NETPRINTERSRCH) ? RESOURCETYPE_PRINT : RESOURCETYPE_ANY;
  735.     DWORD dwScope = pnr ? RESOURCE_GLOBALNET : RESOURCE_CONTEXT;
  736.     if ((_uDisplayType == RESOURCEDISPLAYTYPE_SERVER) &&
  737.         (grfFlags & SHCONTF_SHAREABLE))
  738.     {
  739.         dwScope = RESOURCE_SHAREABLE;   // hidden admin shares for this server
  740.     }
  741.     DWORD err = WNetOpenEnum(dwScope, dwType, RESOURCEUSAGE_ALL, pnr, phEnum);
  742.     if ((err != WN_SUCCESS) && hwnd)
  743.     {
  744.         // UI has been enabled
  745. #ifndef WINNT
  746.         //
  747.         // If it failed, because the user has not been logged on,
  748.         // give him/her a chance to logon at this moment.
  749.         //
  750.         if (err == WN_NOT_LOGGED_ON)
  751.         {
  752.             err = WNetLogon(pnr ? pnr->lpProvider : NULL, hwnd);
  753.             if (err == WN_SUCCESS)
  754.                 err = WNetOpenEnum(dwScope, dwType, RESOURCEUSAGE_ALL, pnr, phEnum);
  755.         }
  756. #endif // !WINNT
  757.         //
  758.         //  If it failed because you are not authenticated yet,
  759.         // we need to let the user loggin to this network resource.
  760.         //
  761.         // REVIEW: Ask LenS to review this code.
  762.         if (err == WN_NOT_AUTHENTICATED || 
  763.             err == ERROR_LOGON_FAILURE || 
  764.             err == WN_BAD_PASSWORD || 
  765.             err == WN_ACCESS_DENIED)
  766.         {
  767.             // Retry with password dialog box.
  768.             err = WNetAddConnection3(hwnd, pnr, NULL, NULL, CONNECT_TEMPORARY | CONNECT_INTERACTIVE);
  769.             if (err == WN_SUCCESS)
  770.                 err = WNetOpenEnum(dwScope, dwType, RESOURCEUSAGE_ALL, pnr, phEnum);
  771.         }
  772.         UINT idTemplate = pnr && pnr->lpRemoteName ? IDS_ENUMERR_NETTEMPLATE2 : IDS_ENUMERR_NETTEMPLATE1;   
  773.         SHEnumErrorMessageBox(hwnd, idTemplate, err, pnr ? pnr->lpRemoteName : NULL, TRUE, MB_OK | MB_ICONHAND);
  774.     }
  775.     return err;
  776. }
  777. STDMETHODIMP CNetFolder::EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList** ppenum)
  778. {
  779.     HRESULT hr = E_OUTOFMEMORY;
  780.     ENUM_DATA *penet = (ENUM_DATA *)LocalAlloc(LPTR, SIZEOF(ENUM_DATA));
  781.     if (penet)
  782.     {
  783.         DWORD err;
  784.         TCHAR szProvider[MAX_PATH];
  785.         AddRef();
  786.         penet->pnf  = this;
  787.         ASSERT(penet->anr[0].lpRemoteName == NULL);
  788.         ASSERT(penet->dwRemote == 0);
  789.         ASSERT(penet->peunk == NULL);
  790.         ASSERT(penet->cItems == 0);
  791.         ASSERT(penet->iItem == 0);
  792.         penet->anr[0].lpProvider = (LPTSTR) _GetProvider(NULL, szProvider, ARRAYSIZE(szProvider));
  793.         if (_uDisplayType != RESOURCEDISPLAYTYPE_ROOT &&
  794.             _uDisplayType != RESOURCEDISPLAYTYPE_NETWORK)
  795.         {
  796.             penet->anr[0].lpRemoteName = _pszResName;
  797.         }
  798.         err = _OpenEnum(hwnd, grfFlags, &penet->anr[0],  &penet->hEnum);
  799.         if (err == WN_SUCCESS)
  800.         {
  801.             penet->grfFlags = grfFlags;
  802.             hr = SHCreateEnumObjects(hwnd, penet, EnumCallBack, ppenum);
  803.         }
  804.         else
  805.         {
  806.             Release();
  807.             LocalFree(penet);
  808.             hr = HRESULT_FROM_WIN32(err);
  809.         }
  810.     }
  811.     return hr;
  812. }
  813. LPCIDNETRESOURCE NET_IsValidID(LPCITEMIDLIST pidl)
  814. {
  815.     if (pidl && !ILIsEmpty(pidl) && ((pidl->mkid.abID[0] & SHID_GROUPMASK) == SHID_NET))
  816.         return (LPCIDNETRESOURCE)pidl;
  817.     return NULL;
  818. }
  819. STDMETHODIMP CNetFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void** ppvOut)
  820. {
  821.     HRESULT hres;
  822.     LPCIDNETRESOURCE pidn;
  823.     *ppvOut = NULL;
  824.     pidn = NET_IsValidID(pidl);
  825.     if (pidn)
  826.     {
  827.         IShellFolder *psfJunction;
  828.         LPITEMIDLIST pidlInit = NULL;
  829.         LPITEMIDLIST pidlTarget = NULL;
  830.         LPCITEMIDLIST pidlRight = _ILNext(pidl);
  831.         BOOL fRightIsEmpty = ILIsEmpty(pidlRight);
  832.         LPCIDNETRESOURCE pidnProvider = NET_FHasProvider(pidn) ? pidn :_pidnForProvider;
  833.         hres = S_OK;
  834.         // lets get the IDLISTs we are going to use to initialize the shell folder
  835.         // if we are doing a single level bind then then ILCombine otherwise
  836.         // be more careful.
  837.         pidlInit = ILCombineParentAndFirst(_pidl, pidl, pidlRight);
  838.         if ( _pidlTarget )
  839.             pidlTarget = ILCombineParentAndFirst(_pidlTarget, pidl, pidlRight);
  840.         if ( !pidlInit || (!pidlTarget && _pidlTarget) )
  841.            hres = E_OUTOFMEMORY;
  842.         // now create the folder object we are using, and either return that    
  843.         // object to the caller, or continue the binding down.
  844.         if ( SUCCEEDED(hres) )
  845.         {
  846.             hres = _CreateFolderForItem(pidlInit, pidlTarget, pidnProvider, 
  847.                                         fRightIsEmpty ? riid : IID_IShellFolder, 
  848.                                         fRightIsEmpty ? ppvOut : (void **)&psfJunction);
  849.             if ( !fRightIsEmpty && SUCCEEDED(hres) )
  850.             {
  851.                 hres = psfJunction->BindToObject(pidlRight, pbc, riid, ppvOut);
  852.                 psfJunction->Release();
  853.             }        
  854.         }
  855.         ILFree(pidlInit);
  856.         ILFree(pidlTarget);
  857.     }
  858.     else
  859.     {
  860.         hres = E_INVALIDARG;
  861.     }
  862.     return hres;
  863. }
  864. STDMETHODIMP CNetFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void** ppvOut)
  865. {
  866.     *ppvOut = NULL;
  867.     return E_NOTIMPL;
  868. }
  869. STDMETHODIMP CNetFolder::CompareIDs(LPARAM iCol, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  870. {
  871.     HRESULT hres = E_INVALIDARG;
  872.     LPCIDNETRESOURCE pidn1 = NET_IsValidID(pidl1);
  873.     LPCIDNETRESOURCE pidn2 = NET_IsValidID(pidl2);
  874.     if ( pidn1 && pidn2 )
  875.     {
  876.         TCHAR szBuff1[MAX_PATH], szBuff2[MAX_PATH];
  877.         switch (iCol & SHCIDS_COLUMNMASK)
  878.         {
  879.             case ICOL_COMMENT:
  880.             {
  881.                 hres = ResultFromShort(lstrcmpi(NET_CopyComment(pidn1, szBuff1, ARRAYSIZE(szBuff1)), 
  882.                                                 NET_CopyComment(pidn2, szBuff2, ARRAYSIZE(szBuff2))));
  883.                 if ( hres != 0 )
  884.                     return hres;
  885.                 // drop down into the name comparison
  886.             }
  887.             case ICOL_NAME:
  888.             {
  889.                 // Compare by name.  This is the one case where we need to handle
  890.                 // simple ids in either place.  We will try to resync the items
  891.                 // if we find a case of this before do the compares.
  892.                 // Check for relative IDs.  In particular if one item is at
  893.                 // a server and the other is at RestOfNet then try to resync
  894.                 // the two
  895.                 //
  896.                 if ( NET_IsFake(pidn1) || NET_IsFake(pidn2) )
  897.                 {
  898.                     // if either pidn1 or pidn2 is fake then we assume they are identical,
  899.                     // this allows us to compare a simple net ID to a real net ID.  we
  900.                     // assume that if this fails later then the world will be happy
  901.                     hres = 0;
  902.                 }
  903.                 else
  904.                 {
  905.                     // otherwise lets look at the names and provider strings accordingly
  906.                     NET_CopyResName(pidn1, szBuff1, ARRAYSIZE(szBuff1));
  907.                     NET_CopyResName(pidn2, szBuff2, ARRAYSIZE(szBuff2));
  908.                     hres = ResultFromShort(lstrcmpi(szBuff1, szBuff2));
  909.                     // If they're still identical, compare provider names.
  910.                     if ( (hres == 0) && (iCol & SHCIDS_ALLFIELDS) )
  911.                     {
  912.                         LPCTSTR pszProv1 = _GetProvider(pidn1, szBuff1, ARRAYSIZE(szBuff1));
  913.                         LPCTSTR pszProv2 = _GetProvider(pidn2, szBuff2, ARRAYSIZE(szBuff2));
  914.                         if (pszProv1 && pszProv2)
  915.                             hres = ResultFromShort(lstrcmp(pszProv1, pszProv2));
  916.                         else
  917.                         {
  918.                             if (pszProv1 || pszProv2)
  919.                                 hres = ResultFromShort(pszProv1 ? 1 : -1);
  920.                             else
  921.                                 hres = ResultFromShort(0);
  922.                         }
  923.                     }
  924.                 }
  925.                 // If they identical, compare the rest of IDs.
  926.                 if (hres == 0)
  927.                     hres = ILCompareRelIDs((IShellFolder*)this, (LPCITEMIDLIST)pidn1, (LPCITEMIDLIST)pidn2);
  928.             }
  929.         }
  930.     }
  931.     return hres;
  932. }
  933. STDMETHODIMP CNetFolder::CreateViewObject(HWND hwnd, REFIID riid, void** ppvOut)
  934. {
  935.     HRESULT hres;
  936.     *ppvOut = NULL;
  937.     if (IsEqualIID(riid, IID_IShellView))
  938.     {
  939.         SFV_CREATE sSFV;
  940.         sSFV.cbSize   = sizeof(sSFV);
  941.         sSFV.psvOuter = NULL;
  942.         sSFV.psfvcb   = Net_CreateSFVCB((IShellFolder*) this, _uDisplayType, _pidl,
  943.             SHCNE_RENAMEITEM | SHCNE_RENAMEFOLDER | 
  944.             SHCNE_CREATE | SHCNE_DELETE | SHCNE_UPDATEDIR | SHCNE_UPDATEITEM |
  945.             SHCNE_MKDIR | SHCNE_RMDIR);
  946.         QueryInterface(IID_IShellFolder, (void**) &sSFV.pshf);   // in case we are agregated
  947.         hres = SHCreateShellFolderView(&sSFV, (IShellView**) ppvOut);
  948.         if (sSFV.pshf)
  949.             sSFV.pshf->Release();
  950.         if (sSFV.psfvcb)
  951.             sSFV.psfvcb->Release();
  952.     }
  953.     else if (IsEqualIID(riid, IID_IContextMenu))
  954.     {
  955.         IShellFolder* psfOuter;
  956.         hres = QueryInterface(IID_IShellFolder, (void**) &psfOuter);
  957.         if (SUCCEEDED(hres))
  958.         {
  959.             hres = CDefFolderMenu_Create(_pidl, hwnd, 0, NULL, psfOuter, 
  960.                 CNetwork_DFMCallBackBG, NULL, NULL, (IContextMenu**) ppvOut);
  961.             psfOuter->Release();
  962.         }
  963.     }
  964.     else
  965.     {
  966.         hres = E_NOINTERFACE;
  967.     }
  968.     return hres;
  969. }
  970.     
  971. STDMETHODIMP CNetFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST* apidl, ULONG* prgfInOut)
  972. {
  973.     HRESULT hres;
  974.     if (cidl == 0)
  975.     {
  976.         *prgfInOut &= (SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_HASSUBFOLDER |
  977.                        SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_CANMONIKER);
  978.         hres = S_OK;
  979.     }
  980.     else
  981.     {
  982.         hres = Multi_GetAttributesOf((IShellFolder2*) this, cidl, apidl, prgfInOut, GAOCallbackNet);
  983.     }
  984.     return hres;
  985. }
  986. STDMETHODIMP CNetFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, STRRET* pStrRet)
  987. {
  988.     HRESULT hres;
  989.     LPCIDNETRESOURCE pidn = NET_IsValidID(pidl);
  990.     if (pidn)
  991.     {
  992.         TCHAR szPath[MAX_PATH];
  993.         LPCITEMIDLIST pidlNext = _ILNext(pidl);
  994.         if (dwFlags & SHGDN_FORPARSING)
  995.         {
  996.             if (dwFlags & SHGDN_INFOLDER)
  997.             {
  998.                 NET_CopyResName(pidn, szPath, ARRAYSIZE(szPath));
  999.                 if (ILIsEmpty(pidlNext))
  1000.                 {
  1001.                     // we just need the last part of the display name (IN FOLDER)
  1002.                     LPTSTR pszT = StrRChr(szPath, NULL, TEXT('\'));
  1003.                     if (!pszT)
  1004.                         pszT = szPath;
  1005.                     else
  1006.                         pszT++; // move past ''
  1007.                     hres = StringToStrRet(pszT, pStrRet);
  1008.                 }
  1009.                 else
  1010.                 {
  1011.                     hres = ILGetRelDisplayName((IShellFolder*) this, pStrRet, pidl, szPath, MAKEINTRESOURCE(IDS_DSPTEMPLATE_WITH_BACKSLASH));
  1012.                 }
  1013.             }
  1014.             else
  1015.             {
  1016.                 LPCITEMIDLIST pidlRight = _ILNext(pidl);
  1017.                 if ( ILIsEmpty(pidlRight) )
  1018.                 {
  1019.                     hres = _GetPathForItem(pidn, szPath);
  1020.                     if (SUCCEEDED(hres))
  1021.                     {
  1022.                         hres = StringToStrRet(szPath, pStrRet);
  1023.                     }
  1024.                 }
  1025.                 else
  1026.                 {
  1027.                     IShellFolder *psfJunction;
  1028.                     //Get the pidn which has network provider information.
  1029.                     LPCIDNETRESOURCE pidnProvider = NET_FHasProvider(pidn) ? pidn :_pidnForProvider;
  1030.                     LPITEMIDLIST pidlInit, pidlTarget = NULL;
  1031.                     pidlInit = ILCombineParentAndFirst(_pidl, pidl, pidlRight);                    
  1032.                     if ( _pidlTarget )
  1033.                         pidlTarget = ILCombineParentAndFirst(_pidlTarget, pidl, pidlRight);
  1034.     
  1035.                     if ( !pidlInit || (_pidlTarget && !pidlTarget) )
  1036.                         return E_OUTOFMEMORY;
  1037.                     hres = _CreateFolderForItem(pidlInit, pidlTarget, pidnProvider, IID_IShellFolder, (void **)&psfJunction);
  1038.                     if ( SUCCEEDED(hres) )
  1039.                     {
  1040.                         hres = psfJunction->GetDisplayNameOf(pidlRight, dwFlags, pStrRet);
  1041.                         psfJunction->Release();
  1042.                     }
  1043.                     ILFree(pidlInit);
  1044.                     ILFree(pidlTarget);
  1045.                 }
  1046.             }
  1047.         }
  1048.         else
  1049.         {
  1050.             hres = _GetFormatName(pidn, pStrRet);
  1051.             if (SUCCEEDED(hres) && !(dwFlags & SHGDN_INFOLDER) && (NET_GetFlags(pidn) & SHID_JUNCTION))
  1052.             {
  1053.                 TCHAR szServer[MAX_PATH];
  1054.                 LPITEMIDLIST pidlServer = _pidl;
  1055.                 if (_pidlTarget)
  1056.                     pidlServer = _pidlTarget;
  1057.                 SHGetNameAndFlags(pidlServer, SHGDN_FORPARSING, szServer, ARRAYSIZE(szServer), NULL);
  1058.                 StrRetFormat(pStrRet, pidl, MAKEINTRESOURCE(IDS_DSPTEMPLATE_WITH_ON), SkipServerSlashes(szServer));
  1059.             }
  1060.         }
  1061.     }
  1062.     else
  1063.         hres = E_INVALIDARG;
  1064.     return hres;
  1065. }
  1066. STDMETHODIMP CNetFolder::SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD dwRes, LPITEMIDLIST* ppidl)
  1067. {
  1068.     if (ppidl) 
  1069.         *ppidl = NULL;
  1070.     return E_NOTIMPL;   // not supported
  1071. }
  1072. STDMETHODIMP CNetFolder::GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST* apidl,
  1073.                                        REFIID riid, UINT* prgfInOut, void** ppvOut)
  1074. {
  1075.     HRESULT hres = E_INVALIDARG;
  1076.     LPCIDNETRESOURCE pidn = cidl ? NET_IsValidID(apidl[0]) : NULL;
  1077.     *ppvOut = NULL;
  1078.     if ((IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW)) && pidn)
  1079.     {
  1080.         UINT iIndex;
  1081.         if (_IsPrintShare(pidn))
  1082.             iIndex = (UINT)EIRESID(IDI_PRINTER_NET);
  1083.         else if (NET_IsRemoteFld(pidn))
  1084.             iIndex = II_RNA;
  1085.         else
  1086.             iIndex = SILGetIconIndex(apidl[0], c_aicmpNet, ARRAYSIZE(c_aicmpNet));
  1087.         hres = SHCreateDefExtIcon(NULL, iIndex, iIndex, GIL_PERCLASS, riid, ppvOut);
  1088.     }
  1089.     else if (IsEqualIID(riid, IID_IContextMenu) && pidn)
  1090.     {
  1091.         HKEY ahkeys[NKID_COUNT];
  1092.         hres = _OpenKeys(pidn, ahkeys);
  1093.         if (SUCCEEDED(hres))
  1094.         {
  1095.             IShellFolder* psfOuter;
  1096.             hres = QueryInterface(IID_IShellFolder, (void**) &psfOuter);
  1097.             if (SUCCEEDED(hres))
  1098.             {
  1099.                 hres = CDefFolderMenu_Create2(_pidl, hwnd, cidl, apidl, 
  1100.                         psfOuter, _GetCallbackType(pidn), 
  1101.                         ARRAYSIZE(ahkeys), ahkeys, (IContextMenu**) ppvOut);
  1102.                 psfOuter->Release();
  1103.             }
  1104.             SHRegCloseKeys(ahkeys, ARRAYSIZE(ahkeys));
  1105.         }
  1106.     }
  1107.     else if (cidl && IsEqualIID(riid, IID_IDataObject))
  1108.     {
  1109.         // Point & Print printer installation assumes that the
  1110.         // netresources from CNETIDLData_GetData and the
  1111.         // pidls from CIDLData_GetData are in the same order.
  1112.         // Keep it this way.
  1113.         hres = CIDLData_CreateFromIDArray2(&c_CNETIDLDataVtbl, _pidl, cidl, apidl,
  1114.                                            (IDataObject**) ppvOut);
  1115.     }
  1116.     else if (pidn && IsEqualIID(riid, IID_IDropTarget))
  1117.     {
  1118.         // special support because this is an item (not a folder)
  1119.         if (_IsPrintShare(pidn))
  1120.         {
  1121.             hres = CIDLDropTarget_Create(hwnd, &c_CPrintDropTargetVtbl, (LPITEMIDLIST)pidn, (IDropTarget**) ppvOut);
  1122.         }
  1123.         else
  1124.         {
  1125.             IShellFolder* psf;
  1126.             hres = BindToObject(apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psf));
  1127.             if (SUCCEEDED(hres))
  1128.             {
  1129.                 hres = psf->CreateViewObject(hwnd, riid, ppvOut);
  1130.                 psf->Release();
  1131.             }
  1132.         }
  1133.     }
  1134.     else if (pidn && IsEqualIID(riid, IID_IQueryInfo))
  1135.     {
  1136.         if (NET_GetDisplayType(pidn) == RESOURCEDISPLAYTYPE_ROOT)
  1137.         {
  1138.             hres = CreateInfoTipFromText(MAKEINTRESOURCE(IDS_RESTOFNETTIP), riid, ppvOut);
  1139.         }
  1140.         else
  1141.         {
  1142.             // Someday maybe have infotips for other things too
  1143.         }
  1144.     }
  1145.     return hres;
  1146. }
  1147. STDMETHODIMP CNetFolder::GetDefaultSearchGUID(LPGUID pguid)
  1148. {
  1149.     *pguid = SRCID_SFindComputer;
  1150.     return S_OK;
  1151. }
  1152. void WINAPI CNetFolder::_CopyEnumElement(void* pDest, const void* pSource, DWORD dwSize)
  1153. {
  1154.     if ( pDest && pSource )
  1155.         memcpy(pDest, pSource, dwSize);
  1156. }
  1157. STDMETHODIMP CNetFolder::EnumSearches(IEnumExtraSearch** ppenum)
  1158. {
  1159.     HRESULT hres = E_NOTIMPL;
  1160.     
  1161.     *ppenum = NULL;
  1162.     
  1163.     // if the restriction is set then this item should be enumerated from the registry
  1164.     // so we fail, else enumerate it
  1165.     // only enumerate if we actually have a network to search against
  1166.     if (!SHRestricted(REST_HASFINDCOMPUTERS) &&
  1167.         (GetSystemMetrics(SM_NETWORK) & RNC_NETWORKS))
  1168.     {
  1169.         EXTRASEARCH *pxs = (EXTRASEARCH *)LocalAlloc(LPTR, sizeof(EXTRASEARCH));
  1170.         if (pxs)
  1171.         {
  1172.             pxs->guidSearch = SRCID_SFindComputer;
  1173.             if (LoadStringW(g_hinst, IDS_FC_NAME,     pxs->wszFriendlyName, SIZEOF(pxs->wszFriendlyName)))
  1174.             {      
  1175.                 *ppenum = (IEnumExtraSearch*)CStandardEnum_CreateInstance(IID_IEnumExtraSearch, FALSE,
  1176.                             1, sizeof(EXTRASEARCH), pxs, _CopyEnumElement);
  1177.                 if (*ppenum == NULL)
  1178.                 {
  1179.                     LocalFree(pxs);
  1180.                     hres = E_OUTOFMEMORY;
  1181.                 }
  1182.                 else
  1183.                     hres = S_OK;
  1184.             }
  1185.         }
  1186.         else
  1187.             hres = E_OUTOFMEMORY;
  1188.     }
  1189.     return hres;
  1190. }
  1191. STDMETHODIMP CNetFolder::GetDefaultColumn(DWORD dwRes, ULONG* pSort, ULONG* pDisplay)
  1192. {
  1193.     return E_NOTIMPL;
  1194. }
  1195. STDMETHODIMP CNetFolder::GetDefaultColumnState(UINT iColumn, DWORD* pdwState)
  1196. {
  1197.     HRESULT hr = S_OK;
  1198.     *pdwState = 0;
  1199.     
  1200.     if (iColumn < ARRAYSIZE(s_net_cols))
  1201.     {
  1202.         *pdwState |= SHCOLSTATE_TYPE_STR | SHCOLSTATE_ONBYDEFAULT;
  1203.     }
  1204.     else
  1205.     {
  1206.         hr = E_INVALIDARG;
  1207.     }
  1208.     
  1209.     return hr;
  1210. }
  1211. STDMETHODIMP CNetFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID* pscid, VARIANT* pv)
  1212. {
  1213.     HRESULT hres = E_NOTIMPL;
  1214.     LPCIDNETRESOURCE pidn = NET_IsValidID(pidl);
  1215.     if (pidn)
  1216.     {
  1217.         if (IsEqualSCID(*pscid, SCID_NETRESOURCE))
  1218.         {
  1219.             // Office calls SHGetDataFromIDList() with a large buffer to hold all
  1220.             // of the strings in the NETRESOURCE structure, so we need to make sure
  1221.             // that our variant can hold enough data to pass back to it:
  1222.             BYTE rgBuffer[sizeof(NETRESOURCEW) + (4 * MAX_PATH * sizeof(WCHAR))];
  1223.             hres = _GetNetResource(pidn, (NETRESOURCEW*) rgBuffer, sizeof(rgBuffer));
  1224.             if (SUCCEEDED(hres))
  1225.             {
  1226.                 hres = InitVariantFromBuffer(pv, rgBuffer, sizeof(rgBuffer));
  1227.                 if (SUCCEEDED(hres))
  1228.                 {
  1229.                     // Fixup pointers in structure to point within the variant
  1230.                     // instead of our stack variable (rgBuffer):
  1231.                     ASSERT(pv->vt == (VT_ARRAY | VT_UI1));
  1232.                     NETRESOURCEW* pnrw = (NETRESOURCEW*) pv->parray->pvData;
  1233.                     if (pnrw->lpLocalName)
  1234.                     {
  1235.                         pnrw->lpLocalName = (LPWSTR) ((BYTE*) pnrw +
  1236.                                                       ((BYTE*) pnrw->lpLocalName - rgBuffer));
  1237.                     }
  1238.                     if (pnrw->lpRemoteName)
  1239.                     {
  1240.                         pnrw->lpRemoteName = (LPWSTR) ((BYTE*) pnrw +
  1241.                                                        ((BYTE*) pnrw->lpRemoteName - rgBuffer));
  1242.                     }
  1243.                     if (pnrw->lpComment)
  1244.                     {
  1245.                         pnrw->lpComment = (LPWSTR) ((BYTE*) pnrw +
  1246.                                                     ((BYTE*) pnrw->lpComment - rgBuffer));
  1247.                     }
  1248.                     if (pnrw->lpProvider)
  1249.                     {
  1250.                         pnrw->lpProvider = (LPWSTR) ((BYTE*) pnrw +
  1251.                                                      ((BYTE*) pnrw->lpProvider - rgBuffer));
  1252.                     }
  1253.                 }
  1254.             }
  1255.         }
  1256.         else if (IsEqualSCID(*pscid, SCID_DESCRIPTIONID))
  1257.         {
  1258.             SHDESCRIPTIONID did;
  1259.             switch(SIL_GetType(pidl) & SHID_TYPEMASK)
  1260.             {
  1261.                 case SHID_NET_DOMAIN:
  1262.                     did.dwDescriptionId = SHDID_NET_DOMAIN;   
  1263.                     break;
  1264.                 case SHID_NET_SERVER:
  1265.                     did.dwDescriptionId = SHDID_NET_SERVER;
  1266.                     break;
  1267.                 case SHID_NET_SHARE:
  1268.                     did.dwDescriptionId = SHDID_NET_SHARE;    
  1269.                     break;
  1270.                 case SHID_NET_RESTOFNET:
  1271.                     did.dwDescriptionId = SHDID_NET_RESTOFNET;
  1272.                     break;
  1273.                 default:
  1274.                     did.dwDescriptionId = SHDID_NET_OTHER;      
  1275.                     break;
  1276.             }
  1277.             did.clsid = CLSID_NULL;
  1278.             hres = InitVariantFromBuffer(pv, &did, sizeof(did));
  1279.         }
  1280.         else if (IsEqualSCID(*pscid, SCID_Comment))
  1281.         {
  1282.             TCHAR szTemp[MAX_PATH];
  1283.             NET_CopyComment(pidn, szTemp, ARRAYSIZE(szTemp));
  1284.             hres = InitVariantFromStr(pv, szTemp);
  1285.         }
  1286.         else if (IsEqualSCID(*pscid, SCID_NAME))
  1287.         {
  1288.             TCHAR szTemp[MAX_PATH];
  1289.             
  1290.             NET_CopyResName(pidn, szTemp, ARRAYSIZE(szTemp));
  1291.             hres = InitVariantFromStr(pv, szTemp);
  1292.         }
  1293.     }
  1294.     else
  1295.     {
  1296.         IShellFolder2* psfFiles;
  1297.         hres = v_GetFileFolder(&psfFiles);
  1298.         if (SUCCEEDED(hres))
  1299.             hres = psfFiles->GetDetailsEx(pidl, pscid, pv);            
  1300.     }
  1301.     return hres;
  1302. }
  1303. STDMETHODIMP CNetFolder::GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pDetails)
  1304. {
  1305.     TCHAR szTemp[MAX_PATH];
  1306.     LPCIDNETRESOURCE pidn;
  1307.     if (iColumn >= ARRAYSIZE(s_net_cols))
  1308.         return E_NOTIMPL;
  1309.     pDetails->str.uType = STRRET_CSTR;
  1310.     pDetails->str.cStr[0] = 0;
  1311.     if (!pidl)
  1312.     {
  1313.         pDetails->fmt = s_net_cols[iColumn].iFmt;
  1314.         pDetails->cxChar = s_net_cols[iColumn].cchCol;
  1315.         return ResToStrRet(s_net_cols[iColumn].ids, &pDetails->str);
  1316.     }
  1317.     pidn = NET_IsValidID(pidl);
  1318.     switch (iColumn)
  1319.     {
  1320.         case ICOL_NAME:
  1321.             if (pidn)
  1322.             {
  1323.                 NET_CopyResName(pidn, szTemp, ARRAYSIZE(szTemp));
  1324.                 return StringToStrRet(szTemp, &pDetails->str);
  1325.             }
  1326.             else
  1327.             {
  1328.                 IShellFolder2* psfFiles;
  1329.                 if (SUCCEEDED(v_GetFileFolder(&psfFiles)))
  1330.                     return psfFiles->GetDisplayNameOf(pidl, SHGDN_NORMAL, &pDetails->str);
  1331.             }
  1332.             break;
  1333.         case ICOL_COMMENT:
  1334.             if (pidn)
  1335.             {
  1336.                 NET_CopyComment(pidn, szTemp, ARRAYSIZE(szTemp));
  1337.                 return StringToStrRet(szTemp, &pDetails->str);
  1338.             }
  1339.             else 
  1340.             {
  1341.                 IShellFolder2* psfFiles;
  1342.                 if (SUCCEEDED(v_GetFileFolder(&psfFiles)))
  1343.                 {
  1344.                     // call the nethood folder and get the comment field from that, we cannot
  1345.                     // use the column index we have, instead we must use GetDetailsEx and
  1346.                     // pass the unique columne ID.
  1347.                     return MapSCIDToDetailsOf(psfFiles, pidl, &SCID_Comment, pDetails);
  1348.                 }
  1349.             }
  1350.             break;
  1351.     }
  1352.     return S_OK;
  1353. }
  1354. STDMETHODIMP CNetFolder::MapColumnToSCID(UINT iColumn, SHCOLUMNID* pscid)
  1355. {
  1356.     return MapColumnToSCIDImpl(s_net_cols, ARRAYSIZE(s_net_cols), iColumn, pscid);
  1357. }
  1358. // IPersist methods
  1359. STDMETHODIMP CNetFolder::GetClassID(CLSID* pCLSID)
  1360. {
  1361.     switch (_uDisplayType) 
  1362.     {
  1363.         case RESOURCEDISPLAYTYPE_ROOT:
  1364.             *pCLSID = CLSID_NetworkRoot;
  1365.             break;
  1366.         case RESOURCEDISPLAYTYPE_SERVER:
  1367.             *pCLSID = CLSID_NetworkServer;
  1368.             break;
  1369.         case RESOURCEDISPLAYTYPE_DOMAIN:
  1370.             *pCLSID = CLSID_NetworkDomain;
  1371.             break;
  1372.         case RESOURCEDISPLAYTYPE_SHARE:
  1373.             *pCLSID = CLSID_NetworkShare;
  1374.             break;
  1375.         default:
  1376.             *pCLSID = CLSID_NULL;
  1377.             break;
  1378.     }
  1379.     
  1380.     return S_OK;
  1381. }
  1382. // IPersistFolder method
  1383. STDMETHODIMP CNetFolder::Initialize(LPCITEMIDLIST pidl)
  1384. {
  1385.     ILFree(_pidl);
  1386.     ILFree(_pidlTarget);
  1387.     _pidl = _pidlTarget = NULL;
  1388.     return SHILClone(pidl, &_pidl);
  1389. }
  1390. // IPersistFolder2 method
  1391. STDMETHODIMP CNetFolder::GetCurFolder(LPITEMIDLIST* ppidl)
  1392. {
  1393.     return GetCurFolderImpl(_pidl, ppidl);
  1394. }
  1395. // IPersistFolder3 methods
  1396. STDMETHODIMP CNetFolder::InitializeEx(IBindCtx *pbc, LPCITEMIDLIST pidlRoot, const PERSIST_FOLDER_TARGET_INFO *pfti)
  1397. {
  1398.     ILFree(_pidl);
  1399.     ILFree(_pidlTarget);
  1400.     _pidl = _pidlTarget = NULL;
  1401.     HRESULT hres = SHILClone(pidlRoot, &_pidl);
  1402.     if ( SUCCEEDED(hres) && pfti && pfti->pidlTargetFolder )
  1403.     {
  1404.         hres = SHILClone(pfti->pidlTargetFolder, &_pidlTarget);
  1405.     }
  1406.     return hres;
  1407. }
  1408. STDMETHODIMP CNetFolder::GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO *pfti)
  1409. {
  1410.     HRESULT hres = S_OK;
  1411.     ZeroMemory(pfti, SIZEOF(*pfti));
  1412.     if ( _pidlTarget )
  1413.         hres = SHILClone(_pidlTarget, &pfti->pidlTargetFolder);
  1414.     
  1415.     pfti->dwAttributes = FILE_ATTRIBUTE_DIRECTORY; // maybe add system?
  1416.     pfti->csidl = -1;
  1417.     return hres;
  1418. }
  1419. // IShellIconOverlay
  1420. HRESULT CNetFolder::_GetIconOverlayInfo(LPCIDNETRESOURCE pidn, int *pIndex, DWORD dwFlags)
  1421. {
  1422.     HRESULT hres = E_FAIL;
  1423.     //
  1424.     // For netshare objects we want to get the icon overlay.
  1425.     // If the share is "pinned" to be available offline it will
  1426.     // have the "Offline Files" overlay.
  1427.     //
  1428.     if (RESOURCEDISPLAYTYPE_SHARE == NET_GetDisplayType(pidn))
  1429.     {
  1430.         TCHAR szPath[MAX_PATH];
  1431.         hres = _GetPathForItem(pidn, szPath);
  1432.         if (SUCCEEDED(hres))
  1433.         {
  1434.             IShellIconOverlayManager *psiom;
  1435.             hres = GetIconOverlayManager(&psiom);
  1436.             if (SUCCEEDED(hres))
  1437.             {
  1438.                 WCHAR szPathW[MAX_PATH];
  1439.                 SHTCharToUnicode(szPath, szPathW, ARRAYSIZE(szPathW));
  1440.                 hres = psiom->GetFileOverlayInfo(szPathW, 0, pIndex, dwFlags);
  1441.                 psiom->Release();
  1442.             }
  1443.         }
  1444.     }
  1445.     return hres;
  1446. }
  1447. STDMETHODIMP CNetFolder::GetOverlayIndex(LPCITEMIDLIST pidl, int *pIndex)
  1448. {
  1449.     HRESULT hres = E_FAIL;
  1450.     LPCIDNETRESOURCE pidn = NET_IsValidID(pidl);
  1451.     if (NULL != pidn)
  1452.     {
  1453.         hres = _GetIconOverlayInfo(pidn, pIndex, SIOM_OVERLAYINDEX);
  1454.     }
  1455.     return hres;
  1456. }
  1457. STDMETHODIMP CNetFolder::GetOverlayIconIndex(LPCITEMIDLIST pidl, int *pIndex)
  1458. {
  1459.     HRESULT hres = E_FAIL;
  1460.     LPCIDNETRESOURCE pidn = NET_IsValidID(pidl);
  1461.     if (NULL != pidn)
  1462.     {
  1463.         hres = _GetIconOverlayInfo(pidn, pIndex, SIOM_ICONINDEX);
  1464.     }
  1465.     return hres;
  1466. }
  1467. //
  1468. // Helper function to allow external callers to query information from a
  1469. // network pidl...
  1470. //
  1471. // NOTE NOTE - This function returns a NETRESOURCE structure whose string
  1472. // pointers are not valid.  On Win95 they were pointers back into the pidl's
  1473. // strings (even though the strings were copied into the supplied pv buffer.)
  1474. // Now we make the pointers really point into the buffer.
  1475. //
  1476. HRESULT CNetFolder::_GetNetResource(LPCIDNETRESOURCE pidn, NETRESOURCEW* pnr, int cb)
  1477. {
  1478.     TCHAR szStrings[3][MAX_PATH];
  1479.     LPWSTR psz, lpsz[3] = {NULL, NULL, NULL};
  1480.     int i, cchT;
  1481.     if (cb < SIZEOF(*pnr))
  1482.         return DISP_E_BUFFERTOOSMALL;
  1483.     ZeroMemory(pnr, cb);
  1484.     NET_CopyResName(pidn, szStrings[0], ARRAYSIZE(szStrings[0]));
  1485.     NET_CopyComment(pidn, szStrings[1], ARRAYSIZE(szStrings[1]));
  1486.     _GetProvider(pidn, szStrings[2], ARRAYSIZE(szStrings[2]));
  1487.     // Fill in some of the stuff first.
  1488.     // pnr->dwScope = 0;
  1489.     pnr->dwType = NET_GetType(pidn);
  1490.     pnr->dwDisplayType = NET_GetDisplayType(pidn);
  1491.     pnr->dwUsage = NET_GetUsage(pidn);
  1492.     // pnr->lpLocalName = NULL;
  1493.     // Now lets copy the strings into the buffer and make the pointers
  1494.     // relative to the buffer...
  1495.     psz = (LPWSTR)(pnr + 1);
  1496.     cb -= SIZEOF(*pnr);
  1497.     for (i = 0; i < ARRAYSIZE(szStrings); i++)
  1498.     {
  1499.         if (*szStrings[i])
  1500.         {
  1501.             cchT = (lstrlen(szStrings[i]) + 1) * SIZEOF(TCHAR);
  1502.             if (cchT <= cb)
  1503.             {
  1504.                 SHTCharToUnicode(szStrings[i], psz, cb);
  1505.                 lpsz[i] = psz;
  1506.                 psz += cchT;
  1507.                 cb -= cchT * SIZEOF(TCHAR);
  1508.             }
  1509.             else
  1510.             {
  1511.                 // A hint that the structure is ok,
  1512.                 // but the strings are missing
  1513.                 SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1514.             }
  1515.         }
  1516.     }
  1517.     pnr->lpRemoteName = lpsz[0];
  1518.     pnr->lpComment    = lpsz[1];
  1519.     pnr->lpProvider   = lpsz[2];
  1520.     return S_OK;
  1521. }
  1522. // Replace all the space characters in the provider name with '_'.
  1523. void ReplaceSpacesWithUnderscore(LPTSTR psz)
  1524. {
  1525.     while (psz = StrChr(psz, TEXT(' ')))
  1526.     {
  1527.         *psz = TEXT('_');
  1528.         psz++;              // DBCS safe
  1529.     }
  1530. }
  1531. //
  1532. // This function opens a reg. database key based on the "network provider".
  1533. //
  1534. // Returns:        hkey
  1535. //
  1536. // The caller is responsibe to close the key by calling RegCloseKey().
  1537. //
  1538. HKEY CNetFolder::_OpenProviderKey(LPCIDNETRESOURCE pidn)
  1539. {
  1540.     TCHAR szProvider[MAX_PATH];
  1541.     if (_GetProvider(pidn, szProvider, ARRAYSIZE(szProvider)))
  1542.     {
  1543.         HKEY hkeyProgID = NULL;
  1544.         ReplaceSpacesWithUnderscore(szProvider);
  1545.         RegOpenKey(HKEY_CLASSES_ROOT, szProvider, &hkeyProgID);
  1546.         return hkeyProgID;
  1547.     }
  1548.     return NULL;
  1549. }
  1550. // for netview.cpp
  1551. STDAPI_(BOOL) NET_GetProviderKeyName(IShellFolder* psf, LPTSTR pszName, UINT uNameLen)
  1552. {
  1553.     CNetFolder* pThis;
  1554.     *pszName = 0;
  1555.     if (SUCCEEDED(psf->QueryInterface(CLSID_CNetFldr, (void**) &pThis)) &&
  1556.         pThis->_GetProvider(NULL, pszName, uNameLen))
  1557.     {
  1558.         ReplaceSpacesWithUnderscore(pszName);
  1559.     }
  1560.     return (BOOL)*pszName;
  1561. }
  1562. //
  1563. // This function opens a reg. database key based on the network provider type.
  1564. // The type is a number that is not localized, as opposed to the provider name
  1565. // which may be localized.
  1566. //
  1567. // Arguments:
  1568. //  pidlAbs -- Absolute IDList to a network resource object.
  1569. //
  1570. // Returns:        hkey
  1571. //
  1572. // Notes:
  1573. //  The caller is responsible to close the key by calling RegCloseKey().
  1574. //
  1575. #ifdef WINNT
  1576. HKEY CNetFolder::_OpenProviderTypeKey(LPCIDNETRESOURCE pidn)
  1577. {
  1578.     HKEY hkeyProgID = NULL;
  1579.     TCHAR szProvider[MAX_PATH];
  1580.     if (_GetProvider(pidn, szProvider, ARRAYSIZE(szProvider)))
  1581.     {
  1582.         // Now that we've got the provider name, get the provider id.
  1583.         DWORD dwType;
  1584.         if (WNetGetProviderType(szProvider, &dwType) == WN_SUCCESS)
  1585.         {
  1586.             // convert nis.wNetType to a string, and then open the key
  1587.             // HKEY_CLASSES_ROOTNetworkType<type string>
  1588.             TCHAR szRegValue[MAX_PATH];
  1589.             wsprintf(szRegValue, TEXT("Network\Type\%d"), HIWORD(dwType));
  1590.             RegOpenKey(HKEY_CLASSES_ROOT, szRegValue, &hkeyProgID);
  1591.         }
  1592.     }
  1593.     return hkeyProgID;
  1594. }
  1595. #endif // WINNT
  1596. HRESULT CNetFolder::_OpenKeys(LPCIDNETRESOURCE pidn, HKEY ahkeys[NKID_COUNT])
  1597. {
  1598.     // See if there is a key specific to the type of Network object...
  1599.     ahkeys[0] = ahkeys[1] = ahkeys[2] = ahkeys[3] = ahkeys[4] = ahkeys[5] = NULL;
  1600. #ifdef WINNT
  1601.     ahkeys[NKID_PROVIDERTYPE] = _OpenProviderTypeKey(pidn);
  1602. #endif
  1603.     ahkeys[NKID_PROVIDER] = _OpenProviderKey(pidn);
  1604.     if (NET_GetDisplayType(pidn) == RESOURCEDISPLAYTYPE_SHARE)
  1605.         RegOpenKey(HKEY_CLASSES_ROOT, TEXT("NetShare"), &ahkeys[NKID_NETCLASS]);
  1606.     else if (NET_GetDisplayType(pidn) == RESOURCEDISPLAYTYPE_SERVER)
  1607.         RegOpenKey(HKEY_CLASSES_ROOT, TEXT("NetServer"), &ahkeys[NKID_NETCLASS]);
  1608.     RegOpenKey(HKEY_CLASSES_ROOT, TEXT("Network"), &ahkeys[NKID_NETWORK]);
  1609.     // make sure it is not a printer before adding "Folder" or "directory"
  1610.     if (!_IsPrintShare(pidn))
  1611.     {
  1612.         // Shares should also support directory stuff...
  1613.         if (NET_GetDisplayType(pidn) == RESOURCEDISPLAYTYPE_SHARE)
  1614.             RegOpenKey(HKEY_CLASSES_ROOT, c_szDirectoryClass, &ahkeys[NKID_DIRECTORY]);
  1615.         RegOpenKey(HKEY_CLASSES_ROOT, c_szFolderClass, &ahkeys[NKID_FOLDER]);
  1616.     }
  1617.     return S_OK;
  1618. }
  1619. #ifdef WINNT
  1620. #define WNFMT_PLATFORM  WNFMT_ABBREVIATED | WNFMT_INENUM
  1621. #else
  1622. #define WNFMT_PLATFORM  WNFMT_INENUM    // Win95 net providers improperly implement spec, and shell does too
  1623. #endif // WINNT
  1624. //
  1625. //  This function retrieves the formatted (display) name of the specified network object.
  1626. //
  1627. HRESULT CNetFolder::_GetFormatName(LPCIDNETRESOURCE pidn, STRRET* pStrRet)
  1628. {
  1629.     TCHAR szName[MAX_PATH];
  1630.     NET_CopyResName(pidn, szName, ARRAYSIZE(szName));
  1631.     if ((NET_GetDisplayType(pidn) != RESOURCEDISPLAYTYPE_ROOT) && 
  1632.         (NET_GetDisplayType(pidn) != RESOURCEDISPLAYTYPE_NETWORK))
  1633.     {
  1634.         TCHAR szDisplayName[MAX_PATH], szProvider[MAX_PATH];
  1635.         DWORD dwSize = ARRAYSIZE(szDisplayName);
  1636.         LPCTSTR pszProvider = _GetProvider(pidn, szProvider, ARRAYSIZE(szProvider));
  1637.         if ( pszProvider )
  1638.         {   
  1639.             DWORD dwRes = WNetFormatNetworkName(pszProvider, szName, szDisplayName, &dwSize, WNFMT_PLATFORM, 8 + 1 + 3);
  1640.             if ( dwRes == WN_SUCCESS )            
  1641.                 lstrcpy(szName, szDisplayName);
  1642.         }
  1643.     }
  1644.     return StringToStrRet(szName, pStrRet);
  1645. }
  1646. //
  1647. // resolve non-UNC share names (novell) to UNC style names
  1648. //
  1649. // returns:
  1650. //      TRUE    translated the name
  1651. //      FALSE   didn't translate (maybe error case)
  1652. //