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

471 lines
14 KiB

  1. #include "priv.h"
  2. #include "fldset.h"
  3. #define IShellView_CreateViewWindow(_pi, _piPrev, _pfs, _psb, _prc, _phw) \
  4. (_pi)->CreateViewWindow(_piPrev, _pfs, _psb, _prc, _phw)
  5. #define IShellView2_GetView(_pi, _pv, _flg) \
  6. (_pi)->GetView(_pv, _flg)
  7. #define IShellView2_CreateViewWindow2(_pi, _cParams) \
  8. (_pi)->CreateViewWindow2(_cParams)
  9. #define IUnknown_QueryInterface(_pu, _riid, _pi) \
  10. (_pu)->QueryInterface(_riid, (LPVOID*)_pi)
  11. #define IUnknown_AddRef(_pu) (_pu)->AddRef()
  12. #define IUnknown_Release(_pu) (_pu)->Release()
  13. typedef struct CViewSet
  14. {
  15. HDSA _dsaViews;
  16. } CViewSet;
  17. CViewSet* CViewSet_New()
  18. {
  19. CViewSet* pThis = (CViewSet*)LocalAlloc(LPTR, SIZEOF(CViewSet));
  20. if (!pThis)
  21. {
  22. return(NULL);
  23. }
  24. pThis->_dsaViews = DSA_Create(SIZEOF(SHELLVIEWID), 8);
  25. if (!pThis->_dsaViews)
  26. {
  27. LocalFree(pThis);
  28. pThis = NULL;
  29. }
  30. return(pThis);
  31. }
  32. int CViewSet_Add(CViewSet* that, SHELLVIEWID const* pvid)
  33. {
  34. return(DSA_AppendItem(that->_dsaViews, (LPVOID)pvid));
  35. }
  36. void CViewSet_Delete(CViewSet* that)
  37. {
  38. DSA_Destroy(that->_dsaViews);
  39. that->_dsaViews = NULL;
  40. LocalFree((HLOCAL)that);
  41. that = NULL;
  42. }
  43. void CViewSet_GetDefaultView(CViewSet* that, SHELLVIEWID* pvid)
  44. {
  45. DSA_GetItem(that->_dsaViews, 0, (LPVOID)pvid);
  46. }
  47. void CViewSet_SetDefaultView(CViewSet* that, SHELLVIEWID const* pvid)
  48. {
  49. DSA_SetItem(that->_dsaViews, 0, (LPVOID)pvid);
  50. }
  51. // PERF: A linear search for the view
  52. BOOL CViewSet_IsViewSupported(CViewSet* that, SHELLVIEWID const* pvid)
  53. {
  54. int i;
  55. // Only go down to 1 since item 0 is the default view
  56. for (i=DSA_GetItemCount(that->_dsaViews)-1; i>=1; --i)
  57. {
  58. if (0 == memcmp(pvid, DSA_GetItemPtr(that->_dsaViews, i),
  59. SIZEOF(SHELLVIEWID)))
  60. {
  61. return(TRUE);
  62. }
  63. }
  64. return(FALSE);
  65. }
  66. // PERF: a linear check
  67. BOOL CViewSet_IsSame(CViewSet* that, CViewSet* pThatView)
  68. {
  69. int iView = DSA_GetItemCount(pThatView->_dsaViews);
  70. if (DSA_GetItemCount(that->_dsaViews) != iView)
  71. {
  72. return(FALSE);
  73. }
  74. for (--iView; iView>=1; --iView)
  75. {
  76. if (!CViewSet_IsViewSupported(that,
  77. (SHELLVIEWID const*)DSA_GetItemPtr(pThatView->_dsaViews, iView)))
  78. {
  79. return(FALSE);
  80. }
  81. }
  82. return(TRUE);
  83. }
  84. BOOL CShellViews_Init(CShellViews* that)
  85. {
  86. if (that->_dpaViews)
  87. {
  88. return(TRUE);
  89. }
  90. {
  91. HDPA dpaViews = DPA_Create(4);
  92. if (!dpaViews)
  93. {
  94. return(FALSE);
  95. }
  96. {
  97. CViewSet* pCommViews = CViewSet_New();
  98. if (!pCommViews)
  99. {
  100. DPA_Destroy(dpaViews);
  101. dpaViews = NULL;
  102. return(FALSE);
  103. }
  104. // The first one is the last known view for that set
  105. CViewSet_Add(pCommViews, &VID_LargeIcons);
  106. CViewSet_Add(pCommViews, &VID_LargeIcons);
  107. CViewSet_Add(pCommViews, &VID_SmallIcons);
  108. CViewSet_Add(pCommViews, &VID_Thumbnails);
  109. CViewSet_Add(pCommViews, &VID_List );
  110. CViewSet_Add(pCommViews, &VID_Details );
  111. CViewSet_Add(pCommViews, &VID_Tile );
  112. if (0 != DPA_InsertPtr(dpaViews, 0, pCommViews))
  113. {
  114. CViewSet_Delete(pCommViews);
  115. DPA_Destroy(dpaViews);
  116. dpaViews = NULL;
  117. return(FALSE);
  118. }
  119. that->_dpaViews = dpaViews;
  120. return(TRUE);
  121. }
  122. }
  123. }
  124. void CShellViews_GetDefaultView(CShellViews* that, UINT uViewSet,
  125. SHELLVIEWID* pvid)
  126. {
  127. CViewSet* pViewSet = (CViewSet*)DPA_GetPtr(that->_dpaViews, uViewSet);
  128. if (!pViewSet)
  129. {
  130. pViewSet = (CViewSet*)DPA_GetPtr(that->_dpaViews, 0);
  131. if (!pViewSet)
  132. {
  133. *pvid = VID_LargeIcons;
  134. return;
  135. }
  136. }
  137. CViewSet_GetDefaultView(pViewSet, pvid);
  138. }
  139. void CShellViews_SetDefaultView(CShellViews* that, UINT uViewSet,
  140. SHELLVIEWID const* pvid)
  141. {
  142. CViewSet* pViewSet = (CViewSet*)DPA_GetPtr(that->_dpaViews, uViewSet);
  143. if (!pViewSet)
  144. {
  145. return;
  146. }
  147. CViewSet_SetDefaultView(pViewSet, pvid);
  148. }
  149. // PERF: a linear search for the view set
  150. int CShellViews_Add(CShellViews* that, CViewSet* pThisView, BOOL *pbNew)
  151. {
  152. int iViewSet;
  153. *pbNew = FALSE;
  154. for (iViewSet=0; ; ++iViewSet)
  155. {
  156. CViewSet* pThatView = (CViewSet*)DPA_GetPtr(that->_dpaViews, iViewSet);
  157. if (!pThatView)
  158. {
  159. break;
  160. }
  161. if (CViewSet_IsSame(pThatView, pThisView))
  162. {
  163. // Found the same set; delete the one passed in and hand back the
  164. // existing one
  165. CViewSet_Delete(pThisView);
  166. return(iViewSet);
  167. }
  168. }
  169. // I guess we didn't find it
  170. iViewSet = DPA_AppendPtr(that->_dpaViews, (LPVOID)pThisView);
  171. if (iViewSet < 0)
  172. {
  173. CViewSet_Delete(pThisView);
  174. return(0);
  175. }
  176. *pbNew = TRUE;
  177. return(iViewSet);
  178. }
  179. BOOL CShellViews_IsViewSupported(CShellViews* that, UINT uViewSet,
  180. SHELLVIEWID const*pvid)
  181. {
  182. CViewSet* pViewSet = (CViewSet*)DPA_GetPtr(that->_dpaViews, uViewSet);
  183. if (!pViewSet)
  184. {
  185. return(FALSE);
  186. }
  187. return(CViewSet_IsViewSupported(pViewSet, pvid));
  188. }
  189. int DPA_CViewSet_DeleteCallback(LPVOID p, LPVOID d)
  190. {
  191. if (p)
  192. CViewSet_Delete((CViewSet*)p);
  193. return 1;
  194. }
  195. void CShellViews_Delete(CShellViews* that)
  196. {
  197. if (that && that->_dpaViews)
  198. {
  199. DPA_DestroyCallback(that->_dpaViews, DPA_CViewSet_DeleteCallback, 0);
  200. that->_dpaViews = NULL;
  201. }
  202. }
  203. BOOL FileCabinet_GetDefaultViewID2(FOLDERSETDATABASE* that, SHELLVIEWID* pvid)
  204. {
  205. if (CShellViews_Init(&that->_cViews))
  206. {
  207. CShellViews_GetDefaultView(&that->_cViews, that->_iViewSet, pvid);
  208. return(TRUE);
  209. }
  210. return(FALSE);
  211. }
  212. HRESULT FileCabinet_CreateViewWindow2(IShellBrowser* psb, FOLDERSETDATABASE* that, IShellView *psvNew,
  213. IShellView *psvOld, RECT *prcView, HWND *phWnd)
  214. {
  215. SHELLVIEWID vid, vidOld, vidRestore;
  216. IShellView2 *psv2New;
  217. CViewSet *pThisView;
  218. DWORD dwViewPriority;
  219. BOOL bCalledSV2 = FALSE;
  220. HRESULT hres = S_OK; // init to avoid a bogus C4701 warning
  221. if (!CShellViews_Init(&that->_cViews))
  222. {
  223. // Can't do anything with view sets; just do the old thing
  224. goto OldStyle;
  225. }
  226. // Default to whatever the last "old-style" view is
  227. CShellViews_GetDefaultView(&that->_cViews, 0, &vidOld);
  228. if (psvOld)
  229. {
  230. IShellView2 *psv2Old;
  231. if (SUCCEEDED(IUnknown_QueryInterface(psvOld, IID_IShellView2,
  232. &psv2Old)))
  233. {
  234. // Try to get the current view
  235. if (NOERROR == IShellView2_GetView(psv2Old, &vidOld, SV2GV_CURRENTVIEW))
  236. {
  237. CShellViews_SetDefaultView(&that->_cViews, that->_iViewSet, &vidOld);
  238. }
  239. IUnknown_Release(psv2Old);
  240. }
  241. else
  242. {
  243. // Get the view ID from the folder settings
  244. ViewIDFromViewMode(that->_fld._fs.ViewMode, &vidOld);
  245. CShellViews_SetDefaultView(&that->_cViews, 0, &vidOld);
  246. }
  247. }
  248. pThisView = CViewSet_New();
  249. if (!pThisView)
  250. {
  251. goto OldStyle;
  252. }
  253. if (SUCCEEDED(IUnknown_QueryInterface(psvNew, IID_IShellView2, &psv2New)))
  254. {
  255. SHELLVIEWID vidFolderDefault;
  256. if (NOERROR == IShellView2_GetView(psv2New, &vidFolderDefault, SV2GV_DEFAULTVIEW))
  257. {
  258. // we can now make up a view set for that folder
  259. if (CViewSet_Add(pThisView, &vidFolderDefault) >= 0)
  260. {
  261. int iViewSet;
  262. UINT uView;
  263. BOOL bNew;
  264. // NOTE: This usage of IShellView2::GetView is not documented in MSDN...
  265. for (uView=0; NOERROR==IShellView2_GetView(psv2New, &vid, uView);
  266. ++uView)
  267. {
  268. CViewSet_Add(pThisView, &vid);
  269. }
  270. // Add that view set. we will get an existing view set if it is
  271. // a duplicate
  272. iViewSet = CShellViews_Add(&that->_cViews, pThisView, &bNew);
  273. // This is now owned by CShellViews
  274. pThisView = NULL;
  275. //
  276. // Here is where we decide which view we want to use.
  277. //
  278. // Start with what came from the FOLDERSETDATABASE, then see if
  279. // anyone else has a higher VIEW_PRIORITY_XXX that would override this one.
  280. vidRestore = that->_fld._vidRestore;
  281. dwViewPriority = that->_fld._dwViewPriority;
  282. // ToddB, 8-18-99:
  283. // When we set the _fld._dwViewPriority in WebBrowserOc::Load(IPropertyBag *...) we want that ViewID to stick
  284. // around. Only failing the CShellViews_IsViewSupported call below should set a different view. Even then
  285. // we want to go back to this view on the next navigate. To accomplish this we need to keep the priority of
  286. // that view at what it was originally set to. This can be done by removing the following line of code:
  287. //
  288. // that->_fld._dwViewPriority = VIEW_PRIORITY_NONE;
  289. //
  290. // However, its possible that the line of code above was there for a good reason. I suspect that line was
  291. // originally added simply as a precaution or because the meaning of _vidRestore was not clearly defined in
  292. // relation to navigation inside a WebBrowserOC. I'm leaving the line here and commented out just in case.
  293. // If any new bugs arise about changing the view window and getting the wrong view I would look here first.
  294. // Make sure that what we got is a supported view
  295. if (!CShellViews_IsViewSupported(&that->_cViews, iViewSet, &vidRestore))
  296. {
  297. // Oops, that view isn't supported by this shell ext.
  298. // Set the priority to NONE so that one of the others will override it.
  299. dwViewPriority = VIEW_PRIORITY_NONE;
  300. }
  301. DWORD cbSize;
  302. DWORD dwValue;
  303. DWORD dwShellExtPriority;
  304. cbSize = SIZEOF(dwValue);
  305. if (ERROR_SUCCESS == SHGetValue(HKEY_CURRENT_USER,
  306. TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Advanced"),
  307. TEXT("ClassicViewState"), NULL, &dwValue, &cbSize)
  308. && dwValue)
  309. {
  310. // We want to inherit from the previous folder if at all possible
  311. // Otherwise, we will use the new shell extended view.
  312. // To do this, we set the shell ext view priority lower than inherit
  313. dwShellExtPriority = VIEW_PRIORITY_SHELLEXT_ASBACKUP;
  314. }
  315. else
  316. {
  317. dwShellExtPriority = VIEW_PRIORITY_SHELLEXT;
  318. }
  319. // Let the shell ext select the view if it has higher priority than
  320. // what we already have, and it is supported as well.
  321. if (dwViewPriority <= dwShellExtPriority &&
  322. ((GetUIVersion() >= 5) || (vidFolderDefault != VID_LargeIcons)) && // downlevel browser assumes VID_LargeIcons means "default"
  323. CShellViews_IsViewSupported(&that->_cViews, iViewSet, &vidFolderDefault))
  324. {
  325. // shell extension is more important
  326. vidRestore = vidFolderDefault;
  327. dwViewPriority = dwShellExtPriority;
  328. }
  329. // Maybe we can inherit it from the previous view...
  330. if (dwViewPriority <= VIEW_PRIORITY_INHERIT &&
  331. psvOld &&
  332. bNew &&
  333. CShellViews_IsViewSupported(&that->_cViews, iViewSet, &vidOld))
  334. {
  335. // We just navigated from another shell view. Use the same view as the last
  336. // folder.
  337. vidRestore = vidOld;
  338. dwViewPriority = VIEW_PRIORITY_INHERIT;
  339. }
  340. // We're getting really desperate now...
  341. if (dwViewPriority <= VIEW_PRIORITY_DESPERATE)
  342. {
  343. // Try the last view for the folders current viewset.
  344. CShellViews_GetDefaultView(&that->_cViews, iViewSet, &vidRestore);
  345. dwViewPriority = VIEW_PRIORITY_DESPERATE;
  346. }
  347. // All finished trying to figure out what view to use
  348. ASSERT(dwViewPriority > VIEW_PRIORITY_NONE);
  349. // assure webview no in vid, it is persisted in shellstate now.
  350. {
  351. SV2CVW2_PARAMS cParams =
  352. {
  353. SIZEOF(SV2CVW2_PARAMS),
  354. psvOld,
  355. &that->_fld._fs,
  356. psb,
  357. prcView,
  358. &vidRestore,
  359. NULL,
  360. } ;
  361. hres = IShellView2_CreateViewWindow2(psv2New, &cParams);
  362. bCalledSV2 = TRUE;
  363. *phWnd = cParams.hwndView;
  364. }
  365. if (SUCCEEDED(hres))
  366. {
  367. that->_iViewSet = iViewSet;
  368. }
  369. }
  370. }
  371. IUnknown_Release(psv2New);
  372. }
  373. if (pThisView)
  374. {
  375. CViewSet_Delete(pThisView);
  376. }
  377. if (bCalledSV2)
  378. {
  379. return(hres);
  380. }
  381. OldStyle:
  382. that->_iViewSet = 0;
  383. return IShellView_CreateViewWindow(psvNew, psvOld, &that->_fld._fs, (IShellBrowser*)psb, prcView, phWnd);
  384. }