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.

530 lines
15 KiB

  1. /*****************************************************************************\
  2. FILE: isf.cpp
  3. DESCRIPTION:
  4. This is a base class that implements the default behavior of IShellFolder.
  5. \*****************************************************************************/
  6. #include "priv.h"
  7. #include "isf.h"
  8. #include <shlobj.h>
  9. /*****************************************************************************\
  10. FUNCTION: IShellFolder::ParseDisplayName
  11. DESCRIPTION:
  12. \*****************************************************************************/
  13. HRESULT CBaseFolder::ParseDisplayName(HWND hwnd, LPBC pbcReserved, LPOLESTR pwszDisplayName,
  14. ULONG * pchEaten, LPITEMIDLIST * ppidl, ULONG *pdwAttributes)
  15. {
  16. if (pdwAttributes)
  17. *pdwAttributes = 0;
  18. if (ppidl)
  19. *ppidl = NULL;
  20. return E_NOTIMPL;
  21. }
  22. /*****************************************************************************\
  23. FUNCTION: IShellFolder::EnumObjects
  24. DESCRIPTION:
  25. \*****************************************************************************/
  26. HRESULT CBaseFolder::EnumObjects(HWND hwndOwner, DWORD grfFlags, IEnumIDList ** ppenumIDList)
  27. {
  28. if (ppenumIDList)
  29. *ppenumIDList = NULL;
  30. return E_NOTIMPL;
  31. }
  32. /*****************************************************************************\
  33. FUNCTION: IShellFolder::BindToObject
  34. DESCRIPTION:
  35. \*****************************************************************************/
  36. HRESULT CBaseFolder::BindToObject(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, LPVOID * ppvObj)
  37. {
  38. if (ppvObj)
  39. *ppvObj = NULL;
  40. return E_NOTIMPL;
  41. }
  42. /*****************************************************************************\
  43. FUNCTION: IShellFolder::BindToStorage
  44. DESCRIPTION:
  45. This should be implemented so people can use the File.Open and File.SaveAs
  46. dialogs with this ShellFolder.
  47. \*****************************************************************************/
  48. HRESULT CBaseFolder::BindToStorage(LPCITEMIDLIST pidl, LPBC pbc, REFIID riid, LPVOID * ppvObj)
  49. {
  50. if (ppvObj)
  51. *ppvObj = NULL;
  52. return E_NOTIMPL;
  53. }
  54. /*****************************************************************************\
  55. FUNCTION: IShellFolder::CompareIDs
  56. DESCRIPTION:
  57. This should be implemented so people can use the File.Open and File.SaveAs
  58. dialogs with this ShellFolder.
  59. \*****************************************************************************/
  60. HRESULT CBaseFolder::CompareIDs(LPARAM ici, LPCITEMIDLIST pidl1, LPCITEMIDLIST pidl2)
  61. {
  62. return E_NOTIMPL;
  63. }
  64. /*****************************************************************************\
  65. FUNCTION: IShellFolder::CreateViewObject
  66. DESCRIPTION:
  67. This should be implemented so people can use the File.Open and File.SaveAs
  68. dialogs with this ShellFolder.
  69. \*****************************************************************************/
  70. HRESULT CBaseFolder::CreateViewObject(HWND hwndOwner, REFIID riid, LPVOID * ppvObj)
  71. {
  72. HRESULT hr = E_NOINTERFACE;
  73. *ppvObj = NULL;
  74. if (IsEqualIID(riid, IID_IShellView))
  75. hr = _CreateShellView(hwndOwner, ppvObj);
  76. else if (IsEqualIID(riid, IID_IContextMenu))
  77. hr = _GetUIObjectOf(hwndOwner, 0, NULL, riid, 0, ppvObj, TRUE);
  78. else
  79. hr = E_NOINTERFACE;
  80. return hr;
  81. }
  82. BOOL IsShellIntegration(void)
  83. {
  84. BOOL fResult = FALSE;
  85. HINSTANCE hInst = LoadLibrary(TEXT("shell32.dll"));
  86. if (hInst)
  87. {
  88. LPVOID pv = GetProcAddress(hInst, "DllGetVersion");
  89. if (pv)
  90. fResult = TRUE;
  91. FreeLibrary(hInst);
  92. }
  93. return fResult;
  94. }
  95. HRESULT CBaseFolder::_CreateShellView(HWND hwndOwner, void ** ppvObj, LONG lEvents, FOLDERVIEWMODE fvm,
  96. IShellFolderViewCB * psfvCallBack, LPCITEMIDLIST pidl, LPFNVIEWCALLBACK pfnCallback)
  97. {
  98. HRESULT hr;
  99. IShellFolder * psf;
  100. hr = this->QueryInterface(IID_IShellFolder, (LPVOID *) &psf);
  101. if (EVAL(SUCCEEDED(hr)))
  102. {
  103. SFV_CREATE sfvCreate = // SHCreateShellFolderView struct
  104. {
  105. sizeof(SFV_CREATE),
  106. psf, // psf
  107. NULL, // psvOuter
  108. psfvCallBack // psfvcb - (IShellFolderViewCB *)
  109. };
  110. // SHCreateShellFolderView isn't in the original shell. We can't rely on the
  111. // the Delayload code because it's exported by ordinal and the original
  112. // shell had a different exports by the same number.
  113. if (IsShellIntegration())
  114. hr = _SHCreateShellFolderView(&sfvCreate, (LPSHELLVIEW FAR*)ppvObj);
  115. else
  116. hr = E_FAIL; // Force us to go into the next try.
  117. // If we aren't running on a machine with Shell Integration, SHCreateShellFolderView will fail.
  118. if (FAILED(hr))
  119. {
  120. CSFV csfv;
  121. csfv.cbSize = sizeof(csfv);
  122. csfv.pshf = psf;
  123. csfv.psvOuter = (IShellView *) psfvCallBack; // Hack but it works...
  124. csfv.pidl = pidl; // This is feed to SFVM_GETNOTIFY so it needs to be a pidlTarget.
  125. csfv.lEvents = lEvents;
  126. csfv.pfnCallback = pfnCallback;
  127. csfv.fvm = fvm; // vs. FVM_ICON, ...
  128. hr = SHCreateShellFolderViewEx(&csfv, (LPSHELLVIEW FAR*)ppvObj);
  129. if (SUCCEEDED(hr))
  130. psfvCallBack->AddRef(); // We gave them a ref.
  131. }
  132. psf->Release();
  133. }
  134. return hr;
  135. }
  136. /*****************************************************************************\
  137. FUNCTION: IShellFolder::GetAttributesOf
  138. DESCRIPTION:
  139. \*****************************************************************************/
  140. HRESULT CBaseFolder::GetAttributesOf(UINT cpidl, LPCITEMIDLIST *apidl, ULONG *rgfInOut)
  141. {
  142. return E_NOTIMPL;
  143. }
  144. /*****************************************************************************\
  145. FUNCTION: IShellFolder::GetUIObjectOf
  146. DESCRIPTION:
  147. \*****************************************************************************/
  148. HRESULT CBaseFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST rgpidl[],
  149. REFIID riid, UINT * prgfInOut, LPVOID * ppvObj)
  150. {
  151. return E_NOTIMPL;
  152. }
  153. /*****************************************************************************\
  154. DESCRIPTION:
  155. \*****************************************************************************/
  156. HRESULT CBaseFolder::_GetUIObjectOf(HWND hwndOwner, UINT cidl, LPCITEMIDLIST rgpidl[],
  157. REFIID riid, UINT * prgfInOut, LPVOID * ppvOut, BOOL fFromCreateViewObject)
  158. {
  159. return GetUIObjectOf(hwndOwner, cidl, rgpidl, riid, prgfInOut, ppvOut);
  160. }
  161. /*****************************************************************************\
  162. FUNCTION: IShellFolder::GetDisplayNameOf
  163. DESCRIPTION:
  164. \*****************************************************************************/
  165. HRESULT CBaseFolder::GetDisplayNameOf(LPCITEMIDLIST pidl, DWORD shgno, LPSTRRET pStrRet)
  166. {
  167. return E_NOTIMPL;
  168. }
  169. /*****************************************************************************\
  170. FUNCTION: IShellFolder::SetNameOf
  171. DESCRIPTION:
  172. \*****************************************************************************/
  173. HRESULT CBaseFolder::SetNameOf(HWND hwndOwner, LPCITEMIDLIST pidl, LPCOLESTR pwszName,
  174. DWORD dwReserved, LPITEMIDLIST *ppidlOut)
  175. {
  176. return E_NOTIMPL;
  177. }
  178. //===========================
  179. // *** IShellFolder2 Interface ***
  180. //===========================
  181. //===========================
  182. // *** IPersist Interface ***
  183. //===========================
  184. /*****************************************************************************\
  185. FUNCTION: IPersist::GetClassID
  186. DESCRIPTION:
  187. \*****************************************************************************/
  188. HRESULT CBaseFolder::GetClassID(LPCLSID pClassID)
  189. {
  190. HRESULT hr = E_INVALIDARG;
  191. if (EVAL(pClassID))
  192. {
  193. if (EVAL(m_pClassID))
  194. {
  195. *pClassID = *m_pClassID;
  196. hr = S_OK;
  197. }
  198. else
  199. hr = E_FAIL;
  200. }
  201. return hr;
  202. }
  203. //===========================
  204. // *** IPersistFolder Interface ***
  205. //===========================
  206. /*****************************************************************************\
  207. DESCRIPTION:
  208. \*****************************************************************************/
  209. HRESULT CBaseFolder::Initialize(LPCITEMIDLIST pidl)
  210. {
  211. ASSERT(!m_pidl); // Don't reroot us.
  212. return _Initialize(pidl, NULL, ILGetSize(pidl) - sizeof(pidl->mkid.cb));
  213. }
  214. //===========================
  215. // *** IPersistFolder2 Interface ***
  216. //===========================
  217. /*****************************************************************************\
  218. DESCRIPTION:
  219. \*****************************************************************************/
  220. HRESULT CBaseFolder::GetCurFolder(LPITEMIDLIST *ppidl)
  221. {
  222. HRESULT hr = E_INVALIDARG;
  223. if (EVAL(ppidl))
  224. {
  225. hr = E_FAIL;
  226. if (m_pidlRoot)
  227. {
  228. *ppidl = ILClone(m_pidlRoot);
  229. }
  230. else if (EVAL(m_pidl))
  231. {
  232. *ppidl = GetPublicTargetPidlClone();
  233. }
  234. if (*ppidl)
  235. hr = S_OK;
  236. }
  237. return hr;
  238. }
  239. //===========================
  240. // *** IPersistFolder3 Interface ***
  241. //===========================
  242. HRESULT GetPidlFromPersistFolderTargetInfo(const PERSIST_FOLDER_TARGET_INFO *ppfti, LPITEMIDLIST * ppidl, BOOL fFree)
  243. {
  244. HRESULT hr = E_INVALIDARG;
  245. if (ppidl)
  246. {
  247. *ppidl = NULL;
  248. if (ppfti->pidlTargetFolder)
  249. {
  250. *ppidl = (fFree ? ppfti->pidlTargetFolder : ILClone(ppfti->pidlTargetFolder));
  251. if (*ppidl)
  252. hr = S_OK;
  253. else
  254. hr = E_OUTOFMEMORY;
  255. }
  256. else
  257. {
  258. if (ppfti->szTargetParsingName[0])
  259. {
  260. hr = IEParseDisplayNameWithBCW(CP_ACP, ppfti->szTargetParsingName, NULL, ppidl);
  261. }
  262. if (!*ppidl && (-1 != ppfti->csidl))
  263. {
  264. hr = SHGetSpecialFolderLocation(NULL, ppfti->csidl, ppidl);
  265. }
  266. }
  267. }
  268. return hr;
  269. }
  270. /*****************************************************************************\
  271. DESCRIPTION:
  272. \*****************************************************************************/
  273. HRESULT CBaseFolder::InitializeEx(IBindCtx *pbc, LPCITEMIDLIST pidlRoot, const PERSIST_FOLDER_TARGET_INFO *ppfti)
  274. {
  275. HRESULT hr = E_INVALIDARG;
  276. if (EVAL(pidlRoot))
  277. {
  278. if (ppfti)
  279. {
  280. // We are a Folder Shortcut.
  281. LPITEMIDLIST pidlTarget;
  282. hr = GetPidlFromPersistFolderTargetInfo(ppfti, &pidlTarget, FALSE); // Get the real root.
  283. TraceMsg(TF_FOLDER_SHRTCUTS, "CBaseFolder::InitializeEx() this=%#08lx, pidlTarget=%#08lx, pidlRoot=%#08lx", this, pidlTarget, pidlRoot);
  284. AssertMsg((NULL != pidlTarget), TEXT("CBaseFolder::InitializeEx() We are useless without a pidlTarget so watch me go limp."));
  285. if (pidlTarget)
  286. {
  287. hr = _Initialize(pidlTarget, pidlRoot, m_nIDOffsetToPrivate);
  288. ILFree(pidlTarget);
  289. }
  290. }
  291. else
  292. {
  293. // We aren't a folder shortcut.
  294. hr = Initialize(pidlRoot);
  295. }
  296. }
  297. return hr;
  298. }
  299. HRESULT CBaseFolder::GetFolderTargetInfo(PERSIST_FOLDER_TARGET_INFO *ppfti)
  300. {
  301. HRESULT hr = E_INVALIDARG;
  302. AssertMsg((NULL != ppfti), TEXT("CBaseFolder::GetFolderTargetInfo() Caller passed an invalid param."));
  303. if (ppfti)
  304. {
  305. ZeroMemory(ppfti, sizeof(*ppfti));
  306. ppfti->pidlTargetFolder = ILClone(m_pidlRoot);
  307. ppfti->dwAttributes = -1;
  308. ppfti->csidl = -1;
  309. hr = S_OK;
  310. }
  311. return hr;
  312. }
  313. LPCITEMIDLIST CBaseFolder::GetPrivatePidlReference(void)
  314. {
  315. return _ILSkip(m_pidl, m_nIDOffsetToPrivate);
  316. }
  317. // This function always needs the InternetExplorer pidl.
  318. LPITEMIDLIST CBaseFolder::GetPublicPidlRootIDClone(void)
  319. {
  320. LPITEMIDLIST pidlFull = ILClone(m_pidl);
  321. LPITEMIDLIST pidlPrivStart = _ILSkip(pidlFull, m_nIDOffsetToPrivate);
  322. // Strip all Private ItemIDs
  323. while (!ILIsEmpty(pidlPrivStart))
  324. ILRemoveLastID(pidlPrivStart);
  325. return pidlFull;
  326. }
  327. LPITEMIDLIST CBaseFolder::CreateFullPrivatePidl(LPCITEMIDLIST pidlPrivateSubPidl)
  328. {
  329. return ILCombine(GetPrivatePidlReference(), pidlPrivateSubPidl);
  330. }
  331. LPITEMIDLIST CBaseFolder::CreateFullPublicPidlFromRelative(LPCITEMIDLIST pidlPrivateSubPidl)
  332. {
  333. return ILCombine(GetPublicRootPidlReference(), pidlPrivateSubPidl);
  334. }
  335. LPITEMIDLIST CBaseFolder::CreateFullPublicPidl(LPCITEMIDLIST pidlPrivatePidl)
  336. {
  337. LPITEMIDLIST pidlRoot = GetPublicPidlRootIDClone();
  338. LPITEMIDLIST pidlResult = NULL;
  339. if (pidlRoot)
  340. {
  341. pidlResult = ILCombine(pidlRoot, pidlPrivatePidl);
  342. ILFree(pidlRoot);
  343. }
  344. return pidlResult;
  345. }
  346. HRESULT CBaseFolder::_Initialize(LPCITEMIDLIST pidlTarget, LPCITEMIDLIST pidlRoot, int nBytesToPrivate)
  347. {
  348. HRESULT hr = E_INVALIDARG;
  349. if (pidlTarget)
  350. {
  351. ILFree(m_pidl);
  352. ILFree(m_pidlRoot);
  353. m_pidl = ILClone(pidlTarget);
  354. m_pidlRoot = ILClone(pidlRoot); // This is the Folder Shortcut pidl. We don't use it outselves.
  355. if (m_pidl)
  356. {
  357. m_nIDOffsetToPrivate = nBytesToPrivate;
  358. hr = S_OK;
  359. }
  360. else
  361. hr = E_OUTOFMEMORY;
  362. }
  363. return hr;
  364. }
  365. /****************************************************\
  366. Constructor
  367. \****************************************************/
  368. CBaseFolder::CBaseFolder(LPCLSID pClassID) : m_cRef(1)
  369. {
  370. DllAddRef();
  371. // This needs to be allocated in Zero Inited Memory.
  372. // Assert that all Member Variables are inited to Zero.
  373. ASSERT(!m_pidl);
  374. ASSERT(!m_nIDOffsetToPrivate);
  375. ASSERT(!m_pClassID);
  376. m_pClassID = pClassID;
  377. ASSERT(pClassID);
  378. }
  379. /****************************************************\
  380. Destructor
  381. \****************************************************/
  382. CBaseFolder::~CBaseFolder()
  383. {
  384. Pidl_Set(&m_pidlRoot, NULL); // Folder Shortcut pidl
  385. Pidl_Set(&m_pidl, NULL);
  386. DllRelease();
  387. }
  388. //===========================
  389. // *** IUnknown Interface ***
  390. //===========================
  391. ULONG CBaseFolder::AddRef()
  392. {
  393. m_cRef++;
  394. return m_cRef;
  395. }
  396. ULONG CBaseFolder::Release()
  397. {
  398. ASSERT(m_cRef > 0);
  399. m_cRef--;
  400. if (m_cRef > 0)
  401. return m_cRef;
  402. delete this;
  403. return 0;
  404. }
  405. HRESULT CBaseFolder::QueryInterface(REFIID riid, void **ppvObj)
  406. {
  407. static const QITAB qit[] = {
  408. QITABENTMULTI(CBaseFolder, IShellFolder, IShellFolder2),
  409. QITABENTMULTI(CBaseFolder, IPersist, IPersistFolder),
  410. QITABENTMULTI(CBaseFolder, IPersist, IPersistFolder3),
  411. QITABENTMULTI(CBaseFolder, IPersistFolder, IPersistFolder3),
  412. QITABENTMULTI(CBaseFolder, IPersistFolder2, IPersistFolder3),
  413. QITABENT(CBaseFolder, IShellFolder2),
  414. QITABENT(CBaseFolder, IPersistFolder3),
  415. QITABENT(CBaseFolder, IObjectWithSite),
  416. { 0 },
  417. };
  418. return QISearch(this, qit, riid, ppvObj);
  419. }