Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

4873 lines
153 KiB

  1. #include "shellprv.h"
  2. #include "caggunk.h"
  3. #include "views.h"
  4. #include "ids.h"
  5. #include "shitemid.h"
  6. #include "fstreex.h"
  7. #include "clsobj.h"
  8. #include "datautil.h"
  9. #include "winnetp.h" // RESOURCE_SHAREABLE
  10. #include "prop.h"
  11. #include "infotip.h"
  12. #include "basefvcb.h"
  13. #include "netview.h"
  14. #include "printer.h"
  15. #include "fsdata.h"
  16. #include "idldrop.h"
  17. #include "enumidlist.h"
  18. #include "util.h"
  19. #include <webvw.h>
  20. #define WNNC_NET_LARGEST WNNC_NET_SYMFONET
  21. HRESULT CNetRootDropTarget_CreateInstance(HWND hwnd, LPCITEMIDLIST pidl, IDropTarget **ppdropt);
  22. class CNetData : public CFSIDLData
  23. {
  24. public:
  25. CNetData(LPCITEMIDLIST pidlFolder, UINT cidl, LPCITEMIDLIST apidl[]): CFSIDLData(pidlFolder, cidl, apidl, NULL) { };
  26. // IDataObject methods overwrite
  27. STDMETHODIMP GetData(FORMATETC *pFmtEtc, STGMEDIUM *pstm);
  28. STDMETHODIMP QueryGetData(FORMATETC *pFmtEtc);
  29. protected:
  30. STDMETHODIMP GetHDrop(FORMATETC *pformatetcIn, STGMEDIUM *pmedium);
  31. };
  32. // {22BEB58B-0794-11d2-A4AA-00C04F8EEB3E}
  33. const GUID CLSID_CNetFldr = { 0x22beb58b, 0x794, 0x11d2, 0xa4, 0xaa, 0x0, 0xc0, 0x4f, 0x8e, 0xeb, 0x3e };
  34. // idlist.c
  35. STDAPI_(void) StrRetFormat(STRRET *pStrRet, LPCITEMIDLIST pidlRel, LPCTSTR pszTemplate, LPCTSTR pszAppend);
  36. // in stdenum.cpp
  37. STDAPI_(void *) CStandardEnum_CreateInstance(REFIID riid, BOOL bInterfaces, int cElement, int cbElement, void *rgElements,
  38. void (WINAPI * pfnCopyElement)(void *, const void *, DWORD));
  39. // is a \\server\printer object
  40. BOOL _IsPrintShare(LPCIDNETRESOURCE pidn)
  41. {
  42. return NET_GetDisplayType(pidn) == RESOURCEDISPLAYTYPE_SHARE &&
  43. NET_GetType(pidn) == RESOURCETYPE_PRINT;
  44. }
  45. // column information
  46. enum
  47. {
  48. ICOL_NAME = 0,
  49. ICOL_COMMENT,
  50. ICOL_COMPUTERNAME,
  51. ICOL_NETWORKLOCATION
  52. };
  53. const COLUMN_INFO s_net_cols[] =
  54. {
  55. DEFINE_COL_STR_ENTRY(SCID_NAME, 30, IDS_NAME_COL),
  56. DEFINE_COL_STR_ENTRY(SCID_Comment, 30, IDS_EXCOL_COMMENT),
  57. DEFINE_COL_STR_ENTRY(SCID_COMPUTERNAME, 30, IDS_EXCOL_COMPUTER),
  58. DEFINE_COL_STR_ENTRY(SCID_NETWORKLOCATION, 30, IDS_NETWORKLOCATION),
  59. };
  60. #define MAX_ICOL_NETFOLDER (ICOL_COMMENT+1)
  61. #define MAX_ICOL_NETROOT (ICOL_NETWORKLOCATION+1)
  62. STDAPI CNetwork_DFMCallBackBG(IShellFolder *psf, HWND hwnd, IDataObject *pdtobj, UINT uMsg, WPARAM wParam, LPARAM lParam);
  63. class CNetFolderViewCB;
  64. class CNetFolderEnum;
  65. class CNetFolder : public CAggregatedUnknown,
  66. public IShellFolder2,
  67. public IPersistFolder3,
  68. public IShellIconOverlay
  69. {
  70. friend CNetFolderViewCB;
  71. friend CNetFolderEnum;
  72. public:
  73. // IUnknown
  74. STDMETHODIMP QueryInterface(REFIID riid, void ** ppvObj)
  75. { return CAggregatedUnknown::QueryInterface(riid, ppvObj); };
  76. STDMETHODIMP_(ULONG) AddRef(void)
  77. { return CAggregatedUnknown::AddRef(); };
  78. STDMETHODIMP_(ULONG) Release(void)
  79. { return CAggregatedUnknown::Release(); };
  80. // IShellFolder
  81. STDMETHODIMP ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR lpszDisplayName,
  82. ULONG* pchEaten, LPITEMIDLIST* ppidl, ULONG* pdwAttributes);
  83. STDMETHODIMP EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList ** ppenumIDList);
  84. STDMETHODIMP BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv);
  85. STDMETHODIMP BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppvObj);
  86. STDMETHODIMP CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
  87. STDMETHODIMP CreateViewObject(HWND hwndOwner, REFIID riid, void **ppv);
  88. STDMETHODIMP GetAttributesOf(UINT cidl, LPCITEMIDLIST* apidl, ULONG* rgfInOut);
  89. STDMETHODIMP GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST* apidl,
  90. REFIID riid, UINT* prgfInOut, void **ppv);
  91. STDMETHODIMP GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName);
  92. STDMETHODIMP SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD uFlags,
  93. LPITEMIDLIST* ppidlOut);
  94. // IShellFolder2
  95. STDMETHODIMP GetDefaultSearchGUID(GUID *pGuid);
  96. STDMETHODIMP EnumSearches(IEnumExtraSearch **ppenum);
  97. STDMETHODIMP GetDefaultColumn(DWORD dwRes, ULONG* pSort, ULONG* pDisplay);
  98. STDMETHODIMP GetDefaultColumnState(UINT iColumn, DWORD* pbState)
  99. { return _GetDefaultColumnState(MAX_ICOL_NETFOLDER, iColumn, pbState); }
  100. STDMETHODIMP GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID* pscid, VARIANT* pv);
  101. STDMETHODIMP GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS* pDetails)
  102. { return _GetDetailsOf(MAX_ICOL_NETFOLDER, pidl, iColumn, pDetails); }
  103. STDMETHODIMP MapColumnToSCID(UINT iColumn, SHCOLUMNID* pscid)
  104. { return _MapColumnToSCID(MAX_ICOL_NETFOLDER, iColumn, pscid); }
  105. // IPersist
  106. STDMETHODIMP GetClassID(CLSID* pClassID);
  107. // IPersistFolder
  108. STDMETHODIMP Initialize(LPCITEMIDLIST pidl);
  109. // IPersistFolder2
  110. STDMETHODIMP GetCurFolder(LPITEMIDLIST* ppidl);
  111. // IPersistFolder3
  112. STDMETHOD(InitializeEx)(IBindCtx *pbc, LPCITEMIDLIST pidlRoot, const PERSIST_FOLDER_TARGET_INFO *ppfai);
  113. STDMETHOD(GetFolderTargetInfo)(PERSIST_FOLDER_TARGET_INFO *ppfai);
  114. // *** IShellIconOverlay methods***
  115. STDMETHOD(GetOverlayIndex)(LPCITEMIDLIST pidl, int * pIndex);
  116. STDMETHOD(GetOverlayIconIndex)(LPCITEMIDLIST pidl, int * pIconIndex);
  117. protected:
  118. CNetFolder(IUnknown* punkOuter);
  119. ~CNetFolder();
  120. virtual HRESULT v_GetFileFolder(IShellFolder2 **ppsfFiles)
  121. { *ppsfFiles = NULL; return E_NOTIMPL; };
  122. // used by the CAggregatedUnknown stuff
  123. HRESULT v_InternalQueryInterface(REFIID riid, void **ppvObj);
  124. HRESULT _OpenKeys(LPCIDNETRESOURCE pidn, HKEY ahkeys[]);
  125. LPCTSTR _GetProvider(LPCIDNETRESOURCE pidn, IBindCtx *pbc, LPTSTR pszProvider, UINT cchProvider);
  126. DWORD _OpenEnum(HWND hwnd, DWORD grfFlags, LPNETRESOURCE pnr, HANDLE *phEnum);
  127. static HRESULT _CreateNetIDList(LPIDNETRESOURCE pidnIn,
  128. LPCTSTR pszName, LPCTSTR pszProvider, LPCTSTR pszComment,
  129. LPITEMIDLIST *ppidl);
  130. static HRESULT _NetResToIDList(NETRESOURCE *pnr,
  131. BOOL fKeepNullRemoteName,
  132. BOOL fKeepProviderName,
  133. BOOL fKeepComment,
  134. LPITEMIDLIST *ppidl);
  135. static HRESULT _CreateEntireNetwork(LPITEMIDLIST *ppidl);
  136. static HRESULT _CreateEntireNetworkFullIDList(LPITEMIDLIST *ppidl);
  137. LPTSTR _GetNameForParsing(LPCWSTR pwszName, LPTSTR pszBuffer, INT cchBuffer, LPTSTR *ppszRegItem);
  138. HRESULT _ParseRest(LPBC pbc, LPCWSTR pszRest, LPITEMIDLIST* ppidl, DWORD* pdwAttributes);
  139. HRESULT _AddUnknownIDList(DWORD dwDisplayType, LPITEMIDLIST *ppidl);
  140. HRESULT _ParseSimple(LPBC pbc, LPWSTR pszName, LPITEMIDLIST* ppidl, DWORD* pdwAttributes);
  141. HRESULT _NetResToIDLists(NETRESOURCE *pnr, DWORD dwbuf, LPITEMIDLIST *ppidl);
  142. HRESULT _ParseNetName(HWND hwnd, LPBC pbc, LPCWSTR pwszName, ULONG* pchEaten,
  143. LPITEMIDLIST* ppidl, DWORD* pdwAttributes);
  144. LONG _GetFilePIDLType(LPCITEMIDLIST pidl);
  145. LPITEMIDLIST _AddProviderToPidl(LPITEMIDLIST pidl, LPCTSTR lpProvider);
  146. BOOL _MakeStripToLikeKinds(UINT *pcidl, LPCITEMIDLIST **papidl, BOOL fNetObjects);
  147. HRESULT _GetDefaultColumnState(UINT cColumns, UINT iColumn, DWORD* pdwState);
  148. HRESULT _GetDetailsOf(UINT cColumns, LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pDetails);
  149. HRESULT _MapColumnToSCID(UINT cColumns, UINT iColumn, SHCOLUMNID* pscid);
  150. LPFNDFMCALLBACK _GetCallbackType(LPCIDNETRESOURCE pidn)
  151. { return _IsPrintShare(pidn) ? &PrinterDFMCallBack : &DFMCallBack; };
  152. static HRESULT CALLBACK _AttributesCallbackRoot(IShellFolder2* psf, LPCITEMIDLIST pidl, ULONG* prgfInOut);
  153. LPITEMIDLIST _pidl;
  154. LPITEMIDLIST _pidlTarget; // pidl of where the folder is in the namespace
  155. LPCIDNETRESOURCE _pidnForProvider; // optional provider for this container...
  156. LPTSTR _pszResName; // optional resource name of this container
  157. UINT _uDisplayType; // display type of the folder
  158. IShellFolder2* _psfFiles;
  159. IUnknown* _punkReg;
  160. private:
  161. HRESULT _CreateInstance(LPCITEMIDLIST pidlAbs, LPCITEMIDLIST pidlTarget,
  162. UINT uDisplayType,
  163. LPCIDNETRESOURCE pidnForProvider, LPCTSTR pszResName,
  164. REFIID riid, void **ppv);
  165. friend HRESULT CNetwork_DFMCallBackBG(IShellFolder *psf, HWND hwnd,
  166. IDataObject *pdtobj, UINT uMsg,
  167. WPARAM wParam, LPARAM lParam);
  168. static DWORD CALLBACK _PropertiesThreadProc(void *pv);
  169. static HRESULT DFMCallBack(IShellFolder* psf, HWND hwnd,
  170. IDataObject* pdtobj, UINT uMsg,
  171. WPARAM wParam, LPARAM lParam);
  172. static HRESULT PrinterDFMCallBack(IShellFolder* psf, HWND hwnd,
  173. IDataObject* pdtobj, UINT uMsg,
  174. WPARAM wParam, LPARAM lParam);
  175. static HRESULT CALLBACK _AttributesCallback(IShellFolder2* psf, LPCITEMIDLIST pidl, ULONG* prgfInOut);
  176. BOOL _GetPathForShare(LPCIDNETRESOURCE pidn, LPTSTR pszPath);
  177. HRESULT _GetPathForItem(LPCIDNETRESOURCE pidn, LPTSTR pszPath);
  178. HRESULT _GetPathForItemW(LPCIDNETRESOURCE pidn, LPWSTR pszPath);
  179. HRESULT _CreateFolderForItem(LPBC pbc, LPCITEMIDLIST pidl, LPCITEMIDLIST pidlTarget, LPCIDNETRESOURCE pidnForProvider, REFIID riid, void **ppv);
  180. HRESULT _GetFormatName(LPCIDNETRESOURCE pidn, STRRET* pStrRet);
  181. HRESULT _GetIconOverlayInfo(LPCIDNETRESOURCE pidn, int *pIndex, DWORD dwFlags);
  182. HKEY _OpenProviderTypeKey(LPCIDNETRESOURCE pidn);
  183. HKEY _OpenProviderKey(LPCIDNETRESOURCE pidn);
  184. static void WINAPI _CopyEnumElement(void* pDest, const void* pSource, DWORD dwSize);
  185. HRESULT _GetNetResource(LPCIDNETRESOURCE pidn, NETRESOURCEW* pnr, int cb);
  186. };
  187. class CNetRootFolder : public CNetFolder
  188. {
  189. public:
  190. // IUnknown
  191. STDMETHODIMP QueryInterface(REFIID riid, void ** ppvObj)
  192. { return CNetFolder::QueryInterface(riid, ppvObj); };
  193. STDMETHODIMP_(ULONG) AddRef(void)
  194. { return CNetFolder::AddRef(); };
  195. STDMETHODIMP_(ULONG) Release(void)
  196. { return CNetFolder::Release(); };
  197. // IShellFolder
  198. STDMETHODIMP ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR lpszDisplayName,
  199. ULONG* pchEaten, LPITEMIDLIST* ppidl, ULONG* pdwAttributes);
  200. STDMETHODIMP EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList ** ppenumIDList);
  201. STDMETHODIMP BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv);
  202. STDMETHODIMP BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppvObj)
  203. { return CNetFolder::BindToStorage(pidl, pbc, riid, ppvObj); };
  204. STDMETHODIMP CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
  205. STDMETHODIMP CreateViewObject(HWND hwndOwner, REFIID riid, void **ppv);
  206. STDMETHODIMP GetAttributesOf(UINT cidl, LPCITEMIDLIST* apidl, ULONG* rgfInOut);
  207. STDMETHODIMP GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST* apidl,
  208. REFIID riid, UINT* prgfInOut, void **ppv);
  209. STDMETHODIMP GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, LPSTRRET lpName);
  210. STDMETHODIMP SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD uFlags,
  211. LPITEMIDLIST* ppidlOut);
  212. // IShellFolder2
  213. STDMETHODIMP GetDefaultSearchGUID(GUID *pGuid)
  214. { return CNetFolder::GetDefaultSearchGUID(pGuid); };
  215. STDMETHODIMP EnumSearches(IEnumExtraSearch **ppenum)
  216. { return CNetFolder::EnumSearches(ppenum); };
  217. STDMETHODIMP GetDefaultColumn(DWORD dwRes, ULONG* pSort, ULONG* pDisplay)
  218. { return CNetFolder::GetDefaultColumn(dwRes, pSort, pDisplay); };
  219. STDMETHODIMP GetDefaultColumnState(UINT iColumn, DWORD* pbState)
  220. { return _GetDefaultColumnState(MAX_ICOL_NETROOT, iColumn, pbState); } // +1 for <= check
  221. STDMETHODIMP GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID* pscid, VARIANT* pv)
  222. { return CNetFolder::GetDetailsEx(pidl, pscid, pv); };
  223. STDMETHODIMP GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS* pDetails)
  224. { return _GetDetailsOf(MAX_ICOL_NETROOT, pidl, iColumn, pDetails); };
  225. STDMETHODIMP MapColumnToSCID(UINT iColumn, SHCOLUMNID* pscid)
  226. { return _MapColumnToSCID(MAX_ICOL_NETROOT, iColumn, pscid); }
  227. // IPersist
  228. STDMETHODIMP GetClassID(CLSID* pClassID);
  229. // IPersistFolder
  230. STDMETHODIMP Initialize(LPCITEMIDLIST pidl);
  231. // IPersistFolder2
  232. STDMETHODIMP GetCurFolder(LPITEMIDLIST* ppidl) { return CNetFolder::GetCurFolder(ppidl); };
  233. // IPersistFolder3
  234. STDMETHOD(InitializeEx)(IBindCtx *pbc, LPCITEMIDLIST pidlRoot, const PERSIST_FOLDER_TARGET_INFO *ppfai)
  235. { return CNetFolder::InitializeEx(pbc, pidlRoot, ppfai); };
  236. STDMETHOD(GetFolderTargetInfo)(PERSIST_FOLDER_TARGET_INFO *ppfai)
  237. { return CNetFolder::GetFolderTargetInfo(ppfai); };
  238. protected:
  239. CNetRootFolder(IUnknown* punkOuter) : CNetFolder(punkOuter) { };
  240. ~CNetRootFolder() { ASSERT(NULL != _spThis); _spThis = NULL; };
  241. BOOL v_HandleDelete(PLONG pcRef);
  242. HRESULT v_GetFileFolder(IShellFolder2 **ppsfFiles);
  243. private:
  244. HRESULT _TryParseEntireNet(HWND hwnd, LPBC pbc, WCHAR *pwszName, LPITEMIDLIST *ppidl, DWORD *pdwAttributes);
  245. friend HRESULT CNetwork_CreateInstance(IUnknown* punkOuter, REFIID riid, void **ppv);
  246. static CNetRootFolder* _spThis;
  247. };
  248. class CNetFolderViewCB : public CBaseShellFolderViewCB
  249. {
  250. public:
  251. CNetFolderViewCB(CNetFolder *pFolder);
  252. // IShellFolderViewCB
  253. STDMETHODIMP RealMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
  254. private:
  255. ~CNetFolderViewCB();
  256. HRESULT OnINVOKECOMMAND(DWORD pv, UINT wP);
  257. HRESULT OnGETHELPTEXT(DWORD pv, UINT wPl, UINT wPh, LPTSTR lP);
  258. HRESULT OnREFRESH(DWORD pv, BOOL fPreRefresh);
  259. HRESULT OnDELAYWINDOWCREATE(DWORD pv, HWND hwnd);
  260. HRESULT OnGETCOLSAVESTREAM(DWORD pv, WPARAM wP, IStream **pps);
  261. HRESULT OnDEFITEMCOUNT(DWORD pv, UINT *pnItems);
  262. HRESULT OnGetZone(DWORD pv, DWORD * pdwZone);
  263. HRESULT OnEnumeratedItems(DWORD pv, UINT celt, LPCITEMIDLIST *rgpidl);
  264. HRESULT OnDefViewMode(DWORD pv, FOLDERVIEWMODE* pvm);
  265. HRESULT OnGetDeferredViewSettings(DWORD pv, SFVM_DEFERRED_VIEW_SETTINGS* pSettings);
  266. BOOL _GetProviderKeyName(LPTSTR pszName, UINT uNameLen);
  267. BOOL _EntireNetworkAvailable();
  268. CNetFolder *_pFolder;
  269. UINT _cItems;
  270. // Web View implementation
  271. HRESULT OnGetWebViewLayout(DWORD pv, UINT uViewMode, SFVM_WEBVIEW_LAYOUT_DATA* pData);
  272. HRESULT OnGetWebViewContent(DWORD pv, SFVM_WEBVIEW_CONTENT_DATA* pData);
  273. HRESULT OnGetWebViewTasks(DWORD pv, SFVM_WEBVIEW_TASKSECTION_DATA* pTasks);
  274. public:
  275. static HRESULT _CanShowHNW(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState);
  276. static HRESULT _CanViewComputersNearMe(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState);
  277. static HRESULT _CanSearchActiveDirectory(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState);
  278. static HRESULT _DoRunDll32(LPTSTR pszParameters); // helper to do a ShellExecute of RunDll32.
  279. static HRESULT _OnViewNetConnections(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc);
  280. static HRESULT _OnAddNetworkPlace(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  281. { return _DoRunDll32(TEXT("netplwiz.dll,AddNetPlaceRunDll")); }
  282. static HRESULT _OnHomeNetworkWizard(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  283. { return _DoRunDll32(TEXT("hnetwiz.dll,HomeNetWizardRunDll")); }
  284. static HRESULT _OnViewComputersNearMe(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc);
  285. static HRESULT _OnSearchActiveDirectory(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  286. { return _DoRunDll32(TEXT("dsquery.dll,OpenQueryWindow")); }
  287. };
  288. #define NETFLDR_EVENTS \
  289. SHCNE_RENAMEITEM | SHCNE_RENAMEFOLDER | \
  290. SHCNE_CREATE | SHCNE_DELETE | SHCNE_UPDATEDIR | SHCNE_UPDATEITEM | \
  291. SHCNE_MKDIR | SHCNE_RMDIR
  292. CNetFolderViewCB::CNetFolderViewCB(CNetFolder *pFolder) :
  293. CBaseShellFolderViewCB(pFolder->_pidl, NETFLDR_EVENTS), _pFolder(pFolder)
  294. {
  295. _pFolder->AddRef();
  296. }
  297. CNetFolderViewCB::~CNetFolderViewCB()
  298. {
  299. _pFolder->Release();
  300. }
  301. HRESULT CNetFolderViewCB::OnINVOKECOMMAND(DWORD pv, UINT wP)
  302. {
  303. return CNetwork_DFMCallBackBG(_pFolder, _hwndMain, NULL, DFM_INVOKECOMMAND, wP, 0);
  304. }
  305. HRESULT CNetFolderViewCB::OnGETHELPTEXT(DWORD pv, UINT wPl, UINT wPh, LPTSTR lP)
  306. {
  307. return CNetwork_DFMCallBackBG(_pFolder, _hwndMain, NULL, DFM_GETHELPTEXTW, MAKEWPARAM(wPl, wPh), (LPARAM)lP);
  308. }
  309. HRESULT CNetFolderViewCB::OnREFRESH(DWORD pv, BOOL fPreRefresh)
  310. {
  311. if (fPreRefresh)
  312. {
  313. RefreshNetCrawler();
  314. }
  315. return S_OK;
  316. }
  317. HRESULT CNetFolderViewCB::OnDELAYWINDOWCREATE(DWORD pv, HWND hwnd)
  318. {
  319. // only do delay window processing in the net root.
  320. if (RESOURCEDISPLAYTYPE_GENERIC == _pFolder->_uDisplayType) // MyNetPlaces
  321. {
  322. RefreshNetCrawler();
  323. }
  324. return S_OK;
  325. }
  326. HRESULT CNetFolderViewCB::OnGETCOLSAVESTREAM(DWORD pv, WPARAM wP, IStream **pps)
  327. {
  328. LPCTSTR pszValName;
  329. switch (_pFolder->_uDisplayType)
  330. {
  331. case RESOURCEDISPLAYTYPE_DOMAIN:
  332. pszValName = TEXT("NetDomainColsX");
  333. break;
  334. case RESOURCEDISPLAYTYPE_SERVER:
  335. pszValName = TEXT("NetServerColsX");
  336. break;
  337. default:
  338. return E_FAIL;
  339. }
  340. *pps = OpenRegStream(HKEY_CURRENT_USER, REGSTR_PATH_EXPLORER, pszValName, (DWORD) wP);
  341. return *pps ? S_OK : E_FAIL;
  342. }
  343. // HRESULT CNetFolderViewCB::OnGetZone(DWORD pv, DWORD * pdwZone);
  344. HRESULT CNetFolderViewCB::OnEnumeratedItems(DWORD pv, UINT celt, LPCITEMIDLIST *rgpidl)
  345. {
  346. _cItems = celt;
  347. return S_OK;
  348. }
  349. HRESULT CNetFolderViewCB::OnDefViewMode(DWORD pv, FOLDERVIEWMODE* pvm)
  350. {
  351. if (_cItems < DEFVIEW_FVM_MANY_CUTOFF)
  352. *pvm = FVM_TILE;
  353. else
  354. *pvm = FVM_ICON; // used to pick icon only for My Net Places ((_pFolder->_uDisplayType == RESOURCEDISPLAYTYPE_GENERIC))
  355. return S_OK;
  356. }
  357. HRESULT CNetFolderViewCB::OnGetDeferredViewSettings(DWORD pv, SFVM_DEFERRED_VIEW_SETTINGS* pSettings)
  358. {
  359. OnDefViewMode(pv, &pSettings->fvm);
  360. // if this is the root folder then lets sort accordingly
  361. if (_pFolder->_uDisplayType == RESOURCEDISPLAYTYPE_GENERIC)
  362. {
  363. pSettings->fGroupView = TRUE;
  364. pSettings->uSortCol = ICOL_NETWORKLOCATION;
  365. pSettings->iSortDirection = 1;
  366. }
  367. return S_OK;
  368. }
  369. HRESULT CNetFolderViewCB::OnGetZone(DWORD pv, DWORD * pdwZone)
  370. {
  371. if (pdwZone)
  372. *pdwZone = URLZONE_INTRANET; // default is "Local Intranet"
  373. return S_OK;
  374. }
  375. HRESULT CNetFolderViewCB::OnGetWebViewLayout(DWORD pv, UINT uViewMode, SFVM_WEBVIEW_LAYOUT_DATA* pData)
  376. {
  377. ZeroMemory(pData, sizeof(*pData));
  378. pData->dwLayout = SFVMWVL_NORMAL;
  379. return S_OK;
  380. }
  381. // HNW is shown on X86 pro or personal workgroup only
  382. HRESULT CNetFolderViewCB::_CanShowHNW(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  383. {
  384. #ifdef _WIN64
  385. *puisState = UIS_DISABLED;
  386. return S_OK;
  387. #else
  388. if (IsOS(OS_ANYSERVER))
  389. *puisState = UIS_DISABLED; // Server-type OS
  390. else
  391. *puisState = !IsOS(OS_DOMAINMEMBER) ? UIS_ENABLED : UIS_DISABLED;
  392. return S_OK;
  393. #endif
  394. }
  395. HRESULT CNetFolderViewCB::_CanViewComputersNearMe(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  396. {
  397. if (!SHRestricted(REST_NOCOMPUTERSNEARME))
  398. *puisState = !IsOS(OS_DOMAINMEMBER) ? UIS_ENABLED : UIS_DISABLED;
  399. else
  400. *puisState = UIS_DISABLED;
  401. return S_OK;
  402. }
  403. HRESULT CNetFolderViewCB::_CanSearchActiveDirectory(IUnknown* pv, IShellItemArray *psiItemArray, BOOL fOkToBeSlow, UISTATE* puisState)
  404. {
  405. if (IsOS(OS_DOMAINMEMBER) && (GetEnvironmentVariable(TEXT("USERDNSDOMAIN"), NULL, 0) > 0))
  406. *puisState = UIS_ENABLED;
  407. else
  408. *puisState = UIS_DISABLED;
  409. return S_OK;
  410. }
  411. HRESULT CNetFolderViewCB::_OnViewNetConnections(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  412. {
  413. LPITEMIDLIST pidl;
  414. HRESULT hr = SHGetFolderLocation(NULL, CSIDL_CONNECTIONS, NULL, 0, &pidl);
  415. if (SUCCEEDED(hr))
  416. {
  417. hr = ((CNetFolderViewCB*)(void*)pv)->_BrowseObject(pidl);
  418. ILFree(pidl);
  419. }
  420. return hr;
  421. }
  422. HRESULT CNetFolderViewCB::_DoRunDll32(LPTSTR pszParameters)
  423. {
  424. SHELLEXECUTEINFO sei = {0};
  425. sei.cbSize = sizeof(sei);
  426. sei.lpFile = TEXT("rundll32.exe");
  427. sei.lpParameters = pszParameters;
  428. sei.nShow = SW_SHOWNORMAL;
  429. return ShellExecuteEx(&sei) ? S_OK : E_FAIL;
  430. }
  431. HRESULT CNetFolderViewCB::_OnViewComputersNearMe(IUnknown* pv, IShellItemArray *psiItemArray, IBindCtx *pbc)
  432. {
  433. LPITEMIDLIST pidl;
  434. HRESULT hr = SHGetFolderLocation(NULL, CSIDL_COMPUTERSNEARME, NULL, 0, &pidl);
  435. if (SUCCEEDED(hr))
  436. {
  437. hr = ((CNetFolderViewCB*)(void*)pv)->_BrowseObject(pidl);
  438. ILFree(pidl);
  439. }
  440. return hr;
  441. }
  442. const WVTASKITEM c_MyNetPlacesTaskHeader = WVTI_HEADER(L"shell32.dll", IDS_HEADER_MYNETPLACES, IDS_HEADER_MYNETPLACES_TT);
  443. const WVTASKITEM c_MyNetPlacesTaskList[] =
  444. {
  445. WVTI_ENTRY_ALL(CLSID_NULL, L"shell32.dll", IDS_TASK_ADDNETWORKPLACE, IDS_TASK_ADDNETWORKPLACE_TT, IDI_TASK_ADDNETWORKPLACE, NULL, CNetFolderViewCB::_OnAddNetworkPlace),
  446. WVTI_ENTRY_ALL(CLSID_NULL, L"shell32.dll", IDS_TASK_VIEWNETCONNECTIONS, IDS_TASK_VIEWNETCONNECTIONS_TT, IDI_TASK_VIEWNETCONNECTIONS, NULL, CNetFolderViewCB::_OnViewNetConnections),
  447. WVTI_ENTRY_ALL(CLSID_NULL, L"shell32.dll", IDS_TASK_HOMENETWORKWIZARD, IDS_TASK_HOMENETWORKWIZARD_TT, IDI_TASK_HOMENETWORKWIZARD, CNetFolderViewCB::_CanShowHNW, CNetFolderViewCB::_OnHomeNetworkWizard),
  448. WVTI_ENTRY_ALL(CLSID_NULL, L"shell32.dll", IDS_TASK_COMPUTERSNEARME, IDS_TASK_COMPUTERSNEARME_TT, IDI_GROUP, CNetFolderViewCB::_CanViewComputersNearMe, CNetFolderViewCB::_OnViewComputersNearMe),
  449. WVTI_ENTRY_ALL(CLSID_NULL, L"shell32.dll", IDS_TASK_SEARCHDS, IDS_TASK_SEARCHDS_TT, IDI_TASK_SEARCHDS, CNetFolderViewCB::_CanSearchActiveDirectory, CNetFolderViewCB::_OnSearchActiveDirectory),
  450. };
  451. BOOL CNetFolderViewCB::_EntireNetworkAvailable()
  452. {
  453. BOOL fRet = FALSE;
  454. // Only enable if we're in a Domain
  455. if (IsOS(OS_DOMAINMEMBER) && !SHRestricted(REST_NOENTIRENETWORK))
  456. {
  457. LPITEMIDLIST pidl;
  458. if (SUCCEEDED(CNetFolder::_CreateEntireNetworkFullIDList(&pidl)))
  459. {
  460. // ... and we're not already in the "Entire Network" folder.
  461. if (!ILIsEqual(_pidl, pidl))
  462. {
  463. fRet = TRUE;
  464. }
  465. ILFree(pidl);
  466. }
  467. }
  468. return fRet;
  469. }
  470. HRESULT CNetFolderViewCB::OnGetWebViewContent(DWORD pv, SFVM_WEBVIEW_CONTENT_DATA* pData)
  471. {
  472. ZeroMemory(pData, sizeof(*pData));
  473. Create_IUIElement(&c_MyNetPlacesTaskHeader, &(pData->pFolderTaskHeader));
  474. LPCTSTR rgCsidls[] = { MAKEINTRESOURCE(CSIDL_DRIVES), MAKEINTRESOURCE(CSIDL_PERSONAL), MAKEINTRESOURCE(CSIDL_COMMON_DOCUMENTS), MAKEINTRESOURCE(CSIDL_PRINTERS) };
  475. if (_EntireNetworkAvailable())
  476. {
  477. LPITEMIDLIST pidlEntireNetwork = NULL;
  478. CNetFolder::_CreateEntireNetworkFullIDList(&pidlEntireNetwork);
  479. CreateIEnumIDListOnCSIDLs2(_pidl, pidlEntireNetwork, rgCsidls, ARRAYSIZE(rgCsidls), &(pData->penumOtherPlaces));
  480. ILFree(pidlEntireNetwork);
  481. }
  482. else
  483. {
  484. CreateIEnumIDListOnCSIDLs(_pidl, rgCsidls, ARRAYSIZE(rgCsidls), &(pData->penumOtherPlaces));
  485. }
  486. return S_OK;
  487. }
  488. HRESULT CNetFolderViewCB::OnGetWebViewTasks(DWORD pv, SFVM_WEBVIEW_TASKSECTION_DATA* pTasks)
  489. {
  490. ZeroMemory(pTasks, sizeof(*pTasks));
  491. Create_IEnumUICommand((IUnknown*)(void*)this, c_MyNetPlacesTaskList, ARRAYSIZE(c_MyNetPlacesTaskList), &pTasks->penumFolderTasks);
  492. return S_OK;
  493. }
  494. STDMETHODIMP CNetFolderViewCB::RealMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
  495. {
  496. switch (uMsg)
  497. {
  498. HANDLE_MSG(0, SFVM_INVOKECOMMAND, OnINVOKECOMMAND);
  499. HANDLE_MSG(0, SFVM_GETHELPTEXT, OnGETHELPTEXT);
  500. HANDLE_MSG(0, SFVM_DELAYWINDOWCREATE, OnDELAYWINDOWCREATE);
  501. HANDLE_MSG(0, SFVM_GETCOLSAVESTREAM, OnGETCOLSAVESTREAM);
  502. HANDLE_MSG(0, SFVM_GETZONE, OnGetZone);
  503. HANDLE_MSG(0, SFVM_ENUMERATEDITEMS, OnEnumeratedItems);
  504. HANDLE_MSG(0, SFVM_DEFVIEWMODE, OnDefViewMode);
  505. HANDLE_MSG(0, SFVM_GETDEFERREDVIEWSETTINGS, OnGetDeferredViewSettings);
  506. HANDLE_MSG(0, SFVM_REFRESH, OnREFRESH);
  507. HANDLE_MSG(0, SFVM_GETWEBVIEWLAYOUT, OnGetWebViewLayout);
  508. HANDLE_MSG(0, SFVM_GETWEBVIEWCONTENT, OnGetWebViewContent);
  509. HANDLE_MSG(0, SFVM_GETWEBVIEWTASKS, OnGetWebViewTasks);
  510. default:
  511. return E_FAIL;
  512. }
  513. return S_OK;
  514. }
  515. // Replace all the space characters in the provider name with '_'.
  516. void ReplaceSpacesWithUnderscore(LPTSTR psz)
  517. {
  518. while (psz = StrChr(psz, TEXT(' ')))
  519. {
  520. *psz = TEXT('_');
  521. psz++; // DBCS safe
  522. }
  523. }
  524. BOOL CNetFolderViewCB::_GetProviderKeyName(LPTSTR pszName, UINT uNameLen)
  525. {
  526. if (_pFolder->_GetProvider(NULL, NULL, pszName, uNameLen))
  527. {
  528. ReplaceSpacesWithUnderscore(pszName);
  529. }
  530. return (BOOL)*pszName;
  531. }
  532. // Define a collate order for the hood object types
  533. #define _HOOD_COL_RON 0
  534. #define _HOOD_COL_REMOTE 1
  535. #define _HOOD_COL_FILE 2
  536. #define _HOOD_COL_NET 3
  537. const static ICONMAP c_aicmpNet[] = {
  538. { SHID_NET_NETWORK , II_NETWORK },
  539. { SHID_NET_DOMAIN , II_GROUP },
  540. { SHID_NET_SERVER , II_SERVER },
  541. { SHID_NET_SHARE , (UINT)EIRESID(IDI_SERVERSHARE) },
  542. { SHID_NET_DIRECTORY , II_FOLDER },
  543. { SHID_NET_PRINTER , II_PRINTER },
  544. { SHID_NET_RESTOFNET , II_WORLD },
  545. { SHID_NET_SHAREADMIN , II_DRIVEFIXED },
  546. { SHID_NET_TREE , II_TREE },
  547. { SHID_NET_NDSCONTAINER, (UINT)EIRESID(IDI_NDSCONTAINER) },
  548. };
  549. enum
  550. {
  551. NKID_PROVIDERTYPE = 0,
  552. NKID_PROVIDER,
  553. NKID_NETCLASS,
  554. NKID_NETWORK,
  555. NKID_DIRECTORY,
  556. NKID_FOLDER
  557. };
  558. #define NKID_COUNT 6
  559. // This is one-entry cache for remote junctions resolution
  560. TCHAR g_szLastAttemptedJunctionName[MAX_PATH] = {0};
  561. TCHAR g_szLastResolvedJunctionName[MAX_PATH] = {0};
  562. REGITEMSINFO g_riiNetRoot =
  563. {
  564. REGSTR_PATH_EXPLORER TEXT("\\NetworkNeighborhood\\NameSpace"),
  565. NULL,
  566. TEXT(':'),
  567. SHID_NET_REGITEM,
  568. 1,
  569. SFGAO_CANLINK,
  570. 0,
  571. NULL,
  572. RIISA_ORIGINAL,
  573. NULL,
  574. 0,
  575. 0,
  576. };
  577. CNetRootFolder* CNetRootFolder::_spThis = NULL;
  578. HRESULT CNetFolder::_CreateInstance(LPCITEMIDLIST pidlAbs, LPCITEMIDLIST pidlTarget, UINT uDisplayType,
  579. LPCIDNETRESOURCE pidnForProvider, LPCTSTR pszResName,
  580. REFIID riid, void **ppv)
  581. {
  582. HRESULT hr = E_OUTOFMEMORY;
  583. *ppv = NULL;
  584. if (!ILIsEmpty(pidlAbs))
  585. {
  586. CNetFolder* pNetF = new CNetFolder(NULL);
  587. if (NULL != pNetF)
  588. {
  589. pNetF->_uDisplayType = uDisplayType;
  590. if (pidnForProvider)
  591. {
  592. //Make sure that the pidnProvider has provider information.
  593. ASSERT(NET_FHasProvider(pidnForProvider))
  594. //We are interested only in the provider informarion which is contained in the first entry.
  595. //Its enough if we clone only the first item in the pidl.
  596. pNetF->_pidnForProvider = (LPCIDNETRESOURCE)ILCloneFirst((LPCITEMIDLIST)pidnForProvider);
  597. }
  598. if (pszResName && *pszResName)
  599. pNetF->_pszResName = StrDup(pszResName);
  600. pNetF->_pidl = ILClone(pidlAbs);
  601. pNetF->_pidlTarget = ILClone(pidlTarget);
  602. if (pNetF->_pidl && (!pidlTarget || (pidlTarget && pNetF->_pidlTarget)))
  603. {
  604. if (uDisplayType == RESOURCEDISPLAYTYPE_SERVER)
  605. {
  606. // This is a remote computer. See if there are any remote
  607. // computer registry items. If so, aggregate with the registry
  608. // class.
  609. REGITEMSINFO riiComputer =
  610. {
  611. REGSTR_PATH_EXPLORER TEXT("\\RemoteComputer\\NameSpace"),
  612. NULL,
  613. TEXT(':'),
  614. SHID_NET_REMOTEREGITEM,
  615. -1,
  616. SFGAO_FOLDER | SFGAO_CANLINK,
  617. 0, // no required reg items
  618. NULL,
  619. RIISA_ORIGINAL,
  620. pszResName,
  621. 0,
  622. 0,
  623. };
  624. CRegFolder_CreateInstance(&riiComputer,
  625. (IUnknown*) (IShellFolder*) pNetF,
  626. IID_PPV_ARG(IUnknown, &pNetF->_punkReg));
  627. }
  628. else if (uDisplayType == RESOURCEDISPLAYTYPE_ROOT)
  629. {
  630. //
  631. // this is the entire net icon, so lets create an instance of the regitem folder
  632. // so we can merge in the items from there.
  633. //
  634. REGITEMSINFO riiEntireNet =
  635. {
  636. REGSTR_PATH_EXPLORER TEXT("\\NetworkNeighborhood\\EntireNetwork\\NameSpace"),
  637. NULL,
  638. TEXT(':'),
  639. SHID_NET_REGITEM,
  640. -1,
  641. SFGAO_CANLINK,
  642. 0, // no required reg items
  643. NULL,
  644. RIISA_ORIGINAL,
  645. NULL,
  646. 0,
  647. 0,
  648. };
  649. CRegFolder_CreateInstance(&riiEntireNet,
  650. (IUnknown*) (IShellFolder*) pNetF,
  651. IID_PPV_ARG(IUnknown, &pNetF->_punkReg));
  652. }
  653. else
  654. {
  655. ASSERT(hr == E_OUTOFMEMORY);
  656. }
  657. hr = pNetF->QueryInterface(riid, ppv);
  658. }
  659. pNetF->Release();
  660. }
  661. else
  662. {
  663. ASSERT(hr == E_OUTOFMEMORY);
  664. }
  665. }
  666. else
  667. {
  668. ASSERT(0);
  669. hr = E_INVALIDARG;
  670. }
  671. return hr;
  672. }
  673. HRESULT CNetwork_CreateInstance(IUnknown* punkOuter, REFIID riid, void **ppv)
  674. {
  675. HRESULT hr = S_OK;
  676. *ppv = NULL;
  677. // Must enter critical section to avoid racing against v_HandleDelete
  678. ENTERCRITICAL;
  679. if (NULL != CNetRootFolder::_spThis)
  680. {
  681. hr = CNetRootFolder::_spThis->QueryInterface(riid, ppv);
  682. }
  683. else
  684. {
  685. CNetRootFolder* pNetRootF = new CNetRootFolder(punkOuter);
  686. if (pNetRootF)
  687. {
  688. // Initialize it ourselves to ensure that the cached value
  689. // is the correct one.
  690. hr = pNetRootF->Initialize((LPCITEMIDLIST)&c_idlNet);
  691. if (SUCCEEDED(hr))
  692. {
  693. pNetRootF->_uDisplayType = RESOURCEDISPLAYTYPE_GENERIC;
  694. ASSERT(NULL == pNetRootF->_punkReg);
  695. if (SHRestricted(REST_NOSETFOLDERS))
  696. g_riiNetRoot.iReqItems = 0;
  697. // create the regitems object, he has the NetRoot object as his outer guy.
  698. hr = CRegFolder_CreateInstance(&g_riiNetRoot,
  699. SAFECAST(pNetRootF, IShellFolder2*),
  700. IID_PPV_ARG(IUnknown, &pNetRootF->_punkReg));
  701. // NOTE: not using SHInterlockedCompareExchange() because we have the critsec
  702. CNetRootFolder::_spThis = pNetRootF;
  703. hr = pNetRootF->QueryInterface(riid, ppv);
  704. }
  705. // Release the self-reference, but keep the the _spThis pointer intact
  706. // (it will be reset to NULL in the destructor)
  707. pNetRootF->Release();
  708. }
  709. else
  710. {
  711. hr = E_OUTOFMEMORY;
  712. }
  713. }
  714. LEAVECRITICAL;
  715. return hr;
  716. }
  717. CNetFolder::CNetFolder(IUnknown* punkOuter) :
  718. CAggregatedUnknown (punkOuter)
  719. {
  720. // Assert that we're still using a zero-init flag inside the new operator
  721. ASSERT(NULL == _pidl);
  722. ASSERT(NULL == _pidlTarget);
  723. ASSERT(NULL == _pidnForProvider);
  724. ASSERT(NULL == _pszResName);
  725. ASSERT(0 == _uDisplayType);
  726. ASSERT(NULL == _psfFiles);
  727. ASSERT(NULL == _punkReg);
  728. DllAddRef();
  729. }
  730. CNetFolder::~CNetFolder()
  731. {
  732. ILFree(_pidl);
  733. ILFree(_pidlTarget);
  734. ILFree((LPITEMIDLIST)_pidnForProvider);
  735. if (NULL != _pszResName)
  736. {
  737. LocalFree(_pszResName);
  738. }
  739. if (_psfFiles)
  740. {
  741. _psfFiles->Release();
  742. }
  743. SHReleaseInnerInterface(SAFECAST(this, IShellFolder *), &_punkReg);
  744. DllRelease();
  745. }
  746. CNetFolder *FolderToNetFolder(IUnknown *punk)
  747. {
  748. CNetFolder * pThis = NULL;
  749. return punk && SUCCEEDED(punk->QueryInterface(CLSID_CNetFldr, (void **)&pThis)) ? pThis : NULL;
  750. }
  751. HRESULT CNetFolder::v_InternalQueryInterface(REFIID riid, void **ppv)
  752. {
  753. static const QITAB qit[] = {
  754. QITABENT(CNetFolder, IShellFolder2), // IID_IShellFolder2
  755. QITABENTMULTI(CNetFolder, IShellFolder, IShellFolder2), // IID_IShellFolder
  756. QITABENT(CNetFolder, IPersistFolder3), // IID_IPersistFolder3
  757. QITABENT(CNetFolder, IShellIconOverlay), // IID_IShellIconOverlay
  758. QITABENTMULTI(CNetFolder, IPersistFolder2, IPersistFolder3), // IID_IPersistFolder2
  759. QITABENTMULTI(CNetFolder, IPersistFolder, IPersistFolder3), // IID_IPersistFolder
  760. QITABENTMULTI(CNetFolder, IPersist, IPersistFolder3), // IID_IPersist
  761. QITABENTMULTI2(CNetFolder, IID_IPersistFreeThreadedObject, IPersist), // IID_IPersistFreeThreadedObject
  762. { 0 },
  763. };
  764. if (IsEqualIID(riid, CLSID_CNetFldr))
  765. {
  766. *ppv = this; // get class pointer (unrefed!)
  767. return S_OK;
  768. }
  769. HRESULT hr;
  770. if (_punkReg && RegGetsFirstShot(riid))
  771. {
  772. hr = _punkReg->QueryInterface(riid, ppv);
  773. }
  774. else
  775. {
  776. hr = QISearch(this, qit, riid, ppv);
  777. if ((E_NOINTERFACE == hr) && _punkReg)
  778. {
  779. hr = _punkReg->QueryInterface(riid, ppv);
  780. }
  781. }
  782. return hr;
  783. }
  784. BOOL CNetRootFolder::v_HandleDelete(PLONG pcRef)
  785. {
  786. ASSERT(NULL != pcRef);
  787. ENTERCRITICAL;
  788. // Once inside the critical section things are slightly more stable.
  789. // CNetwork_CreateInstance won't be able to rescue the cached reference
  790. // (and bump the refcount from 0 to 1). And we don't have to worry
  791. // about somebody Release()ing us down to zero a second time, since
  792. // no new references can show up.
  793. //
  794. // HOWEVER! All those scary things could've happened WHILE WE WERE
  795. // WAITING TO ENTER THE CRITICAL SECTION.
  796. //
  797. // While we were waiting, somebody could've called CNetwork_CreateInstance,
  798. // which bumps the reference count back up. So don't destroy ourselves
  799. // if our object got "rescued".
  800. //
  801. // What's more, while we were waiting, that somebody could've then
  802. // Release()d us back down to zero, causing us to be called on that
  803. // other thread, notice that the refcount is indeed zero, and destroy
  804. // the object, all on that other thread. So if we are not the cached
  805. // instance, then don't destroy ourselves since that other thread did
  806. // it already.
  807. //
  808. // And even more, somebody might call CNetwork_CreateInstance again
  809. // and create a brand new object, which might COINCIDENTALLY happen
  810. // to have the same address as the old object we are trying to destroy
  811. // here. But in that case, it's okay to destroy the new object because
  812. // it is indeed the case that the object's reference count is zero and
  813. // deserves to be destroyed.
  814. if (this == _spThis && 0 == *pcRef)
  815. {
  816. *pcRef = 1000; // protect against cached pointers bumping us up then down
  817. delete this;
  818. }
  819. LEAVECRITICAL;
  820. // return TRUE to indicate that we've implemented this function
  821. // (regardless of whether or not this object was actually deleted)
  822. return TRUE;
  823. }
  824. STDMETHODIMP CNetFolder::ParseDisplayName(HWND hwnd, LPBC pbc, WCHAR* pszName, ULONG* pchEaten,
  825. LPITEMIDLIST* ppidl, DWORD* pdwAttributes)
  826. {
  827. return E_NOTIMPL;
  828. }
  829. // new for Win2K, this enables enuming the hidden admin shares
  830. #ifndef RESOURCE_SHAREABLE
  831. #define RESOURCE_SHAREABLE 0x00000006
  832. #endif
  833. //
  834. // in:
  835. // hwnd NULL indicates no UI.
  836. // grfFlags IShellFolder::EnumObjects() SHCONTF_ flags
  837. // pnr in/out params
  838. //
  839. //
  840. DWORD CNetFolder::_OpenEnum(HWND hwnd, DWORD grfFlags, LPNETRESOURCE pnr, HANDLE *phEnum)
  841. {
  842. DWORD dwType = (grfFlags & SHCONTF_NETPRINTERSRCH) ? RESOURCETYPE_PRINT : RESOURCETYPE_ANY;
  843. DWORD dwScope = pnr ? RESOURCE_GLOBALNET : RESOURCE_CONTEXT;
  844. if ((_uDisplayType == RESOURCEDISPLAYTYPE_SERVER) &&
  845. (grfFlags & SHCONTF_SHAREABLE))
  846. {
  847. dwScope = RESOURCE_SHAREABLE; // hidden admin shares for this server
  848. }
  849. DWORD err = WNetOpenEnum(dwScope, dwType, RESOURCEUSAGE_ALL, pnr, phEnum);
  850. if ((err != WN_SUCCESS) && hwnd)
  851. {
  852. // If it failed because you are not authenticated yet,
  853. // we need to let the user loggin to this network resource.
  854. //
  855. // REVIEW: Ask LenS to review this code.
  856. if (err == WN_NOT_AUTHENTICATED ||
  857. err == ERROR_LOGON_FAILURE ||
  858. err == WN_BAD_PASSWORD ||
  859. err == WN_ACCESS_DENIED)
  860. {
  861. // Retry with password dialog box.
  862. err = WNetAddConnection3(hwnd, pnr, NULL, NULL, CONNECT_TEMPORARY | CONNECT_INTERACTIVE);
  863. if (err == WN_SUCCESS)
  864. err = WNetOpenEnum(dwScope, dwType, RESOURCEUSAGE_ALL, pnr, phEnum);
  865. }
  866. UINT idTemplate = pnr && pnr->lpRemoteName ? IDS_ENUMERR_NETTEMPLATE2 : IDS_ENUMERR_NETTEMPLATE1;
  867. SHEnumErrorMessageBox(hwnd, idTemplate, err, pnr ? pnr->lpRemoteName : NULL, TRUE, MB_OK | MB_ICONHAND);
  868. }
  869. return err;
  870. }
  871. // find the share part of a UNC
  872. // \\server\share
  873. // return pointer to "share" or pointer to empty string if none
  874. LPCTSTR PathFindShareName(LPCTSTR pszUNC)
  875. {
  876. LPCTSTR psz = SkipServerSlashes(pszUNC);
  877. if (*psz)
  878. {
  879. psz = StrChr(psz + 1, TEXT('\\'));
  880. if (psz)
  881. psz++;
  882. else
  883. psz = TEXT("");
  884. }
  885. return psz;
  886. }
  887. // Flags for the dwRemote field
  888. #define RMF_CONTEXT 0x00000001 // Entire network is being enumerated
  889. #define RMF_SHOWREMOTE 0x00000002 // Return Remote Services for next enumeration
  890. #define RMF_STOP_ENUM 0x00000004 // Stop enumeration
  891. #define RMF_GETLINKENUM 0x00000008 // Hoodlinks enum needs to be fetched
  892. #define RMF_SHOWLINKS 0x00000010 // Hoodlinks need to be shown
  893. #define RMF_FAKENETROOT 0x00000020 // Don't enumerate the workgroup items
  894. #define RMF_ENTIRENETSHOWN 0x40000000 // Entire network object shown
  895. #define RMF_REMOTESHOWN 0x80000000 // Return Remote Services for next enumeration
  896. class CNetFolderEnum : public CEnumIDListBase
  897. {
  898. public:
  899. // IEnumIDList
  900. STDMETHOD(Next)(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched);
  901. private:
  902. CNetFolderEnum(CNetFolder *pnf, DWORD grfFlags, DWORD dwRemote, HANDLE hEnum);
  903. ~CNetFolderEnum();
  904. friend HRESULT Create_NetFolderEnum(CNetFolder* pnsf, DWORD grfFlags, DWORD dwRemote, HANDLE hEnum, IEnumIDList** ppenum);
  905. CNetFolder *_pnsf; // CNetFolder object we're enumerating
  906. HANDLE _hEnum;
  907. DWORD _grfFlags;
  908. LONG _cItems; // Count of items in buffer
  909. LONG _iItem; // Current index of the item in the buffer
  910. DWORD _dwRemote;
  911. union {
  912. NETRESOURCE _anr[0];
  913. BYTE _szBuffer[8192];
  914. };
  915. IEnumIDList *_peunk; // used for enumerating file system items (links)
  916. };
  917. CNetFolderEnum::CNetFolderEnum(CNetFolder *pnsf, DWORD grfFlags, DWORD dwRemote, HANDLE hEnum) : CEnumIDListBase()
  918. {
  919. _pnsf = pnsf;
  920. _pnsf->AddRef();
  921. _grfFlags = grfFlags;
  922. _dwRemote = dwRemote;
  923. _hEnum = hEnum;
  924. }
  925. HRESULT Create_NetFolderEnum(CNetFolder* pnf, DWORD grfFlags, DWORD dwRemote, HANDLE hEnum, IEnumIDList** ppenum)
  926. {
  927. HRESULT hr;
  928. CNetFolderEnum* p= new CNetFolderEnum(pnf, grfFlags, dwRemote, hEnum);
  929. if (p)
  930. {
  931. hr = p->QueryInterface(IID_PPV_ARG(IEnumIDList, ppenum));
  932. p->Release();
  933. }
  934. else
  935. {
  936. hr = E_OUTOFMEMORY;
  937. *ppenum = NULL;
  938. }
  939. return hr;
  940. }
  941. CNetFolderEnum::~CNetFolderEnum()
  942. {
  943. _pnsf->Release(); // release the "this" ptr we have
  944. if (_peunk)
  945. _peunk->Release();
  946. if (_hEnum)
  947. WNetCloseEnum(_hEnum);
  948. }
  949. STDMETHODIMP CNetFolderEnum::Next(ULONG celt, LPITEMIDLIST *ppidl, ULONG *pceltFetched)
  950. {
  951. HRESULT hr;
  952. *ppidl = NULL;
  953. if (pceltFetched)
  954. *pceltFetched = 0;
  955. // Time to stop enumeration?
  956. if (_dwRemote & RMF_STOP_ENUM)
  957. return S_FALSE; // Yes
  958. // should we try and get the links enumerator?
  959. if (_dwRemote & RMF_GETLINKENUM)
  960. {
  961. IShellFolder2* psfNetHood;
  962. if (SUCCEEDED(_pnsf->v_GetFileFolder(&psfNetHood)))
  963. psfNetHood->EnumObjects(NULL, _grfFlags, &_peunk);
  964. if (_peunk)
  965. _dwRemote |= RMF_SHOWLINKS;
  966. _dwRemote &= ~RMF_GETLINKENUM;
  967. }
  968. // should we be showing the links?
  969. if (_dwRemote & RMF_SHOWLINKS)
  970. {
  971. if (_peunk)
  972. {
  973. ULONG celtFetched;
  974. LPITEMIDLIST pidl;
  975. hr = _peunk->Next(1, &pidl, &celtFetched);
  976. if (hr == S_OK && celtFetched == 1)
  977. {
  978. *ppidl = pidl;
  979. if (pceltFetched)
  980. *pceltFetched = celtFetched;
  981. return S_OK; // Added link
  982. }
  983. }
  984. _dwRemote &= ~RMF_SHOWLINKS; // Done enumerating links
  985. }
  986. hr = S_OK;
  987. // Do we add the remote folder?
  988. // (Note: as a hack to ensure that the remote folder is added
  989. // to the 'hood despite what MPR says, RMF_SHOWREMOTE can be
  990. // set without RMF_CONTEXT set.)
  991. if ((_dwRemote & RMF_SHOWREMOTE) && !(_dwRemote & RMF_REMOTESHOWN))
  992. {
  993. // Yes
  994. // Only try to put the remote entry in once.
  995. _dwRemote |= RMF_REMOTESHOWN;
  996. // Is this not the Context container?
  997. // (See note above as to why we are asking this question.)
  998. if (!(_dwRemote & RMF_CONTEXT))
  999. {
  1000. // Yes; stop after the next time
  1001. _dwRemote |= RMF_STOP_ENUM;
  1002. }
  1003. // We have fallen thru because the remote services is not
  1004. // installed.
  1005. // Is this not the Context container AND the remote folder
  1006. // is not installed?
  1007. if (!(_dwRemote & RMF_CONTEXT))
  1008. {
  1009. // Yes; nothing else to enumerate
  1010. return S_FALSE;
  1011. }
  1012. }
  1013. if (_dwRemote & RMF_FAKENETROOT)
  1014. {
  1015. if ((!(_dwRemote & RMF_ENTIRENETSHOWN)) &&
  1016. (S_FALSE != SHShouldShowWizards(_punkSite)))
  1017. {
  1018. _pnsf->_CreateEntireNetwork(ppidl); // fake entire net
  1019. _dwRemote |= RMF_ENTIRENETSHOWN;
  1020. }
  1021. else
  1022. {
  1023. return S_FALSE; // no more to enumerate
  1024. }
  1025. }
  1026. else
  1027. {
  1028. while (TRUE)
  1029. {
  1030. ULONG err = WN_SUCCESS;
  1031. LPNETRESOURCE pnr;
  1032. if (_iItem >= _cItems)
  1033. {
  1034. DWORD dwSize = sizeof(_szBuffer);
  1035. _cItems = -1; // its signed
  1036. _iItem = 0;
  1037. err = WNetEnumResource(_hEnum, (DWORD*)&_cItems, _szBuffer, &dwSize);
  1038. DebugMsg(DM_TRACE, TEXT("Net EnumCallback: err=%d Count=%d"), err, _cItems);
  1039. }
  1040. pnr = &_anr[_iItem++];
  1041. // Note: the <= below is correct as we already incremented the index...
  1042. if (err == WN_SUCCESS && (_iItem <= _cItems))
  1043. {
  1044. // decide if the thing is a folder or not
  1045. ULONG grfFlagsItem = ((pnr->dwUsage & RESOURCEUSAGE_CONTAINER) ||
  1046. (pnr->dwType == RESOURCETYPE_DISK) ||
  1047. (pnr->dwType == RESOURCETYPE_ANY)) ?
  1048. SHCONTF_FOLDERS : SHCONTF_NONFOLDERS;
  1049. // If this is the context enumeration, we want to insert the
  1050. // Remote Services after the first container.
  1051. //
  1052. // Remember that we need to return the Remote Services in the next iteration.
  1053. if ((pnr->dwUsage & RESOURCEUSAGE_CONTAINER) &&
  1054. (_dwRemote & RMF_CONTEXT))
  1055. {
  1056. _dwRemote |= RMF_SHOWREMOTE;
  1057. }
  1058. if ((_pnsf->_uDisplayType == RESOURCEDISPLAYTYPE_SERVER) &&
  1059. (_grfFlags & SHCONTF_SHAREABLE))
  1060. {
  1061. // filter out ADMIN$ and IPC$, based on str len
  1062. if (lstrlen(PathFindShareName(pnr->lpRemoteName)) > 2)
  1063. {
  1064. grfFlagsItem = 0;
  1065. }
  1066. }
  1067. // if this is a network object, work out if we should hide or note, so
  1068. // convert the provider to its type number and open the key under:
  1069. //
  1070. // HKEY_CLASSES_ROOT\Network\Type\<type string>
  1071. if ((pnr->dwDisplayType == RESOURCEDISPLAYTYPE_NETWORK) &&
  1072. !(_grfFlags & SHCONTF_INCLUDEHIDDEN))
  1073. {
  1074. DWORD dwType;
  1075. if (WNetGetProviderType(pnr->lpProvider, &dwType) == WN_SUCCESS)
  1076. {
  1077. TCHAR szRegValue[MAX_PATH];
  1078. wsprintf(szRegValue, TEXT("Network\\Type\\%d"), HIWORD(dwType));
  1079. BOOL fHide = FALSE;
  1080. DWORD cb = sizeof(fHide);
  1081. if ((ERROR_SUCCESS == SHGetValue(HKEY_CLASSES_ROOT, szRegValue, TEXT("HideProvider"), NULL, &fHide, &cb)) && fHide)
  1082. {
  1083. grfFlagsItem = 0;
  1084. }
  1085. }
  1086. }
  1087. // Check if we found requested type of net resource.
  1088. if (_grfFlags & grfFlagsItem)
  1089. {
  1090. if (SUCCEEDED(_pnsf->_NetResToIDList(pnr, FALSE, TRUE, (_grfFlags & SHCONTF_NONFOLDERS), ppidl)))
  1091. {
  1092. break;
  1093. }
  1094. }
  1095. }
  1096. else if (err == WN_NO_MORE_ENTRIES)
  1097. {
  1098. hr = S_FALSE; // no more element
  1099. break;
  1100. }
  1101. else
  1102. {
  1103. DebugMsg(DM_ERROR, TEXT("sh ER - WNetEnumResource failed (%lx)"), err);
  1104. hr = E_FAIL;
  1105. break;
  1106. }
  1107. }
  1108. }
  1109. if (pceltFetched)
  1110. *pceltFetched = (S_OK == hr) ? 1 : 0;
  1111. return hr;
  1112. }
  1113. STDMETHODIMP CNetFolder::EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList** ppenum)
  1114. {
  1115. NETRESOURCE nr = {0};
  1116. TCHAR szProvider[MAX_PATH];
  1117. nr.lpProvider = (LPTSTR) _GetProvider(NULL, NULL, szProvider, ARRAYSIZE(szProvider));
  1118. if (_uDisplayType != RESOURCEDISPLAYTYPE_ROOT &&
  1119. _uDisplayType != RESOURCEDISPLAYTYPE_NETWORK)
  1120. {
  1121. nr.lpRemoteName = _pszResName;
  1122. }
  1123. HRESULT hr;
  1124. HANDLE hEnum;
  1125. DWORD err = _OpenEnum(hwnd, grfFlags, &nr, &hEnum);
  1126. if (err == WN_SUCCESS)
  1127. {
  1128. hr = Create_NetFolderEnum(this, grfFlags, 0, hEnum, ppenum);
  1129. if (FAILED(hr))
  1130. {
  1131. WNetCloseEnum(hEnum);
  1132. }
  1133. }
  1134. else
  1135. {
  1136. hr = HRESULT_FROM_WIN32(err);
  1137. }
  1138. return hr;
  1139. }
  1140. LPCIDNETRESOURCE NET_IsValidID(LPCITEMIDLIST pidl)
  1141. {
  1142. if (pidl && !ILIsEmpty(pidl) && ((pidl->mkid.abID[0] & SHID_GROUPMASK) == SHID_NET))
  1143. return (LPCIDNETRESOURCE)pidl;
  1144. return NULL;
  1145. }
  1146. STDMETHODIMP CNetFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  1147. {
  1148. HRESULT hr;
  1149. LPCIDNETRESOURCE pidn;
  1150. *ppv = NULL;
  1151. pidn = NET_IsValidID(pidl);
  1152. if (pidn)
  1153. {
  1154. IShellFolder *psfJunction;
  1155. LPITEMIDLIST pidlInit = NULL;
  1156. LPITEMIDLIST pidlTarget = NULL;
  1157. LPCITEMIDLIST pidlRight = _ILNext(pidl);
  1158. BOOL fRightIsEmpty = ILIsEmpty(pidlRight);
  1159. LPCIDNETRESOURCE pidnProvider = NET_FHasProvider(pidn) ? pidn :_pidnForProvider;
  1160. hr = S_OK;
  1161. // lets get the IDLISTs we are going to use to initialize the shell folder
  1162. // if we are doing a single level bind then then ILCombine otherwise
  1163. // be more careful.
  1164. pidlInit = ILCombineParentAndFirst(_pidl, pidl, pidlRight);
  1165. if (_pidlTarget)
  1166. pidlTarget = ILCombineParentAndFirst(_pidlTarget, pidl, pidlRight);
  1167. if (!pidlInit || (!pidlTarget && _pidlTarget))
  1168. hr = E_OUTOFMEMORY;
  1169. // now create the folder object we are using, and either return that
  1170. // object to the caller, or continue the binding down.
  1171. if (SUCCEEDED(hr))
  1172. {
  1173. hr = _CreateFolderForItem(pbc, pidlInit, pidlTarget, pidnProvider,
  1174. fRightIsEmpty ? riid : IID_IShellFolder,
  1175. fRightIsEmpty ? ppv : (void **)&psfJunction);
  1176. if (!fRightIsEmpty && SUCCEEDED(hr))
  1177. {
  1178. hr = psfJunction->BindToObject(pidlRight, pbc, riid, ppv);
  1179. psfJunction->Release();
  1180. }
  1181. }
  1182. ILFree(pidlInit);
  1183. ILFree(pidlTarget);
  1184. }
  1185. else
  1186. {
  1187. hr = E_INVALIDARG;
  1188. }
  1189. return hr;
  1190. }
  1191. STDMETHODIMP CNetFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  1192. {
  1193. return BindToObject(pidl, pbc, riid, ppv);
  1194. }
  1195. STDMETHODIMP CNetFolder::CompareIDs(LPARAM iCol, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  1196. {
  1197. HRESULT hr = E_INVALIDARG;
  1198. LPCIDNETRESOURCE pidn1 = NET_IsValidID(pidl1);
  1199. LPCIDNETRESOURCE pidn2 = NET_IsValidID(pidl2);
  1200. if (pidn1 && pidn2)
  1201. {
  1202. TCHAR szBuff1[MAX_PATH], szBuff2[MAX_PATH];
  1203. switch (iCol & SHCIDS_COLUMNMASK)
  1204. {
  1205. case ICOL_COMMENT:
  1206. {
  1207. hr = ResultFromShort(StrCmpLogicalRestricted(NET_CopyComment(pidn1, szBuff1, ARRAYSIZE(szBuff1)),
  1208. NET_CopyComment(pidn2, szBuff2, ARRAYSIZE(szBuff2))));
  1209. if (hr != 0)
  1210. return hr;
  1211. // drop down into the name comparison
  1212. }
  1213. case ICOL_NAME:
  1214. {
  1215. // Compare by name. This is the one case where we need to handle
  1216. // simple ids in either place. We will try to resync the items
  1217. // if we find a case of this before do the compares.
  1218. // Check for relative IDs. In particular if one item is at
  1219. // a server and the other is at RestOfNet then try to resync
  1220. // the two
  1221. //
  1222. if (NET_IsFake(pidn1) || NET_IsFake(pidn2))
  1223. {
  1224. // if either pidn1 or pidn2 is fake then we assume they are identical,
  1225. // this allows us to compare a simple net ID to a real net ID. we
  1226. // assume that if this fails later then the world will be happy
  1227. hr = 0;
  1228. }
  1229. else
  1230. {
  1231. // otherwise lets look at the names and provider strings accordingly
  1232. NET_CopyResName(pidn1, szBuff1, ARRAYSIZE(szBuff1));
  1233. NET_CopyResName(pidn2, szBuff2, ARRAYSIZE(szBuff2));
  1234. hr = ResultFromShort(StrCmpLogicalRestricted(szBuff1, szBuff2));
  1235. // If they're still identical, compare provider names.
  1236. if ((hr == 0) && (iCol & SHCIDS_ALLFIELDS))
  1237. {
  1238. LPCTSTR pszProv1 = _GetProvider(pidn1, NULL, szBuff1, ARRAYSIZE(szBuff1));
  1239. LPCTSTR pszProv2 = _GetProvider(pidn2, NULL, szBuff2, ARRAYSIZE(szBuff2));
  1240. if (pszProv1 && pszProv2)
  1241. hr = ResultFromShort(lstrcmp(pszProv1, pszProv2));
  1242. else
  1243. {
  1244. if (pszProv1 || pszProv2)
  1245. hr = ResultFromShort(pszProv1 ? 1 : -1);
  1246. else
  1247. hr = ResultFromShort(0);
  1248. }
  1249. }
  1250. }
  1251. // If they identical, compare the rest of IDs.
  1252. if (hr == 0)
  1253. hr = ILCompareRelIDs((IShellFolder*)this, (LPCITEMIDLIST)pidn1, (LPCITEMIDLIST)pidn2, iCol);
  1254. }
  1255. }
  1256. }
  1257. return hr;
  1258. }
  1259. STDMETHODIMP CNetFolder::CreateViewObject(HWND hwnd, REFIID riid, void **ppv)
  1260. {
  1261. HRESULT hr;
  1262. *ppv = NULL;
  1263. if (IsEqualIID(riid, IID_IShellView))
  1264. {
  1265. SFV_CREATE sSFV;
  1266. sSFV.cbSize = sizeof(sSFV);
  1267. sSFV.psvOuter = NULL;
  1268. sSFV.psfvcb = new CNetFolderViewCB(this); // failure is OK, we just get generic support
  1269. QueryInterface(IID_PPV_ARG(IShellFolder, &sSFV.pshf)); // in case we are agregated
  1270. hr = SHCreateShellFolderView(&sSFV, (IShellView**) ppv);
  1271. if (sSFV.pshf)
  1272. sSFV.pshf->Release();
  1273. if (sSFV.psfvcb)
  1274. sSFV.psfvcb->Release();
  1275. }
  1276. else if (IsEqualIID(riid, IID_IContextMenu))
  1277. {
  1278. IShellFolder* psfOuter;
  1279. hr = QueryInterface(IID_PPV_ARG(IShellFolder, &psfOuter));
  1280. if (SUCCEEDED(hr))
  1281. {
  1282. hr = CDefFolderMenu_Create(_pidl, hwnd, 0, NULL, psfOuter,
  1283. CNetwork_DFMCallBackBG, NULL, NULL, (IContextMenu**) ppv);
  1284. psfOuter->Release();
  1285. }
  1286. }
  1287. else
  1288. {
  1289. hr = E_NOINTERFACE;
  1290. }
  1291. return hr;
  1292. }
  1293. typedef HRESULT (CALLBACK *PFNGAOCALLBACK)(IShellFolder2 *psf, LPCITEMIDLIST pidl, ULONG* prgfInOut);
  1294. STDAPI GetAttributesCallback(IShellFolder2 *psf, UINT cidl, LPCITEMIDLIST* apidl, ULONG *prgfInOut, PFNGAOCALLBACK pfnGAOCallback)
  1295. {
  1296. HRESULT hr = S_OK;
  1297. ULONG rgfOut = 0;
  1298. for (UINT i = 0; i < cidl; i++)
  1299. {
  1300. ULONG rgfT = *prgfInOut;
  1301. hr = pfnGAOCallback(psf, apidl[i], &rgfT);
  1302. if (FAILED(hr))
  1303. {
  1304. rgfOut = 0;
  1305. break;
  1306. }
  1307. rgfOut |= rgfT;
  1308. }
  1309. *prgfInOut &= rgfOut;
  1310. return hr;
  1311. }
  1312. STDMETHODIMP CNetFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST* apidl, ULONG* prgfInOut)
  1313. {
  1314. HRESULT hr;
  1315. if (IsSelf(cidl, apidl))
  1316. {
  1317. *prgfInOut &= (SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_HASSUBFOLDER |
  1318. SFGAO_FOLDER | SFGAO_FILESYSANCESTOR);
  1319. hr = S_OK;
  1320. }
  1321. else
  1322. {
  1323. hr = GetAttributesCallback(SAFECAST(this, IShellFolder2*), cidl, apidl, prgfInOut, _AttributesCallback);
  1324. }
  1325. return hr;
  1326. }
  1327. STDMETHODIMP CNetFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, STRRET* pStrRet)
  1328. {
  1329. HRESULT hr;
  1330. LPCIDNETRESOURCE pidn = NET_IsValidID(pidl);
  1331. if (pidn)
  1332. {
  1333. TCHAR szPath[MAX_PATH];
  1334. LPCITEMIDLIST pidlNext = _ILNext(pidl);
  1335. if (dwFlags & SHGDN_FORPARSING)
  1336. {
  1337. if ((dwFlags & SHGDN_INFOLDER) ||
  1338. ((dwFlags & SHGDN_FORADDRESSBAR) && (NET_GetDisplayType(pidn) == RESOURCEDISPLAYTYPE_ROOT))) // the non-infolder name for the root is not good for the address bar
  1339. {
  1340. NET_CopyResName(pidn, szPath, ARRAYSIZE(szPath));
  1341. if (ILIsEmpty(pidlNext))
  1342. {
  1343. // we just need the last part of the display name (IN FOLDER)
  1344. LPTSTR pszT = StrRChr(szPath, NULL, TEXT('\\'));
  1345. if (!pszT)
  1346. pszT = szPath;
  1347. else
  1348. pszT++; // move past '\'
  1349. hr = StringToStrRet(pszT, pStrRet);
  1350. }
  1351. else
  1352. {
  1353. hr = ILGetRelDisplayName((IShellFolder*) this, pStrRet, pidl, szPath, MAKEINTRESOURCE(IDS_DSPTEMPLATE_WITH_BACKSLASH), dwFlags);
  1354. }
  1355. }
  1356. else
  1357. {
  1358. LPCITEMIDLIST pidlRight = _ILNext(pidl);
  1359. if (ILIsEmpty(pidlRight))
  1360. {
  1361. hr = _GetPathForItem(pidn, szPath);
  1362. if (SUCCEEDED(hr))
  1363. {
  1364. hr = StringToStrRet(szPath, pStrRet);
  1365. }
  1366. }
  1367. else
  1368. {
  1369. IShellFolder *psfJunction;
  1370. //Get the pidn which has network provider information.
  1371. LPCIDNETRESOURCE pidnProvider = NET_FHasProvider(pidn) ? pidn :_pidnForProvider;
  1372. LPITEMIDLIST pidlInit, pidlTarget = NULL;
  1373. pidlInit = ILCombineParentAndFirst(_pidl, pidl, pidlRight);
  1374. if (_pidlTarget)
  1375. pidlTarget = ILCombineParentAndFirst(_pidlTarget, pidl, pidlRight);
  1376. if (!pidlInit || (_pidlTarget && !pidlTarget))
  1377. return E_OUTOFMEMORY;
  1378. hr = _CreateFolderForItem(NULL, pidlInit, pidlTarget, pidnProvider, IID_PPV_ARG(IShellFolder, &psfJunction));
  1379. if (SUCCEEDED(hr))
  1380. {
  1381. hr = psfJunction->GetDisplayNameOf(pidlRight, dwFlags, pStrRet);
  1382. psfJunction->Release();
  1383. }
  1384. ILFree(pidlInit);
  1385. ILFree(pidlTarget);
  1386. }
  1387. }
  1388. }
  1389. else
  1390. {
  1391. hr = _GetFormatName(pidn, pStrRet);
  1392. if (SUCCEEDED(hr) && !(dwFlags & SHGDN_INFOLDER) && (NET_GetFlags(pidn) & SHID_JUNCTION))
  1393. {
  1394. TCHAR szServer[MAX_PATH];
  1395. SHGetNameAndFlags(_pidlTarget ? _pidlTarget:_pidl, SHGDN_FORPARSING, szServer, ARRAYSIZE(szServer), NULL);
  1396. TCHAR szDisplay[MAX_PATH];
  1397. hr = SHGetComputerDisplayName(szServer, 0x0, szDisplay, ARRAYSIZE(szDisplay));
  1398. if (SUCCEEDED(hr))
  1399. {
  1400. StrRetFormat(pStrRet, pidl, MAKEINTRESOURCE(IDS_DSPTEMPLATE_WITH_ON), szDisplay);
  1401. }
  1402. }
  1403. }
  1404. }
  1405. else
  1406. hr = E_INVALIDARG;
  1407. return hr;
  1408. }
  1409. STDMETHODIMP CNetFolder::SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR lpszName, DWORD dwRes, LPITEMIDLIST* ppidl)
  1410. {
  1411. if (ppidl)
  1412. *ppidl = NULL;
  1413. return E_NOTIMPL; // not supported
  1414. }
  1415. STDMETHODIMP CNetFolder::GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST* apidl,
  1416. REFIID riid, UINT* prgfInOut, void **ppv)
  1417. {
  1418. HRESULT hr = E_INVALIDARG;
  1419. LPCIDNETRESOURCE pidn = cidl ? NET_IsValidID(apidl[0]) : NULL;
  1420. *ppv = NULL;
  1421. if ((IsEqualIID(riid, IID_IExtractIconA) || IsEqualIID(riid, IID_IExtractIconW)) && pidn)
  1422. {
  1423. UINT iIndex;
  1424. if (_IsPrintShare(pidn))
  1425. iIndex = (UINT)EIRESID(IDI_PRINTER_NET);
  1426. else if (NET_IsRemoteFld(pidn))
  1427. iIndex = II_RNA;
  1428. else
  1429. iIndex = SILGetIconIndex(apidl[0], c_aicmpNet, ARRAYSIZE(c_aicmpNet));
  1430. hr = SHCreateDefExtIcon(NULL, iIndex, iIndex, GIL_PERCLASS, II_FOLDER, riid, ppv);
  1431. }
  1432. else if (IsEqualIID(riid, IID_IContextMenu) && pidn)
  1433. {
  1434. HKEY ahkeys[NKID_COUNT];
  1435. hr = _OpenKeys(pidn, ahkeys);
  1436. if (SUCCEEDED(hr))
  1437. {
  1438. IShellFolder* psfOuter;
  1439. hr = QueryInterface(IID_PPV_ARG(IShellFolder, &psfOuter));
  1440. if (SUCCEEDED(hr))
  1441. {
  1442. hr = CDefFolderMenu_Create2(_pidl, hwnd, cidl, apidl,
  1443. psfOuter, _GetCallbackType(pidn),
  1444. ARRAYSIZE(ahkeys), ahkeys, (IContextMenu**) ppv);
  1445. psfOuter->Release();
  1446. }
  1447. SHRegCloseKeys(ahkeys, ARRAYSIZE(ahkeys));
  1448. }
  1449. }
  1450. else if (cidl && IsEqualIID(riid, IID_IDataObject))
  1451. {
  1452. // Point & Print printer installation assumes that the
  1453. // netresources from CNetData_GetData and the
  1454. // pidls from CIDLData_GetData are in the same order.
  1455. // Keep it this way.
  1456. CNetData *pnd = new CNetData(_pidl, cidl, apidl);
  1457. if (pnd)
  1458. {
  1459. hr = pnd->QueryInterface(riid, ppv);
  1460. pnd->Release();
  1461. }
  1462. else
  1463. hr = E_OUTOFMEMORY;
  1464. }
  1465. else if (pidn && IsEqualIID(riid, IID_IDropTarget))
  1466. {
  1467. // special support because this is an item (not a folder)
  1468. if (_IsPrintShare(pidn))
  1469. {
  1470. LPITEMIDLIST pidl;
  1471. hr = SHILCombine(_pidl, apidl[0], &pidl);
  1472. if (SUCCEEDED(hr))
  1473. {
  1474. hr = CPrinterDropTarget_CreateInstance(hwnd, pidl, (IDropTarget**)ppv);
  1475. ILFree(pidl);
  1476. }
  1477. }
  1478. else
  1479. {
  1480. IShellFolder *psf;
  1481. hr = BindToObject(apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psf));
  1482. if (SUCCEEDED(hr))
  1483. {
  1484. hr = psf->CreateViewObject(hwnd, riid, ppv);
  1485. psf->Release();
  1486. }
  1487. }
  1488. }
  1489. else if (pidn && IsEqualIID(riid, IID_IQueryInfo))
  1490. {
  1491. if (NET_GetDisplayType(pidn) == RESOURCEDISPLAYTYPE_ROOT)
  1492. {
  1493. hr = CreateInfoTipFromText(MAKEINTRESOURCE(IDS_RESTOFNETTIP), riid, ppv);
  1494. }
  1495. else
  1496. {
  1497. // Someday maybe have infotips for other things too
  1498. }
  1499. }
  1500. return hr;
  1501. }
  1502. STDMETHODIMP CNetFolder::GetDefaultSearchGUID(LPGUID pguid)
  1503. {
  1504. *pguid = SRCID_SFindComputer;
  1505. return S_OK;
  1506. }
  1507. void WINAPI CNetFolder::_CopyEnumElement(void* pDest, const void* pSource, DWORD dwSize)
  1508. {
  1509. if (pDest && pSource)
  1510. memcpy(pDest, pSource, dwSize);
  1511. }
  1512. STDMETHODIMP CNetFolder::EnumSearches(IEnumExtraSearch** ppenum)
  1513. {
  1514. HRESULT hr = E_NOTIMPL;
  1515. *ppenum = NULL;
  1516. // if the restriction is set then this item should be enumerated from the registry
  1517. // so we fail, else enumerate it
  1518. // only enumerate if we actually have a network to search against
  1519. if (!SHRestricted(REST_HASFINDCOMPUTERS) &&
  1520. (GetSystemMetrics(SM_NETWORK) & RNC_NETWORKS))
  1521. {
  1522. EXTRASEARCH *pxs = (EXTRASEARCH *)LocalAlloc(LPTR, sizeof(EXTRASEARCH));
  1523. if (pxs)
  1524. {
  1525. pxs->guidSearch = SRCID_SFindComputer;
  1526. if (LoadStringW(g_hinst, IDS_FC_NAME, pxs->wszFriendlyName, sizeof(pxs->wszFriendlyName)))
  1527. {
  1528. *ppenum = (IEnumExtraSearch*)CStandardEnum_CreateInstance(IID_IEnumExtraSearch, FALSE,
  1529. 1, sizeof(EXTRASEARCH), pxs, _CopyEnumElement);
  1530. if (*ppenum == NULL)
  1531. {
  1532. LocalFree(pxs);
  1533. hr = E_OUTOFMEMORY;
  1534. }
  1535. else
  1536. hr = S_OK;
  1537. }
  1538. }
  1539. else
  1540. hr = E_OUTOFMEMORY;
  1541. }
  1542. return hr;
  1543. }
  1544. STDMETHODIMP CNetFolder::GetDefaultColumn(DWORD dwRes, ULONG* pSort, ULONG* pDisplay)
  1545. {
  1546. return E_NOTIMPL;
  1547. }
  1548. HRESULT CNetFolder::_GetDefaultColumnState(UINT cColumns, UINT iColumn, DWORD* pdwState)
  1549. {
  1550. *pdwState = 0;
  1551. HRESULT hr = S_OK;
  1552. if (iColumn < cColumns)
  1553. {
  1554. *pdwState = s_net_cols[iColumn].csFlags;
  1555. if (iColumn >= 1)
  1556. *pdwState |= SHCOLSTATE_SLOW; // comment is slow for net root
  1557. }
  1558. else
  1559. {
  1560. hr = E_INVALIDARG;
  1561. }
  1562. return hr;
  1563. }
  1564. STDMETHODIMP CNetFolder::GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID* pscid, VARIANT* pv)
  1565. {
  1566. HRESULT hr = E_NOTIMPL;
  1567. LPCIDNETRESOURCE pidn = NET_IsValidID(pidl);
  1568. if (pidn)
  1569. {
  1570. if (IsEqualSCID(*pscid, SCID_NETRESOURCE))
  1571. {
  1572. // Office calls SHGetDataFromIDList() with a large buffer to hold all
  1573. // of the strings in the NETRESOURCE structure, so we need to make sure
  1574. // that our variant can hold enough data to pass back to it:
  1575. BYTE rgBuffer[sizeof(NETRESOURCEW) + (4 * MAX_PATH * sizeof(WCHAR))];
  1576. hr = _GetNetResource(pidn, (NETRESOURCEW*) rgBuffer, sizeof(rgBuffer));
  1577. if (SUCCEEDED(hr))
  1578. {
  1579. hr = InitVariantFromBuffer(pv, rgBuffer, sizeof(rgBuffer));
  1580. if (SUCCEEDED(hr))
  1581. {
  1582. // Fixup pointers in structure to point within the variant
  1583. // instead of our stack variable (rgBuffer):
  1584. ASSERT(pv->vt == (VT_ARRAY | VT_UI1));
  1585. NETRESOURCEW* pnrw = (NETRESOURCEW*) pv->parray->pvData;
  1586. if (pnrw->lpLocalName)
  1587. {
  1588. pnrw->lpLocalName = (LPWSTR) ((BYTE*) pnrw +
  1589. ((BYTE*) pnrw->lpLocalName - rgBuffer));
  1590. }
  1591. if (pnrw->lpRemoteName)
  1592. {
  1593. pnrw->lpRemoteName = (LPWSTR) ((BYTE*) pnrw +
  1594. ((BYTE*) pnrw->lpRemoteName - rgBuffer));
  1595. }
  1596. if (pnrw->lpComment)
  1597. {
  1598. pnrw->lpComment = (LPWSTR) ((BYTE*) pnrw +
  1599. ((BYTE*) pnrw->lpComment - rgBuffer));
  1600. }
  1601. if (pnrw->lpProvider)
  1602. {
  1603. pnrw->lpProvider = (LPWSTR) ((BYTE*) pnrw +
  1604. ((BYTE*) pnrw->lpProvider - rgBuffer));
  1605. }
  1606. }
  1607. }
  1608. }
  1609. else if (IsEqualSCID(*pscid, SCID_DESCRIPTIONID))
  1610. {
  1611. SHDESCRIPTIONID did;
  1612. switch(SIL_GetType(pidl) & SHID_TYPEMASK)
  1613. {
  1614. case SHID_NET_DOMAIN:
  1615. did.dwDescriptionId = SHDID_NET_DOMAIN;
  1616. break;
  1617. case SHID_NET_SERVER:
  1618. did.dwDescriptionId = SHDID_NET_SERVER;
  1619. break;
  1620. case SHID_NET_SHARE:
  1621. did.dwDescriptionId = SHDID_NET_SHARE;
  1622. break;
  1623. case SHID_NET_RESTOFNET:
  1624. did.dwDescriptionId = SHDID_NET_RESTOFNET;
  1625. break;
  1626. default:
  1627. did.dwDescriptionId = SHDID_NET_OTHER;
  1628. break;
  1629. }
  1630. did.clsid = CLSID_NULL;
  1631. hr = InitVariantFromBuffer(pv, &did, sizeof(did));
  1632. }
  1633. else if (IsEqualSCID(*pscid, SCID_Comment))
  1634. {
  1635. TCHAR szTemp[MAX_PATH];
  1636. hr = InitVariantFromStr(pv, NET_CopyComment(pidn, szTemp, ARRAYSIZE(szTemp)));
  1637. }
  1638. else if (IsEqualSCID(*pscid, SCID_NAME))
  1639. {
  1640. TCHAR szTemp[MAX_PATH];
  1641. hr = InitVariantFromStr(pv, NET_CopyResName(pidn, szTemp, ARRAYSIZE(szTemp)));
  1642. }
  1643. }
  1644. else
  1645. {
  1646. IShellFolder2* psfFiles;
  1647. hr = v_GetFileFolder(&psfFiles);
  1648. if (SUCCEEDED(hr))
  1649. hr = psfFiles->GetDetailsEx(pidl, pscid, pv);
  1650. }
  1651. return hr;
  1652. }
  1653. HRESULT CNetFolder::_GetDetailsOf(UINT cColumns, LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pDetails)
  1654. {
  1655. HRESULT hr = S_OK;
  1656. pDetails->str.uType = STRRET_CSTR;
  1657. pDetails->str.cStr[0] = 0;
  1658. if (NULL == pidl)
  1659. {
  1660. hr = GetDetailsOfInfo(s_net_cols, cColumns, iColumn, pDetails);
  1661. }
  1662. else
  1663. {
  1664. SHCOLUMNID scid;
  1665. hr = MapColumnToSCID(iColumn, &scid);
  1666. if (SUCCEEDED(hr))
  1667. {
  1668. VARIANT var;
  1669. hr = GetDetailsEx(pidl, &scid, &var);
  1670. if (SUCCEEDED(hr))
  1671. {
  1672. TCHAR szTemp[MAX_PATH];
  1673. hr = SHFormatForDisplay(scid.fmtid,
  1674. scid.pid,
  1675. (PROPVARIANT*)&var,
  1676. PUIFFDF_DEFAULT,
  1677. szTemp,
  1678. ARRAYSIZE(szTemp));
  1679. if (SUCCEEDED(hr))
  1680. {
  1681. hr = StringToStrRet(szTemp, &pDetails->str);
  1682. }
  1683. VariantClear(&var);
  1684. }
  1685. }
  1686. }
  1687. return hr;
  1688. }
  1689. HRESULT CNetFolder::_MapColumnToSCID(UINT cColumns, UINT iColumn, SHCOLUMNID* pscid)
  1690. {
  1691. return MapColumnToSCIDImpl(s_net_cols, cColumns, iColumn, pscid);
  1692. }
  1693. // IPersist methods
  1694. STDMETHODIMP CNetFolder::GetClassID(CLSID* pCLSID)
  1695. {
  1696. switch (_uDisplayType)
  1697. {
  1698. case RESOURCEDISPLAYTYPE_ROOT:
  1699. *pCLSID = CLSID_NetworkRoot;
  1700. break;
  1701. case RESOURCEDISPLAYTYPE_SERVER:
  1702. *pCLSID = CLSID_NetworkServer;
  1703. break;
  1704. case RESOURCEDISPLAYTYPE_DOMAIN:
  1705. *pCLSID = CLSID_NetworkDomain;
  1706. break;
  1707. case RESOURCEDISPLAYTYPE_SHARE:
  1708. *pCLSID = CLSID_NetworkShare;
  1709. break;
  1710. default:
  1711. *pCLSID = CLSID_NULL;
  1712. break;
  1713. }
  1714. return S_OK;
  1715. }
  1716. // IPersistFolder method
  1717. STDMETHODIMP CNetFolder::Initialize(LPCITEMIDLIST pidl)
  1718. {
  1719. ILFree(_pidl);
  1720. ILFree(_pidlTarget);
  1721. _pidl = _pidlTarget = NULL;
  1722. return SHILClone(pidl, &_pidl);
  1723. }
  1724. // IPersistFolder2 method
  1725. STDMETHODIMP CNetFolder::GetCurFolder(LPITEMIDLIST* ppidl)
  1726. {
  1727. return GetCurFolderImpl(_pidl, ppidl);
  1728. }
  1729. // IPersistFolder3 methods
  1730. STDMETHODIMP CNetFolder::InitializeEx(IBindCtx *pbc, LPCITEMIDLIST pidlRoot, const PERSIST_FOLDER_TARGET_INFO *pfti)
  1731. {
  1732. ILFree(_pidl);
  1733. ILFree(_pidlTarget);
  1734. _pidl = _pidlTarget = NULL;
  1735. HRESULT hr = SHILClone(pidlRoot, &_pidl);
  1736. if (SUCCEEDED(hr) && pfti && pfti->pidlTargetFolder)
  1737. {
  1738. hr = SHILClone(pfti->pidlTargetFolder, &_pidlTarget);
  1739. }
  1740. return hr;
  1741. }
  1742. STDMETHODIMP CNetFolder::GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO *pfti)
  1743. {
  1744. HRESULT hr = S_OK;
  1745. ZeroMemory(pfti, sizeof(*pfti));
  1746. if (_pidlTarget)
  1747. hr = SHILClone(_pidlTarget, &pfti->pidlTargetFolder);
  1748. pfti->dwAttributes = FILE_ATTRIBUTE_DIRECTORY; // maybe add system?
  1749. pfti->csidl = -1;
  1750. return hr;
  1751. }
  1752. // IShellIconOverlay
  1753. HRESULT CNetFolder::_GetIconOverlayInfo(LPCIDNETRESOURCE pidn, int *pIndex, DWORD dwFlags)
  1754. {
  1755. HRESULT hr = E_FAIL;
  1756. //
  1757. // For netshare objects we want to get the icon overlay.
  1758. // If the share is "pinned" to be available offline it will
  1759. // have the "Offline Files" overlay.
  1760. //
  1761. if (RESOURCEDISPLAYTYPE_SHARE == NET_GetDisplayType(pidn))
  1762. {
  1763. TCHAR szPath[MAX_PATH];
  1764. hr = _GetPathForItem(pidn, szPath);
  1765. if (SUCCEEDED(hr))
  1766. {
  1767. IShellIconOverlayManager *psiom;
  1768. hr = GetIconOverlayManager(&psiom);
  1769. if (SUCCEEDED(hr))
  1770. {
  1771. WCHAR szPathW[MAX_PATH];
  1772. SHTCharToUnicode(szPath, szPathW, ARRAYSIZE(szPathW));
  1773. hr = psiom->GetFileOverlayInfo(szPathW, 0, pIndex, dwFlags);
  1774. psiom->Release();
  1775. }
  1776. }
  1777. }
  1778. return hr;
  1779. }
  1780. STDMETHODIMP CNetFolder::GetOverlayIndex(LPCITEMIDLIST pidl, int *pIndex)
  1781. {
  1782. HRESULT hr = E_FAIL;
  1783. LPCIDNETRESOURCE pidn = NET_IsValidID(pidl);
  1784. if (NULL != pidn)
  1785. {
  1786. hr = _GetIconOverlayInfo(pidn, pIndex, SIOM_OVERLAYINDEX);
  1787. }
  1788. return hr;
  1789. }
  1790. STDMETHODIMP CNetFolder::GetOverlayIconIndex(LPCITEMIDLIST pidl, int *pIndex)
  1791. {
  1792. HRESULT hr = E_FAIL;
  1793. LPCIDNETRESOURCE pidn = NET_IsValidID(pidl);
  1794. if (NULL != pidn)
  1795. {
  1796. hr = _GetIconOverlayInfo(pidn, pIndex, SIOM_ICONINDEX);
  1797. }
  1798. return hr;
  1799. }
  1800. //
  1801. // Helper function to allow external callers to query information from a
  1802. // network pidl...
  1803. //
  1804. // NOTE NOTE - This function returns a NETRESOURCE structure whose string
  1805. // pointers are not valid. On Win95 they were pointers back into the pidl's
  1806. // strings (even though the strings were copied into the supplied pv buffer.)
  1807. // Now we make the pointers really point into the buffer.
  1808. //
  1809. HRESULT CNetFolder::_GetNetResource(LPCIDNETRESOURCE pidn, NETRESOURCEW* pnr, int cb)
  1810. {
  1811. TCHAR szStrings[3][MAX_PATH];
  1812. LPWSTR psz, lpsz[3] = {NULL, NULL, NULL};
  1813. int i, cchT;
  1814. if (cb < sizeof(*pnr))
  1815. return DISP_E_BUFFERTOOSMALL;
  1816. ZeroMemory(pnr, cb);
  1817. NET_CopyResName(pidn, szStrings[0], ARRAYSIZE(szStrings[0]));
  1818. NET_CopyComment(pidn, szStrings[1], ARRAYSIZE(szStrings[1]));
  1819. _GetProvider(pidn, NULL, szStrings[2], ARRAYSIZE(szStrings[2]));
  1820. // Fill in some of the stuff first.
  1821. // pnr->dwScope = 0;
  1822. pnr->dwType = NET_GetType(pidn);
  1823. pnr->dwDisplayType = NET_GetDisplayType(pidn);
  1824. pnr->dwUsage = NET_GetUsage(pidn);
  1825. // pnr->lpLocalName = NULL;
  1826. // Now lets copy the strings into the buffer and make the pointers
  1827. // relative to the buffer...
  1828. psz = (LPWSTR)(pnr + 1);
  1829. cb -= sizeof(*pnr);
  1830. for (i = 0; i < ARRAYSIZE(szStrings); i++)
  1831. {
  1832. if (*szStrings[i])
  1833. {
  1834. cchT = (lstrlen(szStrings[i]) + 1) * sizeof(TCHAR);
  1835. if (cchT <= cb)
  1836. {
  1837. SHTCharToUnicode(szStrings[i], psz, cb/sizeof(TCHAR));
  1838. lpsz[i] = psz;
  1839. psz += cchT;
  1840. cb -= cchT * sizeof(TCHAR);
  1841. }
  1842. else
  1843. {
  1844. // A hint that the structure is ok,
  1845. // but the strings are missing
  1846. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  1847. }
  1848. }
  1849. }
  1850. pnr->lpRemoteName = lpsz[0];
  1851. pnr->lpComment = lpsz[1];
  1852. pnr->lpProvider = lpsz[2];
  1853. return S_OK;
  1854. }
  1855. //
  1856. // This function opens a reg. database key based on the "network provider".
  1857. //
  1858. // Returns: hkey
  1859. //
  1860. // The caller is responsibe to close the key by calling RegCloseKey().
  1861. //
  1862. HKEY CNetFolder::_OpenProviderKey(LPCIDNETRESOURCE pidn)
  1863. {
  1864. TCHAR szProvider[MAX_PATH];
  1865. if (_GetProvider(pidn, NULL, szProvider, ARRAYSIZE(szProvider)))
  1866. {
  1867. HKEY hkeyProgID = NULL;
  1868. ReplaceSpacesWithUnderscore(szProvider);
  1869. RegOpenKey(HKEY_CLASSES_ROOT, szProvider, &hkeyProgID);
  1870. return hkeyProgID;
  1871. }
  1872. return NULL;
  1873. }
  1874. //
  1875. // This function opens a reg. database key based on the network provider type.
  1876. // The type is a number that is not localized, as opposed to the provider name
  1877. // which may be localized.
  1878. //
  1879. // Arguments:
  1880. // pidlAbs -- Absolute IDList to a network resource object.
  1881. //
  1882. // Returns: hkey
  1883. //
  1884. // Notes:
  1885. // The caller is responsible to close the key by calling RegCloseKey().
  1886. //
  1887. HKEY CNetFolder::_OpenProviderTypeKey(LPCIDNETRESOURCE pidn)
  1888. {
  1889. HKEY hkeyProgID = NULL;
  1890. TCHAR szProvider[MAX_PATH];
  1891. if (_GetProvider(pidn, NULL, szProvider, ARRAYSIZE(szProvider)))
  1892. {
  1893. // Now that we've got the provider name, get the provider id.
  1894. DWORD dwType;
  1895. if (WNetGetProviderType(szProvider, &dwType) == WN_SUCCESS)
  1896. {
  1897. // convert nis.wNetType to a string, and then open the key
  1898. // HKEY_CLASSES_ROOT\Network\Type\<type string>
  1899. TCHAR szRegValue[MAX_PATH];
  1900. wsprintf(szRegValue, TEXT("Network\\Type\\%d"), HIWORD(dwType));
  1901. RegOpenKey(HKEY_CLASSES_ROOT, szRegValue, &hkeyProgID);
  1902. }
  1903. }
  1904. return hkeyProgID;
  1905. }
  1906. HRESULT CNetFolder::_OpenKeys(LPCIDNETRESOURCE pidn, HKEY ahkeys[NKID_COUNT])
  1907. {
  1908. // See if there is a key specific to the type of Network object...
  1909. COMPILETIME_ASSERT(6 == NKID_COUNT);
  1910. ahkeys[0] = ahkeys[1] = ahkeys[2] = ahkeys[3] = ahkeys[4] = ahkeys[5] = NULL;
  1911. ahkeys[NKID_PROVIDERTYPE] = _OpenProviderTypeKey(pidn);
  1912. ahkeys[NKID_PROVIDER] = _OpenProviderKey(pidn);
  1913. if (NET_GetDisplayType(pidn) == RESOURCEDISPLAYTYPE_SHARE)
  1914. RegOpenKey(HKEY_CLASSES_ROOT, TEXT("NetShare"), &ahkeys[NKID_NETCLASS]);
  1915. else if (NET_GetDisplayType(pidn) == RESOURCEDISPLAYTYPE_SERVER)
  1916. RegOpenKey(HKEY_CLASSES_ROOT, TEXT("NetServer"), &ahkeys[NKID_NETCLASS]);
  1917. RegOpenKey(HKEY_CLASSES_ROOT, TEXT("Network"), &ahkeys[NKID_NETWORK]);
  1918. // make sure it is not a printer before adding "Folder" or "directory"
  1919. if (!_IsPrintShare(pidn))
  1920. {
  1921. // Shares should also support directory stuff...
  1922. if (NET_GetDisplayType(pidn) == RESOURCEDISPLAYTYPE_SHARE)
  1923. RegOpenKey(HKEY_CLASSES_ROOT, TEXT("Directory"), &ahkeys[NKID_DIRECTORY]);
  1924. RegOpenKey(HKEY_CLASSES_ROOT, c_szFolderClass, &ahkeys[NKID_FOLDER]);
  1925. }
  1926. return S_OK;
  1927. }
  1928. #define WNFMT_PLATFORM WNFMT_ABBREVIATED | WNFMT_INENUM
  1929. //
  1930. // This function retrieves the formatted (display) name of the specified network object.
  1931. //
  1932. HRESULT CNetFolder::_GetFormatName(LPCIDNETRESOURCE pidn, STRRET* pStrRet)
  1933. {
  1934. HRESULT hr = E_FAIL;
  1935. TCHAR szName[MAX_PATH];
  1936. NET_CopyResName(pidn, szName, ARRAYSIZE(szName));
  1937. if (NET_GetDisplayType(pidn) == RESOURCEDISPLAYTYPE_SERVER)
  1938. {
  1939. TCHAR szMachineName[MAX_PATH];
  1940. TCHAR szComment[MAX_PATH];
  1941. NET_CopyResName(pidn, szMachineName, ARRAYSIZE(szMachineName));
  1942. NET_CopyComment(pidn, szComment, ARRAYSIZE(szComment));
  1943. hr = SHBuildDisplayMachineName(szMachineName, szComment, szName, ARRAYSIZE(szName));
  1944. }
  1945. if (FAILED(hr) &&
  1946. (NET_GetDisplayType(pidn) != RESOURCEDISPLAYTYPE_ROOT) &&
  1947. (NET_GetDisplayType(pidn) != RESOURCEDISPLAYTYPE_NETWORK))
  1948. {
  1949. TCHAR szDisplayName[MAX_PATH], szProvider[MAX_PATH];
  1950. DWORD dwSize = ARRAYSIZE(szDisplayName);
  1951. LPCTSTR pszProvider = _GetProvider(pidn, NULL, szProvider, ARRAYSIZE(szProvider));
  1952. if (pszProvider)
  1953. {
  1954. DWORD dwRes = WNetFormatNetworkName(pszProvider, szName, szDisplayName, &dwSize, WNFMT_PLATFORM, 8 + 1 + 3);
  1955. if (dwRes == WN_SUCCESS)
  1956. lstrcpy(szName, szDisplayName);
  1957. }
  1958. }
  1959. return StringToStrRet(szName, pStrRet);
  1960. }
  1961. //
  1962. // resolve non-UNC share names (novell) to UNC style names
  1963. //
  1964. // returns:
  1965. // TRUE translated the name
  1966. // FALSE didn't translate (maybe error case)
  1967. //
  1968. // WARNING: If we use too much stack space then we will cause
  1969. // faults by over flowing the stack. Millennium #94818
  1970. BOOL CNetFolder::_GetPathForShare(LPCIDNETRESOURCE pidn, LPTSTR pszPath)
  1971. {
  1972. BOOL fRet = FALSE;
  1973. *pszPath = TEXT('\0');
  1974. LPTSTR pszAccessName = (LPTSTR)LocalAlloc(LPTR, sizeof(TCHAR) * MAX_PATH * 3);
  1975. if (pszAccessName)
  1976. {
  1977. LPTSTR pszRemoteName = pszAccessName + MAX_PATH;
  1978. LPTSTR pszProviderName = pszRemoteName + MAX_PATH;
  1979. NET_CopyResName(pidn, pszRemoteName, MAX_PATH);
  1980. if (NULL != _pszResName)
  1981. {
  1982. //
  1983. // Combine the folder name with the share name
  1984. // to create a UNC path.
  1985. //
  1986. // Borrow the pszProviderName buffer for a bit.
  1987. //
  1988. PathCombine(pszProviderName, _pszResName, pszRemoteName);
  1989. //
  1990. // To be safe: UNC prefix implies that name is available using FS access
  1991. // Theoretically it also should be routed to MPR, but it is late to do this
  1992. //
  1993. if (PathIsUNC(pszProviderName))
  1994. {
  1995. lstrcpy(pszPath, pszProviderName);
  1996. fRet = FALSE;
  1997. }
  1998. else
  1999. {
  2000. pszProviderName[0] = TEXT('\0');
  2001. }
  2002. }
  2003. if (!*pszPath)
  2004. {
  2005. // Check cache
  2006. ENTERCRITICAL;
  2007. if (lstrcmpi(g_szLastAttemptedJunctionName, pszRemoteName) == 0)
  2008. {
  2009. // cache hit
  2010. lstrcpy(pszPath, g_szLastResolvedJunctionName);
  2011. fRet = TRUE;
  2012. }
  2013. LEAVECRITICAL;
  2014. }
  2015. if (!*pszPath)
  2016. {
  2017. NETRESOURCE nr = {0};
  2018. DWORD err, dwRedir, dwResult;
  2019. DWORD cchAccessName;
  2020. nr.lpRemoteName = pszRemoteName;
  2021. nr.lpProvider = (LPTSTR) _GetProvider(pidn, NULL, pszProviderName, MAX_PATH);
  2022. nr.dwType = NET_GetType(pidn);
  2023. nr.dwUsage = NET_GetUsage(pidn);
  2024. nr.dwDisplayType = NET_GetDisplayType(pidn);
  2025. dwRedir = CONNECT_TEMPORARY;
  2026. // Prepare access name buffer and net resource request buffer
  2027. //
  2028. cchAccessName = MAX_PATH;
  2029. pszAccessName[0] = 0;
  2030. err = WNetUseConnection(NULL, &nr, NULL, NULL, dwRedir, pszAccessName, &cchAccessName, &dwResult);
  2031. if ((WN_SUCCESS != err) || !pszAccessName[0])
  2032. {
  2033. // perf idea: might be good to cache the last failed junction bind
  2034. // and early out on the next attempt. One slight problem this
  2035. // might encounter: what if we cache a failure, the user changes
  2036. // state to fix the problem, but we hit our failure cache...
  2037. //
  2038. lstrcpy(pszPath, pszRemoteName);
  2039. fRet = FALSE;
  2040. }
  2041. else
  2042. {
  2043. // Get the return name
  2044. lstrcpy(pszPath, pszAccessName);
  2045. fRet = TRUE;
  2046. // Update success cache entry
  2047. ENTERCRITICAL;
  2048. lstrcpy(g_szLastAttemptedJunctionName, pszRemoteName);
  2049. lstrcpy(g_szLastResolvedJunctionName, pszAccessName);
  2050. LEAVECRITICAL;
  2051. }
  2052. }
  2053. LocalFree(pszAccessName);
  2054. }
  2055. return fRet;
  2056. }
  2057. // in:
  2058. // pidn may be multi-level net resource pidl like
  2059. // [entire net] [provider] [server] [share] [... file sys]
  2060. // or [server] [share] [... file sys]
  2061. HRESULT CNetFolder::_GetPathForItem(LPCIDNETRESOURCE pidn, LPTSTR pszPath)
  2062. {
  2063. *pszPath = 0;
  2064. // loop down
  2065. for (; !ILIsEmpty((LPCITEMIDLIST)pidn) ; pidn = (LPCIDNETRESOURCE)_ILNext((LPCITEMIDLIST)pidn))
  2066. {
  2067. if (NET_GetFlags(pidn) & SHID_JUNCTION) // \\server\share or strike/sys
  2068. {
  2069. _GetPathForShare(pidn, pszPath);
  2070. break; // below this we don't know about any of the PIDLs
  2071. }
  2072. else
  2073. {
  2074. // if this is entire network then return the canonical name for
  2075. // this object.
  2076. if (NET_GetDisplayType(pidn) == RESOURCEDISPLAYTYPE_ROOT)
  2077. StrCpyN(pszPath, TEXT("EntireNetwork"), MAX_PATH);
  2078. else
  2079. NET_CopyResName(pidn, pszPath, MAX_PATH);
  2080. }
  2081. }
  2082. return *pszPath ? S_OK : E_NOTIMPL;
  2083. }
  2084. HRESULT CNetFolder::_GetPathForItemW(LPCIDNETRESOURCE pidn, LPWSTR pszPath)
  2085. {
  2086. return _GetPathForItem(pidn, pszPath);
  2087. }
  2088. // in:
  2089. // pidl
  2090. //
  2091. // takes the last items and create a folder for it, assuming the first section is the
  2092. // used to initialze. the riid and ppv are used to return an object.
  2093. //
  2094. HRESULT CNetFolder::_CreateFolderForItem(LPBC pbc, LPCITEMIDLIST pidl, LPCITEMIDLIST pidlTarget, LPCIDNETRESOURCE pidnForProvider, REFIID riid, void **ppv)
  2095. {
  2096. LPCITEMIDLIST pidlLast = ILFindLastID(pidl);
  2097. LPCIDNETRESOURCE pidn = NET_IsValidID(pidlLast);
  2098. if (!pidn)
  2099. return E_INVALIDARG;
  2100. HRESULT hr;
  2101. if (NET_IsRemoteFld(pidn))
  2102. {
  2103. // note: I think this is dead functionality. it was used in NT4 but we can't find
  2104. // the impl of this CLSID_Remote anymore...
  2105. IPersistFolder * ppf;
  2106. hr = SHCoCreateInstance(NULL, &CLSID_Remote, NULL, IID_PPV_ARG(IPersistFolder, &ppf));
  2107. if (SUCCEEDED(hr))
  2108. {
  2109. hr= ppf->Initialize(pidl);
  2110. if (SUCCEEDED(hr))
  2111. hr = ppf->QueryInterface(riid, ppv);
  2112. ppf->Release();
  2113. }
  2114. }
  2115. else if (NET_GetFlags(pidn) & SHID_JUNCTION) // \\server\share or strike/sys
  2116. {
  2117. PERSIST_FOLDER_TARGET_INFO * ppfti = (PERSIST_FOLDER_TARGET_INFO *) LocalAlloc(LPTR, sizeof(PERSIST_FOLDER_TARGET_INFO));
  2118. if (ppfti)
  2119. {
  2120. ppfti->pidlTargetFolder = (LPITEMIDLIST)pidlTarget;
  2121. _GetPathForItemW(pidn, ppfti->szTargetParsingName);
  2122. ppfti->csidl = -1;
  2123. ppfti->dwAttributes = FILE_ATTRIBUTE_DIRECTORY; // maybe add system?
  2124. hr = CFSFolder_CreateFolder(NULL, pbc, pidl, ppfti, riid, ppv);
  2125. LocalFree(ppfti);
  2126. }
  2127. else
  2128. hr = E_OUTOFMEMORY;
  2129. }
  2130. else
  2131. {
  2132. TCHAR szPath[MAX_PATH];
  2133. NET_CopyResName(pidn, szPath, ARRAYSIZE(szPath));
  2134. hr = _CreateInstance(pidl, pidlTarget, NET_GetDisplayType(pidn), pidnForProvider, szPath, riid, ppv);
  2135. }
  2136. return hr;
  2137. }
  2138. // get the provider for an item or the folder itself. since some items don't have the
  2139. // provider stored we fall back to the folder to get the provider in that case
  2140. //
  2141. // in:
  2142. // pidn item to get provider for. if NULL get provider for the folder
  2143. // pbc IBindCtx to get provider for. if NULL get provider from pidn or folder.
  2144. //
  2145. // returns:
  2146. // NULL no provider in the item or the folder
  2147. // non NULL address of passed in buffer
  2148. LPCTSTR CNetFolder::_GetProvider(LPCIDNETRESOURCE pidn, IBindCtx *pbc, LPTSTR pszProvider, UINT cchProvider)
  2149. {
  2150. // attempt to get the provider from the property bag
  2151. IPropertyBag *ppb;
  2152. if (pbc && SUCCEEDED(pbc->GetObjectParam(STR_PARSE_NETFOLDER_INFO, (IUnknown**)&ppb)))
  2153. {
  2154. HRESULT hr = SHPropertyBag_ReadStr(ppb, STR_PARSE_NETFOLDER_PROVIDERNAME, pszProvider, cchProvider);
  2155. ppb->Release();
  2156. if (SUCCEEDED(hr) && *pszProvider)
  2157. {
  2158. return pszProvider;
  2159. }
  2160. }
  2161. // from the IDLIST
  2162. if (pidn && NET_CopyProviderName(pidn, pszProvider, cchProvider))
  2163. return pszProvider;
  2164. // from our state
  2165. if (_pidnForProvider)
  2166. {
  2167. NET_CopyProviderName(_pidnForProvider, pszProvider, cchProvider);
  2168. return pszProvider;
  2169. }
  2170. *pszProvider = 0;
  2171. return NULL;
  2172. }
  2173. const NETPROVIDERS c_rgProviderMap[] =
  2174. {
  2175. { TEXT("Microsoft Network"), HIWORD(WNNC_NET_LANMAN) },
  2176. { TEXT("NetWare"), HIWORD(WNNC_NET_NETWARE) }
  2177. };
  2178. // construct a net idlist either copying the existing data from a pidl or
  2179. // from a NETRESOURCE structure
  2180. HRESULT CNetFolder::_CreateNetIDList(LPIDNETRESOURCE pidnIn,
  2181. LPCTSTR pszName, LPCTSTR pszProvider, LPCTSTR pszComment,
  2182. LPITEMIDLIST *ppidl)
  2183. {
  2184. LPBYTE pb;
  2185. UINT cbmkid = sizeof(IDNETRESOURCE) - sizeof(CHAR);
  2186. UINT cchName, cchProvider, cchComment, cbProviderType = 0;
  2187. LPIDNETRESOURCE pidn;
  2188. WORD wNetType = 0;
  2189. BOOL fUnicode = FALSE;
  2190. UINT cchAnsiName, cchAnsiProvider, cchAnsiComment;
  2191. CHAR szAnsiName[MAX_PATH], szAnsiProvider[MAX_PATH], szAnsiComment[MAX_PATH];
  2192. ASSERT(ppidl != NULL);
  2193. *ppidl = NULL;
  2194. if (!pszName)
  2195. pszName = c_szNULL; // For now put in an empty string...
  2196. if (pszProvider)
  2197. cbProviderType += sizeof(WORD);
  2198. // Win9x shipped with one set of provider name which are
  2199. // different on NT. Therefore lets convert the NT one to
  2200. // something that Win9x can understand.
  2201. if (pszProvider)
  2202. {
  2203. cbProviderType = sizeof(WORD);
  2204. DWORD dwType, dwRes = WNetGetProviderType(pszProvider, &dwType);
  2205. if (dwRes == WN_SUCCESS)
  2206. {
  2207. wNetType = HIWORD(dwType);
  2208. for (int i = 0; i < ARRAYSIZE(c_rgProviderMap); i++)
  2209. {
  2210. if (c_rgProviderMap[i].wNetType == wNetType)
  2211. {
  2212. pszProvider = c_rgProviderMap[i].lpName;
  2213. break;
  2214. }
  2215. }
  2216. }
  2217. }
  2218. // compute the string lengths ready to build an IDLIST
  2219. cchName = lstrlen(pszName)+1;
  2220. cchProvider = pszProvider ? lstrlen(pszProvider)+1 : 0;
  2221. cchComment = pszComment ? lstrlen(pszComment)+1 : 0;
  2222. cchAnsiName = 0;
  2223. cchAnsiProvider = 0;
  2224. cchAnsiComment = 0;
  2225. fUnicode = !DoesStringRoundTrip(pszName, szAnsiName, ARRAYSIZE(szAnsiProvider));
  2226. cchAnsiName = lstrlenA(szAnsiName)+1;
  2227. if (pszProvider)
  2228. {
  2229. fUnicode |= !DoesStringRoundTrip(pszProvider, szAnsiProvider, ARRAYSIZE(szAnsiProvider));
  2230. cchAnsiProvider = lstrlenA(szAnsiProvider)+1;
  2231. }
  2232. if (pszComment)
  2233. {
  2234. fUnicode |= !DoesStringRoundTrip(pszComment, szAnsiComment, ARRAYSIZE(szAnsiComment));
  2235. cchAnsiComment = lstrlenA(szAnsiComment)+1;
  2236. }
  2237. // allocate and fill the IDLIST header
  2238. cbmkid += cbProviderType+cchAnsiName + cchAnsiProvider + cchAnsiComment;
  2239. if (fUnicode)
  2240. cbmkid += (sizeof(WCHAR)*(cchName+cchProvider+cchComment));
  2241. pidn = (LPIDNETRESOURCE)_ILCreate(cbmkid + sizeof(USHORT));
  2242. if (!pidn)
  2243. return E_OUTOFMEMORY;
  2244. pidn->cb = (WORD)cbmkid;
  2245. pidn->bFlags = pidnIn->bFlags;
  2246. pidn->uType = pidnIn->uType;
  2247. pidn->uUsage = pidnIn->uUsage;
  2248. if (pszProvider)
  2249. pidn->uUsage |= NET_HASPROVIDER;
  2250. if (pszComment)
  2251. pidn->uUsage |= NET_HASCOMMENT;
  2252. pb = (LPBYTE) pidn->szNetResName;
  2253. //
  2254. // write the ANSI strings into the IDLIST
  2255. //
  2256. StrCpyA((PSTR) pb, szAnsiName);
  2257. pb += cchAnsiName;
  2258. if (pszProvider)
  2259. {
  2260. StrCpyA((PSTR) pb, szAnsiProvider);
  2261. pb += cchAnsiProvider;
  2262. }
  2263. if (pszComment)
  2264. {
  2265. StrCpyA((PSTR) pb, szAnsiComment);
  2266. pb += cchAnsiComment;
  2267. }
  2268. // if we are going to be UNICODE then lets write those strings also.
  2269. // Note that we must use unaligned string copies since the is no
  2270. // promse that the ANSI strings will have an even number of characters
  2271. // in them.
  2272. if (fUnicode)
  2273. {
  2274. pidn->uUsage |= NET_UNICODE;
  2275. ualstrcpyW((UNALIGNED WCHAR *)pb, pszName);
  2276. pb += cchName*sizeof(WCHAR);
  2277. if (pszProvider)
  2278. {
  2279. ualstrcpyW((UNALIGNED WCHAR *)pb, pszProvider);
  2280. pb += cchProvider*sizeof(WCHAR);
  2281. }
  2282. if (pszComment)
  2283. {
  2284. ualstrcpyW((UNALIGNED WCHAR *)pb, pszComment);
  2285. pb += cchComment*sizeof(WCHAR);
  2286. }
  2287. }
  2288. //
  2289. // and the trailing provider type
  2290. //
  2291. if (cbProviderType)
  2292. {
  2293. // Store the provider type
  2294. pb = (LPBYTE)pidn + pidn->cb - sizeof(WORD);
  2295. *((UNALIGNED WORD *)pb) = wNetType;
  2296. }
  2297. *ppidl = (LPITEMIDLIST)pidn;
  2298. return S_OK;
  2299. }
  2300. // wrapper for converting a NETRESOURCE into an IDLIST via _CreateNetPidl
  2301. HRESULT CNetFolder::_NetResToIDList(NETRESOURCE *pnr,
  2302. BOOL fKeepNullRemoteName,
  2303. BOOL fKeepProviderName,
  2304. BOOL fKeepComment,
  2305. LPITEMIDLIST *ppidl)
  2306. {
  2307. NETRESOURCE nr = *pnr;
  2308. LPITEMIDLIST pidl;
  2309. LPTSTR pszName, pszProvider, pszComment;
  2310. IDNETRESOURCE idn;
  2311. LPTSTR psz;
  2312. if (ppidl)
  2313. *ppidl = NULL;
  2314. switch (pnr->dwDisplayType)
  2315. {
  2316. case RESOURCEDISPLAYTYPE_NETWORK:
  2317. pszName = pnr->lpProvider;
  2318. break;
  2319. case RESOURCEDISPLAYTYPE_ROOT:
  2320. pszName =pnr->lpComment;
  2321. break;
  2322. default:
  2323. {
  2324. pszName = pnr->lpRemoteName;
  2325. if (!fKeepNullRemoteName && (!pszName || !*pszName))
  2326. return E_FAIL;
  2327. if (pszName && *pszName)
  2328. {
  2329. psz = (LPTSTR)SkipServerSlashes(pnr->lpRemoteName);
  2330. if ( *psz )
  2331. PathMakePretty(psz);
  2332. }
  2333. }
  2334. break;
  2335. }
  2336. pszProvider = fKeepProviderName ? nr.lpProvider:NULL;
  2337. pszComment = fKeepComment ? nr.lpComment:NULL;
  2338. idn.bFlags = (BYTE)(SHID_NET | (pnr->dwDisplayType & 0x0f));
  2339. idn.uType = (BYTE)(pnr->dwType & 0x0f);
  2340. idn.uUsage = (BYTE)(pnr->dwUsage & 0x0f);
  2341. // Is the current resource a share of some kind and not a container
  2342. if ((pnr->dwDisplayType == RESOURCEDISPLAYTYPE_SHARE || pnr->dwDisplayType == RESOURCEDISPLAYTYPE_SHAREADMIN) &&
  2343. !(pnr->dwUsage & RESOURCEUSAGE_CONTAINER))
  2344. {
  2345. // If so, remember to delegate children of this folder to FSFolder
  2346. idn.bFlags |= (BYTE)SHID_JUNCTION; // \\server\share type thing
  2347. }
  2348. HRESULT hr = _CreateNetIDList(&idn, pszName, pszProvider, pszComment, &pidl);
  2349. if (SUCCEEDED(hr))
  2350. {
  2351. if (ppidl)
  2352. *ppidl = pidl;
  2353. }
  2354. return hr;
  2355. }
  2356. HRESULT CNetFolder::_CreateEntireNetwork(LPITEMIDLIST *ppidl)
  2357. {
  2358. TCHAR szPath[MAX_PATH];
  2359. NETRESOURCE nr = {0};
  2360. // We need to add the Rest of network entry. This is psuedo
  2361. // bogus, as we should either always do it ourself or have
  2362. // MPR always do it, but here it goes...
  2363. LoadString(HINST_THISDLL, IDS_RESTOFNET, szPath, ARRAYSIZE(szPath));
  2364. nr.dwDisplayType = RESOURCEDISPLAYTYPE_ROOT;
  2365. nr.dwType = RESOURCETYPE_ANY;
  2366. nr.dwUsage = RESOURCEUSAGE_CONTAINER;
  2367. nr.lpComment = szPath;
  2368. return _NetResToIDList(&nr, FALSE, FALSE, FALSE, ppidl);
  2369. }
  2370. HRESULT CNetFolder::_CreateEntireNetworkFullIDList(LPITEMIDLIST *ppidl)
  2371. {
  2372. // CLSID_NetworkPlaces\EntireNetwork
  2373. return SHILCreateFromPath(TEXT("::{208D2C60-3AEA-1069-A2D7-08002B30309D}\\EntireNetwork"), ppidl, NULL);
  2374. }
  2375. //
  2376. // To be called back from within CDefFolderMenu
  2377. //
  2378. STDAPI CNetwork_DFMCallBackBG(IShellFolder *psf, HWND hwnd,
  2379. IDataObject *pdtobj, UINT uMsg,
  2380. WPARAM wParam, LPARAM lParam)
  2381. {
  2382. HRESULT hr = S_OK;
  2383. CNetFolder *pThis = FolderToNetFolder(psf);
  2384. if (NULL == pThis)
  2385. return E_UNEXPECTED;
  2386. switch(uMsg)
  2387. {
  2388. case DFM_MERGECONTEXTMENU_BOTTOM:
  2389. if (!(wParam & (CMF_VERBSONLY | CMF_DVFILE)))
  2390. {
  2391. CDefFolderMenu_MergeMenu(HINST_THISDLL, POPUP_PROPERTIES_BG, 0, (LPQCMINFO)lParam);
  2392. }
  2393. break;
  2394. case DFM_GETHELPTEXT:
  2395. LoadStringA(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPSTR)lParam, HIWORD(wParam));
  2396. break;
  2397. case DFM_GETHELPTEXTW:
  2398. LoadStringW(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPWSTR)lParam, HIWORD(wParam));
  2399. break;
  2400. case DFM_INVOKECOMMAND:
  2401. switch (wParam)
  2402. {
  2403. case FSIDM_PROPERTIESBG:
  2404. hr = SHPropertiesForPidl(hwnd, pThis->_pidl, (LPCTSTR)lParam);
  2405. break;
  2406. default:
  2407. // This is one of view menu items, use the default code.
  2408. hr = S_FALSE;
  2409. break;
  2410. }
  2411. break;
  2412. default:
  2413. hr = E_NOTIMPL;
  2414. break;
  2415. }
  2416. return hr;
  2417. }
  2418. //
  2419. // To be called back from within CDefFolderMenu
  2420. //
  2421. STDAPI CNetFolder::DFMCallBack(IShellFolder* psf, HWND hwnd,
  2422. IDataObject* pdtobj, UINT uMsg,
  2423. WPARAM wParam, LPARAM lParam)
  2424. {
  2425. HRESULT hr = S_OK;
  2426. switch(uMsg)
  2427. {
  2428. case DFM_MERGECONTEXTMENU:
  2429. if (pdtobj)
  2430. {
  2431. STGMEDIUM medium;
  2432. LPIDA pida;
  2433. LPQCMINFO pqcm = (LPQCMINFO)lParam;
  2434. UINT idCmdBase = pqcm->idCmdFirst; // must be called before merge
  2435. CDefFolderMenu_MergeMenu(HINST_THISDLL, POPUP_NETWORK_ITEM, 0, pqcm);
  2436. pida = DataObj_GetHIDA(pdtobj, &medium);
  2437. if (pida)
  2438. {
  2439. if (pida->cidl > 0)
  2440. {
  2441. LPIDNETRESOURCE pidn = (LPIDNETRESOURCE)IDA_GetIDListPtr(pida, 0);
  2442. // Only enable "connect" command if the first one is a share.
  2443. if (pidn)
  2444. {
  2445. ULONG rgf = 0;
  2446. if(NET_GetFlags(pidn) & SHID_JUNCTION &&
  2447. !SHRestricted(REST_NONETCONNECTDISCONNECT))
  2448. {
  2449. EnableMenuItem(pqcm->hmenu, idCmdBase + FSIDM_CONNECT,
  2450. MF_CHECKED | MF_BYCOMMAND);
  2451. }
  2452. }
  2453. }
  2454. HIDA_ReleaseStgMedium(pida, &medium);
  2455. }
  2456. }
  2457. break;
  2458. case DFM_GETHELPTEXT:
  2459. LoadStringA(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPSTR)lParam, HIWORD(wParam));
  2460. break;
  2461. case DFM_GETHELPTEXTW:
  2462. LoadStringW(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPWSTR)lParam, HIWORD(wParam));
  2463. break;
  2464. case DFM_INVOKECOMMAND:
  2465. switch(wParam)
  2466. {
  2467. case DFM_CMD_PROPERTIES:
  2468. hr = SHLaunchPropSheet(_PropertiesThreadProc, pdtobj, (LPCTSTR)lParam, psf, NULL);
  2469. break;
  2470. case DFM_CMD_LINK:
  2471. {
  2472. hr = S_FALSE; // do the default shortcut stuff
  2473. CNetFolder *pThis = FolderToNetFolder(psf);
  2474. if (pThis)
  2475. {
  2476. // net hood special case. in this case we want to create the shortuct
  2477. // in the net hood, not offer to put this on the desktop
  2478. IShellFolder2* psfFiles;
  2479. if (SUCCEEDED(pThis->v_GetFileFolder(&psfFiles)))
  2480. {
  2481. CFSFolder_CreateLinks(hwnd, psfFiles, pdtobj, (LPCTSTR)lParam, CMIC_MASK_FLAG_NO_UI);
  2482. hr = S_OK; // we created the links
  2483. }
  2484. }
  2485. }
  2486. break;
  2487. case FSIDM_CONNECT:
  2488. if (pdtobj)
  2489. {
  2490. STGMEDIUM medium;
  2491. LPIDA pida = DataObj_GetHIDA(pdtobj, &medium);
  2492. if (pida)
  2493. {
  2494. for (UINT i = 0; i < pida->cidl; i++)
  2495. {
  2496. LPIDNETRESOURCE pidn = (LPIDNETRESOURCE)IDA_GetIDListPtr(pida, i);
  2497. // Only execute "connect" on shares.
  2498. if (NET_GetFlags(pidn) & SHID_JUNCTION)
  2499. {
  2500. TCHAR szName[MAX_PATH];
  2501. LPTSTR pszName = NET_CopyResName(pidn, szName, ARRAYSIZE(szName));
  2502. DWORD err = SHStartNetConnectionDialog(hwnd, pszName, RESOURCETYPE_DISK);
  2503. DebugMsg(DM_TRACE, TEXT("CNet FSIDM_CONNECT (%s, %x)"), szName, err);
  2504. // events will get generated automatically
  2505. }
  2506. }
  2507. HIDA_ReleaseStgMedium(pida, &medium);
  2508. }
  2509. }
  2510. break;
  2511. default:
  2512. // This is one of view menu items, use the default code.
  2513. hr = S_FALSE;
  2514. break;
  2515. }
  2516. break;
  2517. default:
  2518. hr = E_NOTIMPL;
  2519. break;
  2520. }
  2521. return hr;
  2522. }
  2523. STDAPI CNetFolder::PrinterDFMCallBack(IShellFolder* psf, HWND hwnd,
  2524. IDataObject* pdtobj, UINT uMsg,
  2525. WPARAM wParam, LPARAM lParam)
  2526. {
  2527. HRESULT hr = S_OK;
  2528. switch(uMsg)
  2529. {
  2530. case DFM_MERGECONTEXTMENU:
  2531. //
  2532. // Returning S_FALSE indicates no need to get verbs from
  2533. // extensions.
  2534. //
  2535. hr = S_FALSE;
  2536. break;
  2537. // if anyone hooks our context menu, we want to be on top (Open)
  2538. case DFM_MERGECONTEXTMENU_TOP:
  2539. if (pdtobj)
  2540. {
  2541. LPQCMINFO pqcm = (LPQCMINFO)lParam;
  2542. // insert verbs
  2543. CDefFolderMenu_MergeMenu(HINST_THISDLL, POPUP_NETWORK_PRINTER, 0, pqcm);
  2544. SetMenuDefaultItem(pqcm->hmenu, 0, MF_BYPOSITION);
  2545. }
  2546. break;
  2547. case DFM_GETHELPTEXT:
  2548. LoadStringA(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPSTR)lParam, HIWORD(wParam));
  2549. break;
  2550. case DFM_GETHELPTEXTW:
  2551. LoadStringW(HINST_THISDLL, LOWORD(wParam) + IDS_MH_FSIDM_FIRST, (LPWSTR)lParam, HIWORD(wParam));
  2552. break;
  2553. case DFM_INVOKECOMMAND:
  2554. switch (wParam)
  2555. {
  2556. case DFM_CMD_PROPERTIES:
  2557. hr = SHLaunchPropSheet(_PropertiesThreadProc, pdtobj, (LPCTSTR)lParam, psf, NULL);
  2558. break;
  2559. case DFM_CMD_LINK:
  2560. // do the default create shortcut crap
  2561. return S_FALSE;
  2562. case FSIDM_OPENPRN:
  2563. case FSIDM_NETPRN_INSTALL:
  2564. {
  2565. STGMEDIUM medium;
  2566. LPIDA pida = DataObj_GetHIDA(pdtobj, &medium);
  2567. if (pida)
  2568. {
  2569. UINT action;
  2570. // set up the operation we are going to perform
  2571. switch (wParam)
  2572. {
  2573. case FSIDM_OPENPRN:
  2574. action = PRINTACTION_OPENNETPRN;
  2575. break;
  2576. case FSIDM_NETPRN_INSTALL:
  2577. action = PRINTACTION_NETINSTALL;
  2578. break;
  2579. default: // FSIDM_CONNECT_PRN
  2580. action = (UINT)-1;
  2581. break;
  2582. }
  2583. for (UINT i = 0; i < pida->cidl; i++)
  2584. {
  2585. LPIDNETRESOURCE pidn = (LPIDNETRESOURCE)IDA_GetIDListPtr(pida, i);
  2586. // Only execute command for a net print share
  2587. if (_IsPrintShare(pidn))
  2588. {
  2589. TCHAR szName[MAX_PATH];
  2590. NET_CopyResName(pidn,szName,ARRAYSIZE(szName));
  2591. SHInvokePrinterCommand(hwnd, action, szName, NULL, FALSE);
  2592. }
  2593. } // for (i...
  2594. HIDA_ReleaseStgMedium(pida, &medium);
  2595. } // if (medium.hGlobal)
  2596. break;
  2597. } // case ID_NETWORK_PRINTER_INSTALL, FSIDM_CONNECT_PRN
  2598. default:
  2599. hr = E_FAIL;
  2600. break;
  2601. } // switch(wparam)
  2602. break;
  2603. default:
  2604. hr = E_NOTIMPL;
  2605. break;
  2606. }
  2607. return hr;
  2608. }
  2609. //
  2610. // REVIEW: Almost identical code in fstreex.c
  2611. //
  2612. DWORD CALLBACK CNetFolder::_PropertiesThreadProc(void *pv)
  2613. {
  2614. PROPSTUFF* pps = (PROPSTUFF *)pv;
  2615. ULONG_PTR dwCookie = 0;
  2616. ActivateActCtx(NULL, &dwCookie);
  2617. CNetFolder *pThis = FolderToNetFolder(pps->psf);
  2618. if (pThis)
  2619. {
  2620. STGMEDIUM medium;
  2621. LPIDA pida = DataObj_GetHIDA(pps->pdtobj, &medium);
  2622. if (pida)
  2623. {
  2624. // Yes, do context menu.
  2625. HKEY ahkeys[NKID_COUNT];
  2626. LPCIDNETRESOURCE pnid = (LPCIDNETRESOURCE)IDA_GetIDListPtr(pida, 0);
  2627. if (pnid)
  2628. {
  2629. HRESULT hr = pThis->_OpenKeys(pnid, ahkeys);
  2630. if (SUCCEEDED(hr))
  2631. {
  2632. LPTSTR pszCaption = SHGetCaption(medium.hGlobal);
  2633. SHOpenPropSheet(pszCaption, ahkeys, ARRAYSIZE(ahkeys),
  2634. &CLSID_ShellNetDefExt,
  2635. pps->pdtobj, NULL, pps->pStartPage);
  2636. if (pszCaption)
  2637. SHFree(pszCaption);
  2638. SHRegCloseKeys(ahkeys, ARRAYSIZE(ahkeys));
  2639. }
  2640. }
  2641. HIDA_ReleaseStgMedium(pida, &medium);
  2642. }
  2643. }
  2644. return S_OK;
  2645. }
  2646. STDAPI CNetFolder::_AttributesCallback(IShellFolder2* psf, LPCITEMIDLIST pidl, ULONG* prgfInOut)
  2647. {
  2648. LPCIDNETRESOURCE pidn = (LPCIDNETRESOURCE)pidl;
  2649. ULONG rgfOut = SFGAO_CANLINK | SFGAO_HASPROPSHEET | SFGAO_HASSUBFOLDER |
  2650. SFGAO_FOLDER | SFGAO_FILESYSANCESTOR | SFGAO_STORAGEANCESTOR;
  2651. if (NET_GetFlags(pidn) & SHID_JUNCTION)
  2652. {
  2653. if ((NET_GetType(pidn) == RESOURCETYPE_DISK) ||
  2654. (NET_GetType(pidn) == RESOURCETYPE_ANY))
  2655. rgfOut |= SFGAO_FILESYSTEM | SFGAO_DROPTARGET | SFGAO_CANCOPY | SFGAO_CANMOVE | SFGAO_STORAGE;
  2656. else
  2657. rgfOut &= ~(SFGAO_FILESYSANCESTOR | SFGAO_STORAGEANCESTOR);
  2658. }
  2659. if (_IsPrintShare(pidn))
  2660. {
  2661. rgfOut |= SFGAO_DROPTARGET; // for drag and drop printing
  2662. rgfOut &= ~(SFGAO_FILESYSANCESTOR | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSTEM | SFGAO_FOLDER | SFGAO_HASSUBFOLDER);
  2663. }
  2664. if (NET_IsRemoteFld(pidn))
  2665. {
  2666. rgfOut &= ~(SFGAO_FILESYSANCESTOR | SFGAO_STORAGEANCESTOR | SFGAO_FILESYSTEM);
  2667. }
  2668. *prgfInOut = rgfOut;
  2669. return S_OK;
  2670. }
  2671. // This is only used by the CNetRootFolder subclass, but because we can only QI for
  2672. // CLSID_NetFldr, and we can't access protected members of any CNetFolder instance
  2673. // from a member function of CNetRootFolder, we'll make it belong to CNetFolder
  2674. HRESULT CALLBACK CNetFolder::_AttributesCallbackRoot(IShellFolder2* psf, LPCITEMIDLIST pidl, ULONG* prgfInOut)
  2675. {
  2676. HRESULT hr;
  2677. CNetFolder* pNetF = FolderToNetFolder(psf);
  2678. if (pNetF)
  2679. {
  2680. if (NET_IsValidID(pidl))
  2681. {
  2682. hr = pNetF->CNetFolder::GetAttributesOf(1, &pidl, prgfInOut);
  2683. }
  2684. else
  2685. {
  2686. IShellFolder2* psfFiles;
  2687. hr = pNetF->v_GetFileFolder(&psfFiles);
  2688. if (SUCCEEDED(hr))
  2689. hr = psfFiles->GetAttributesOf(1, &pidl, prgfInOut);
  2690. }
  2691. }
  2692. else
  2693. hr = E_FAIL;
  2694. return hr;
  2695. }
  2696. // this is called by netfind.c
  2697. STDAPI CNetwork_EnumSearches(IShellFolder2* psf2, IEnumExtraSearch **ppenum)
  2698. {
  2699. *ppenum = NULL;
  2700. CNetFolder* pNetF = FolderToNetFolder(psf2);
  2701. return pNetF ? pNetF->EnumSearches(ppenum) : E_INVALIDARG;
  2702. }
  2703. // given the resulting ppidl and a pszRest continue to parse through and add in the remainder
  2704. // of the file system path.
  2705. HRESULT CNetFolder::_ParseRest(LPBC pbc, LPCWSTR pszRest, LPITEMIDLIST* ppidl, DWORD* pdwAttributes)
  2706. {
  2707. HRESULT hr = S_OK;
  2708. // skip leading \ if there is one present
  2709. if (pszRest && pszRest[0] == L'\\')
  2710. pszRest++;
  2711. if (pszRest && pszRest[0])
  2712. {
  2713. // need to QI to get the agregated case
  2714. IShellFolder* psfBind;
  2715. hr = QueryInterface(IID_PPV_ARG(IShellFolder, &psfBind));
  2716. if (SUCCEEDED(hr))
  2717. {
  2718. // pass down to pick off stuff below including regitems and file names
  2719. IShellFolder* psfSub;
  2720. hr = psfBind->BindToObject(*ppidl, NULL, IID_PPV_ARG(IShellFolder, &psfSub));
  2721. if (SUCCEEDED(hr))
  2722. {
  2723. LPITEMIDLIST pidlSubDir;
  2724. hr = psfSub->ParseDisplayName(NULL, pbc, (LPWSTR)pszRest, NULL, &pidlSubDir, pdwAttributes);
  2725. if (SUCCEEDED(hr))
  2726. {
  2727. hr = SHILAppend(pidlSubDir, ppidl);
  2728. }
  2729. psfSub->Release();
  2730. }
  2731. psfBind->Release();
  2732. }
  2733. }
  2734. else
  2735. {
  2736. if (pdwAttributes)
  2737. {
  2738. LPCITEMIDLIST apidlLast[1] = { ILFindLastID(*ppidl) };
  2739. hr = GetAttributesOf(1, apidlLast, pdwAttributes);
  2740. }
  2741. }
  2742. return hr;
  2743. }
  2744. // generate an IDLIST from the NETRESOURCESTRUCTURE we have by
  2745. // walking up its parents trying to determine where we
  2746. // are in the namespace
  2747. BOOL _GetParentResource(NETRESOURCE *pnr, DWORD *pdwbuf)
  2748. {
  2749. if ((pnr->dwDisplayType == RESOURCEDISPLAYTYPE_ROOT) ||
  2750. (WN_SUCCESS != WNetGetResourceParent(pnr, pnr, pdwbuf)))
  2751. {
  2752. return FALSE;
  2753. }
  2754. return TRUE;
  2755. }
  2756. HRESULT CNetFolder::_NetResToIDLists(NETRESOURCE *pnr, DWORD dwbuf, LPITEMIDLIST *ppidl)
  2757. {
  2758. HRESULT hr = S_OK;
  2759. do
  2760. {
  2761. LPITEMIDLIST pidlT;
  2762. hr = _NetResToIDList(pnr, TRUE, TRUE, TRUE, &pidlT);
  2763. if (SUCCEEDED(hr))
  2764. {
  2765. hr = SHILPrepend(pidlT, ppidl); // NOTE: SHILPrepend frees on failure
  2766. }
  2767. }
  2768. while (SUCCEEDED(hr) && _GetParentResource(pnr, &dwbuf));
  2769. return hr;
  2770. }
  2771. // get the parsable network name from the object
  2772. LPTSTR CNetFolder::_GetNameForParsing(LPCWSTR pwszName, LPTSTR pszBuffer, INT cchBuffer, LPTSTR *ppszRegItem)
  2773. {
  2774. LPTSTR pszRegItem = NULL;
  2775. INT cSlashes = 0;
  2776. *ppszRegItem = NULL;
  2777. SHUnicodeToTChar(pwszName, pszBuffer, cchBuffer);
  2778. // remove the trailing \ if there is one, NTLanMan barfs if we pass a string containing it
  2779. INT cchPath = lstrlen(pszBuffer)-1;
  2780. if (cchPath > 2)
  2781. {
  2782. // We don't need to call CharPrev if cchPath <= 2.
  2783. // Calling CharPrev is expensive.
  2784. LPTSTR lpTmp = CharPrev(pszBuffer, pszBuffer + cchPath + 1);
  2785. if (*lpTmp == TEXT('\\'))
  2786. *lpTmp = TEXT('\0');
  2787. }
  2788. // lets walk the name, look for \:: squence to signify the start of a regitem name,
  2789. // and if the number of slashes is > 2 then we should bail
  2790. LPTSTR pszUNC = pszBuffer+2;
  2791. while (pszUNC && *pszUNC && (cSlashes < 2))
  2792. {
  2793. if ((pszUNC[0] == TEXT('\\')) &&
  2794. (pszUNC[1] == TEXT(':')) && (pszUNC[2] == TEXT(':')))
  2795. {
  2796. *ppszRegItem = pszUNC;
  2797. break;
  2798. }
  2799. pszUNC = StrChr(pszUNC+1, TEXT('\\'));
  2800. cSlashes++;
  2801. }
  2802. return pszUNC;
  2803. }
  2804. HRESULT CNetFolder::_ParseNetName(HWND hwnd, LPBC pbc,
  2805. LPCWSTR pwszName, ULONG* pchEaten,
  2806. LPITEMIDLIST *ppidl, DWORD *pdwAttrib)
  2807. {
  2808. HRESULT hr;
  2809. struct _NRTEMP
  2810. {
  2811. NETRESOURCE nr;
  2812. TCHAR szBuffer[1024];
  2813. } nrOut = { 0 };
  2814. TCHAR szPath[MAX_PATH];
  2815. DWORD dwres, dwbuf = sizeof(nrOut.szBuffer);
  2816. LPTSTR pszServerShare = NULL;
  2817. LPTSTR pszRestOfName = NULL;
  2818. LPTSTR pszFakeRestOfName = NULL;
  2819. LPTSTR pszRegItem = NULL;
  2820. // validate the name before we start cracking it...
  2821. pszFakeRestOfName = _GetNameForParsing(pwszName, szPath, ARRAYSIZE(szPath), &pszRegItem);
  2822. NETRESOURCE nr = { 0 };
  2823. nr.lpRemoteName = szPath;
  2824. nr.dwType = RESOURCETYPE_ANY;
  2825. TCHAR szProviderTemp[256];
  2826. nr.lpProvider = (LPTSTR)_GetProvider(NULL, pbc, szProviderTemp, ARRAYSIZE(szProviderTemp));
  2827. dwres = WNetGetResourceInformation(&nr, &nrOut.nr, &dwbuf, &pszRestOfName);
  2828. if (WN_SUCCESS != dwres)
  2829. {
  2830. TCHAR cT;
  2831. LPTSTR pszTemp;
  2832. // truncate the string at the \\server\share to try and parse the name,
  2833. // note at this point if MPR resolves the alias on a Novel server this could
  2834. // get very confusing (eg. \\strike\foo\bah may resolve to \\string\bla,
  2835. // yet our concept of what pszRestOfName will be wrong!
  2836. if (pszFakeRestOfName)
  2837. {
  2838. cT = *pszFakeRestOfName;
  2839. *pszFakeRestOfName = TEXT('\0');
  2840. }
  2841. dwres = WNetGetResourceInformation(&nr, &nrOut.nr, &dwbuf, &pszTemp);
  2842. if (dwres != WN_SUCCESS)
  2843. {
  2844. // we failed to get a net connection using the truncated string,
  2845. // so lets try and use a new connect (eg. prompt for creds)
  2846. // NOTE: shouldn't we only be doing this if its an access denied type error?
  2847. dwres = WNetUseConnection(hwnd, &nr, NULL, NULL, hwnd ? CONNECT_INTERACTIVE:0, NULL, NULL, NULL);
  2848. if (dwres == WN_SUCCESS)
  2849. {
  2850. dwres = WNetGetResourceInformation(&nr, &nrOut, &dwbuf, &pszTemp);
  2851. }
  2852. }
  2853. if (pszFakeRestOfName)
  2854. *pszFakeRestOfName = cT;
  2855. pszRestOfName = pszFakeRestOfName;
  2856. }
  2857. if (WN_SUCCESS == dwres)
  2858. {
  2859. WCHAR wszRestOfName[MAX_PATH] = { 0 };
  2860. if (pszRestOfName)
  2861. SHTCharToUnicode(pszRestOfName, wszRestOfName, ARRAYSIZE(wszRestOfName));
  2862. // assume we are truncating at the regitem and parsing through
  2863. if (pszRegItem)
  2864. pszRestOfName = pszRegItem;
  2865. // attempt to convert the NETRESOURCE to a string to IDLISTS by walking the
  2866. // parents, then add in Entire Network
  2867. hr = _NetResToIDLists(&nrOut.nr, dwbuf, ppidl);
  2868. if (SUCCEEDED(hr))
  2869. {
  2870. LPITEMIDLIST pidlT;
  2871. hr = _CreateEntireNetwork(&pidlT);
  2872. if (SUCCEEDED(hr))
  2873. {
  2874. hr = SHILPrepend(pidlT, ppidl); // NOTE: SHILPrepend frees on failure
  2875. }
  2876. }
  2877. // if we have a local string then lets continue to parse it by binding to
  2878. // its parent folder, otherwise we just want to return the attributes
  2879. if (SUCCEEDED(hr))
  2880. {
  2881. if (SUCCEEDED(DisplayNameOf(this, *ppidl, SHGDN_FORPARSING, szPath, ARRAYSIZE(szPath))))
  2882. {
  2883. NPTRegisterNameToPidlTranslation(szPath, *ppidl); // no _ILNext b/c this is relative to the Net Places folder
  2884. }
  2885. hr = _ParseRest(pbc, wszRestOfName, ppidl, pdwAttrib);
  2886. }
  2887. }
  2888. else
  2889. {
  2890. hr = HRESULT_FROM_WIN32(dwres);
  2891. }
  2892. return hr;
  2893. }
  2894. //
  2895. // simple name parsing for the network paths. this makes big assumptions about the
  2896. // \\server\share format we are given, and the type of IDLISTs to return.
  2897. //
  2898. HRESULT CNetFolder::_AddUnknownIDList(DWORD dwDisplayType, LPITEMIDLIST *ppidl)
  2899. {
  2900. NETRESOURCE nr = { 0 };
  2901. nr.dwScope = RESOURCE_GLOBALNET;
  2902. nr.dwDisplayType = dwDisplayType;
  2903. nr.dwUsage = RESOURCEUSAGE_CONTAINER;
  2904. nr.lpRemoteName = TEXT("\0"); // null name means fake item
  2905. LPITEMIDLIST pidlT;
  2906. HRESULT hr = _NetResToIDList(&nr, TRUE, FALSE, FALSE, &pidlT);
  2907. if (SUCCEEDED(hr))
  2908. {
  2909. hr = SHILAppend(pidlT, ppidl);
  2910. if (FAILED(hr))
  2911. ILFree(pidlT);
  2912. }
  2913. return hr;
  2914. }
  2915. HRESULT CNetFolder::_ParseSimple(LPBC pbc, LPWSTR pszName, LPITEMIDLIST* ppidl, DWORD* pdwAttributes)
  2916. {
  2917. HRESULT hr = S_OK;
  2918. NETRESOURCE nr = {0};
  2919. LPWSTR pszSlash;
  2920. LPITEMIDLIST pidlT;
  2921. USES_CONVERSION;
  2922. *ppidl = NULL;
  2923. // create the entire network IDLIST, provider and domain elements
  2924. hr = _CreateEntireNetwork(ppidl);
  2925. if (SUCCEEDED(hr))
  2926. hr = _AddUnknownIDList(RESOURCEDISPLAYTYPE_NETWORK, ppidl);
  2927. if (SUCCEEDED(hr))
  2928. hr = _AddUnknownIDList(RESOURCEDISPLAYTYPE_DOMAIN, ppidl);
  2929. // create the server IDLIST
  2930. if (SUCCEEDED(hr))
  2931. {
  2932. pszSlash = StrChrW(pszName+2, L'\\');
  2933. if (pszSlash)
  2934. *pszSlash = L'\0';
  2935. nr.dwScope = RESOURCE_GLOBALNET;
  2936. nr.dwDisplayType = RESOURCEDISPLAYTYPE_SERVER;
  2937. nr.dwType = RESOURCETYPE_DISK;
  2938. nr.dwUsage = RESOURCEUSAGE_CONTAINER;
  2939. nr.lpRemoteName = W2T(pszName);
  2940. hr = _NetResToIDList(&nr, FALSE, FALSE, FALSE, &pidlT);
  2941. if (SUCCEEDED(hr))
  2942. hr = SHILAppend(pidlT, ppidl);
  2943. if (pszSlash)
  2944. *pszSlash = L'\\';
  2945. // if we have a trailing \ then lets add in the share part of the IDLIST
  2946. if (SUCCEEDED(hr) && pszSlash)
  2947. {
  2948. pszSlash = StrChrW(pszSlash+1, L'\\');
  2949. if (pszSlash)
  2950. *pszSlash = L'\0';
  2951. nr.dwDisplayType = RESOURCEDISPLAYTYPE_SHARE;
  2952. nr.dwUsage = RESOURCEUSAGE_CONNECTABLE;
  2953. nr.lpRemoteName = W2T(pszName);
  2954. hr = _NetResToIDList(&nr, FALSE, FALSE, FALSE, &pidlT);
  2955. if (SUCCEEDED(hr))
  2956. hr = SHILAppend(pidlT, ppidl);
  2957. if (pszSlash)
  2958. *pszSlash = L'\\';
  2959. }
  2960. }
  2961. if (SUCCEEDED(hr))
  2962. {
  2963. hr = _ParseRest(pbc, pszSlash, ppidl, pdwAttributes);
  2964. }
  2965. return hr;
  2966. }
  2967. // try parsing out the EntireNet or localised version. if we find that object then try and
  2968. // parse through that to the regitems or other objects which live below. this inturn
  2969. // will cause an instance of CNetFolder to be created to generate the other parsing names.
  2970. //
  2971. // returns:
  2972. // S_FALSE - not rest of net, try something else
  2973. // S_OK - was rest of net, use this
  2974. // FAILED(hr) - error result, return
  2975. HRESULT CNetRootFolder::_TryParseEntireNet(HWND hwnd, LPBC pbc, WCHAR *pwszName, LPITEMIDLIST *ppidl, DWORD *pdwAttributes)
  2976. {
  2977. HRESULT hr = S_FALSE; // skip, not rest of net
  2978. *ppidl = NULL;
  2979. if (!PathIsUNCW(pwszName))
  2980. {
  2981. const WCHAR szEntireNetwork[] = L"EntireNetwork";
  2982. WCHAR szRestOfNet[128];
  2983. INT cchRestOfNet = LoadStringW(HINST_THISDLL, IDS_RESTOFNET, szRestOfNet, ARRAYSIZE(szRestOfNet));
  2984. BOOL fRestOfNet = !StrCmpNIW(szRestOfNet, pwszName, cchRestOfNet);
  2985. if (!fRestOfNet && !StrCmpNIW(szEntireNetwork, pwszName, ARRAYSIZE(szEntireNetwork)-1))
  2986. {
  2987. fRestOfNet = TRUE;
  2988. cchRestOfNet = ARRAYSIZE(szEntireNetwork)-1;
  2989. }
  2990. if (fRestOfNet)
  2991. {
  2992. hr = _CreateEntireNetwork(ppidl);
  2993. if (SUCCEEDED(hr))
  2994. {
  2995. if (pdwAttributes)
  2996. {
  2997. GetAttributesOf(1, (LPCITEMIDLIST *)ppidl, pdwAttributes);
  2998. }
  2999. hr = S_OK;
  3000. }
  3001. //
  3002. // if we find extra stuff after the name then lets bind and continue the parsing
  3003. // from there on. this is needed so the we can access regitems burried inside
  3004. // entire net.
  3005. //
  3006. // eg: EntireNetwork\\::{clsid}
  3007. //
  3008. if (SUCCEEDED(hr) &&
  3009. (pwszName[cchRestOfNet] == L'\\') && pwszName[cchRestOfNet+1])
  3010. {
  3011. IShellFolder *psfRestOfNet;
  3012. hr = BindToObject(*ppidl, NULL, IID_PPV_ARG(IShellFolder, &psfRestOfNet));
  3013. if (SUCCEEDED(hr))
  3014. {
  3015. LPITEMIDLIST pidl;
  3016. hr = psfRestOfNet->ParseDisplayName(hwnd, pbc, pwszName+cchRestOfNet+1, NULL, &pidl, pdwAttributes);
  3017. if (SUCCEEDED(hr))
  3018. {
  3019. hr = SHILAppend(pidl, ppidl);
  3020. }
  3021. psfRestOfNet->Release();
  3022. }
  3023. }
  3024. }
  3025. }
  3026. return hr;
  3027. }
  3028. // CNetRootFolder::ParseDisplayname
  3029. // - swtich based on the file system context to see if we need to do a simple parse or not,
  3030. // - check for "EntireNet" and delegate parsing as required.
  3031. STDMETHODIMP CNetRootFolder::ParseDisplayName(HWND hwnd, LPBC pbc, WCHAR* pszName, ULONG* pchEaten, LPITEMIDLIST* ppidl, DWORD* pdwAttributes)
  3032. {
  3033. if (!ppidl)
  3034. return E_INVALIDARG;
  3035. *ppidl = NULL;
  3036. if (!pszName)
  3037. return E_INVALIDARG;
  3038. HRESULT hr = _TryParseEntireNet(hwnd, pbc, pszName, ppidl, pdwAttributes);
  3039. if (hr == S_FALSE)
  3040. {
  3041. if (PathIsUNCW(pszName))
  3042. {
  3043. LPCITEMIDLIST pidlMapped;
  3044. LPTSTR pszRest = NPTMapNameToPidl(pszName, &pidlMapped);
  3045. if (pidlMapped)
  3046. {
  3047. hr = SHILClone(pidlMapped, ppidl);
  3048. if (SUCCEEDED(hr))
  3049. {
  3050. hr = _ParseRest(pbc, pszRest, ppidl, pdwAttributes);
  3051. }
  3052. }
  3053. else
  3054. {
  3055. if (S_OK == SHIsFileSysBindCtx(pbc, NULL))
  3056. {
  3057. hr = _ParseSimple(pbc, pszName, ppidl, pdwAttributes);
  3058. }
  3059. else
  3060. {
  3061. hr = _ParseNetName(hwnd, pbc, pszName, pchEaten, ppidl, pdwAttributes);
  3062. }
  3063. }
  3064. }
  3065. else
  3066. {
  3067. hr = HRESULT_FROM_WIN32(ERROR_BAD_NET_NAME);
  3068. }
  3069. if ((HRESULT_FROM_WIN32(ERROR_BAD_NET_NAME) == hr))
  3070. {
  3071. IShellFolder2 *psfFiles;
  3072. if (SUCCEEDED(v_GetFileFolder(&psfFiles)))
  3073. {
  3074. hr = psfFiles->ParseDisplayName(hwnd, pbc, pszName, pchEaten, ppidl, pdwAttributes);
  3075. }
  3076. }
  3077. }
  3078. if (FAILED(hr))
  3079. {
  3080. ILFree(*ppidl);
  3081. *ppidl = NULL;
  3082. }
  3083. return hr;
  3084. }
  3085. STDMETHODIMP CNetRootFolder::EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList** ppenum)
  3086. {
  3087. DWORD dwRemote = RMF_GETLINKENUM;
  3088. HANDLE hEnum = NULL;
  3089. // Do we enumerate the workgroup?
  3090. if (!SHRestricted(REST_ENUMWORKGROUP))
  3091. {
  3092. // Don't enumerate the workgroup, if the restriction says so
  3093. dwRemote |= RMF_FAKENETROOT;
  3094. // Check the WNet policy to see if we should be showing the
  3095. // entire net object. If not, mark it as shown so that the
  3096. // enumerator doesn't return it.
  3097. if (SHRestricted(REST_NOENTIRENETWORK))
  3098. dwRemote |= RMF_ENTIRENETSHOWN;
  3099. }
  3100. // if we are not faking the net root then lets call _OpenEnum, otherwise lets ignore
  3101. if (!(dwRemote & RMF_FAKENETROOT))
  3102. {
  3103. DWORD err = _OpenEnum(hwnd, grfFlags, NULL, &hEnum);
  3104. // Always add the remote folder to the 'hood
  3105. if (WN_SUCCESS != err)
  3106. {
  3107. // Yes; still show remote anyway (only)
  3108. dwRemote |= RMF_SHOWREMOTE;
  3109. }
  3110. else
  3111. {
  3112. // No; allow everything to be enumerated in the 'hood.
  3113. dwRemote |= RMF_CONTEXT;
  3114. }
  3115. }
  3116. HRESULT hr = Create_NetFolderEnum(this, grfFlags, dwRemote, hEnum, ppenum);
  3117. if (FAILED(hr) && hEnum)
  3118. {
  3119. WNetCloseEnum(hEnum);
  3120. }
  3121. return hr;
  3122. }
  3123. STDMETHODIMP CNetRootFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppv)
  3124. {
  3125. HRESULT hr;
  3126. if (NET_IsValidID(pidl))
  3127. hr = CNetFolder::BindToObject(pidl, pbc, riid, ppv);
  3128. else
  3129. {
  3130. IShellFolder2* psfFiles;
  3131. hr = v_GetFileFolder(&psfFiles);
  3132. if (SUCCEEDED(hr))
  3133. hr = psfFiles->BindToObject(pidl, pbc, riid, ppv);
  3134. }
  3135. return hr;
  3136. }
  3137. STDMETHODIMP CNetRootFolder::CompareIDs(LPARAM iCol, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  3138. {
  3139. HRESULT hr = E_INVALIDARG;
  3140. // First obtain the collate type of the pidls and their respective
  3141. // collate order.
  3142. LONG iColateType1 = _GetFilePIDLType(pidl1);
  3143. LONG iColateType2 = _GetFilePIDLType(pidl2);
  3144. if (iColateType1 == iColateType2)
  3145. {
  3146. // pidls are of same type.
  3147. if (iColateType1 == _HOOD_COL_FILE) // two file system pidls
  3148. {
  3149. IShellFolder2* psfFiles;
  3150. if (SUCCEEDED(v_GetFileFolder(&psfFiles)))
  3151. {
  3152. if (0 == (iCol & SHCIDS_COLUMNMASK))
  3153. {
  3154. // special case this for perf, this is the name compare
  3155. hr = psfFiles->CompareIDs(iCol, pidl1, pidl2);
  3156. }
  3157. else
  3158. {
  3159. SHCOLUMNID scid;
  3160. MapColumnToSCID((UINT)iCol & SHCIDS_COLUMNMASK, &scid);
  3161. int iRet = CompareBySCID(psfFiles, &scid, pidl1, pidl2);
  3162. hr = ResultFromShort(iRet);
  3163. }
  3164. }
  3165. }
  3166. else
  3167. {
  3168. // pidls same and are not of type file,
  3169. // so both must be a type understood
  3170. // by the CNetwork class - pass on to compare.
  3171. hr = CNetFolder::CompareIDs(iCol, pidl1, pidl2);
  3172. }
  3173. }
  3174. else
  3175. {
  3176. // ensure that entire network ends up at the head of the list
  3177. LPCIDNETRESOURCE pidn1 = NET_IsValidID(pidl1);
  3178. LPCIDNETRESOURCE pidn2 = NET_IsValidID(pidl2);
  3179. if ((pidn1 && (NET_GetDisplayType(pidn1) == RESOURCEDISPLAYTYPE_ROOT)) ||
  3180. (pidn2 && (NET_GetDisplayType(pidn2) == RESOURCEDISPLAYTYPE_ROOT)))
  3181. {
  3182. if (iColateType1 == _HOOD_COL_FILE)
  3183. return ResultFromShort(1);
  3184. else
  3185. return ResultFromShort(-1);
  3186. }
  3187. // pidls are not of same type, so have already been correctly
  3188. // collated (consequently, sorting is first by type and
  3189. // then by subfield).
  3190. hr = ResultFromShort(((iColateType2 - iColateType1) > 0) ? 1 : -1);
  3191. }
  3192. return hr;
  3193. }
  3194. STDMETHODIMP CNetRootFolder::CreateViewObject(HWND hwnd, REFIID riid, void **ppv)
  3195. {
  3196. ASSERT(ILIsEqual(_pidl, (LPCITEMIDLIST)&c_idlNet));
  3197. if (IsEqualIID(riid, IID_IDropTarget))
  3198. {
  3199. return CNetRootDropTarget_CreateInstance(hwnd, _pidl, (IDropTarget**) ppv);
  3200. }
  3201. return CNetFolder::CreateViewObject(hwnd, riid, ppv);
  3202. }
  3203. STDMETHODIMP CNetRootFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, ULONG* prgfInOut)
  3204. {
  3205. HRESULT hr;
  3206. if (IsSelf(cidl, apidl))
  3207. {
  3208. // The user can rename links in the hood.
  3209. hr = CNetFolder::GetAttributesOf(cidl, apidl, prgfInOut);
  3210. *prgfInOut |= SFGAO_CANRENAME;
  3211. }
  3212. else
  3213. {
  3214. hr = GetAttributesCallback(SAFECAST(this, IShellFolder2*), cidl, apidl, prgfInOut, _AttributesCallbackRoot);
  3215. }
  3216. return hr;
  3217. }
  3218. STDMETHODIMP CNetRootFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD dwFlags, STRRET* pStrRet)
  3219. {
  3220. HRESULT hr;
  3221. if (NET_IsValidID(pidl) || IsSelf(1, &pidl))
  3222. {
  3223. hr = CNetFolder::GetDisplayNameOf(pidl, dwFlags, pStrRet);
  3224. }
  3225. else
  3226. {
  3227. IShellFolder2* psfFiles;
  3228. hr = v_GetFileFolder(&psfFiles);
  3229. if (SUCCEEDED(hr))
  3230. hr = psfFiles->GetDisplayNameOf(pidl, dwFlags, pStrRet);
  3231. }
  3232. return hr;
  3233. }
  3234. STDMETHODIMP CNetRootFolder::SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR lpszName,
  3235. DWORD dwRes, LPITEMIDLIST* ppidl)
  3236. {
  3237. HRESULT hr;
  3238. if (NET_IsValidID(pidl))
  3239. {
  3240. hr = CNetFolder::SetNameOf(hwnd, pidl, lpszName, dwRes, ppidl);
  3241. }
  3242. else
  3243. {
  3244. IShellFolder2* psfFiles;
  3245. hr = v_GetFileFolder(&psfFiles);
  3246. if (SUCCEEDED(hr))
  3247. hr = psfFiles->SetNameOf(hwnd, pidl, lpszName, dwRes, ppidl);
  3248. }
  3249. return hr;
  3250. }
  3251. STDMETHODIMP CNetRootFolder::GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST* apidl,
  3252. REFIID riid, UINT* prgfInOut, void **ppv)
  3253. {
  3254. HRESULT hr = E_INVALIDARG;
  3255. LPCIDNETRESOURCE pidn = cidl ? NET_IsValidID(apidl[0]) : NULL;
  3256. BOOL fStriped = FALSE;
  3257. *ppv = NULL;
  3258. if (pidn)
  3259. {
  3260. fStriped = _MakeStripToLikeKinds(&cidl, &apidl, TRUE);
  3261. if (IsEqualIID(riid, IID_IContextMenu))
  3262. {
  3263. HKEY ahkeys[NKID_COUNT];
  3264. hr = _OpenKeys(pidn, ahkeys);
  3265. if (SUCCEEDED(hr))
  3266. {
  3267. IShellFolder* psfOuter;
  3268. hr = QueryInterface(IID_PPV_ARG(IShellFolder, &psfOuter));
  3269. if (SUCCEEDED(hr))
  3270. {
  3271. hr = CDefFolderMenu_Create2(_pidl, hwnd, cidl, apidl,
  3272. psfOuter, _GetCallbackType(pidn),
  3273. ARRAYSIZE(ahkeys), ahkeys, (IContextMenu**) ppv);
  3274. psfOuter->Release();
  3275. }
  3276. SHRegCloseKeys(ahkeys, ARRAYSIZE(ahkeys));
  3277. }
  3278. }
  3279. else
  3280. hr = CNetFolder::GetUIObjectOf(hwnd, cidl, apidl, riid, prgfInOut, ppv);
  3281. }
  3282. else
  3283. {
  3284. fStriped = _MakeStripToLikeKinds(&cidl, &apidl, FALSE);
  3285. IShellFolder2* psfFiles;
  3286. hr = v_GetFileFolder(&psfFiles);
  3287. if (SUCCEEDED(hr))
  3288. hr = psfFiles->GetUIObjectOf(hwnd, cidl, apidl, riid, prgfInOut, ppv);
  3289. }
  3290. if (fStriped)
  3291. LocalFree((HLOCAL)apidl);
  3292. return hr;
  3293. }
  3294. STDMETHODIMP CNetRootFolder::GetClassID(CLSID* pCLSID)
  3295. {
  3296. *pCLSID = CLSID_NetworkPlaces;
  3297. return S_OK;
  3298. }
  3299. STDMETHODIMP CNetRootFolder::Initialize(LPCITEMIDLIST pidl)
  3300. {
  3301. ASSERT(ILIsEqual(pidl, (LPCITEMIDLIST)&c_idlNet));
  3302. ASSERT(AssertIsIDListInNameSpace(pidl, &CLSID_NetworkPlaces) && ILIsEmpty(_ILNext(pidl)));
  3303. // Only allow the Net root on the desktop
  3304. // Don't initialize more than once; we are a singleton object.
  3305. // This is theoretically redundant with the InterlockedCompareExchange
  3306. // below, but redundant reinitialization is by far the common case
  3307. // so we'll optimize it.
  3308. if (_pidl)
  3309. return S_OK;
  3310. LPITEMIDLIST pidlNew;
  3311. HRESULT hr = SHILClone(pidl, &pidlNew);
  3312. if (SUCCEEDED(hr))
  3313. {
  3314. if (SHInterlockedCompareExchange((void**)&_pidl, pidlNew, 0))
  3315. {
  3316. // Some other thread raced with us, throw away our copy
  3317. ILFree(pidlNew);
  3318. }
  3319. }
  3320. return hr;
  3321. }
  3322. LONG CNetFolder::_GetFilePIDLType(LPCITEMIDLIST pidl)
  3323. {
  3324. if (NET_IsValidID(pidl))
  3325. {
  3326. if (NET_IsRemoteFld((LPIDNETRESOURCE)pidl))
  3327. {
  3328. return _HOOD_COL_REMOTE;
  3329. }
  3330. if (NET_GetDisplayType((LPIDNETRESOURCE)pidl) == RESOURCEDISPLAYTYPE_ROOT)
  3331. {
  3332. return _HOOD_COL_RON;
  3333. }
  3334. return _HOOD_COL_NET;
  3335. }
  3336. return _HOOD_COL_FILE;
  3337. }
  3338. /* This function adds a provider name to an IDLIST that doesn't already have one. */
  3339. /* A new IDLIST pointer is returned; the old pointer is no longer valid. */
  3340. LPITEMIDLIST CNetFolder::_AddProviderToPidl(LPITEMIDLIST pidl, LPCTSTR lpProvider)
  3341. {
  3342. LPIDNETRESOURCE pidn = (LPIDNETRESOURCE)pidl;
  3343. if (!NET_FHasProvider(pidn))
  3344. {
  3345. LPITEMIDLIST pidlres;
  3346. TCHAR szName[MAX_PATH], szComment[MAX_PATH];
  3347. // construct a new IDLIST preserving the name, comment and other information
  3348. NET_CopyResName(pidn, szName, ARRAYSIZE(szName));
  3349. NET_CopyComment(pidn, szComment, ARRAYSIZE(szComment));
  3350. HRESULT hr = _CreateNetIDList(pidn, szName, lpProvider, szComment[0] ? szComment:NULL, &pidlres);
  3351. if (SUCCEEDED(hr) && !ILIsEmpty(_ILNext(pidl)))
  3352. {
  3353. LPITEMIDLIST pidlT;
  3354. hr = SHILCombine(pidlres, _ILNext(pidl), &pidlT);
  3355. if (SUCCEEDED(hr))
  3356. {
  3357. ILFree(pidlres);
  3358. pidlres = pidlT;
  3359. }
  3360. }
  3361. // if we have a result, free the old PIDL and return the new
  3362. if (SUCCEEDED(hr))
  3363. {
  3364. ILFree(pidl);
  3365. pidl = pidlres;
  3366. }
  3367. }
  3368. return pidl;
  3369. }
  3370. BOOL CNetFolder::_MakeStripToLikeKinds(UINT *pcidl, LPCITEMIDLIST **papidl, BOOL fNetObjects)
  3371. {
  3372. BOOL bRet = FALSE;
  3373. LPITEMIDLIST *apidl = (LPITEMIDLIST*)*papidl;
  3374. int cidl = *pcidl;
  3375. for (int i = 0; i < cidl; i++)
  3376. {
  3377. if ((NET_IsValidID(apidl[i]) != NULL) != fNetObjects)
  3378. {
  3379. LPCITEMIDLIST *apidlHomo = (LPCITEMIDLIST *)LocalAlloc(LPTR, sizeof(*apidlHomo) * cidl);
  3380. if (!apidlHomo)
  3381. return FALSE;
  3382. int cpidlHomo = 0;
  3383. for (i = 0; i < cidl; i++)
  3384. {
  3385. if ((NET_IsValidID(apidl[i]) != NULL) == fNetObjects)
  3386. apidlHomo[cpidlHomo++] = apidl[i];
  3387. }
  3388. // Setup to use the stripped version of the pidl array...
  3389. *pcidl = cpidlHomo;
  3390. *papidl = apidlHomo;
  3391. bRet = TRUE;
  3392. }
  3393. }
  3394. return bRet;
  3395. }
  3396. HRESULT CNetRootFolder::v_GetFileFolder(IShellFolder2 **psf)
  3397. {
  3398. HRESULT hr = SHCacheTrackingFolder((LPCITEMIDLIST)&c_idlNet, CSIDL_NETHOOD, &_psfFiles);
  3399. *psf = _psfFiles;
  3400. return hr;
  3401. }
  3402. //
  3403. // pmedium and pformatetcIn == NULL if we are handling QueryGetData
  3404. //
  3405. HRESULT CNetData::GetHDrop(FORMATETC *pformatetcIn, STGMEDIUM *pmedium)
  3406. {
  3407. HRESULT hr = E_INVALIDARG; // assume error
  3408. STGMEDIUM medium;
  3409. LPIDA pida = DataObj_GetHIDA(this, &medium);
  3410. if (pida)
  3411. {
  3412. // Get the first one to see the type.
  3413. LPCIDNETRESOURCE pidn = (LPCIDNETRESOURCE)IDA_GetIDListPtr(pida, 0);
  3414. if (NULL == pidn)
  3415. hr = E_FAIL;
  3416. if (pidn && (NET_GetFlags(pidn) & SHID_JUNCTION) &&
  3417. (NET_GetType(pidn) == RESOURCETYPE_DISK))
  3418. {
  3419. // Get HDrop only if we are handling IDataObject::GetData (pmedium != NULL)
  3420. if (pmedium)
  3421. {
  3422. // We have non-null FORMATETC and STGMEDIUM - get the HDrop
  3423. hr = CFSIDLData::GetHDrop(pformatetcIn, pmedium);
  3424. }
  3425. else
  3426. {
  3427. hr = S_OK; // We were handling QueryGetData
  3428. }
  3429. }
  3430. HIDA_ReleaseStgMedium(pida, &medium);
  3431. }
  3432. return hr;
  3433. }
  3434. LPTSTR NET_GetProviderFromRes(LPCIDNETRESOURCE pidn, LPTSTR pszBuff, UINT cchBuff);
  3435. // By the way...Win95 shipped with the below provider
  3436. // names. Since the name can be changed and be localized,
  3437. // we have to try and map these correctly for net pidl
  3438. // interop.
  3439. //
  3440. // get the network resource name from an item. this is not a file system path!
  3441. //
  3442. // example:
  3443. // server \\server or strike/sys
  3444. // share \\server\share or strike/sys
  3445. // printer \\server\printer
  3446. // provider "provider name"
  3447. // entire net "Entire Network"
  3448. //
  3449. // in:
  3450. // pidn the item
  3451. // cchBuff size of buffer in chars.
  3452. //
  3453. // out:
  3454. // pszBuff return buffer
  3455. //
  3456. // returns:
  3457. // address of the input buffer (pszBuff)
  3458. //
  3459. LPTSTR NET_CopyResName(LPCIDNETRESOURCE pidn, LPTSTR pszBuff, UINT cchBuff)
  3460. {
  3461. if (NET_IsUnicode(pidn))
  3462. {
  3463. LPBYTE pb = (LPBYTE)pidn->szNetResName;
  3464. pb += lstrlenA((LPSTR)pb) + 1; // Skip over ansi net name
  3465. if (NET_FHasProvider(pidn))
  3466. pb += lstrlenA((LPSTR)pb) + 1; // Skip over ansi provider
  3467. if (NET_FHasComment(pidn))
  3468. pb += lstrlenA((LPSTR)pb) + 1; // Skip over comment
  3469. ualstrcpyn(pszBuff, (LPNWSTR)pb, cchBuff);
  3470. }
  3471. else
  3472. {
  3473. SHAnsiToTChar(pidn->szNetResName, pszBuff, cchBuff);
  3474. }
  3475. return pszBuff;
  3476. }
  3477. //
  3478. // get the provider name from an item. some items do not have providers stored
  3479. // in them. for example the "*" indicates where the provider is stored in the
  3480. // two different forms of network pidls.
  3481. // [entire net] [provider *] [server] [share] [... file system]
  3482. // [server *] [share] [... file system]
  3483. // in:
  3484. // pidn item (single item PIDL) to try to get the provider name from
  3485. // cchBuff size in chars.
  3486. // out:
  3487. // pszBuff output
  3488. //
  3489. LPTSTR NET_CopyProviderName(LPCIDNETRESOURCE pidn, LPTSTR pszBuff, UINT cchBuff)
  3490. {
  3491. *pszBuff = 0;
  3492. if (!NET_FHasProvider(pidn))
  3493. return NULL;
  3494. // try the wNetType at the end of the pidl
  3495. const BYTE *pb = (LPBYTE)pidn + pidn->cb - sizeof(WORD);
  3496. DWORD dwNetType = *((UNALIGNED WORD *)pb) << 16;
  3497. if (dwNetType && (dwNetType <= WNNC_NET_LARGEST) &&
  3498. (WNetGetProviderName(dwNetType, pszBuff, (ULONG*)&cchBuff) == WN_SUCCESS))
  3499. {
  3500. return pszBuff;
  3501. }
  3502. // Try the old way...
  3503. pb = (LPBYTE)pidn->szNetResName + lstrlenA(pidn->szNetResName) + 1; // Skip over ansi net name
  3504. if (NET_IsUnicode(pidn))
  3505. {
  3506. pb += lstrlenA((LPSTR)pb) + 1; // Skip over ansi provider
  3507. if (NET_FHasComment(pidn))
  3508. pb += lstrlenA((LPSTR)pb) + 1; // Skip over comment
  3509. pb += (ualstrlen((LPNWSTR)pb) + 1) * sizeof(WCHAR); // skip over unicode net name
  3510. ualstrcpyn(pszBuff, (LPNWSTR)pb, cchBuff);
  3511. }
  3512. else
  3513. {
  3514. SHAnsiToTChar((LPSTR)pb, pszBuff, cchBuff);
  3515. }
  3516. // Map from Win95 net provider name if possible...
  3517. for (int i = 0; i < ARRAYSIZE(c_rgProviderMap); i++)
  3518. {
  3519. if (lstrcmp(pszBuff, c_rgProviderMap[i].lpName) == 0)
  3520. {
  3521. DWORD dwNetType = c_rgProviderMap[i].wNetType << 16;
  3522. if (dwNetType && (dwNetType <= WNNC_NET_LARGEST))
  3523. {
  3524. *pszBuff = 0;
  3525. WNetGetProviderName(dwNetType, pszBuff, (LPDWORD)&cchBuff);
  3526. }
  3527. break;
  3528. }
  3529. }
  3530. return pszBuff;
  3531. }
  3532. //
  3533. // get the comment if there is one from the net item
  3534. //
  3535. LPTSTR NET_CopyComment(LPCIDNETRESOURCE pidn, LPTSTR pszBuff, UINT cchBuff)
  3536. {
  3537. *pszBuff = 0;
  3538. LPCSTR pszT = pidn->szNetResName + lstrlenA(pidn->szNetResName) + 1;
  3539. if (NET_FHasComment(pidn))
  3540. {
  3541. if (NET_FHasProvider(pidn))
  3542. pszT += lstrlenA(pszT) + 1;
  3543. if (NET_IsUnicode(pidn))
  3544. {
  3545. pszT += lstrlenA(pszT) + 1; // Skip Ansi comment
  3546. LPNCWSTR pszW = (LPNCWSTR)pszT; // We're at the unicode portion of the pidl
  3547. pszW += ualstrlen(pszW) + 1; // Skip Unicode Name
  3548. if (NET_FHasProvider(pidn))
  3549. pszW += ualstrlen(pszW) + 1; // Skip Unicode Provider
  3550. ualstrcpyn(pszBuff, pszW, cchBuff);
  3551. }
  3552. else
  3553. {
  3554. SHAnsiToUnicode(pszT, pszBuff, cchBuff);
  3555. }
  3556. }
  3557. return pszBuff;
  3558. }
  3559. // pidlRemainder will be filled in (only in the TRUE return case) with a
  3560. // pointer to the part of the IDL (if any) past the remote regitem.
  3561. // This value may be used, for example, to differentiate between a remote
  3562. // printer folder and a printer under a remote printer folder
  3563. BOOL NET_IsRemoteRegItem(LPCITEMIDLIST pidl, REFCLSID rclsid, LPCITEMIDLIST* ppidlRemainder)
  3564. {
  3565. BOOL bRet = FALSE;
  3566. // in "My Network Places"
  3567. if (pidl && IsIDListInNameSpace(pidl, &CLSID_NetworkPlaces))
  3568. {
  3569. LPCITEMIDLIST pidlStart = pidl; // save this
  3570. // Now, search for a server item. HACKHACK: this assume everything from
  3571. // the NetHood to the server item is a shell pidl with a bFlags field!!
  3572. for (pidl = _ILNext(pidl); !ILIsEmpty(pidl); pidl = _ILNext(pidl))
  3573. {
  3574. if ((SIL_GetType(pidl) & SHID_TYPEMASK) == SHID_NET_SERVER)
  3575. {
  3576. LPITEMIDLIST pidlToTest;
  3577. // Found a server. Is the thing after it a remote registry item?
  3578. pidl = _ILNext(pidl);
  3579. *ppidlRemainder = _ILNext(pidl);
  3580. pidlToTest = ILCloneUpTo(pidlStart, *ppidlRemainder);
  3581. if (pidlToTest)
  3582. {
  3583. CLSID clsid;
  3584. bRet = SUCCEEDED(GetCLSIDFromIDList(pidlToTest, &clsid)) && IsEqualCLSID(rclsid, clsid);
  3585. ILFree(pidlToTest);
  3586. }
  3587. break; // done
  3588. }
  3589. }
  3590. }
  3591. return bRet;
  3592. }
  3593. //
  3594. // Get the provider name from an absolute IDLIST.
  3595. // Parameters:
  3596. // pidlAbs -- Specifies the Absolute IDList to the file system object
  3597. //
  3598. LPTSTR NET_GetProviderFromIDList(LPCITEMIDLIST pidlAbs, LPTSTR pszBuff, UINT cchBuff)
  3599. {
  3600. return NET_GetProviderFromRes((LPCIDNETRESOURCE)_ILNext(pidlAbs), pszBuff, cchBuff);
  3601. }
  3602. //
  3603. // Get the provider name from a relative IDLIST.
  3604. // in:
  3605. // pidn potentially multi level item to try to get the resource from
  3606. //
  3607. LPTSTR NET_GetProviderFromRes(LPCIDNETRESOURCE pidn, LPTSTR pszBuffer, UINT cchBuffer)
  3608. {
  3609. // If this guy is the REST of network item, we increment to the
  3610. // next IDLIST - If at root return NULL
  3611. if (pidn->cb == 0)
  3612. return NULL;
  3613. //
  3614. // If the IDLIST starts with a ROOT_REGITEM, then skip to the
  3615. // next item in the list...
  3616. if (pidn->bFlags == SHID_ROOT_REGITEM)
  3617. {
  3618. pidn = (LPIDNETRESOURCE)_ILNext((LPITEMIDLIST)pidn);
  3619. if (pidn->cb == 0)
  3620. return NULL;
  3621. }
  3622. // If the IDLIST includes Entire Network, the provider will be
  3623. // part of the next component.
  3624. if (NET_GetDisplayType(pidn) == RESOURCEDISPLAYTYPE_ROOT)
  3625. {
  3626. pidn = (LPIDNETRESOURCE)_ILNext((LPITEMIDLIST)pidn);
  3627. if (pidn->cb == 0)
  3628. return NULL;
  3629. }
  3630. // If the next component after the 'hood or Entire Network is
  3631. // a network object, its name is the provider name, else the
  3632. // provider name comes after the remote name.
  3633. if (NET_GetDisplayType(pidn) == RESOURCEDISPLAYTYPE_NETWORK)
  3634. {
  3635. // Simply return the name field back for the item.
  3636. return NET_CopyResName(pidn, pszBuffer, cchBuffer);
  3637. }
  3638. else
  3639. {
  3640. // Nope one of the items in the neighborhood view was selected
  3641. // The Provider name is stored after ther resource name
  3642. return NET_CopyProviderName(pidn, pszBuffer, cchBuffer);
  3643. }
  3644. }
  3645. #define PTROFFSET(pBase, p) ((int) ((LPBYTE)(p) - (LPBYTE)(pBase)))
  3646. //
  3647. // fill in pmedium with a NRESARRAY
  3648. //
  3649. // pmedium == NULL if we are handling QueryGetData
  3650. //
  3651. STDAPI CNetData_GetNetResource(IDataObject *pdtobj, STGMEDIUM *pmedium)
  3652. {
  3653. HRESULT hr = E_OUTOFMEMORY;
  3654. LPITEMIDLIST pidl;
  3655. STGMEDIUM medium;
  3656. LPIDA pida = DataObj_GetHIDA(pdtobj, &medium);
  3657. ASSERT(pida && pida->cidl);
  3658. // First, get the provider name from the first one (assuming they are common).
  3659. pidl = IDA_ILClone(pida, 0);
  3660. if (pidl)
  3661. {
  3662. TCHAR szProvider[MAX_PATH];
  3663. LPCTSTR pszProvider = NET_GetProviderFromIDList(pidl, szProvider, ARRAYSIZE(szProvider));
  3664. if (pmedium)
  3665. {
  3666. TCHAR szName[MAX_PATH];
  3667. UINT cbHeader = sizeof(NRESARRAY) + (sizeof(NETRESOURCE) * (pida->cidl - 1));
  3668. UINT cbRequired, iItem;
  3669. // Calculate required size
  3670. cbRequired = cbHeader;
  3671. if (pszProvider)
  3672. cbRequired += (lstrlen(pszProvider) + 1) * sizeof(TCHAR);
  3673. for (iItem = 0; iItem < pida->cidl; iItem++)
  3674. {
  3675. LPCIDNETRESOURCE pidn = (LPCIDNETRESOURCE)IDA_GetIDListPtr(pida, iItem);
  3676. NET_CopyResName(pidn, szName, ARRAYSIZE(szName));
  3677. cbRequired += (lstrlen(szName) + 1) * sizeof(TCHAR);
  3678. }
  3679. //
  3680. // Indicate that the caller should release hmem.
  3681. //
  3682. pmedium->pUnkForRelease = NULL;
  3683. pmedium->tymed = TYMED_HGLOBAL;
  3684. pmedium->hGlobal = GlobalAlloc(GPTR, cbRequired);
  3685. if (pmedium->hGlobal)
  3686. {
  3687. LPNRESARRAY panr = (LPNRESARRAY)pmedium->hGlobal;
  3688. LPTSTR pszT = (LPTSTR)((LPBYTE)panr + cbHeader);
  3689. LPTSTR pszEnd = (LPTSTR)((LPBYTE)panr + cbRequired);
  3690. UINT offProvider = 0;
  3691. panr->cItems = pida->cidl;
  3692. // Copy the provider name. This is not necessary,
  3693. // if we are dragging providers.
  3694. if (pszProvider)
  3695. {
  3696. lstrcpy(pszT, pszProvider);
  3697. offProvider = PTROFFSET(panr, pszT);
  3698. pszT += lstrlen(pszT) + 1;
  3699. }
  3700. //
  3701. // For each item, fill each NETRESOURCE and append resource
  3702. // name at the end. Note that we should put offsets in
  3703. // lpProvider and lpRemoteName.
  3704. //
  3705. for (iItem = 0; iItem < pida->cidl; iItem++)
  3706. {
  3707. LPNETRESOURCE pnr = &panr->nr[iItem];
  3708. LPCIDNETRESOURCE pidn = (LPCIDNETRESOURCE)IDA_GetIDListPtr(pida, iItem);
  3709. ASSERT(pnr->dwScope == 0);
  3710. ASSERT(pnr->lpLocalName==NULL);
  3711. ASSERT(pnr->lpComment==NULL);
  3712. pnr->dwType = NET_GetType(pidn);
  3713. pnr->dwDisplayType = NET_GetDisplayType(pidn);
  3714. pnr->dwUsage = NET_GetUsage(pidn);
  3715. NET_CopyResName(pidn, pszT, (UINT)(pszEnd-pszT));
  3716. if (pnr->dwDisplayType == RESOURCEDISPLAYTYPE_ROOT)
  3717. {
  3718. pnr->lpProvider = NULL;
  3719. pnr->lpRemoteName = NULL;
  3720. }
  3721. else if (pnr->dwDisplayType == RESOURCEDISPLAYTYPE_NETWORK)
  3722. {
  3723. *((UINT *) &pnr->lpProvider) = PTROFFSET(panr, pszT);
  3724. ASSERT(pnr->lpRemoteName == NULL);
  3725. }
  3726. else
  3727. {
  3728. *((UINT *) &pnr->lpProvider) = offProvider;
  3729. *((UINT *) &pnr->lpRemoteName) = PTROFFSET(panr, pszT);
  3730. }
  3731. pszT += lstrlen(pszT) + 1;
  3732. }
  3733. ASSERT(pszEnd == pszT);
  3734. hr = S_OK;
  3735. }
  3736. }
  3737. else
  3738. {
  3739. hr = S_OK; // handing QueryGetData, yes, we have it
  3740. }
  3741. ILFree(pidl);
  3742. }
  3743. HIDA_ReleaseStgMedium(pida, &medium);
  3744. return hr;
  3745. }
  3746. // fill in pmedium with an HGLOBAL version of a NRESARRAY
  3747. STDAPI CNetData_GetNetResourceForFS(IDataObject *pdtobj, STGMEDIUM *pmedium)
  3748. {
  3749. HRESULT hr = E_OUTOFMEMORY;
  3750. LPITEMIDLIST pidlAbs;
  3751. STGMEDIUM medium;
  3752. LPIDA pida = DataObj_GetHIDA(pdtobj, &medium);
  3753. ASSERT(pida && medium.hGlobal); // we created this...
  3754. //
  3755. // NOTES: Even though we may have multiple FS objects in this HIDA,
  3756. // we know that they share the root. Therefore, getting the pidl for
  3757. // the first item is always sufficient.
  3758. //
  3759. pidlAbs = IDA_ILClone(pida, 0);
  3760. if (pidlAbs)
  3761. {
  3762. LPITEMIDLIST pidl;
  3763. ASSERT(AssertIsIDListInNameSpace(pidlAbs, &CLSID_NetworkPlaces));
  3764. //
  3765. // Look for the JUNCTION point (starting from the second ID)
  3766. //
  3767. for (pidl = _ILNext(pidlAbs); !ILIsEmpty(pidl); pidl = _ILNext(pidl))
  3768. {
  3769. LPIDNETRESOURCE pidn = (LPIDNETRESOURCE)pidl;
  3770. if (NET_GetFlags(pidn) & SHID_JUNCTION)
  3771. {
  3772. //
  3773. // We found the JUNCTION point (which is s share).
  3774. // Return the HNRES to it.
  3775. //
  3776. TCHAR szProvider[MAX_PATH];
  3777. TCHAR szRemote[MAX_PATH];
  3778. UINT cbRequired;
  3779. LPCTSTR pszProvider = NET_GetProviderFromIDList(pidlAbs, szProvider, ARRAYSIZE(szProvider));
  3780. LPCTSTR pszRemoteName = NET_CopyResName(pidn, szRemote, ARRAYSIZE(szRemote));
  3781. UINT cbProvider = lstrlen(pszProvider) * sizeof(TCHAR) + sizeof(TCHAR);
  3782. //
  3783. // This should not be a provider node.
  3784. // This should not be the last ID in pidlAbs.
  3785. //
  3786. ASSERT(pszProvider != pszRemoteName);
  3787. ASSERT(!ILIsEmpty(_ILNext(pidl)));
  3788. cbRequired = sizeof(NRESARRAY) + cbProvider + lstrlen(pszRemoteName) * sizeof(TCHAR) + sizeof(TCHAR);
  3789. pmedium->pUnkForRelease = NULL;
  3790. pmedium->tymed = TYMED_HGLOBAL;
  3791. pmedium->hGlobal = GlobalAlloc(GPTR, cbRequired);
  3792. if (pmedium->hGlobal)
  3793. {
  3794. LPNRESARRAY panr = (LPNRESARRAY)pmedium->hGlobal;
  3795. LPNETRESOURCE pnr = &panr->nr[0];
  3796. LPTSTR pszT = (LPTSTR)(panr + 1);
  3797. ASSERT(pnr->dwScope == 0);
  3798. ASSERT(pnr->lpLocalName == NULL);
  3799. ASSERT(pnr->lpComment == NULL);
  3800. panr->cItems = 1;
  3801. pnr->dwType = NET_GetType(pidn);
  3802. pnr->dwDisplayType = NET_GetDisplayType(pidn);
  3803. pnr->dwUsage = NET_GetUsage(pidn);
  3804. *((UINT *) &pnr->lpProvider) = sizeof(NRESARRAY);
  3805. lstrcpy(pszT, pszProvider);
  3806. ASSERT(PTROFFSET(panr, pszT) == sizeof(NRESARRAY));
  3807. pszT += cbProvider / sizeof(TCHAR);
  3808. *((UINT *) &pnr->lpRemoteName) = sizeof(NRESARRAY) + cbProvider;
  3809. ASSERT(PTROFFSET(panr, pszT) == (int)sizeof(NRESARRAY) + (int)cbProvider);
  3810. lstrcpy(pszT, pszRemoteName);
  3811. ASSERT(((LPBYTE)panr) + cbRequired == (LPBYTE)pszT + (lstrlen(pszT) + 1) * sizeof(TCHAR));
  3812. hr = S_OK;
  3813. }
  3814. else
  3815. {
  3816. hr = E_OUTOFMEMORY;
  3817. }
  3818. break;
  3819. }
  3820. }
  3821. ASSERT(!ILIsEmpty(pidl)); // We should have found the junction point.
  3822. ILFree(pidlAbs);
  3823. }
  3824. HIDA_ReleaseStgMedium(pida, &medium);
  3825. return hr;
  3826. }
  3827. STDMETHODIMP CNetData::QueryGetData(FORMATETC *pformatetc)
  3828. {
  3829. if (pformatetc->tymed & TYMED_HGLOBAL)
  3830. {
  3831. if (pformatetc->cfFormat == g_cfNetResource)
  3832. return CNetData_GetNetResource(this, NULL);
  3833. if (pformatetc->cfFormat == CF_HDROP)
  3834. return GetHDrop(NULL, NULL);
  3835. }
  3836. return CFSIDLData::QueryGetData(pformatetc);
  3837. }
  3838. STDMETHODIMP CNetData::GetData(FORMATETC *pformatetc, STGMEDIUM *pmedium)
  3839. {
  3840. if (pformatetc->tymed & TYMED_HGLOBAL)
  3841. {
  3842. if (pformatetc->cfFormat == g_cfNetResource)
  3843. return CNetData_GetNetResource(this, pmedium);
  3844. if (pformatetc->cfFormat == CF_HDROP)
  3845. return GetHDrop(pformatetc, pmedium);
  3846. }
  3847. return CFSIDLData::GetData(pformatetc, pmedium);
  3848. }
  3849. BOOL GetPathFromDataObject(IDataObject *pdtobj, DWORD dwData, LPTSTR pszFileName)
  3850. {
  3851. BOOL bRet = FALSE;
  3852. BOOL fUnicode = FALSE;
  3853. HRESULT hr;
  3854. if (dwData & (DTID_FDESCW | DTID_FDESCA))
  3855. {
  3856. FORMATETC fmteW = {g_cfFileGroupDescriptorW, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  3857. STGMEDIUM medium = {0};
  3858. hr = pdtobj->GetData(&fmteW, &medium);
  3859. if (SUCCEEDED(hr))
  3860. {
  3861. fUnicode = TRUE;
  3862. }
  3863. else
  3864. {
  3865. FORMATETC fmteA = {g_cfFileGroupDescriptorA, NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL};
  3866. hr = pdtobj->GetData(&fmteA, &medium);
  3867. }
  3868. if (SUCCEEDED(hr))
  3869. {
  3870. if (fUnicode)
  3871. {
  3872. FILEGROUPDESCRIPTORW *pfgdW = (FILEGROUPDESCRIPTORW *)GlobalLock(medium.hGlobal);
  3873. if (pfgdW)
  3874. {
  3875. if (pfgdW->cItems == 1)
  3876. {
  3877. SHUnicodeToTChar(pfgdW->fgd[0].cFileName, pszFileName, MAX_PATH);
  3878. }
  3879. bRet = TRUE;
  3880. GlobalUnlock(medium.hGlobal);
  3881. }
  3882. }
  3883. else
  3884. {
  3885. FILEGROUPDESCRIPTORA *pfgdA = (FILEGROUPDESCRIPTORA*)GlobalLock(medium.hGlobal);
  3886. if (pfgdA)
  3887. {
  3888. if (pfgdA->cItems == 1)
  3889. {
  3890. SHAnsiToTChar(pfgdA->fgd[0].cFileName, pszFileName, MAX_PATH);
  3891. }
  3892. bRet = TRUE;
  3893. GlobalUnlock(medium.hGlobal);
  3894. }
  3895. }
  3896. ReleaseStgMedium(&medium);
  3897. }
  3898. }
  3899. return bRet;
  3900. }
  3901. class CNetRootDropTarget : public CIDLDropTarget
  3902. {
  3903. friend HRESULT CNetRootDropTarget_CreateInstance(HWND hwnd, LPCITEMIDLIST pidl, IDropTarget **ppdropt);
  3904. public:
  3905. CNetRootDropTarget(HWND hwnd) : CIDLDropTarget(hwnd) { };
  3906. // IDropTarget methods overwirte
  3907. STDMETHODIMP DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
  3908. STDMETHODIMP Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect);
  3909. private:
  3910. ~CNetRootDropTarget();
  3911. IDropTarget *_pdtgHood; // file system drop target
  3912. };
  3913. CNetRootDropTarget::~CNetRootDropTarget()
  3914. {
  3915. if (_pdtgHood)
  3916. _pdtgHood->Release();
  3917. }
  3918. STDMETHODIMP CNetRootDropTarget::DragEnter(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  3919. {
  3920. CIDLDropTarget::DragEnter(pdtobj, grfKeyState, pt, pdwEffect);
  3921. if ((m_dwData & (DTID_NETRES | DTID_HIDA)) == (DTID_NETRES | DTID_HIDA))
  3922. {
  3923. // NETRESOURCE (DTID_NETRES) allow link
  3924. *pdwEffect &= DROPEFFECT_LINK;
  3925. }
  3926. else if (((m_dwData & (DTID_FDESCW | DTID_CONTENTS)) == (DTID_FDESCW | DTID_CONTENTS)) ||
  3927. ((m_dwData & (DTID_FDESCA | DTID_CONTENTS)) == (DTID_FDESCA | DTID_CONTENTS)) )
  3928. {
  3929. // dragging an URL from the web browser gives a FILECONTENTS version
  3930. // of a .URL file. accept that here for Internet Shortcut (.url)
  3931. TCHAR szFileName[MAX_PATH];
  3932. if (GetPathFromDataObject(pdtobj, m_dwData, szFileName) &&
  3933. (0 == lstrcmpi(PathFindExtension(szFileName), TEXT(".url"))))
  3934. {
  3935. *pdwEffect &= DROPEFFECT_LINK;
  3936. }
  3937. else
  3938. {
  3939. *pdwEffect = DROPEFFECT_NONE;
  3940. }
  3941. }
  3942. else
  3943. {
  3944. *pdwEffect = DROPEFFECT_NONE;
  3945. }
  3946. m_dwEffectLastReturned = *pdwEffect;
  3947. return S_OK;
  3948. }
  3949. STDMETHODIMP CNetRootDropTarget::Drop(IDataObject *pdtobj, DWORD grfKeyState, POINTL pt, DWORD *pdwEffect)
  3950. {
  3951. *pdwEffect &= DROPEFFECT_LINK;
  3952. HRESULT hr = CIDLDropTarget::DragDropMenu(DROPEFFECT_LINK, pdtobj,
  3953. pt, pdwEffect, NULL, NULL, POPUP_NONDEFAULTDD, grfKeyState);
  3954. if (*pdwEffect)
  3955. {
  3956. if (!_pdtgHood)
  3957. {
  3958. LPITEMIDLIST pidl = SHCloneSpecialIDList(NULL, CSIDL_NETHOOD, FALSE);
  3959. if (pidl)
  3960. {
  3961. IShellFolder *psf;
  3962. if (SUCCEEDED(SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder, pidl, &psf))))
  3963. {
  3964. psf->CreateViewObject(_GetWindow(), IID_PPV_ARG(IDropTarget, &_pdtgHood));
  3965. psf->Release();
  3966. }
  3967. ILFree(pidl);
  3968. }
  3969. }
  3970. if (_pdtgHood)
  3971. {
  3972. // force link through the dwEffect and keyboard
  3973. *pdwEffect &= DROPEFFECT_LINK;
  3974. grfKeyState = MK_LBUTTON | MK_CONTROL | MK_SHIFT | MK_FAKEDROP;
  3975. hr = SHSimulateDrop(_pdtgHood, pdtobj, grfKeyState, NULL, pdwEffect);
  3976. }
  3977. else
  3978. *pdwEffect = 0;
  3979. }
  3980. CIDLDropTarget::DragLeave();
  3981. return hr;
  3982. }
  3983. HRESULT CNetRootDropTarget_CreateInstance(HWND hwnd, LPCITEMIDLIST pidl, IDropTarget **ppdropt)
  3984. {
  3985. *ppdropt = NULL;
  3986. HRESULT hr;
  3987. CNetRootDropTarget *pnrdt = new CNetRootDropTarget(hwnd);
  3988. if (pnrdt)
  3989. {
  3990. hr = pnrdt->_Init(pidl);
  3991. if (SUCCEEDED(hr))
  3992. pnrdt->QueryInterface(IID_PPV_ARG(IDropTarget, ppdropt));
  3993. pnrdt->Release();
  3994. }
  3995. else
  3996. hr = E_OUTOFMEMORY;
  3997. return hr;
  3998. }
  3999. // This part is psuedo bogus. Basically we have problems at times doing a
  4000. // translation from things like \\pyrex\user to the appropriate PIDL,
  4001. // especially if you want to avoid the overhead of hitting the network and
  4002. // also problems of knowing if the server is in the "HOOD"
  4003. //
  4004. // We must maintain the mapping table in UNICODE internally, because
  4005. // IShellFolder::ParseDisplayName uses UNICODE, and we don't want to have
  4006. // to deal with lstrlen(dbcs) != lstrlen(sbcs) problems.
  4007. //
  4008. typedef struct _NPT_ITEM
  4009. {
  4010. struct _NPT_ITEM *pnptNext; // Pointer to next item;
  4011. LPCITEMIDLIST pidl; // The pidl
  4012. USHORT cchName; // size of the name in characters.
  4013. WCHAR szName[1]; // The name to translate from
  4014. } NPT_ITEM;
  4015. // Each process will maintain their own list.
  4016. NPT_ITEM *g_pnptHead = NULL;
  4017. //
  4018. // Function to register translations from Path to IDList translations.
  4019. //
  4020. void NPTRegisterNameToPidlTranslation(LPCTSTR pszPath, LPCITEMIDLIST pidl)
  4021. {
  4022. NPT_ITEM *pnpt;
  4023. int cItemsRemoved = 0;
  4024. WCHAR szPath[MAX_PATH];
  4025. // We currently are only interested in UNC Roots
  4026. // If the table becomes large we can reduce this to only servers...
  4027. if (!PathIsUNC(pszPath))
  4028. return; // Not interested.
  4029. //
  4030. // If this item is not a root we need to count how many items to remove
  4031. //
  4032. SHTCharToUnicode(pszPath, szPath, ARRAYSIZE(szPath));
  4033. while (!PathIsUNCServerShare(szPath))
  4034. {
  4035. cItemsRemoved++;
  4036. if (!PathRemoveFileSpecW(szPath))
  4037. return; // Did not get back to a valid root
  4038. }
  4039. ENTERCRITICAL;
  4040. // We don't want to add duplicates
  4041. for (pnpt = g_pnptHead; pnpt != NULL ; pnpt = pnpt->pnptNext)
  4042. {
  4043. if (StrCmpIW(szPath, pnpt->szName) == 0)
  4044. break;
  4045. }
  4046. if (pnpt == NULL)
  4047. {
  4048. UINT cch = lstrlenW(szPath);
  4049. pnpt = (NPT_ITEM *)LocalAlloc(LPTR, sizeof(NPT_ITEM) + cch * sizeof(WCHAR));
  4050. if (pnpt)
  4051. {
  4052. pnpt->pidl = ILClone(pidl);
  4053. if (pnpt->pidl)
  4054. {
  4055. while (cItemsRemoved--)
  4056. {
  4057. ILRemoveLastID((LPITEMIDLIST)pnpt->pidl);
  4058. }
  4059. pnpt->pnptNext = g_pnptHead;
  4060. g_pnptHead = pnpt;
  4061. pnpt->cchName = (USHORT) cch;
  4062. lstrcpyW(pnpt->szName, szPath);
  4063. }
  4064. else
  4065. {
  4066. LocalFree((HLOCAL)pnpt);
  4067. }
  4068. }
  4069. }
  4070. LEAVECRITICAL;
  4071. }
  4072. // The main function to attemp to map a portion of the name into an idlist
  4073. // Right now limit it to UNC roots
  4074. //
  4075. LPWSTR NPTMapNameToPidl(LPCWSTR pszPath, LPCITEMIDLIST *ppidl)
  4076. {
  4077. NPT_ITEM *pnpt;
  4078. *ppidl = NULL;
  4079. ENTERCRITICAL;
  4080. // See if we can find the item in the list.
  4081. for (pnpt = g_pnptHead; pnpt != NULL ; pnpt = pnpt->pnptNext)
  4082. {
  4083. if (IntlStrEqNIW(pszPath, pnpt->szName, pnpt->cchName) &&
  4084. ((pszPath[pnpt->cchName] == TEXT('\\')) || (pszPath[pnpt->cchName] == TEXT('\0'))))
  4085. {
  4086. break;
  4087. }
  4088. }
  4089. LEAVECRITICAL;
  4090. // See if we found a match
  4091. if (pnpt == NULL)
  4092. return NULL;
  4093. // Found a match
  4094. *ppidl = pnpt->pidl;
  4095. return (LPWSTR)pszPath + pnpt->cchName; // points to slash
  4096. }