Leaked source code of windows server 2003
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.

2716 lines
86 KiB

  1. #include "priv.h"
  2. #include "sccls.h"
  3. #include "dochost.h"
  4. #include "resource.h"
  5. #include "stdenum.h"
  6. #include <idhidden.h>
  7. #include "shdocfl.h"
  8. #include <mluisupp.h>
  9. HRESULT CDocObjectView_Create(IShellView** ppv, IShellFolder* psf, LPCITEMIDLIST pidl);
  10. #define DM_STARTUP 0
  11. #define DM_CDOFPDN 0 // CDocObjectFolder::ParseDisplayName
  12. class CDocObjectFolder : public IShellFolder2,
  13. public IPersistFolder2,
  14. public IBrowserFrameOptions
  15. {
  16. public:
  17. CDocObjectFolder(LPCITEMIDLIST pidlRoot = NULL);
  18. // IUnknown
  19. STDMETHODIMP QueryInterface(REFIID, void **);
  20. STDMETHODIMP_(ULONG) AddRef(void);
  21. STDMETHODIMP_(ULONG) Release(void);
  22. // IShellFolder
  23. STDMETHODIMP ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR pszDisplayName,
  24. ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes);
  25. STDMETHODIMP EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList);
  26. STDMETHODIMP BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppvOut);
  27. STDMETHODIMP BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppvObj);
  28. STDMETHODIMP CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
  29. STDMETHODIMP CreateViewObject (HWND hwnd, REFIID riid, void **ppvOut);
  30. STDMETHODIMP GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, ULONG *rgfInOut);
  31. STDMETHODIMP GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST * apidl,
  32. REFIID riid, UINT * prgfInOut, void **ppvOut);
  33. STDMETHODIMP GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, STRRET *pName);
  34. STDMETHODIMP SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR pszName,
  35. DWORD uFlags, LPITEMIDLIST * ppidlOut);
  36. // IShellFolder2
  37. STDMETHODIMP GetDefaultSearchGUID(LPGUID pGuid);
  38. STDMETHODIMP EnumSearches(LPENUMEXTRASEARCH *ppenum);
  39. STDMETHODIMP GetDefaultColumn(DWORD dwRes, ULONG *pSort, ULONG *pDisplay) { return E_NOTIMPL; };
  40. STDMETHODIMP GetDefaultColumnState(UINT iColumn, DWORD *pbState) { return E_NOTIMPL; };
  41. STDMETHODIMP GetDetailsEx(LPCITEMIDLIST pidl, const SHCOLUMNID *pscid, VARIANT *pv) { return E_NOTIMPL; };
  42. STDMETHODIMP GetDetailsOf(LPCITEMIDLIST pidl, UINT iColumn, SHELLDETAILS *pDetails){ return E_NOTIMPL; };
  43. STDMETHODIMP MapColumnToSCID(UINT iCol, SHCOLUMNID *pscid) { return E_NOTIMPL; };
  44. // IPersistFolder
  45. STDMETHODIMP GetClassID(LPCLSID pClassID);
  46. STDMETHODIMP Initialize(LPCITEMIDLIST pidl);
  47. // IPersistFolder2
  48. STDMETHODIMP GetCurFolder(LPITEMIDLIST* ppidl);
  49. // IBrowserFrameOptions
  50. STDMETHODIMP GetFrameOptions(IN BROWSERFRAMEOPTIONS dwMask, OUT BROWSERFRAMEOPTIONS * pdwOptions);
  51. protected:
  52. ~CDocObjectFolder();
  53. LONG _cRef;
  54. LPITEMIDLIST _pidlRoot;
  55. };
  56. //========================================================================
  57. // CDocObjectFolder members
  58. //========================================================================
  59. CDocObjectFolder::CDocObjectFolder(LPCITEMIDLIST pidlRoot)
  60. : _cRef(1), _pidlRoot(NULL)
  61. {
  62. TraceMsg(TF_SHDLIFE, "ctor CDocObjectFolder %x", this);
  63. DllAddRef();
  64. if (pidlRoot)
  65. _pidlRoot = ILClone(pidlRoot);
  66. }
  67. CDocObjectFolder::~CDocObjectFolder()
  68. {
  69. TraceMsg(TF_SHDLIFE, "dtor CDocObjectFolder %x", this);
  70. if (_pidlRoot)
  71. ILFree(_pidlRoot);
  72. DllRelease();
  73. }
  74. HRESULT CDocObjectFolder::QueryInterface(REFIID riid, void **ppvObj)
  75. {
  76. static const QITAB qit[] = {
  77. QITABENTMULTI(CDocObjectFolder, IShellFolder, IShellFolder2),
  78. QITABENT(CDocObjectFolder, IShellFolder2),
  79. QITABENTMULTI(CDocObjectFolder, IPersistFolder, IPersistFolder2),
  80. QITABENT(CDocObjectFolder, IPersistFolder2),
  81. QITABENT(CDocObjectFolder, IBrowserFrameOptions),
  82. { 0 },
  83. };
  84. return QISearch(this, qit, riid, ppvObj);
  85. }
  86. ULONG CDocObjectFolder::AddRef()
  87. {
  88. return InterlockedIncrement(&_cRef);
  89. }
  90. ULONG CDocObjectFolder::Release()
  91. {
  92. ASSERT( 0 != _cRef );
  93. ULONG cRef = InterlockedDecrement(&_cRef);
  94. if ( 0 == cRef )
  95. {
  96. delete this;
  97. }
  98. return cRef;
  99. }
  100. HRESULT CDocObjectFolder::ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR pwszDisplayName,
  101. ULONG *pchEaten, LPITEMIDLIST *ppidl, ULONG *pdwAttributes)
  102. {
  103. AssertMsg(FALSE, TEXT("CDocObjFolder - Called Improperly - ZekeL"));
  104. *ppidl = NULL;
  105. return E_UNEXPECTED;
  106. }
  107. HRESULT CDocObjectFolder::EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList)
  108. {
  109. *ppenumIDList = NULL;
  110. return E_UNEXPECTED;
  111. }
  112. HRESULT CDocObjectFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppvOut)
  113. {
  114. AssertMsg(FALSE, TEXT("CDocObjFolder - Called Improperly - ZekeL"));
  115. *ppvOut = NULL;
  116. return E_UNEXPECTED;
  117. }
  118. HRESULT CDocObjectFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppvObj)
  119. {
  120. AssertMsg(FALSE, TEXT("CDocObjFolder - Called Improperly - ZekeL"));
  121. *ppvObj = NULL;
  122. return E_UNEXPECTED;
  123. }
  124. HRESULT CDocObjectFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  125. {
  126. AssertMsg(FALSE, TEXT("CDocObjFolder - Called Improperly - ZekeL"));
  127. return E_UNEXPECTED;
  128. }
  129. HRESULT CDocObjectFolder::CreateViewObject(HWND hwnd, REFIID riid, void **ppvOut)
  130. {
  131. HRESULT hres = E_FAIL;
  132. if (IsEqualIID(riid, IID_IShellView))
  133. {
  134. hres = CDocObjectView_Create((IShellView**)ppvOut, this, _pidlRoot);
  135. }
  136. else
  137. {
  138. hres = E_NOINTERFACE;
  139. *ppvOut = NULL;
  140. }
  141. return hres;
  142. }
  143. HRESULT CDocObjectFolder::GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST *apidl,
  144. REFIID riid, UINT *prgfInOut, void **ppvOut)
  145. {
  146. AssertMsg(FALSE, TEXT("CDocObjFolder - Called Improperly - ZekeL"));
  147. *ppvOut = NULL;
  148. return E_UNEXPECTED;
  149. }
  150. HRESULT CDocObjectFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, ULONG *rgfInOut)
  151. {
  152. // we should never have any children.
  153. ASSERT(cidl == 0);
  154. if (cidl != 0)
  155. return E_UNEXPECTED;
  156. if (*rgfInOut)
  157. {
  158. // they want to know about the document itself
  159. ASSERT(_pidlRoot);
  160. return SHGetAttributesOf(_pidlRoot, rgfInOut);
  161. }
  162. return S_OK;
  163. }
  164. HRESULT CDocObjectFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, STRRET *pName)
  165. {
  166. AssertMsg(FALSE, TEXT("CDocObjFolder - Called Improperly - ZekeL"));
  167. return E_UNEXPECTED;
  168. }
  169. HRESULT CDocObjectFolder::SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR pszName,
  170. DWORD uFlags, LPITEMIDLIST *ppidlOut)
  171. {
  172. return E_UNEXPECTED;
  173. }
  174. HRESULT CDocObjectFolder::GetDefaultSearchGUID(GUID *pGuid)
  175. {
  176. *pGuid = SRCID_SWebSearch;
  177. return S_OK;
  178. }
  179. HRESULT CDocObjectFolder::EnumSearches(LPENUMEXTRASEARCH *ppenum)
  180. {
  181. *ppenum = NULL;
  182. return E_NOTIMPL;
  183. }
  184. HRESULT CDocObjectFolder::GetClassID(CLSID *pClassID)
  185. {
  186. *pClassID = CLSID_CDocObjectFolder;
  187. return S_OK;
  188. }
  189. HRESULT CDocObjectFolder::Initialize(LPCITEMIDLIST pidl)
  190. {
  191. if (_pidlRoot)
  192. {
  193. ILFree(_pidlRoot);
  194. _pidlRoot = NULL;
  195. }
  196. if (pidl)
  197. _pidlRoot = ILClone(pidl);
  198. return S_OK;
  199. }
  200. HRESULT CDocObjectFolder::GetCurFolder(LPITEMIDLIST* ppidl)
  201. {
  202. return SHILClone(_pidlRoot, ppidl);
  203. }
  204. // IBrowserFrameOptions
  205. #define BASE_OPTIONS \
  206. (BFO_BROWSER_PERSIST_SETTINGS | BFO_RENAME_FOLDER_OPTIONS_TOINTERNET | \
  207. BFO_PREFER_IEPROCESS | BFO_ENABLE_HYPERLINK_TRACKING | \
  208. BFO_USE_IE_LOGOBANDING | BFO_ADD_IE_TOCAPTIONBAR | BFO_GO_HOME_PAGE | \
  209. BFO_USE_IE_TOOLBAR | BFO_NO_PARENT_FOLDER_SUPPORT | BFO_NO_REOPEN_NEXT_RESTART | \
  210. BFO_SHOW_NAVIGATION_CANCELLED)
  211. // IBrowserFrameOptions
  212. HRESULT CDocObjectFolder::GetFrameOptions(IN BROWSERFRAMEOPTIONS dwMask, OUT BROWSERFRAMEOPTIONS * pdwOptions)
  213. {
  214. // We are hosting a DocObj?
  215. BOOL fIsFileURL = FALSE;
  216. // Is this under the Internet Name Space? Yes for
  217. // HTTP and FTP owned by the IE name space. MSIEFTP
  218. // pidls are passed straight to that folder.
  219. // This function will return FALSE for non-IE stuff
  220. // but we will then want to check if it's a file system
  221. // thing that wants to act like a web page because it's
  222. // MIME TYPE or other association is associated with the web.
  223. if (!IsURLChild(_pidlRoot, TRUE))
  224. {
  225. // Since IsURLChild() returned FALSE, this must be in the file system.
  226. // This case will happen with:
  227. // C:\foo.htm
  228. // http://www.yahoo.com/
  229. // http://bryanst/resume.doc
  230. // http://bryanst/notes.txt
  231. // <Start Page> [I couldn't find a case that hit CInternetFolder]
  232. // C:\foo.doc (use the addressbar to repro)
  233. fIsFileURL = TRUE;
  234. }
  235. *pdwOptions = dwMask & BASE_OPTIONS;
  236. if (!fIsFileURL)
  237. {
  238. // Add the Offline Support when we aren't in the file system.
  239. *pdwOptions |= dwMask & (BFO_USE_IE_OFFLINE_SUPPORT | BFO_USE_DIALUP_REF);
  240. }
  241. return S_OK;
  242. }
  243. STDAPI CDocObjectFolder_CreateInstance(IUnknown* pUnkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
  244. {
  245. CDocObjectFolder *psf = new CDocObjectFolder;
  246. if (psf)
  247. {
  248. *ppunk = SAFECAST(psf, IShellFolder *);
  249. return S_OK;
  250. }
  251. return E_OUTOFMEMORY;
  252. }
  253. class CInternetFolder : CDocObjectFolder
  254. {
  255. public:
  256. CInternetFolder(LPCITEMIDLIST pidlRoot = NULL) ;
  257. // IUnknown
  258. STDMETHODIMP QueryInterface(REFIID, void **);
  259. STDMETHODIMP_(ULONG) AddRef(void);
  260. STDMETHODIMP_(ULONG) Release(void);
  261. // IShellFolder
  262. STDMETHODIMP ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR pszDisplayName,
  263. ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes);
  264. STDMETHODIMP EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList);
  265. STDMETHODIMP BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppvOut);
  266. STDMETHODIMP BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppvObj);
  267. STDMETHODIMP CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2);
  268. STDMETHODIMP GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, ULONG *rgfInOut);
  269. STDMETHODIMP GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST *apidl,
  270. REFIID riid, UINT *prgfInOut, void **ppvOut);
  271. STDMETHODIMP GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, STRRET *pName);
  272. STDMETHODIMP SetNameOf(HWND hwnd, LPCITEMIDLIST pidl, LPCOLESTR pszName,
  273. DWORD uFlags, LPITEMIDLIST * ppidlOut);
  274. // IPersistFolder
  275. STDMETHODIMP GetClassID(CLSID *pClassID);
  276. // IBrowserFrameOptions
  277. STDMETHODIMP GetFrameOptions(IN BROWSERFRAMEOPTIONS dwMask, OUT BROWSERFRAMEOPTIONS * pdwOptions);
  278. protected:
  279. ~CInternetFolder();
  280. HRESULT _CreateProtocolHandler(LPCSTR pszProtocol, IBindCtx * pbc, IShellFolder **ppsf);
  281. HRESULT _CreateProtocolHandlerFromPidl(LPCITEMIDLIST pidl, IBindCtx * pbc, IShellFolder **ppsf);
  282. HRESULT _GetAttributesOfProtocol(LPCSTR pszProtocol, LPCITEMIDLIST *apidl, UINT cpidl, ULONG *rgfInOut);
  283. HRESULT _FaultInUrlHandler(LPCSTR pszProtocol, LPCTSTR pszUrl, IUnknown * punkSite);
  284. HRESULT _ConditionallyFaultInUrlHandler(LPCSTR pszProtocol, LPCTSTR pszUrl, IBindCtx * pbc);
  285. HRESULT _AssocCreate(LPCITEMIDLIST pidl, REFIID riid, void * *ppv);
  286. HRESULT _GetScheme(LPCITEMIDLIST pidl, LPWSTR pszOut, DWORD cchOut);
  287. HRESULT _GetUIObjectFromShortcut(LPCITEMIDLIST pidl, REFIID riid, void **ppvOut);
  288. HRESULT _GetTitle(LPCWSTR pszUrl, STRRET *pstr);
  289. HRESULT _InitHistoryStg(IUrlHistoryStg **pphist);
  290. IUrlHistoryStg *_phist;
  291. };
  292. CInternetFolder::CInternetFolder(LPCITEMIDLIST pidlRoot)
  293. : CDocObjectFolder(pidlRoot)
  294. {
  295. TraceMsg(TF_URLNAMESPACE, "[%X] ctor CInternetFolder", this);
  296. ASSERT(NULL == _phist);
  297. }
  298. CInternetFolder::~CInternetFolder()
  299. {
  300. ATOMICRELEASE(_phist);
  301. TraceMsg(TF_URLNAMESPACE, "[%X] dtor CInternetFolder", this);
  302. }
  303. HRESULT CInternetFolder::QueryInterface(REFIID riid, void **ppvObj)
  304. {
  305. static const QITAB qit[] = {
  306. QITABENTMULTI(CInternetFolder, IShellFolder, IShellFolder2),
  307. QITABENT(CInternetFolder, IShellFolder2),
  308. QITABENTMULTI(CDocObjectFolder, IPersistFolder, IPersistFolder2),
  309. QITABENT(CDocObjectFolder, IPersistFolder2),
  310. QITABENT(CInternetFolder, IBrowserFrameOptions),
  311. { 0 },
  312. };
  313. return QISearch(this, qit, riid, ppvObj);
  314. }
  315. ULONG CInternetFolder::AddRef()
  316. {
  317. return InterlockedIncrement(&_cRef);
  318. }
  319. ULONG CInternetFolder::Release()
  320. {
  321. ASSERT( 0 != _cRef );
  322. ULONG cRef = InterlockedDecrement(&_cRef);
  323. if ( 0 == cRef )
  324. {
  325. delete this;
  326. }
  327. return cRef;
  328. }
  329. typedef struct tagURLID
  330. {
  331. ITEMIDLIST idl; // cb and SHID
  332. BYTE bType; // URLID
  333. UINT uiCP; // Code Page
  334. WCHAR achUrl[1]; // variable size string
  335. } URLID;
  336. #define SHID_INTERNET 0x60
  337. #define SHID_INTERNET_SITE 0x61 // IE name space item
  338. #define URLID_URLBASEA 0x00
  339. /////// URLID_LOCATION 0x01 // LEGACY IE3/4 used for Frag IDs
  340. /////// URLID_FTPFOLDER 0x02 // LEGACY used by a pre-release FTP Folder dll
  341. #define URLID_PROTOCOL 0x03 // this is actually a delegated protocol
  342. #define URLID_URLBASEW 0x80 //
  343. // URLIDF_UNICODE 0x80 // URLID_ is actually of UNICODE type
  344. #ifdef UNICODE
  345. #define URLID_URLBASE URLID_URLBASEW
  346. #else
  347. #define URLID_URLBASE URLID_URLBASEA
  348. #endif
  349. typedef const UNALIGNED URLID *PCURLID;
  350. typedef UNALIGNED URLID *PURLID;
  351. #define PDID_SIG MAKEWORD(SHID_INTERNET_SITE, URLID_PROTOCOL)
  352. inline PCDELEGATEITEMID _IsValidDelegateID(LPCITEMIDLIST pidl)
  353. {
  354. PCDELEGATEITEMID pdi = (PCDELEGATEITEMID)pidl;
  355. ASSERT(pdi);
  356. if ((pdi->cbSize >= (SIZEOF(PDELEGATEITEMID)-1))
  357. && (pdi->wOuter == PDID_SIG))
  358. return pdi;
  359. return NULL;
  360. }
  361. LPCSTR _PidlToDelegateProtocol(LPCITEMIDLIST pidl)
  362. {
  363. PCDELEGATEITEMID pdi = _IsValidDelegateID(pidl);
  364. if (pdi)
  365. return (LPCSTR)&(pdi->rgb[pdi->cbInner]);
  366. return NULL;
  367. }
  368. inline PCURLID _IsValidUrlID(LPCITEMIDLIST pidl)
  369. {
  370. PCURLID purlid = (PCURLID)pidl;
  371. ASSERT(purlid);
  372. // 98/12/22 #263932 vtan: ANSI and Unicode URLs are both valid. Use function
  373. // _ExtractURL to extract the URL from the PIDL as a Unicode string.
  374. if (purlid->idl.mkid.cb >= SIZEOF(URLID)
  375. && (purlid->idl.mkid.abID[0] == SHID_INTERNET_SITE)
  376. && (purlid->bType == URLID_URLBASEA || purlid->bType == URLID_URLBASEW || _IsValidDelegateID(pidl)))
  377. return purlid;
  378. return NULL;
  379. }
  380. // 98/12/22 #263932 vtan: IE4 stores the PIDL in a stream as an ANSI
  381. // string. IE5 stores the PIDL in a stream as a Unicode string. This
  382. // functions reads the string (ANSI or Unicode) and converts it to
  383. // an internal Unicode string which is what will be written to the stream.
  384. void _ExtractURL (PCURLID pURLID, LPWSTR wszURL, int iCharCount)
  385. {
  386. if (pURLID->bType == URLID_URLBASEA)
  387. {
  388. char aszURL[MAX_URL_STRING];
  389. ualstrcpynA(aszURL, reinterpret_cast<const char*>(pURLID->achUrl), sizeof(aszURL));
  390. SHAnsiToUnicode(aszURL, wszURL, iCharCount);
  391. }
  392. else if (pURLID->bType == URLID_URLBASEW)
  393. {
  394. ualstrcpynW(wszURL, pURLID->achUrl, iCharCount);
  395. }
  396. }
  397. // 99/01/04 vtan: Added the following to help compare URLIDs which
  398. // can be AA/UU/AU/UA and perform the correct comparison.
  399. int _CompareURL (PCURLID pURLID1, PCURLID pURLID2)
  400. {
  401. int iResult;
  402. if ((pURLID1->bType == URLID_URLBASEA) && (pURLID2->bType == URLID_URLBASEA))
  403. {
  404. iResult = ualstrcmpA(reinterpret_cast<const char*>(pURLID1->achUrl), reinterpret_cast<const char*>(pURLID2->achUrl));
  405. }
  406. else if ((pURLID1->bType == URLID_URLBASEW) && (pURLID2->bType == URLID_URLBASEW))
  407. {
  408. iResult = ualstrcmpW(pURLID1->achUrl, pURLID2->achUrl);
  409. }
  410. else
  411. {
  412. PCURLID pCompareURLID;
  413. WCHAR wszURL[MAX_URL_STRING];
  414. // AU/UA comparison. To be efficient only convert the ANSI URLID
  415. // to Unicode and perform the comparison in Unicode.
  416. if (pURLID1->bType == URLID_URLBASEA)
  417. {
  418. pCompareURLID = pURLID2;
  419. _ExtractURL(pURLID1, wszURL, SIZECHARS(wszURL));
  420. }
  421. else
  422. {
  423. pCompareURLID = pURLID1;
  424. _ExtractURL(pURLID2, wszURL, SIZECHARS(wszURL));
  425. }
  426. iResult = ualstrcmpW(pCompareURLID->achUrl, wszURL);
  427. }
  428. return iResult;
  429. }
  430. IShellFolder* g_psfInternet = NULL;
  431. STDAPI CDelegateMalloc_Create(void *pv, UINT cbSize, WORD wOuter, IMalloc **ppmalloc);
  432. //
  433. // this might modify pszName if it's not a fully qualified url!
  434. BOOL _ValidateURL(LPTSTR pszName, DWORD dwFlags)
  435. {
  436. //
  437. // WARNING: In order to allow URL extensions, we assume all strings
  438. // which contains ":" in it is a valid string.
  439. // Assumptions are:
  440. //
  441. // (1) CDesktop::ParseDisplayName parse file system strings first.
  442. // (2) URL moniker will return an error correctly if URL is not valid.
  443. // (3) someone else (the desktop folder) handles shell: URLs
  444. // they should not be used directly by the browser
  445. //
  446. HRESULT hr = IURLQualify(pszName, dwFlags, pszName, NULL, NULL);
  447. DWORD nScheme = GetUrlScheme(pszName);
  448. return SUCCEEDED(hr) && (-1 != nScheme) && (URL_SCHEME_SHELL != nScheme);
  449. }
  450. LPITEMIDLIST IEILAppendFragment(LPITEMIDLIST pidl, LPCWSTR pszFragment)
  451. {
  452. // WARNING: See IE5 bug #'s 86951 and 36497 for more details.
  453. // In a nutshell, we're rolling back the change for 36497 because
  454. // the change caused many more problems with customers than
  455. // the behavior we had in IE4.
  456. //
  457. // Because we're not ensuring that
  458. // the fragment is prefixed with a '#', there may be
  459. // cases where the URL in the address bar looks wrong,
  460. // as well as cases where a hyperlink to a different doc
  461. // or HTML page may fail if it contains a fragment.
  462. return ILAppendHiddenStringW(pidl, IDLHID_URLFRAGMENT, pszFragment);
  463. }
  464. // browser only uglyness... we need to construct a desktop relative "regitem" pidl for
  465. // the internet since browser only shell does not support psf->ParseDisplayName("::{guid}", &pidl)
  466. // this uses the same layout as REGITEMs so we have PIDL compatibility with integrated mode
  467. // this ensures that a shortcut to the IE icon made in browser only mode works in integrated
  468. #ifndef NOPRAGMAS
  469. #pragma pack(1)
  470. #endif
  471. typedef struct
  472. {
  473. WORD cb;
  474. BYTE bFlags;
  475. BYTE bReserved; // This is to get DWORD alignment
  476. CLSID clsid;
  477. } IDITEM; // IDREGITEM
  478. typedef struct
  479. {
  480. IDITEM idri;
  481. USHORT cbNext;
  482. } IDLITEM; // IDLREGITEM
  483. #ifndef NOPRAGMAS
  484. #pragma pack()
  485. #endif
  486. // stolen from shell32\shitemid.h
  487. #define SHID_ROOT_REGITEM 0x1f // MyDocuments, Internet, etc
  488. const IDLITEM c_idlInetRoot =
  489. {
  490. {SIZEOF(IDITEM), SHID_ROOT_REGITEM, 0,
  491. { 0x871C5380, 0x42A0, 0x1069, 0xA2,0xEA,0x08,0x00,0x2B,0x30,0x30,0x9D },/* CLSID_Internet */ }, 0,
  492. };
  493. LPCITEMIDLIST c_pidlURLRoot = (LPCITEMIDLIST)&c_idlInetRoot;
  494. // it must be an absolute pidl with a root regitem id at the front
  495. // if we're a rooted explorer, this is always false
  496. // this means we're definitely in nashville, so we shouldn't have a split
  497. // world
  498. PCURLID _FindUrlChild(LPCITEMIDLIST pidl, BOOL fIncludeHome = FALSE)
  499. {
  500. if ((pidl == NULL) ||
  501. (pidl->mkid.cb != sizeof(IDITEM)) ||
  502. (pidl->mkid.abID[0] != SHID_ROOT_REGITEM))
  503. {
  504. return NULL;
  505. }
  506. //
  507. // the clsid in the pidl must be our internet folder's
  508. //
  509. if (!IsEqualGUID(((IDITEM*)pidl)->clsid, CLSID_Internet))
  510. {
  511. ASSERT(!IsEqualGUID(((IDITEM*)pidl)->clsid, CLSID_CURLFolder));
  512. return NULL;
  513. }
  514. // go to the child...
  515. pidl = _ILNext(pidl);
  516. //
  517. // if it is a pidl to the internet root then it is the IE3 Home Page
  518. //
  519. if (fIncludeHome && ILIsEmpty(pidl))
  520. return (PCURLID)pidl;
  521. //
  522. // otherwise it is our child if it is a site object
  523. //
  524. return _IsValidUrlID(pidl);
  525. }
  526. STDAPI_(BOOL) IsURLChild(LPCITEMIDLIST pidl, BOOL fIncludeHome)
  527. {
  528. return (NULL != _FindUrlChild(pidl, fIncludeHome));
  529. }
  530. BOOL IEILGetFragment(LPCITEMIDLIST pidl, LPWSTR pszFragment, DWORD cchFragment)
  531. {
  532. return ILGetHiddenStringW(pidl, IDLHID_URLFRAGMENT, pszFragment, cchFragment);
  533. }
  534. UINT IEILGetCP(LPCITEMIDLIST pidl)
  535. {
  536. PCURLID purlid = _FindUrlChild((pidl));
  537. if (purlid)
  538. {
  539. if (!_IsValidDelegateID((LPCITEMIDLIST)purlid))
  540. return purlid->uiCP;
  541. }
  542. return CP_ACP;
  543. }
  544. LPITEMIDLIST _UrlIdCreate(UINT uiCP, LPCTSTR pszUrl)
  545. {
  546. //
  547. // the URLID has a variable sized string
  548. // member. but we put the arbitrary limit
  549. // of MAX_URL_STRING because that is what
  550. // we use everywhere else. we could just remove the
  551. // limit however.
  552. //
  553. USHORT cb = (USHORT)SIZEOF(URLID) - (USHORT)CbFromCch(1);
  554. USHORT cchUrl = lstrlen(pszUrl) + 1;
  555. cchUrl = (USHORT)min(cchUrl, MAX_URL_STRING);
  556. cb += CbFromCch(cchUrl);
  557. PURLID purlid = (PURLID)IEILCreate(cb + SIZEOF(USHORT));
  558. if (purlid)
  559. {
  560. // everything is actually aligned right now...
  561. purlid->idl.mkid.cb = cb;
  562. purlid->idl.mkid.abID[0] = SHID_INTERNET_SITE;
  563. purlid->bType = URLID_URLBASE;
  564. purlid->uiCP = uiCP;
  565. ualstrcpyn(purlid->achUrl, pszUrl, cchUrl);
  566. }
  567. return (LPITEMIDLIST) purlid;
  568. }
  569. LPITEMIDLIST UrlToPidl(UINT uiCP, LPCTSTR pszUrl)
  570. {
  571. LPITEMIDLIST pidlRet;
  572. LPCTSTR pszAttachedFrag = UrlGetLocation(pszUrl);
  573. TCHAR szURLBuf[MAX_URL_STRING];
  574. // deal with URL's that still include the location (as in ParseDisplayName)
  575. if (pszAttachedFrag)
  576. {
  577. INT cch = (INT) min((pszAttachedFrag-pszUrl+1), ARRAYSIZE(szURLBuf));
  578. StrCpyN(szURLBuf, pszUrl, cch);
  579. pszUrl = szURLBuf;
  580. }
  581. ASSERT(pszUrl);
  582. pidlRet = _UrlIdCreate(uiCP, pszUrl);
  583. if (pidlRet && pszAttachedFrag && *pszAttachedFrag)
  584. pidlRet = IEILAppendFragment(pidlRet, pszAttachedFrag);
  585. return pidlRet;
  586. }
  587. typedef struct
  588. {
  589. LPCSTR pszProtocol;
  590. const CLSID * pCLSID;
  591. } FAULTIN_URLHANDERS;
  592. // TODO: If there are other URL Handlers, add them here.
  593. const FAULTIN_URLHANDERS c_FaultInUrlHandlers[] =
  594. {
  595. {"ftp", &CLSID_FTPShellExtension}
  596. };
  597. HRESULT CInternetFolder::_FaultInUrlHandler(LPCSTR pszProtocol, LPCTSTR pszUrl, IUnknown * punkSite)
  598. {
  599. HRESULT hr = S_OK;
  600. if (pszProtocol)
  601. {
  602. for (int nIndex = 0; nIndex < ARRAYSIZE(c_FaultInUrlHandlers); nIndex++)
  603. {
  604. if (!StrCmpIA(pszProtocol, c_FaultInUrlHandlers[nIndex].pszProtocol))
  605. {
  606. // Only fault in the feature if we are navigating to an FTP directory.
  607. if ((0 == nIndex) && !UrlIs(pszUrl, URLIS_DIRECTORY))
  608. {
  609. // It's not an ftp directory, so skip it.
  610. continue;
  611. }
  612. // FTP has a URL Shell Extension handler that is optionally
  613. // installed. Fault it in now if it's needed.
  614. uCLSSPEC ucs;
  615. QUERYCONTEXT qc = { 0 };
  616. HWND hwnd = NULL;
  617. ucs.tyspec = TYSPEC_CLSID;
  618. ucs.tagged_union.clsid = *c_FaultInUrlHandlers[nIndex].pCLSID;
  619. IUnknown_GetWindow(punkSite, &hwnd);
  620. if (EVAL(hwnd))
  621. {
  622. // Make it modal while the dialog is being displayed.
  623. IUnknown_EnableModless(punkSite, FALSE);
  624. FaultInIEFeature(hwnd, &ucs, &qc, 0);
  625. IUnknown_EnableModless(punkSite, TRUE);
  626. }
  627. break; // pidl can only have 1 procotol, so we don't need to check the other protocol.
  628. }
  629. }
  630. }
  631. return hr; // We don't care if it didn't make it.
  632. }
  633. HRESULT CInternetFolder::_ConditionallyFaultInUrlHandler(LPCSTR pszProtocol, LPCTSTR pszUrl, IBindCtx * pbc)
  634. {
  635. HRESULT hr = S_OK;
  636. // Faulting in the feature will probably require UI, so we need to assure that the caller
  637. // will allow this.
  638. if (pbc)
  639. {
  640. IUnknown * punkSite = NULL;
  641. pbc->GetObjectParam(STR_DISPLAY_UI_DURING_BINDING, &punkSite);
  642. if (punkSite)
  643. {
  644. hr = _FaultInUrlHandler(pszProtocol, pszUrl, punkSite);
  645. punkSite->Release();
  646. }
  647. }
  648. ASSERT(SUCCEEDED(hr));
  649. return S_OK; // We don't care if it didn't make it.
  650. }
  651. // returns:
  652. // success S_OK
  653. // failure FAILED(hres)
  654. HRESULT CInternetFolder::_CreateProtocolHandler(LPCSTR pszProtocol, IBindCtx * pbc, IShellFolder **ppsf)
  655. {
  656. HRESULT hres;
  657. CHAR szCLSID[GUIDSTR_MAX];
  658. DWORD cbSize = SIZEOF(szCLSID);
  659. *ppsf = NULL;
  660. if (pszProtocol &&
  661. SHGetValueA(HKEY_CLASSES_ROOT, pszProtocol, "ShellFolder", NULL, &szCLSID, &cbSize) == ERROR_SUCCESS)
  662. {
  663. CLSID clsid;
  664. IShellFolder *psf;
  665. GUIDFromStringA(szCLSID, &clsid);
  666. if (!SHSkipJunction(pbc, &clsid))
  667. {
  668. hres = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellFolder, &psf));
  669. if (SUCCEEDED(hres))
  670. {
  671. // IPersistFolder is optional
  672. IPersistFolder *ppf;
  673. if (SUCCEEDED(psf->QueryInterface(IID_PPV_ARG(IPersistFolder, &ppf))))
  674. {
  675. ppf->Initialize(_pidlRoot);
  676. ppf->Release();
  677. }
  678. IDelegateFolder *pdf;
  679. hres = psf->QueryInterface(IID_PPV_ARG(IDelegateFolder, &pdf));
  680. if (SUCCEEDED(hres))
  681. {
  682. // REVIEW: we could cache the malloc on a per protocol basis
  683. // to avoid creating these over and over
  684. IMalloc *pmalloc;
  685. hres = CDelegateMalloc_Create((void*)pszProtocol, (lstrlenA(pszProtocol) + 1), PDID_SIG, &pmalloc);
  686. if (SUCCEEDED(hres))
  687. {
  688. hres = pdf->SetItemAlloc(pmalloc);
  689. pmalloc->Release();
  690. }
  691. pdf->Release();
  692. }
  693. if (SUCCEEDED(hres))
  694. {
  695. hres = S_OK; // force all success codes to S_OK
  696. *ppsf = psf;
  697. }
  698. else
  699. psf->Release();
  700. }
  701. }
  702. else
  703. hres = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  704. }
  705. else
  706. hres = E_FAIL;
  707. return hres;
  708. }
  709. // returns:
  710. // S_FALSE if it is not a delegate protocol PIDL
  711. // hres of the bind opteration to the delegate protocol handler
  712. HRESULT CInternetFolder::_CreateProtocolHandlerFromPidl(LPCITEMIDLIST pidl, IBindCtx * pbc, IShellFolder **ppsf)
  713. {
  714. LPCSTR pszProtocol = _PidlToDelegateProtocol(pidl);
  715. if (pszProtocol)
  716. {
  717. HRESULT hres = _CreateProtocolHandler(pszProtocol, pbc, ppsf);
  718. ASSERT(hres != S_FALSE); // enforce the return value comment
  719. return hres;
  720. }
  721. *ppsf = NULL;
  722. return S_FALSE; // not a protocal PIDL
  723. }
  724. BOOL _GetUrlProtocol(LPCTSTR pszUrl, LPSTR pszProtocol, DWORD cchProtocol)
  725. {
  726. TCHAR sz[MAX_PATH];
  727. DWORD cch = SIZECHARS(sz);
  728. if (SUCCEEDED(UrlGetPart(pszUrl, sz, &cch, URL_PART_SCHEME, 0)))
  729. {
  730. SHTCharToAnsi(sz, pszProtocol, cchProtocol);
  731. return TRUE;
  732. }
  733. return FALSE;
  734. }
  735. UINT CodePageFromBindCtx(LPBC pbc)
  736. {
  737. UINT uiCP = CP_ACP;
  738. IDwnCodePage *pDwnCP;
  739. if (pbc && SUCCEEDED(pbc->QueryInterface(IID_PPV_ARG(IDwnCodePage, &pDwnCP))))
  740. {
  741. uiCP = pDwnCP->GetCodePage();
  742. pDwnCP->Release();
  743. }
  744. return uiCP;
  745. }
  746. #define STR_PARSE_INTERNET_DONT_ESCAPE_SPACES L"Parse Internet Dont Escape Spaces"
  747. HRESULT CInternetFolder::ParseDisplayName(HWND hwnd, LPBC pbc, LPOLESTR pwszDisplayName,
  748. ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes)
  749. {
  750. HRESULT hres = E_FAIL;
  751. TCHAR szName[MAX_URL_STRING];
  752. StrCpyN(szName, pwszDisplayName, ARRAYSIZE(szName));
  753. if (!PathIsFilePath(szName))
  754. {
  755. if (_ValidateURL(szName, 0) || ShouldShellExecURL(szName))
  756. {
  757. CHAR szProtocol[MAX_PATH];
  758. DWORD cchName = ARRAYSIZE(szName);
  759. IShellFolder *psfHandler;
  760. BOOL fProtocolExists;
  761. // fShellExecParse is set when we detect we are being called for
  762. // ShellExecute purposes. We don't want to auto-bind to the
  763. // shell protocol handler for things like ftp: in this case
  764. // because we need to invoke the default ftp handler for ShellExecute.
  765. BOOL fShellExecParse;
  766. // if we're down here, then the szName was really a url so try to encode it.
  767. // turn spaces to %20, unless we are being called from shellexec
  768. // in which case we allow spaces in the URL
  769. if (!BindCtx_ContainsObject(pbc, STR_PARSE_INTERNET_DONT_ESCAPE_SPACES))
  770. {
  771. UrlEscape(szName, szName, &cchName, URL_ESCAPE_SPACES_ONLY);
  772. fShellExecParse = FALSE;
  773. }
  774. else
  775. {
  776. // Make sure the default registered protocol handler gets invoked for
  777. // ShellExecute.
  778. fShellExecParse = TRUE;
  779. }
  780. fProtocolExists = _GetUrlProtocol(szName, szProtocol, ARRAYSIZE(szProtocol));
  781. _ConditionallyFaultInUrlHandler(szProtocol, szName, pbc);
  782. if (!fShellExecParse &&
  783. fProtocolExists &&
  784. _CreateProtocolHandler(szProtocol, pbc, &psfHandler) == S_OK)
  785. {
  786. TraceMsg(TF_PIDLWRAP, "Asking \"%s\" handler to parse %s (%08X) into a pidl", szProtocol, szName, szName);
  787. hres = psfHandler->ParseDisplayName(hwnd, pbc,
  788. pwszDisplayName, pchEaten,
  789. ppidl, pdwAttributes);
  790. TraceMsg(TF_PIDLWRAP, "the result is %08X, the pidl is %08X", hres, *ppidl);
  791. psfHandler->Release();
  792. TraceMsg(TF_URLNAMESPACE, "CODF::PDN(%s) called psfHandler and returning %x",
  793. szName, hres);
  794. }
  795. else
  796. {
  797. *ppidl = UrlToPidl(CodePageFromBindCtx(pbc), szName);
  798. if (*ppidl)
  799. {
  800. if (pdwAttributes)
  801. hres = _GetAttributesOfProtocol(NULL, (LPCITEMIDLIST *)ppidl, 1, pdwAttributes);
  802. else
  803. hres = S_OK;
  804. }
  805. else
  806. hres = E_OUTOFMEMORY;
  807. TraceMsg(TF_URLNAMESPACE, "CODF::PDN(%s) called UrlToPidl and returning %x", szName, hres);
  808. }
  809. }
  810. else
  811. {
  812. TraceMsg(DM_CDOFPDN, "CDOF::PDN(%s) returning E_FAIL because of (%s) is FALSE", szName, TEXT("(_ValidateURL(szName) || ShouldShellExecURL( szName ))"));
  813. }
  814. }
  815. return hres;
  816. }
  817. class CInternetFolderDummyEnum : public IEnumIDList
  818. {
  819. public:
  820. CInternetFolderDummyEnum();
  821. // *** IUnknown methods ***
  822. STDMETHODIMP QueryInterface(REFIID,void **);
  823. STDMETHODIMP_(ULONG) AddRef(void);
  824. STDMETHODIMP_(ULONG) Release(void);
  825. // *** IEnumIDList methods ***
  826. STDMETHODIMP Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched);
  827. STDMETHODIMP Skip(ULONG celt) {return E_NOTIMPL;}
  828. STDMETHODIMP Reset(void){return E_NOTIMPL;}
  829. STDMETHODIMP Clone(LPENUMIDLIST *ppenum){return E_NOTIMPL;}
  830. protected:
  831. ~CInternetFolderDummyEnum() {;}
  832. long _cRef;
  833. };
  834. CInternetFolderDummyEnum::CInternetFolderDummyEnum() : _cRef(1)
  835. {
  836. }
  837. HRESULT CInternetFolderDummyEnum::QueryInterface(REFIID riid, void **ppvObj)
  838. {
  839. static const QITAB qit[] = {
  840. QITABENT(CInternetFolderDummyEnum, IEnumIDList),
  841. { 0 },
  842. };
  843. return QISearch(this, qit, riid, ppvObj);
  844. }
  845. ULONG CInternetFolderDummyEnum::AddRef()
  846. {
  847. return InterlockedIncrement(&_cRef);
  848. }
  849. ULONG CInternetFolderDummyEnum::Release()
  850. {
  851. ASSERT( 0 != _cRef );
  852. ULONG cRef = InterlockedDecrement(&_cRef);
  853. if ( 0 == cRef )
  854. {
  855. delete this;
  856. }
  857. return cRef;
  858. }
  859. HRESULT CInternetFolderDummyEnum::Next(ULONG celt, LPITEMIDLIST *rgelt, ULONG *pceltFetched)
  860. {
  861. pceltFetched = 0;
  862. return S_FALSE;
  863. }
  864. HRESULT CInternetFolder::EnumObjects(HWND hwnd, DWORD grfFlags, IEnumIDList **ppenumIDList)
  865. {
  866. CInternetFolderDummyEnum *pdummy = new CInternetFolderDummyEnum();
  867. if (pdummy)
  868. {
  869. *ppenumIDList = (IEnumIDList *)pdummy;
  870. return S_OK;
  871. }
  872. return E_OUTOFMEMORY;
  873. }
  874. HRESULT CInternetFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppvOut)
  875. {
  876. IShellFolder *psfHandler = NULL;
  877. BOOL fUseDefault = TRUE;
  878. *ppvOut = NULL;
  879. if (!_IsValidUrlID(pidl))
  880. return E_INVALIDARG;
  881. HRESULT hres = _CreateProtocolHandlerFromPidl(pidl, pbc, &psfHandler);
  882. if (hres == S_OK)
  883. {
  884. // NOTE: We allow Shell Extensions to take over URL handling on a per
  885. // URL basis. We entered the _CreateProtocolHandlerFromPidl()
  886. // block of code above because
  887. // a shell extension is registered to take over handling this
  888. // URL. The above call to IShellFolder::BindToObject() just failed,
  889. // so we need to fall back and handle it in the traditional way.
  890. // This can be used by Shell Extensions, like the Ftp ShellExt, to
  891. // let the browser (us) handle URLs that are either inaccessible because of
  892. // the proxy or allow the browser to handle it so the traditional code
  893. // will: 1) download the item(s), 2) sniff the data for the type, 3)
  894. // use the suggested MIME type from the server or in the web page, 4)
  895. // check the file for type extension mappings, 5)
  896. // check any downloaded file for security certificates, and 6) display
  897. // Open/Save dialogs.
  898. hres = psfHandler->BindToObject(pidl, pbc, riid, ppvOut);
  899. // the handler will return ERROR_CANCELLED if it wants default behavior
  900. if (HRESULT_FROM_WIN32(ERROR_CANCELLED) != hres)
  901. fUseDefault = FALSE;
  902. }
  903. if (fUseDefault)
  904. {
  905. STRRET strRet;
  906. if (psfHandler)
  907. {
  908. // we had a delegated folder that failed, need a normal pidl
  909. hres = psfHandler->GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strRet);
  910. }
  911. else
  912. hres = GetDisplayNameOf(pidl, SHGDN_FORPARSING, &strRet);
  913. TCHAR szUrl[MAX_URL_STRING];
  914. if (SUCCEEDED(hres) &&
  915. SUCCEEDED(hres = StrRetToBuf(&strRet, pidl, szUrl, ARRAYSIZE(szUrl))))
  916. {
  917. if (IsEqualIID(IID_IMoniker, riid))
  918. {
  919. hres = MonikerFromURL(szUrl, (IMoniker **)ppvOut);
  920. }
  921. else // DEFAULT
  922. {
  923. // create a ShellFolder for the caller
  924. hres = E_OUTOFMEMORY;
  925. LPITEMIDLIST pidlT = NULL;
  926. // if we are using a handler but it returned cancelled,
  927. // then we need to recreate the pidl for ourselves to use
  928. // otherwise we just use the one that was passed in,
  929. // which we assume was the one we created.
  930. if (psfHandler)
  931. {
  932. pidlT = UrlToPidl(CP_ACP, szUrl);
  933. pidl = pidlT;
  934. }
  935. if (pidl)
  936. {
  937. LPITEMIDLIST pidlFull = ILCombine(_pidlRoot, pidl);
  938. if (pidlFull)
  939. {
  940. CDocObjectFolder *psf = new CDocObjectFolder(pidlFull);
  941. if (psf)
  942. {
  943. hres = psf->QueryInterface(riid, ppvOut);
  944. psf->Release();
  945. }
  946. ILFree(pidlFull);
  947. }
  948. ILFree(pidlT);
  949. }
  950. }
  951. }
  952. }
  953. if (psfHandler)
  954. psfHandler->Release();
  955. return hres;
  956. }
  957. HRESULT CInternetFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, void **ppvObj)
  958. {
  959. IShellFolder *psfHandler;
  960. *ppvObj = NULL;
  961. if (!_IsValidUrlID(pidl))
  962. return E_INVALIDARG;
  963. HRESULT hres = _CreateProtocolHandlerFromPidl(pidl, pbc, &psfHandler);
  964. if (hres != S_FALSE)
  965. {
  966. if (SUCCEEDED(hres))
  967. {
  968. hres = psfHandler->BindToStorage(pidl, pbc, riid, ppvObj);
  969. psfHandler->Release();
  970. }
  971. return hres;
  972. }
  973. *ppvObj = NULL;
  974. return E_NOINTERFACE;
  975. }
  976. int CALLBACK CompareDelegateProtocols(void *pv1, void *pv2, LPARAM lParam)
  977. {
  978. LPCSTR psz1 = _PidlToDelegateProtocol((LPCITEMIDLIST)pv1);
  979. LPCSTR psz2 = _PidlToDelegateProtocol((LPCITEMIDLIST)pv2);
  980. if (psz1 && psz2)
  981. {
  982. int iRet = StrCmpA(psz1, psz2);
  983. if (0 == iRet && lParam)
  984. *((LPCSTR *)lParam) = psz1;
  985. }
  986. else if (psz1)
  987. {
  988. return 1;
  989. }
  990. else if (psz2)
  991. {
  992. return -1;
  993. }
  994. return 0;
  995. }
  996. HRESULT CInternetFolder::CompareIDs(LPARAM lParam, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  997. {
  998. int iRet;
  999. ASSERT(!ILIsEmpty(pidl1) && !ILIsEmpty(pidl2));
  1000. // Check for protocol pidls.
  1001. LPCSTR psz = NULL;
  1002. iRet = CompareDelegateProtocols((void *)pidl1, (void *)pidl2, (LPARAM)&psz);
  1003. if (iRet)
  1004. return ResultFromShort(iRet);
  1005. if (psz)
  1006. {
  1007. IShellFolder *psfHandler;
  1008. if (_CreateProtocolHandler(psz, NULL, &psfHandler) == S_OK)
  1009. {
  1010. iRet = psfHandler->CompareIDs(lParam, pidl1, pidl2);
  1011. psfHandler->Release();
  1012. return ResultFromShort(iRet);
  1013. }
  1014. }
  1015. // we only have one layer of children
  1016. ASSERT(ILIsEmpty(_ILNext(pidl1)));
  1017. ASSERT(ILIsEmpty(_ILNext(pidl2)));
  1018. PCURLID purlid1 = _IsValidUrlID(pidl1);
  1019. if (purlid1)
  1020. {
  1021. PCURLID purlid2 = _IsValidUrlID(pidl2);
  1022. if (purlid2)
  1023. {
  1024. iRet = _CompareURL(purlid1, purlid2);
  1025. }
  1026. else
  1027. {
  1028. iRet = -1;
  1029. }
  1030. }
  1031. else
  1032. {
  1033. iRet = 1;
  1034. }
  1035. return ResultFromShort(iRet);
  1036. }
  1037. HRESULT CInternetFolder::_GetAttributesOfProtocol(LPCSTR pszProtocol,
  1038. LPCITEMIDLIST *apidl,
  1039. UINT cpidl, ULONG *rgfInOut)
  1040. {
  1041. HRESULT hres;
  1042. ASSERT(cpidl);
  1043. if (pszProtocol)
  1044. {
  1045. //
  1046. // We have a protocol. Find the protocol handler
  1047. // and pass it the bundle of pidls.
  1048. //
  1049. IShellFolder *psfHandler;
  1050. hres = _CreateProtocolHandler(pszProtocol, NULL, &psfHandler);
  1051. if (hres == S_OK)
  1052. {
  1053. hres = psfHandler->GetAttributesOf(cpidl, apidl, rgfInOut);
  1054. psfHandler->Release();
  1055. }
  1056. }
  1057. else if (_IsValidUrlID(apidl[0]))
  1058. {
  1059. ULONG uOut = SFGAO_CANLINK | SFGAO_BROWSABLE | SFGAO_STREAM;
  1060. *rgfInOut &= uOut;
  1061. hres = S_OK;
  1062. }
  1063. else
  1064. hres = E_INVALIDARG;
  1065. return hres;
  1066. }
  1067. HRESULT CInternetFolder::GetAttributesOf(UINT cidl, LPCITEMIDLIST *apidl, ULONG *rgfInOut)
  1068. {
  1069. if (*rgfInOut)
  1070. {
  1071. //
  1072. // Internet folder case.
  1073. //
  1074. LPCSTR pszProtocol;
  1075. if (cidl == 0)
  1076. {
  1077. //
  1078. // They are asking about the Internet Folder itself.
  1079. //
  1080. *rgfInOut &= SFGAO_FOLDER | SFGAO_CANLINK | SFGAO_STREAM;
  1081. }
  1082. else if (cidl == 1)
  1083. {
  1084. //
  1085. // Often we are asked about only one child,
  1086. // so we optimize that case.
  1087. //
  1088. pszProtocol = _PidlToDelegateProtocol(apidl[0]);
  1089. _GetAttributesOfProtocol(pszProtocol, apidl, cidl, rgfInOut);
  1090. }
  1091. else
  1092. {
  1093. //
  1094. // They are asking about multiple internet children.
  1095. // These children may have different protocols,
  1096. // so we have to find the GetAttributesOf handler for
  1097. // each group of protocols in the list.
  1098. //
  1099. LPCITEMIDLIST pidlBase;
  1100. UINT i, cpidlGroup;
  1101. // Create a list of pidls sorted by protocol.
  1102. HDPA hdpa = DPA_Create(100);
  1103. if (!hdpa)
  1104. return E_OUTOFMEMORY;
  1105. for (i = 0; i < cidl; i++)
  1106. {
  1107. DPA_AppendPtr(hdpa, (void *)apidl[i]);
  1108. }
  1109. DPA_Sort(hdpa, CompareDelegateProtocols, NULL);
  1110. //
  1111. // Call GetAttributesOf on each protocol group.
  1112. // A group
  1113. // starts at pidlBase
  1114. // contains cpidlGroup pidls
  1115. // has a protocol of pszProtocol
  1116. //
  1117. pidlBase = (LPCITEMIDLIST)DPA_FastGetPtr(hdpa, 0);
  1118. pszProtocol = NULL;
  1119. cpidlGroup = 0;
  1120. for (i = 0; *rgfInOut && (i < cidl); i++)
  1121. {
  1122. LPCITEMIDLIST pidlNew = (LPCITEMIDLIST)DPA_FastGetPtr(hdpa, i);
  1123. LPCSTR pszProtocolNew = _PidlToDelegateProtocol(pidlNew);
  1124. if (pszProtocolNew)
  1125. {
  1126. // See if we have a new protocol.
  1127. if (!pszProtocol || StrCmpA(pszProtocol, pszProtocolNew))
  1128. {
  1129. // We have a new protocol, time to process
  1130. // the last batch pidls.
  1131. _GetAttributesOfProtocol(pszProtocol, &pidlBase, cpidlGroup, rgfInOut);
  1132. pidlBase = pidlNew;
  1133. pszProtocol = pszProtocolNew;
  1134. cpidlGroup = 0;
  1135. }
  1136. }
  1137. cpidlGroup++;
  1138. }
  1139. if (*rgfInOut)
  1140. {
  1141. ASSERT(cpidlGroup);
  1142. _GetAttributesOfProtocol(pszProtocol, &pidlBase, cpidlGroup, rgfInOut);
  1143. }
  1144. DPA_Destroy(hdpa);
  1145. hdpa = NULL;
  1146. }
  1147. }
  1148. return S_OK;
  1149. }
  1150. BOOL GetCommonProtocol(LPCITEMIDLIST *apidl, UINT cpidl, LPCSTR *ppszProtocol)
  1151. {
  1152. UINT ipidl;
  1153. LPCSTR pszProtocol;
  1154. LPCSTR pszProtocolNext;
  1155. *ppszProtocol = NULL;
  1156. if (cpidl == 0)
  1157. {
  1158. return TRUE; // No pidls - no protocols, but they do all match!
  1159. }
  1160. //
  1161. // Grab the protocol of the first pidl, and use it to compare
  1162. // against the rest of the pidls.
  1163. //
  1164. pszProtocol = _PidlToDelegateProtocol(apidl[0]);
  1165. for (ipidl=1; ipidl<cpidl; ipidl++)
  1166. {
  1167. pszProtocolNext = _PidlToDelegateProtocol(apidl[ipidl]);
  1168. //
  1169. // Check if the protocols are different.
  1170. //
  1171. if ((pszProtocol != pszProtocolNext) &&
  1172. ((pszProtocol == NULL) ||
  1173. (pszProtocolNext == NULL) ||
  1174. (StrCmpA(pszProtocol, pszProtocolNext) != 0)))
  1175. {
  1176. return FALSE;
  1177. }
  1178. }
  1179. *ppszProtocol = pszProtocol;
  1180. return TRUE;
  1181. }
  1182. HRESULT _CombineHidden(LPCITEMIDLIST pidl, DWORD dwIEFlags, LPWSTR pszName, DWORD cchName)
  1183. {
  1184. HRESULT hres = S_OK;
  1185. //
  1186. // need to correctly append the fragment and query to the base
  1187. // if pszName is a DOSPATH, it will be converted to a
  1188. // file: URL so that it can accomadate the location
  1189. //
  1190. WCHAR sz[MAX_URL_STRING];
  1191. DWORD cch = cchName;
  1192. if (ILGetHiddenStringW(pidl, IDLHID_URLQUERY, sz, SIZECHARS(sz)))
  1193. hres = UrlCombineW(pszName, sz, pszName, &cch, 0);
  1194. if (!(dwIEFlags & IEGDN_NOFRAGMENT) && IEILGetFragment(pidl, sz, SIZECHARS(sz)))
  1195. {
  1196. hres = UrlCombineW(pszName, sz, pszName, &cchName, 0);
  1197. }
  1198. // else
  1199. // BUBBUG - should we return just the fragment in some case?
  1200. return hres;
  1201. }
  1202. HRESULT CInternetFolder::_GetUIObjectFromShortcut(LPCITEMIDLIST pidl, REFIID riid, void **ppvOut)
  1203. {
  1204. HRESULT hres = E_NOINTERFACE;
  1205. STRRET str;
  1206. TCHAR sz[MAX_URL_STRING];
  1207. if (SUCCEEDED(GetDisplayNameOf(pidl, SHGDN_FORPARSING, &str))
  1208. && SUCCEEDED(StrRetToBuf(&str, pidl, sz, ARRAYSIZE(sz)))
  1209. && SUCCEEDED(_CombineHidden(pidl, 0, sz, ARRAYSIZE(sz))))
  1210. {
  1211. IUniformResourceLocator *purl;
  1212. hres = CoCreateInstance(CLSID_InternetShortcut, NULL, CLSCTX_INPROC_SERVER,
  1213. IID_PPV_ARG(IUniformResourceLocator, &purl));
  1214. if (SUCCEEDED(hres))
  1215. {
  1216. hres = purl->SetURL(sz, 0);
  1217. if (SUCCEEDED(hres))
  1218. {
  1219. IShellLink * psl;
  1220. if (SUCCEEDED(purl->QueryInterface(IID_PPV_ARG(IShellLink, &psl))))
  1221. {
  1222. if (SUCCEEDED(GetDisplayNameOf(pidl, SHGDN_INFOLDER, &str)) &&
  1223. SUCCEEDED(StrRetToBuf(&str, pidl, sz, ARRAYSIZE(sz))))
  1224. {
  1225. PathRenameExtension(sz, TEXT(".url"));
  1226. psl->SetDescription(sz);
  1227. }
  1228. psl->Release();
  1229. }
  1230. hres = purl->QueryInterface(riid, ppvOut);
  1231. }
  1232. purl->Release();
  1233. }
  1234. }
  1235. return hres;
  1236. }
  1237. HRESULT CInternetFolder::_GetScheme(LPCITEMIDLIST pidl, LPWSTR pszOut, DWORD cchOut)
  1238. {
  1239. STRRET str;
  1240. LPCSTR pszProtocol = _PidlToDelegateProtocol(pidl);
  1241. if (pszProtocol)
  1242. {
  1243. SHAnsiToUnicode(pszProtocol, pszOut, cchOut);
  1244. return S_OK;
  1245. }
  1246. else if (SUCCEEDED(GetDisplayNameOf(pidl, SHGDN_FORPARSING, &str)))
  1247. {
  1248. WCHAR sz[MAX_URL_STRING];
  1249. if (SUCCEEDED(StrRetToBufW(&str, pidl, sz, ARRAYSIZE(sz))))
  1250. {
  1251. return UrlGetPartW(sz, pszOut, &cchOut, URL_PART_SCHEME, 0);
  1252. }
  1253. }
  1254. return E_FAIL;
  1255. }
  1256. HRESULT CInternetFolder::_AssocCreate(LPCITEMIDLIST pidl, REFIID riid, void * *ppv)
  1257. {
  1258. *ppv = NULL;
  1259. IQueryAssociations *pqa;
  1260. HRESULT hr = AssocCreate(CLSID_QueryAssociations, IID_PPV_ARG(IQueryAssociations, &pqa));
  1261. if (SUCCEEDED(hr))
  1262. {
  1263. WCHAR szScheme[MAX_PATH];
  1264. _GetScheme(pidl, szScheme, SIZECHARS(szScheme));
  1265. hr = pqa->Init(0, szScheme, NULL, NULL);
  1266. if (SUCCEEDED(hr))
  1267. hr = pqa->QueryInterface(riid, ppv);
  1268. pqa->Release();
  1269. }
  1270. return hr;
  1271. }
  1272. HRESULT CInternetFolder::GetUIObjectOf(HWND hwnd, UINT cidl, LPCITEMIDLIST *apidl,
  1273. REFIID riid, UINT *prgfInOut, void **ppvOut)
  1274. {
  1275. HRESULT hres = E_NOINTERFACE;
  1276. LPCSTR pszProtocol;
  1277. *ppvOut = NULL;
  1278. if (apidl[0] && GetCommonProtocol(apidl, cidl, &pszProtocol) && pszProtocol)
  1279. {
  1280. IShellFolder *psfHandler;
  1281. hres = _CreateProtocolHandlerFromPidl(apidl[0], NULL, &psfHandler);
  1282. if (hres != S_FALSE)
  1283. {
  1284. if (SUCCEEDED(hres))
  1285. {
  1286. hres = psfHandler->GetUIObjectOf(hwnd, 1, apidl, riid, prgfInOut, ppvOut);
  1287. psfHandler->Release();
  1288. }
  1289. return hres;
  1290. }
  1291. }
  1292. else if (IsEqualIID(riid, IID_IExtractIconA)
  1293. || IsEqualIID(riid, IID_IExtractIconW)
  1294. || IsEqualIID(riid, IID_IContextMenu)
  1295. || IsEqualIID(riid, IID_IQueryInfo)
  1296. || IsEqualIID(riid, IID_IDataObject))
  1297. {
  1298. // WARNING - we only support this for one at a time.
  1299. if (cidl == 1)
  1300. {
  1301. hres = _GetUIObjectFromShortcut(apidl[0], riid, ppvOut);
  1302. }
  1303. }
  1304. else if (IsEqualIID(riid, IID_IQueryAssociations))
  1305. {
  1306. // WARNING - we only support this for one at a time.
  1307. if (cidl == 1)
  1308. {
  1309. hres = _AssocCreate(apidl[0], riid, ppvOut);
  1310. }
  1311. }
  1312. return hres;
  1313. }
  1314. HRESULT CInternetFolder::_InitHistoryStg(IUrlHistoryStg **pphist)
  1315. {
  1316. HRESULT hr;
  1317. if (!_phist)
  1318. {
  1319. hr = CoCreateInstance(CLSID_CUrlHistory, NULL, CLSCTX_INPROC_SERVER,
  1320. IID_PPV_ARG(IUrlHistoryStg, &_phist));
  1321. }
  1322. if (_phist)
  1323. {
  1324. *pphist = _phist;
  1325. _phist->AddRef();
  1326. return S_OK;
  1327. }
  1328. return hr;
  1329. }
  1330. HRESULT CInternetFolder::_GetTitle(LPCWSTR pszUrl, STRRET *pstr)
  1331. {
  1332. ASSERT(pszUrl);
  1333. IUrlHistoryStg *phist;
  1334. HRESULT hr = _InitHistoryStg(&phist);
  1335. if (SUCCEEDED(hr))
  1336. {
  1337. ASSERT(phist);
  1338. STATURL stat = {0};
  1339. hr = phist->QueryUrl(pszUrl, STATURL_QUERYFLAG_NOURL, &stat);
  1340. if (SUCCEEDED(hr) && stat.pwcsTitle)
  1341. {
  1342. hr = StringToStrRet(stat.pwcsTitle, pstr);
  1343. CoTaskMemFree(stat.pwcsTitle);
  1344. }
  1345. else
  1346. hr = E_FAIL;
  1347. phist->Release();
  1348. }
  1349. return hr;
  1350. }
  1351. HRESULT CInternetFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD uFlags, STRRET *pstr)
  1352. {
  1353. IShellFolder *psfHandler;
  1354. HRESULT hr = _CreateProtocolHandlerFromPidl(pidl, NULL, &psfHandler);
  1355. if (hr != S_FALSE)
  1356. {
  1357. if (SUCCEEDED(hr))
  1358. {
  1359. hr = psfHandler->GetDisplayNameOf(pidl, uFlags, pstr);
  1360. psfHandler->Release();
  1361. }
  1362. return hr;
  1363. }
  1364. // FEATURE ZEKEL - should i handle more SHGDN flags here?? - Zekel - 24-NOV-98
  1365. PCURLID purlid = _IsValidUrlID(pidl);
  1366. if (purlid)
  1367. {
  1368. WCHAR sz[MAX_URL_STRING];
  1369. _ExtractURL(purlid, sz, SIZECHARS(sz));
  1370. if (SHGDN_NORMAL != uFlags)
  1371. hr = StringToStrRet(sz, pstr);
  1372. else
  1373. {
  1374. hr = _GetTitle(sz, pstr);
  1375. // fallback to the URL if necessary
  1376. if (FAILED(hr))
  1377. hr = StringToStrRet(sz, pstr);
  1378. }
  1379. }
  1380. else
  1381. hr = E_INVALIDARG;
  1382. return hr;
  1383. }
  1384. HRESULT CInternetFolder::SetNameOf(HWND hwnd, LPCITEMIDLIST pidl,
  1385. LPCOLESTR pszName, DWORD uFlags,
  1386. LPITEMIDLIST * ppidlOut)
  1387. {
  1388. IShellFolder *psfHandler;
  1389. HRESULT hres = _CreateProtocolHandlerFromPidl(pidl, NULL, &psfHandler);
  1390. if (hres != S_FALSE)
  1391. {
  1392. if (SUCCEEDED(hres))
  1393. {
  1394. hres = psfHandler->SetNameOf(hwnd, pidl, pszName, uFlags, ppidlOut);
  1395. psfHandler->Release();
  1396. }
  1397. return hres;
  1398. }
  1399. return E_FAIL;
  1400. }
  1401. HRESULT CInternetFolder::GetClassID(CLSID *pClassID)
  1402. {
  1403. *pClassID = CLSID_Internet;
  1404. return S_OK;
  1405. }
  1406. // IBrowserFrameOptions
  1407. HRESULT CInternetFolder::GetFrameOptions(IN BROWSERFRAMEOPTIONS dwMask, OUT BROWSERFRAMEOPTIONS * pdwOptions)
  1408. {
  1409. // The only case I know of that we hit this code is when you select "Internet Explorer" in the
  1410. // Folder Browser Band.
  1411. HRESULT hr = E_INVALIDARG;
  1412. if (pdwOptions)
  1413. {
  1414. // CInternetFolder should only be used for the "Internet Explorer" pidl that
  1415. // points to the Start Page, so find the start page and substitute it during
  1416. // navigation.
  1417. *pdwOptions |= dwMask & (BFO_SUBSTITUE_INTERNET_START_PAGE | BASE_OPTIONS);
  1418. hr = S_OK;
  1419. }
  1420. return hr;
  1421. }
  1422. #ifdef DEBUG
  1423. extern void remove_from_memlist(void *pv);
  1424. #endif
  1425. STDAPI CInternetFolder_CreateInstance(IUnknown* pUnkOuter, IUnknown **ppunk, LPCOBJECTINFO poi)
  1426. {
  1427. CInternetFolder *psf = new CInternetFolder;
  1428. if (psf)
  1429. {
  1430. //
  1431. // HACK:
  1432. //
  1433. // SHELL32 caches c_sfInetRoot in a static DATA section
  1434. // and never release it. It caches an instance of CInternetFolder
  1435. // and never release it. Therefore, we are removing this object
  1436. // from the to-be-memleak-detected list to avoid a false alarm
  1437. // assuming that we don't realy leak this object.
  1438. // Please don't copy it to another place unless you are really
  1439. // sure that it's OK not to detect leaks in that scenario.
  1440. // (SatoNa)
  1441. //
  1442. HRESULT hr = psf->QueryInterface(IID_PPV_ARG(IUnknown, ppunk));
  1443. psf->Release();
  1444. return hr;
  1445. }
  1446. return E_OUTOFMEMORY;
  1447. }
  1448. STDAPI MonikerFromURL(LPCWSTR wszPath, IMoniker** ppmk)
  1449. {
  1450. HRESULT hres = CreateURLMoniker(NULL, wszPath, ppmk);
  1451. if (FAILED(hres))
  1452. {
  1453. IBindCtx* pbc;
  1454. hres = CreateBindCtx(0, &pbc);
  1455. if (SUCCEEDED(hres))
  1456. {
  1457. // Fall back to a system (file) moniker
  1458. ULONG cchEaten = 0;
  1459. hres = MkParseDisplayName(pbc, wszPath, &cchEaten, ppmk);
  1460. pbc->Release();
  1461. }
  1462. }
  1463. return hres;
  1464. }
  1465. STDAPI MonikerFromString(LPCTSTR szPath, IMoniker** ppmk)
  1466. {
  1467. return MonikerFromURL(szPath, ppmk);
  1468. }
  1469. HRESULT InitPSFInternet()
  1470. {
  1471. if (g_psfInternet)
  1472. return S_OK;
  1473. IShellFolder *psfTemp;
  1474. HRESULT hres = CoCreateInstance(CLSID_CURLFolder, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellFolder, &psfTemp));
  1475. if (SUCCEEDED(hres))
  1476. {
  1477. IPersistFolder* ppsf;
  1478. hres = psfTemp->QueryInterface(IID_PPV_ARG(IPersistFolder, &ppsf));
  1479. if (SUCCEEDED(hres))
  1480. {
  1481. hres = ppsf->Initialize(c_pidlURLRoot);
  1482. if (SUCCEEDED(hres))
  1483. {
  1484. if (SHInterlockedCompareExchange((void **)&g_psfInternet, psfTemp, 0) == 0)
  1485. psfTemp->AddRef(); // global now holds ref
  1486. }
  1487. ppsf->Release();
  1488. }
  1489. psfTemp->Release();
  1490. }
  1491. return hres;
  1492. }
  1493. HRESULT _GetInternetRoot(IShellFolder **ppsfRoot)
  1494. {
  1495. HRESULT hr = InitPSFInternet();
  1496. *ppsfRoot = NULL;
  1497. if (SUCCEEDED(hr))
  1498. {
  1499. g_psfInternet->AddRef();
  1500. *ppsfRoot = g_psfInternet;
  1501. }
  1502. return hr;
  1503. }
  1504. HRESULT _GetRoot(LPCITEMIDLIST pidl, BOOL fIsUrl, IShellFolder **ppsfRoot)
  1505. {
  1506. HRESULT hr;
  1507. *ppsfRoot = NULL;
  1508. if (fIsUrl)
  1509. {
  1510. ASSERT(IsURLChild(pidl, TRUE));
  1511. TraceMsg(TF_URLNAMESPACE, "IEBTO(%x) using the Internet", pidl);
  1512. hr = _GetInternetRoot(ppsfRoot);
  1513. }
  1514. else
  1515. {
  1516. ASSERT(ILIsRooted(pidl));
  1517. TraceMsg(TF_URLNAMESPACE, "IEBTO(%x) using Rooted", pidl);
  1518. CLSID clsid;
  1519. ILRootedGetClsid(pidl, &clsid);
  1520. if (IsEqualGUID(clsid, CLSID_ShellDesktop))
  1521. {
  1522. hr = SHBindToObject(NULL, IID_IShellFolder, ILRootedFindIDList(pidl), (void **)ppsfRoot);
  1523. }
  1524. else
  1525. {
  1526. IShellFolder *psf;
  1527. hr = SHCoCreateInstance(NULL, &clsid, NULL, IID_PPV_ARG(IShellFolder, &psf));
  1528. if (SUCCEEDED(hr))
  1529. {
  1530. LPCITEMIDLIST pidlRoot = ILRootedFindIDList(pidl);
  1531. if (!pidlRoot)
  1532. pidlRoot = &s_idlNULL;
  1533. IPersistFolder* ppf;
  1534. hr = psf->QueryInterface(IID_PPV_ARG(IPersistFolder, &ppf));
  1535. if (SUCCEEDED(hr))
  1536. {
  1537. hr = ppf->Initialize(pidlRoot);
  1538. ppf->Release();
  1539. }
  1540. // hand over the reference
  1541. *ppsfRoot = psf;
  1542. }
  1543. }
  1544. }
  1545. return hr;
  1546. }
  1547. STDAPI_(BOOL) IEILIsEqual(LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2, BOOL fIgnoreHidden)
  1548. {
  1549. UINT cb = ILGetSize(pidl1);
  1550. if (cb != ILGetSize(pidl2) || 0 != memcmp(pidl1, pidl2, cb))
  1551. {
  1552. // THEY are binarily different
  1553. BOOL fRet = FALSE;
  1554. BOOL fWebOnly = FALSE;
  1555. if (IsURLChild(pidl1, TRUE) || IsURLChild(pidl2, TRUE))
  1556. fWebOnly = TRUE;
  1557. if ((IsURLChild(pidl1, FALSE) && IsURLChild(pidl2, FALSE))
  1558. || (ILIsRooted(pidl1) && ILIsEqualRoot(pidl1, pidl2)))
  1559. {
  1560. IShellFolder *psf;
  1561. if (SUCCEEDED(_GetRoot(pidl1, fWebOnly, &psf)))
  1562. {
  1563. if (0 == psf->CompareIDs(0, _ILNext(pidl1), _ILNext(pidl2)))
  1564. fRet = TRUE;
  1565. psf->Release();
  1566. }
  1567. }
  1568. if (!fRet && !fWebOnly)
  1569. {
  1570. #undef ILIsEqual
  1571. fRet = ILIsEqual(pidl1, pidl2);
  1572. }
  1573. if (fRet && !fIgnoreHidden)
  1574. {
  1575. fRet = (0 == ILCompareHiddenString(pidl1, pidl2, IDLHID_URLFRAGMENT));
  1576. if (fRet)
  1577. fRet = (0 == ILCompareHiddenString(pidl1, pidl2, IDLHID_URLQUERY));
  1578. if (fRet)
  1579. fRet = (0 == ILCompareHiddenString(pidl1, pidl2, IDLHID_NAVIGATEMARKER));
  1580. }
  1581. return fRet;
  1582. }
  1583. return TRUE;
  1584. }
  1585. // pszName must be MAX_URL_STRING
  1586. STDAPI IEGetDisplayName(LPCITEMIDLIST pidl, LPWSTR pszName, UINT uFlags)
  1587. {
  1588. return IEGetNameAndFlagsEx(pidl, uFlags, 0, pszName, MAX_URL_STRING, NULL);
  1589. }
  1590. HRESULT _GetInternetFolderName(LPWSTR pszName, DWORD cchName)
  1591. {
  1592. LPCTSTR pszKey;
  1593. DWORD cbSize = CbFromCch(cchName);
  1594. if (4 > GetUIVersion())
  1595. pszKey = TEXT("CLSID\\{FBF23B42-E3F0-101B-8488-00AA003E56F8}");
  1596. else
  1597. pszKey = TEXT("CLSID\\{871C5380-42A0-1069-A2EA-08002B30309D}");
  1598. if (NOERROR == SHGetValue(HKEY_CLASSES_ROOT, pszKey, NULL, NULL, pszName, &cbSize)
  1599. && *pszName)
  1600. return S_OK;
  1601. if (MLLoadString(IDS_REG_THEINTERNET, pszName, cchName)
  1602. && *pszName)
  1603. return S_OK;
  1604. return E_UNEXPECTED;
  1605. }
  1606. STDAPI IEGetNameAndFlagsEx(LPCITEMIDLIST pidl, UINT uSHFlags, DWORD dwIEFlags, LPWSTR pszName, DWORD cchName, DWORD *prgfInOutAttrs)
  1607. {
  1608. HRESULT hres = E_FAIL;
  1609. if (pszName)
  1610. {
  1611. *pszName = 0;
  1612. }
  1613. // for support of NON-integrated builds, and
  1614. // to expedite handling of URLs while browsing
  1615. if (IsURLChild(pidl, FALSE))
  1616. {
  1617. hres = InitPSFInternet();
  1618. if (SUCCEEDED(hres))
  1619. {
  1620. if (pszName)
  1621. {
  1622. STRRET str;
  1623. hres = g_psfInternet->GetDisplayNameOf(_ILNext(pidl), uSHFlags, &str);
  1624. if (SUCCEEDED(hres))
  1625. {
  1626. StrRetToBufW(&str, pidl, pszName, cchName);
  1627. }
  1628. }
  1629. if (prgfInOutAttrs)
  1630. hres = IEGetAttributesOf(pidl, prgfInOutAttrs);
  1631. }
  1632. }
  1633. else if (GetUIVersion() <= 4 && IsURLChild(pidl, TRUE))
  1634. {
  1635. //
  1636. // we need to support requests for the Internet SFs
  1637. // Friendly name. on NT5 we will always have something
  1638. // even when the SF is hidden. but on older versions
  1639. // of the shell, it was possible to delete the folder
  1640. // by just removing the icon from the desktop
  1641. //
  1642. if (pszName)
  1643. hres = _GetInternetFolderName(pszName, cchName);
  1644. if (prgfInOutAttrs)
  1645. hres = IEGetAttributesOf(pidl, prgfInOutAttrs);
  1646. }
  1647. else if (ILIsRooted(pidl))
  1648. {
  1649. IShellFolder *psf;
  1650. LPCITEMIDLIST pidlChild;
  1651. hres = IEBindToParentFolder(pidl, &psf, &pidlChild);
  1652. if (SUCCEEDED(hres))
  1653. {
  1654. if (pszName)
  1655. {
  1656. STRRET str;
  1657. hres = IShellFolder_GetDisplayNameOf(psf, pidlChild, uSHFlags, &str, 0);
  1658. if (SUCCEEDED(hres))
  1659. {
  1660. hres = StrRetToBufW(&str, pidlChild, pszName, cchName);
  1661. }
  1662. }
  1663. if (prgfInOutAttrs)
  1664. hres = psf->GetAttributesOf(ILIsEmpty(pidlChild) ? 0 : 1, &pidlChild, prgfInOutAttrs);
  1665. psf->Release();
  1666. }
  1667. }
  1668. else
  1669. hres = SHGetNameAndFlags(pidl, uSHFlags, pszName, cchName, prgfInOutAttrs);
  1670. if (SUCCEEDED(hres) && pszName && (uSHFlags & SHGDN_FORPARSING))
  1671. {
  1672. hres = _CombineHidden(pidl, dwIEFlags, pszName, cchName);
  1673. }
  1674. TraceMsg(TF_URLNAMESPACE, "IEGDN(%s) returning %x", pszName, hres);
  1675. return hres;
  1676. }
  1677. STDAPI IEGetNameAndFlags(LPCITEMIDLIST pidl, UINT uFlags, LPWSTR pszName, DWORD cchName, DWORD *prgfInOutAttrs)
  1678. {
  1679. return IEGetNameAndFlagsEx(pidl, uFlags, 0, pszName, cchName, prgfInOutAttrs);
  1680. }
  1681. BOOL _ClassIsBrowsable(LPCTSTR pszClass)
  1682. {
  1683. BOOL fRet = FALSE;
  1684. HKEY hk;
  1685. if (SUCCEEDED(AssocQueryKey(0, ASSOCKEY_CLASS, pszClass, NULL, &hk)))
  1686. {
  1687. fRet = (NOERROR == RegQueryValueEx(hk, TEXT("DocObject"), NULL, NULL, NULL, NULL)
  1688. || NOERROR == RegQueryValueEx(hk, TEXT("BrowseInPlace"), NULL, NULL, NULL, NULL));
  1689. RegCloseKey(hk);
  1690. }
  1691. return fRet;
  1692. }
  1693. BOOL _MimeIsBrowsable(LPCTSTR pszExt)
  1694. {
  1695. BOOL fRet = FALSE;
  1696. TCHAR sz[MAX_PATH];
  1697. DWORD dwSize = ARRAYSIZE(sz);
  1698. if (SUCCEEDED(AssocQueryString(0, ASSOCSTR_CONTENTTYPE, pszExt, NULL, sz, &dwSize)))
  1699. {
  1700. TCHAR szKey[MAX_PATH];
  1701. dwSize = SIZEOF(sz);
  1702. // Get the CLSID for the handler of this content type.
  1703. wnsprintf(szKey, ARRAYSIZE(szKey), TEXT("MIME\\Database\\Content Type\\%s"), sz);
  1704. // reuse sz for the clsid
  1705. if (NOERROR == SHGetValue(HKEY_CLASSES_ROOT, szKey, TEXT("CLSID"), NULL, (void *) sz, &dwSize))
  1706. {
  1707. fRet = _ClassIsBrowsable(sz);
  1708. }
  1709. }
  1710. return fRet;
  1711. }
  1712. BOOL _StorageIsBrowsable(LPCTSTR pszPath)
  1713. {
  1714. BOOL fRet = FALSE;
  1715. //
  1716. // If the file is STILL not browsable, try to open it as a structured storage
  1717. // and check its CLSID.
  1718. //
  1719. IStorage *pStg = NULL;
  1720. if (StgOpenStorage(pszPath, NULL, STGM_SHARE_EXCLUSIVE, NULL, 0, &pStg ) == S_OK && pStg)
  1721. {
  1722. STATSTG statstg;
  1723. if (pStg->Stat( &statstg, STATFLAG_NONAME ) == S_OK)
  1724. {
  1725. TCHAR szClsid[GUIDSTR_MAX];
  1726. SHStringFromGUIDW(statstg.clsid, szClsid, SIZECHARS(szClsid));
  1727. fRet = _ClassIsBrowsable(szClsid);
  1728. }
  1729. pStg->Release();
  1730. }
  1731. return fRet;
  1732. }
  1733. BOOL _IEIsBrowsable(LPCITEMIDLIST pidl)
  1734. {
  1735. TCHAR szPath[MAX_PATH];
  1736. BOOL fRet = FALSE;
  1737. if (SUCCEEDED(SHGetPathFromIDList(pidl, szPath)))
  1738. {
  1739. // Don't change the order of the following OR'd conditions because
  1740. // we want the HTML test to go first. Also, the NT5 shell will
  1741. // do the ClassIsBrowsable check for us, so we should avoid repeating
  1742. // that check.
  1743. if (PathIsHTMLFile(szPath)
  1744. || _ClassIsBrowsable(szPath)
  1745. || _MimeIsBrowsable(PathFindExtension(szPath))
  1746. || _StorageIsBrowsable(szPath))
  1747. fRet = TRUE;
  1748. }
  1749. return fRet;
  1750. }
  1751. HRESULT _IEGetAttributesOf(LPCITEMIDLIST pidl, DWORD* pdwAttribs, BOOL fAllowExtraChecks)
  1752. {
  1753. HRESULT hres = E_FAIL;
  1754. DWORD dwAttribs = *pdwAttribs;
  1755. BOOL fExtraCheckForBrowsable = FALSE;
  1756. //
  1757. // REARCHITECT - Check if we need to execute an additional logic - ZekeL - 7-JAN-99
  1758. // to see if it's browsable or not. this is necessary on shell32s from NT4/win95/IE4
  1759. // both NT4/win95 have no notion of SFGAO_BROWSABLE, and even though
  1760. // IE4 does, it doesnt handle it correctly for UNICODE file names.
  1761. // We are just as thorough (more) in our private check, so just defer to it.
  1762. //
  1763. // 78777: Even if we are on NT5, IE can browse things that Shell thinks is not
  1764. // browsable, for example, .htm files when Netscape is the default browser.
  1765. // So we should do the extra check on every platform.
  1766. if (fAllowExtraChecks && (dwAttribs & SFGAO_BROWSABLE))
  1767. {
  1768. dwAttribs |= SFGAO_FILESYSTEM | SFGAO_FOLDER;
  1769. fExtraCheckForBrowsable = TRUE;
  1770. }
  1771. IShellFolder* psfParent;
  1772. LPCITEMIDLIST pidlChild;
  1773. if (ILIsEmpty(pidl))
  1774. {
  1775. hres = SHGetDesktopFolder(&psfParent);
  1776. pidlChild = pidl;
  1777. }
  1778. else if (ILIsRooted(pidl) && ILIsEmpty(_ILNext(pidl)))
  1779. {
  1780. //
  1781. // when getting the attributes of the root itself, we
  1782. // decide its better to just limit the attribs to
  1783. // some easily supported subset. we used to always
  1784. // fail, but that is a little extreme.
  1785. //
  1786. // we could also try to get the attributes from HKCR\CLSID\{clsid}\shellfolder\attributes
  1787. //
  1788. *pdwAttribs &= (SFGAO_FOLDER);
  1789. return S_OK;
  1790. }
  1791. else
  1792. {
  1793. if (GetUIVersion() < 4 && IsURLChild(pidl, TRUE))
  1794. {
  1795. IShellFolder *psfRoot;
  1796. //
  1797. // if we are Browser Only, and this is the
  1798. // internet folder itself that we are interested
  1799. // in, then we need to bind to it by hand
  1800. // and query it with cidl = 0
  1801. //
  1802. hres = _GetInternetRoot(&psfRoot);
  1803. if (SUCCEEDED(hres))
  1804. {
  1805. hres = SHBindToFolderIDListParent(psfRoot, _ILNext(pidl), IID_PPV_ARG(IShellFolder, &psfParent), &pidlChild);
  1806. psfRoot->Release();
  1807. }
  1808. }
  1809. else if (ILIsRooted(pidl))
  1810. hres = IEBindToParentFolder(pidl, &psfParent, &pidlChild);
  1811. else
  1812. hres = SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psfParent), &pidlChild);
  1813. }
  1814. if (SUCCEEDED(hres))
  1815. {
  1816. ASSERT(psfParent);
  1817. hres = psfParent->GetAttributesOf(ILIsEmpty(pidlChild) ? 0 : 1, &pidlChild, &dwAttribs);
  1818. if (FAILED(hres))
  1819. TraceMsg(TF_WARNING, "IEGetAttribs psfParent->GetAttr failed %x", hres);
  1820. psfParent->Release();
  1821. }
  1822. else
  1823. TraceMsg(TF_WARNING, "IEGetAttribs BindTOParent failed %x", hres);
  1824. //
  1825. // This is the extra logic we need to execute if this is a browser
  1826. // only mode to get the right "browsable" attribute flag to DocObjects.
  1827. //
  1828. if (fExtraCheckForBrowsable && !(dwAttribs & SFGAO_BROWSABLE))
  1829. {
  1830. if ((dwAttribs & (SFGAO_FILESYSTEM | SFGAO_FOLDER)) == SFGAO_FILESYSTEM)
  1831. {
  1832. if (_IEIsBrowsable(pidl))
  1833. dwAttribs |= SFGAO_BROWSABLE;
  1834. }
  1835. }
  1836. *pdwAttribs &= dwAttribs;
  1837. return hres;
  1838. }
  1839. HRESULT IEGetAttributesOf(LPCITEMIDLIST pidl, DWORD* pdwAttribs)
  1840. {
  1841. return _IEGetAttributesOf(pidl, pdwAttribs, TRUE);
  1842. }
  1843. // BRYANST: 7/22/97 - NT Bug #188099
  1844. // shell32.dll in IE4 SI and only in that version had a bug if pbc was passed
  1845. // to IShellFolder::BindToObject() (fstreex.c!FSBindToFSFolder), it would fail
  1846. // to bind to Shell Extensions that extended file system folders, such as:
  1847. // the history folder, the occache, etc. We work around this by passing a NULL pbc
  1848. // if the destination is an IE4 shell32.dll and it will go thru FSBindToFSFolder().
  1849. BOOL ShouldWorkAroundBCBug(LPCITEMIDLIST pidl)
  1850. {
  1851. BOOL fWillBCCauseBug = FALSE;
  1852. if (4 == GetUIVersion())
  1853. {
  1854. LPITEMIDLIST pidlCopy = ILClone(pidl);
  1855. LPITEMIDLIST pidlIterate = pidlCopy;
  1856. // Skip the first two ItemIDs. (#1 could be My Computer)
  1857. if (!ILIsEmpty(pidlIterate))
  1858. {
  1859. IShellFolder * psf;
  1860. // (#2 could be CFSFolder::BindToObject())
  1861. pidlIterate = _ILNext(pidlIterate);
  1862. if (!ILIsEmpty(pidlIterate))
  1863. {
  1864. pidlIterate = _ILNext(pidlIterate);
  1865. // Remove everything else so we bind directly to CFSFolder::BindToObject()
  1866. pidlIterate->mkid.cb = 0;
  1867. if (SUCCEEDED(IEBindToObject(pidlCopy, &psf)))
  1868. {
  1869. IPersist * pp;
  1870. if (SUCCEEDED(psf->QueryInterface(IID_PPV_ARG(IPersist, &pp))))
  1871. {
  1872. CLSID clsid;
  1873. if (SUCCEEDED(pp->GetClassID(&clsid)) &&
  1874. IsEqualCLSID(clsid, CLSID_ShellFSFolder))
  1875. {
  1876. fWillBCCauseBug = TRUE;
  1877. }
  1878. pp->Release();
  1879. }
  1880. psf->Release();
  1881. }
  1882. }
  1883. }
  1884. ILFree(pidlCopy);
  1885. }
  1886. return fWillBCCauseBug;
  1887. }
  1888. typedef enum
  1889. {
  1890. SHOULDBIND_DOCOBJ,
  1891. SHOULDBIND_DESKTOP,
  1892. SHOULDBIND_NONE,
  1893. } SHOULDBIND;
  1894. //
  1895. // _ShouldDocObjBind()
  1896. // returns
  1897. // SHOULDBIND_DOCOBJ - Should just use DocObjectFolder directly
  1898. // SHOULDBIND_DESKTOP - bind through the desktop
  1899. // SHOULDBIND_NONE - FAIL the bind...
  1900. //
  1901. SHOULDBIND _ShouldDocObjBind(DWORD dwAttribs, BOOL fStrictBind)
  1902. {
  1903. if (fStrictBind)
  1904. {
  1905. if ((dwAttribs & (SFGAO_FOLDER | SFGAO_BROWSABLE | SFGAO_FILESYSTEM)) == (SFGAO_BROWSABLE | SFGAO_FILESYSTEM))
  1906. return SHOULDBIND_DOCOBJ;
  1907. else
  1908. return SHOULDBIND_DESKTOP;
  1909. }
  1910. else
  1911. {
  1912. if (dwAttribs & (SFGAO_FOLDER | SFGAO_BROWSABLE))
  1913. return SHOULDBIND_DESKTOP;
  1914. // manually bind using our CDocObjectFolder for
  1915. // files which are not DocObject. Without this code, file:
  1916. // to non-Docobject files (such as multi-media files)
  1917. // won't do anything.
  1918. //
  1919. // is is needed for non integraded browser mode
  1920. //
  1921. if (dwAttribs & SFGAO_FILESYSTEM)
  1922. return SHOULDBIND_DOCOBJ;
  1923. else
  1924. return SHOULDBIND_NONE;
  1925. }
  1926. }
  1927. STDAPI _IEBindToObjectInternal(BOOL fStrictBind, LPCITEMIDLIST pidl, IBindCtx * pbc, REFIID riid, void **ppvOut)
  1928. {
  1929. IShellFolder *psfTemp;
  1930. HRESULT hr;
  1931. *ppvOut = NULL;
  1932. // Special case: If we have the pidl for the "Desktop" then just use the Desktop folder itself
  1933. if (ILIsEmpty(pidl))
  1934. {
  1935. hr = SHGetDesktopFolder(&psfTemp);
  1936. if (SUCCEEDED(hr))
  1937. {
  1938. hr = psfTemp->QueryInterface(riid, ppvOut);
  1939. psfTemp->Release();
  1940. }
  1941. }
  1942. else
  1943. {
  1944. BOOL fIsUrlChild = IsURLChild(pidl, TRUE);
  1945. if (fIsUrlChild || ILIsRooted(pidl))
  1946. {
  1947. hr = _GetRoot(pidl, fIsUrlChild, &psfTemp);
  1948. if (SUCCEEDED(hr))
  1949. {
  1950. pidl = _ILNext(pidl);
  1951. if (!ILIsEmpty(pidl))
  1952. hr = psfTemp->BindToObject(pidl, pbc, riid, ppvOut);
  1953. else
  1954. hr = psfTemp->QueryInterface(riid, ppvOut);
  1955. psfTemp->Release();
  1956. }
  1957. }
  1958. else
  1959. {
  1960. // non integrated browser mode will succeed on
  1961. // BindToObject(IID_IShellFolder) even for things that should
  1962. // fail (files). to avoid the down stream problems caused by this we
  1963. // filter out things that are not "browseable" up front,
  1964. //
  1965. // NOTE: this does not work on simple PIDLs
  1966. DWORD dwAttribs = SFGAO_FOLDER | SFGAO_BROWSABLE | SFGAO_FILESYSTEM;
  1967. hr = _IEGetAttributesOf(pidl, &dwAttribs, fStrictBind);
  1968. if (SUCCEEDED(hr))
  1969. {
  1970. switch (_ShouldDocObjBind(dwAttribs, fStrictBind))
  1971. {
  1972. case SHOULDBIND_DOCOBJ:
  1973. {
  1974. //
  1975. // shortcircuit and bind using our CDocObjectFolder for
  1976. // files which are BROWSABLE. Without this code, file:
  1977. // to non-Docobject files (such as multi-media files)
  1978. // won't do anything.
  1979. //
  1980. // is is needed for non integraded browser mode
  1981. //
  1982. CDocObjectFolder *pdof = new CDocObjectFolder();
  1983. TraceMsg(TF_URLNAMESPACE, "IEBTO(%x) using DocObjectFolder", pidl);
  1984. if (pdof)
  1985. {
  1986. hr = pdof->Initialize(pidl);
  1987. if (SUCCEEDED(hr))
  1988. hr = pdof->QueryInterface(riid, ppvOut);
  1989. pdof->Release();
  1990. }
  1991. else
  1992. hr = E_OUTOFMEMORY;
  1993. }
  1994. break;
  1995. case SHOULDBIND_DESKTOP:
  1996. {
  1997. //
  1998. // This is the normal case. We just bind down through the desktop...
  1999. //
  2000. TraceMsg(TF_URLNAMESPACE, "IEBTO(%x) using Desktop", pidl);
  2001. hr = SHGetDesktopFolder(&psfTemp);
  2002. if (SUCCEEDED(hr))
  2003. {
  2004. // BRYANST: 7/22/97 - NT Bug #188099
  2005. // shell32.dll in IE4 SI and only in that version had a bug if pbc was passed
  2006. // to IShellFolder::BindToObject() (fstreex.c!FSBindToFSFolder), it would fail
  2007. // to bind to Shell Extensions that extended file system folders, such as:
  2008. // the history folder, the occache, etc. We work around this by passing a NULL pbc
  2009. // if the destination is an IE4 shell32.dll and it will go thru FSBindToFSFolder().
  2010. if (pbc && ShouldWorkAroundBCBug(pidl))
  2011. {
  2012. pbc = NULL;
  2013. }
  2014. hr = psfTemp->BindToObject(pidl, pbc, riid, ppvOut);
  2015. psfTemp->Release();
  2016. }
  2017. }
  2018. break;
  2019. default:
  2020. hr = E_FAIL;
  2021. }
  2022. }
  2023. }
  2024. }
  2025. if (SUCCEEDED(hr) && !*ppvOut)
  2026. {
  2027. // Some NSEs have bugs where they will fail to fill in the
  2028. // out pointer but return SUCCEEDED(hr). WS_FTP is one example
  2029. // in NT #413950.
  2030. TraceMsg(TF_URLNAMESPACE, "IEBTO() BUG!!! An NSE succeeded but returned a NULL interface pointer.");
  2031. hr = E_FAIL;
  2032. }
  2033. TraceMsg(TF_URLNAMESPACE, "IEBTO(%x) returning %x", pidl, hr);
  2034. return hr;
  2035. }
  2036. STDAPI IEBindToObjectEx(LPCITEMIDLIST pidl, IBindCtx *pbc, REFIID riid, void **ppvOut)
  2037. {
  2038. return _IEBindToObjectInternal(TRUE, pidl, pbc, riid, ppvOut);
  2039. }
  2040. STDAPI IEBindToObject(LPCITEMIDLIST pidl, IShellFolder **ppsfOut)
  2041. {
  2042. return _IEBindToObjectInternal(TRUE, pidl, NULL, IID_PPV_ARG(IShellFolder, ppsfOut));
  2043. }
  2044. // CLASSIC BIND here
  2045. HRESULT IEBindToObjectForNavigate(LPCITEMIDLIST pidl, IBindCtx * pbc, IShellFolder **ppsfOut)
  2046. {
  2047. return _IEBindToObjectInternal(FALSE, pidl, pbc, IID_PPV_ARG(IShellFolder, ppsfOut));
  2048. }
  2049. //
  2050. // CDwnCodePage: Dummy supports IBindCtx interface object only for casting
  2051. // It holds codepage info to pass via LPBC parameter
  2052. //
  2053. class CDwnCodePage : public IBindCtx
  2054. , public IDwnCodePage
  2055. {
  2056. public:
  2057. // IUnknown methods
  2058. STDMETHODIMP QueryInterface(REFIID riid, void **ppvObj);
  2059. STDMETHODIMP_(ULONG) AddRef(void);
  2060. STDMETHODIMP_(ULONG) Release(void);
  2061. // IBindCtx methods
  2062. STDMETHODIMP RegisterObjectBound(IUnknown *punk) { return (_pbc ? _pbc->RegisterObjectBound(punk) : E_NOTIMPL); };
  2063. STDMETHODIMP RevokeObjectBound(IUnknown *punk) { return (_pbc ? _pbc->RevokeObjectBound(punk) : E_NOTIMPL); };
  2064. STDMETHODIMP ReleaseBoundObjects(void) { return (_pbc ? _pbc->ReleaseBoundObjects() : E_NOTIMPL); };
  2065. STDMETHODIMP SetBindOptions(BIND_OPTS *pbindopts) { return (_pbc ? _pbc->SetBindOptions(pbindopts) : E_NOTIMPL); };
  2066. STDMETHODIMP GetBindOptions(BIND_OPTS *pbindopts) { return (_pbc ? _pbc->GetBindOptions(pbindopts) : E_NOTIMPL); };
  2067. STDMETHODIMP GetRunningObjectTable(IRunningObjectTable **pprot) { *pprot = NULL; return (_pbc ? _pbc->GetRunningObjectTable(pprot) : E_NOTIMPL); };
  2068. STDMETHODIMP RegisterObjectParam(LPOLESTR pszKey, IUnknown *punk) { return (_pbc ? _pbc->RegisterObjectParam(pszKey, punk) : E_NOTIMPL); };
  2069. STDMETHODIMP GetObjectParam(LPOLESTR pszKey, IUnknown **ppunk) { *ppunk = NULL; return (_pbc ? _pbc->GetObjectParam(pszKey, ppunk) : E_NOTIMPL); };
  2070. STDMETHODIMP EnumObjectParam(IEnumString **ppenum) { *ppenum = NULL; return (_pbc ? _pbc->EnumObjectParam(ppenum) : E_NOTIMPL); };
  2071. STDMETHODIMP RevokeObjectParam(LPOLESTR pszKey) { return (_pbc ? _pbc->RevokeObjectParam(pszKey) : E_NOTIMPL); };
  2072. STDMETHODIMP RemoteSetBindOptions(BIND_OPTS2 *pbindopts) { return E_NOTIMPL; };
  2073. STDMETHODIMP RemoteGetBindOptions(BIND_OPTS2 *pbindopts) { return E_NOTIMPL; };
  2074. // IDwnCodePage methods
  2075. STDMETHODIMP_(UINT) GetCodePage(void) { return _uiCodePage; };
  2076. STDMETHODIMP SetCodePage(UINT uiCodePage) { _uiCodePage = uiCodePage; return S_OK; };
  2077. // Constructor
  2078. CDwnCodePage(IBindCtx * pbc, UINT uiCodePage) : _cRef(1) { _uiCodePage = uiCodePage; _pbc = NULL; IUnknown_Set((IUnknown **)&_pbc, (IUnknown *)pbc); };
  2079. ~CDwnCodePage() { ATOMICRELEASE(_pbc); };
  2080. private:
  2081. int _cRef;
  2082. UINT _uiCodePage;
  2083. IBindCtx * _pbc;
  2084. };
  2085. STDAPI CDwnCodePage::QueryInterface(REFIID riid, void **ppvObj)
  2086. {
  2087. static const QITAB qit[] = {
  2088. QITABENT(CDwnCodePage, IBindCtx),
  2089. QITABENT(CDwnCodePage, IDwnCodePage),
  2090. { 0 },
  2091. };
  2092. return QISearch(this, qit, riid, ppvObj);
  2093. }
  2094. STDAPI_(ULONG) CDwnCodePage::AddRef()
  2095. {
  2096. _cRef++;
  2097. return _cRef;
  2098. }
  2099. STDAPI_(ULONG) CDwnCodePage::Release()
  2100. {
  2101. _cRef--;
  2102. if (0 < _cRef)
  2103. return _cRef;
  2104. delete this;
  2105. return 0;
  2106. }
  2107. // IEParseDisplayName() will do all of the below functionality in IECreateFromPathCPWithBC()
  2108. // plus the following two things:
  2109. // 1. It will call ParseURLFromOutsideSource(), so this is more friendly to
  2110. // strings from outside sources.
  2111. // 2. If the URL has a fragment, this function will pass out a PIDL with the last
  2112. // ID being the location.
  2113. HRESULT IECreateFromPathCPWithBCW(UINT uiCP, LPCWSTR pszPath, IBindCtx * pbc, LPITEMIDLIST *ppidlOut)
  2114. {
  2115. TraceMsg(TF_URLNAMESPACE, "IECFP(%s) called", pszPath);
  2116. HRESULT hr = S_OK;
  2117. WCHAR szPath[MAX_URL_STRING];
  2118. WCHAR szBuf[MAX_PATH];
  2119. DWORD cchBuf = ARRAYSIZE(szBuf);
  2120. CDwnCodePage DwnCodePage(pbc, uiCP);
  2121. DWORD len;
  2122. // Initialize for failure case
  2123. *ppidlOut = NULL;
  2124. // if we are passed a NULL path, then there is no way we can convert it to a pidl.
  2125. // in some cases the reason we are passed a NULL path is because the IShellFolder
  2126. // provider was unable to generate a parseable display name (MSN Classic 1.3 is
  2127. // a very good example, they return E_NOTIMPL).
  2128. if ( ((len = lstrlen( pszPath )) == 0) || len >= MAX_URL_STRING )
  2129. {
  2130. return E_FAIL;
  2131. }
  2132. // Is this a "file:" URL?
  2133. if (IsFileUrlW(pszPath) && SUCCEEDED(hr = PathCreateFromUrl(pszPath, szBuf, &cchBuf, 0)))
  2134. pszPath = szBuf;
  2135. BOOL fIsFilePath = PathIsFilePath(pszPath);
  2136. #ifdef FEATURE_IE_USE_DESKTOP_PARSING
  2137. //
  2138. // in order to take advantage of whatever enhancements the desktop
  2139. // makes to parsing (eg, WebFolders and shell: URLs), then we allow
  2140. // the desktop first go at it. it will loop back into the internet
  2141. // shell folder if all the special cases fail.
  2142. // maybe use a reg setting to control???
  2143. //
  2144. //
  2145. if (fIsFilePath || GetUIVersion() >= 5)
  2146. #else // !FEATURE_IE_USE_DESKTOP_PARSING
  2147. //
  2148. // right now we just use the desktop if its a file path or
  2149. // it is a shell: URL on NT5
  2150. //
  2151. if (fIsFilePath || (GetUIVersion() >= 5 && URL_SCHEME_SHELL == GetUrlSchemeW(pszPath)))
  2152. #endif // FEATURE_IE_USE_DESKTOP_PARSING
  2153. {
  2154. ASSERT(SUCCEEDED(hr));
  2155. // Resolve any dot-dot path reference and remove trailing backslash
  2156. if (fIsFilePath)
  2157. {
  2158. PathCanonicalize(szPath, pszPath);
  2159. pszPath = szPath;
  2160. // This call will cause a network hit: one connection attempt to \\server\IPC$
  2161. // and then a series of FindFirst's - one for each directory.
  2162. if (StrChr(pszPath, L'*') || StrChr(pszPath, L'?'))
  2163. {
  2164. hr = E_FAIL;
  2165. }
  2166. }
  2167. if (SUCCEEDED(hr))
  2168. {
  2169. hr = SHILCreateFromPath(pszPath, ppidlOut, NULL);
  2170. TraceMsg(DM_CDOFPDN, "IECreateFromPath psDesktop->PDN(%s) returned %x", pszPath, hr);
  2171. }
  2172. }
  2173. else
  2174. {
  2175. //
  2176. // Need to put in buffer since ParseDisplayName doesn't take a 'const' string.
  2177. StrCpyN(szPath, pszPath, ARRAYSIZE(szPath));
  2178. pszPath = szPath;
  2179. // Avoid the network and disk hits above for non-file urls.
  2180. // This code path is taken on http: folks so a nice optimization. We will then drop
  2181. // down below where we check the internet namespace.
  2182. IShellFolder *psfRoot;
  2183. hr = _GetInternetRoot(&psfRoot);
  2184. if (SUCCEEDED(hr))
  2185. {
  2186. TraceMsg(TF_URLNAMESPACE, "IECFP(%s) calling g_psfInternet->PDN %x", pszPath, hr);
  2187. LPITEMIDLIST pidlRel;
  2188. hr = psfRoot->ParseDisplayName(NULL, (IBindCtx*)&DwnCodePage, szPath, NULL, &pidlRel, NULL);
  2189. TraceMsg(DM_CDOFPDN, "IECreateFromPath called psfInternet->PDN(%s) %x", pszPath, hr);
  2190. if (SUCCEEDED(hr))
  2191. {
  2192. *ppidlOut = ILCombine(c_pidlURLRoot, pidlRel);
  2193. if (!*ppidlOut)
  2194. hr = E_OUTOFMEMORY;
  2195. ILFree(pidlRel);
  2196. }
  2197. psfRoot->Release();
  2198. }
  2199. }
  2200. // NOTE: NT5 beta 3 and before had a call to SHSimpleIDListFromPath().
  2201. // This is very bad because it will parse any garbage and prevent
  2202. // the caller from finding invalid strings. I(BryanSt) needed
  2203. // this fixed for IEParseDisplayNameWithBCW() would fail on invalid
  2204. // address bar strings ("Search Get Rich Quick").
  2205. TraceMsg(TF_URLNAMESPACE, "IECFP(%s) returning %x (hr=%x)",
  2206. pszPath, *ppidlOut, hr);
  2207. return hr;
  2208. }
  2209. HRESULT IECreateFromPathCPWithBCA(UINT uiCP, LPCSTR pszPath, IBindCtx * pbc, LPITEMIDLIST *ppidlOut)
  2210. {
  2211. WCHAR szPath[MAX_URL_STRING];
  2212. ASSERT(lstrlenA(pszPath) < ARRAYSIZE(szPath));
  2213. SHAnsiToUnicodeCP(uiCP, pszPath, szPath, ARRAYSIZE(szPath));
  2214. return IECreateFromPathCPWithBCW(uiCP, szPath, pbc, ppidlOut);
  2215. }
  2216. HRESULT IEParseDisplayName(UINT uiCP, LPCTSTR pszPath, LPITEMIDLIST * ppidlOut)
  2217. {
  2218. return IEParseDisplayNameWithBCW(uiCP, pszPath, NULL, ppidlOut);
  2219. }
  2220. // This function will do two things that IECreateFromPathCPWithBC() will not do:
  2221. // 1. It will add the "Query" section of the URL into the pidl.
  2222. // 2. If the URL has a fragment, this function will pass out a PIDL with the last
  2223. // ID being the location.
  2224. // NOTE: If the caller needs the string to be "cleaned up" because the user manually
  2225. // entered the URL, the caller needs to call ParseURLFromOutsideSource() before
  2226. // calling this function. That function should only be called on strings entered
  2227. // by the user because of the perf hit and it could incorrectly format valid
  2228. // parsible display names. For example, ParseURLFromOutsideSource() will
  2229. // convert the string "My Computer" into a search URL for yahoo.com
  2230. // (http://www.yahoo.com/search.asp?p=My+p=Computer) when some callers
  2231. // want that string parsed by an IShellFolder in the desktop.
  2232. HRESULT IEParseDisplayNameWithBCW(UINT uiCP, LPCWSTR pwszPath, IBindCtx * pbc, LPITEMIDLIST * ppidlOut)
  2233. {
  2234. TCHAR szPath[MAX_URL_STRING];
  2235. LPCWSTR pwszFileLocation = NULL;
  2236. WCHAR szQuery[MAX_URL_STRING];
  2237. HRESULT hres;
  2238. szQuery[0] = TEXT('\0');
  2239. #ifdef DEBUG
  2240. if (IsFlagSet(g_dwDumpFlags, DF_URL))
  2241. {
  2242. TraceMsg(DM_TRACE, "IEParseDisplayName got %s", szPath);
  2243. }
  2244. #endif
  2245. // We want to remove QUERY and FRAGMENT sections of
  2246. // FILE URLs because they need to be added in "Hidden" pidls.
  2247. // Also, URLs need to be escaped all the time except for paths
  2248. // to facility parsing and because we already removed all other
  2249. // parts of the URL (Query and Fragment).
  2250. if (IsFileUrlW(pwszPath))
  2251. {
  2252. DWORD cchQuery = SIZECHARS(szQuery) - 1;
  2253. pwszFileLocation = UrlGetLocationW(pwszPath);
  2254. if (SUCCEEDED(UrlGetPart(pwszPath, szQuery+1, &cchQuery, URL_PART_QUERY, 0)) && cchQuery)
  2255. szQuery[0] = TEXT('?');
  2256. DWORD cchPath = ARRAYSIZE(szPath);
  2257. if (FAILED(PathCreateFromUrl(pwszPath, szPath, &cchPath, 0)))
  2258. {
  2259. // Failed to parse it back. Use the original.
  2260. StrCpyN(szPath, pwszPath, ARRAYSIZE(szPath));
  2261. }
  2262. }
  2263. else
  2264. {
  2265. // If we failed, just try to use the original
  2266. StrCpyN(szPath, pwszPath, ARRAYSIZE(szPath));
  2267. }
  2268. #ifdef DEBUG
  2269. if (IsFlagSet(g_dwDumpFlags, DF_URL))
  2270. TraceMsg(DM_TRACE, "IEParseDisplayName calling IECreateFromPath %s", szPath);
  2271. #endif
  2272. hres = IECreateFromPathCPWithBC(uiCP, szPath, pbc, ppidlOut);
  2273. if (SUCCEEDED(hres) && pwszFileLocation)
  2274. {
  2275. ASSERT(*ppidlOut);
  2276. *ppidlOut = IEILAppendFragment(*ppidlOut, pwszFileLocation);
  2277. hres = *ppidlOut ? S_OK : E_OUTOFMEMORY;
  2278. }
  2279. if (SUCCEEDED(hres) && szQuery[0] == TEXT('?'))
  2280. {
  2281. *ppidlOut = ILAppendHiddenString(*ppidlOut, IDLHID_URLQUERY, szQuery);
  2282. hres = *ppidlOut ? S_OK : E_OUTOFMEMORY;
  2283. }
  2284. return hres;
  2285. }