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.

429 lines
10 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1997.
  5. //
  6. // File: S H U T I L . C P P
  7. //
  8. // Contents: Various shell utilities to be used by the connections shell
  9. //
  10. // Notes:
  11. //
  12. // Author: jeffspr 21 Oct 1997
  13. //
  14. //----------------------------------------------------------------------------
  15. #include "pch.h"
  16. #pragma hdrstop
  17. //+---------------------------------------------------------------------------
  18. //
  19. // Function: HrDupeShellStringLength
  20. //
  21. // Purpose: Duplicate a string using SHAlloc, so we can return it to the
  22. // shell. This is required because the shell typically releases
  23. // the strings that we pass it (so we need to use their
  24. // allocator).
  25. //
  26. // Arguments:
  27. // pszInput [in] String to duplicate
  28. // cchInput [in] Count of characters to copy (not including null term)
  29. // ppszOutput [out] Return pointer for the newly allocated string.
  30. //
  31. // Returns:
  32. //
  33. // Author: jeffspr 21 Oct 1997
  34. //
  35. // Notes:
  36. //
  37. HRESULT HrDupeShellStringLength(
  38. PCWSTR pszInput,
  39. ULONG cchInput,
  40. PWSTR * ppszOutput)
  41. {
  42. HRESULT hr = S_OK;
  43. Assert(pszInput);
  44. Assert(ppszOutput);
  45. ULONG cbString = (cchInput + 1) * sizeof(WCHAR);
  46. // Allocate a new POLESTR block, which the shell can then free.
  47. //
  48. PWSTR pszOutput = (PWSTR) SHAlloc(cbString);
  49. // If the alloc failed, return E_OUTOFMEMORY
  50. //
  51. if (NULL != pszOutput)
  52. {
  53. // Copy the memory into the alloc'd block
  54. //
  55. CopyMemory(pszOutput, pszInput, cbString);
  56. pszOutput[cchInput] = 0;
  57. *ppszOutput = pszOutput;
  58. }
  59. else
  60. {
  61. *ppszOutput = NULL;
  62. hr = E_OUTOFMEMORY;
  63. }
  64. TraceHr(ttidError, FAL, hr, FALSE, "HrDupeShellStringLength");
  65. return hr;
  66. }
  67. //+---------------------------------------------------------------------------
  68. //
  69. // Function: HrLoadPopupMenu
  70. //
  71. // Purpose: Load a popup menu as the first child of a loadable parent
  72. // menu
  73. //
  74. // Arguments:
  75. // hinst [in] Our instance handle
  76. // id [in] ID of the parent menu
  77. // phmenu [out] Return pointer for the popup menu
  78. //
  79. // Returns:
  80. //
  81. // Author: jeffspr 27 Oct 1997
  82. //
  83. // Notes:
  84. //
  85. HRESULT HrLoadPopupMenu(
  86. HINSTANCE hinst,
  87. UINT id,
  88. HMENU * phmenu)
  89. {
  90. HRESULT hr = S_OK;
  91. HMENU hmParent = NULL;
  92. HMENU hmPopup = NULL;
  93. Assert(id);
  94. Assert(hinst);
  95. Assert(phmenu);
  96. // Load the parent menu
  97. //
  98. hmParent = LoadMenu(hinst, MAKEINTRESOURCE(id));
  99. if (NULL == hmParent)
  100. {
  101. AssertSz(FALSE, "Can't load parent menu in HrLoadPopupMenu");
  102. hr = HrFromLastWin32Error();
  103. }
  104. else
  105. {
  106. // Load the popup from the parent (first submenu), then
  107. // remove the parent menu
  108. //
  109. hmPopup = GetSubMenu(hmParent, 0);
  110. RemoveMenu(hmParent, 0, MF_BYPOSITION);
  111. DestroyMenu(hmParent);
  112. }
  113. if (phmenu)
  114. {
  115. *phmenu = hmPopup;
  116. }
  117. TraceHr(ttidError, FAL, hr, FALSE, "HrLoadPopupMenu");
  118. return hr;
  119. }
  120. HRESULT HrGetMenuFromID(
  121. HMENU hmenuMain,
  122. UINT uID,
  123. HMENU * phmenu)
  124. {
  125. HRESULT hr = S_OK;
  126. HMENU hmenuReturn = NULL;
  127. MENUITEMINFO mii = {0};
  128. Assert(hmenuMain);
  129. Assert(uID);
  130. Assert(phmenu);
  131. mii.cbSize = sizeof(mii);
  132. mii.fMask = MIIM_SUBMENU;
  133. mii.cch = 0; // just in case
  134. if (!GetMenuItemInfo(hmenuMain, uID, FALSE, &mii))
  135. {
  136. hr = E_FAIL;
  137. }
  138. else
  139. {
  140. hmenuReturn = mii.hSubMenu;
  141. }
  142. if (phmenu)
  143. {
  144. *phmenu = mii.hSubMenu;
  145. }
  146. TraceHr(ttidError, FAL, hr, FALSE, "HrGetMenuFromID");
  147. return hr;
  148. }
  149. INT IMergePopupMenus(
  150. HMENU hmMain,
  151. HMENU hmMerge,
  152. int idCmdFirst,
  153. int idCmdLast)
  154. {
  155. HRESULT hr = S_OK;
  156. int iCount = 0;
  157. int idTemp = 0;
  158. int idMax = idCmdFirst;
  159. HMENU hmFromId = NULL;
  160. for (iCount = GetMenuItemCount(hmMerge) - 1; iCount >= 0; --iCount)
  161. {
  162. MENUITEMINFO mii = {0};
  163. mii.cbSize = sizeof(mii);
  164. mii.fMask = MIIM_ID | MIIM_SUBMENU;
  165. mii.cch = 0; // just in case
  166. mii.hSubMenu = NULL;
  167. if (!GetMenuItemInfo(hmMerge, iCount, TRUE, &mii))
  168. {
  169. TraceHr(ttidError, FAL, E_FAIL, FALSE, "GetMenuItemInfo failed in iMergePopupMenus");
  170. continue;
  171. }
  172. hr = HrGetMenuFromID(hmMain, mii.wID, &hmFromId);
  173. if (SUCCEEDED(hr))
  174. {
  175. idTemp = Shell_MergeMenus(
  176. hmFromId,
  177. mii.hSubMenu,
  178. 0,
  179. idCmdFirst,
  180. idCmdLast,
  181. MM_ADDSEPARATOR | MM_SUBMENUSHAVEIDS);
  182. if (idMax < idTemp)
  183. {
  184. idMax = idTemp;
  185. }
  186. }
  187. else
  188. {
  189. TraceHr(ttidError, FAL, E_FAIL, FALSE, "HrGetMenuFromId failed in iMergePopupMenus");
  190. continue;
  191. }
  192. }
  193. return idMax;
  194. }
  195. VOID MergeMenu(
  196. HINSTANCE hinst,
  197. UINT idMainMerge,
  198. UINT idPopupMerge,
  199. LPQCMINFO pqcm)
  200. {
  201. HMENU hmMerge = NULL;
  202. UINT idMax = 0;
  203. UINT idTemp = 0;
  204. Assert(pqcm);
  205. Assert(idMainMerge || idPopupMerge);
  206. Assert(hinst);
  207. idMax = pqcm->idCmdFirst;
  208. if (idMainMerge
  209. && (SUCCEEDED(HrLoadPopupMenu(hinst, idMainMerge, &hmMerge))))
  210. {
  211. Assert(hmMerge);
  212. if (hmMerge)
  213. {
  214. idMax = Shell_MergeMenus(
  215. pqcm->hmenu,
  216. hmMerge,
  217. pqcm->indexMenu,
  218. pqcm->idCmdFirst,
  219. pqcm->idCmdLast,
  220. MM_SUBMENUSHAVEIDS);
  221. DestroyMenu(hmMerge);
  222. }
  223. }
  224. if (idPopupMerge
  225. && (hmMerge = LoadMenu(hinst, MAKEINTRESOURCE(idPopupMerge))) != NULL)
  226. {
  227. idTemp = IMergePopupMenus(
  228. pqcm->hmenu,
  229. hmMerge,
  230. pqcm->idCmdFirst,
  231. pqcm->idCmdLast);
  232. if (idMax < idTemp)
  233. {
  234. idMax = idTemp;
  235. }
  236. DestroyMenu(hmMerge);
  237. }
  238. pqcm->idCmdFirst = idMax;
  239. }
  240. //+---------------------------------------------------------------------------
  241. //
  242. // Function: GenerateEvent
  243. //
  244. // Purpose: Generate a Shell Notification event.
  245. //
  246. // Arguments:
  247. // lEventId [in] The event ID to post
  248. // pidlFolder [in] Folder pidl
  249. // pidlIn [in] First pidl that we reference
  250. // pidlNewIn [in] If needed, the second pidl.
  251. //
  252. // Returns:
  253. //
  254. // Author: jeffspr 16 Dec 1997
  255. //
  256. // Notes:
  257. //
  258. VOID GenerateEvent(LONG lEventId, const LPCITEMIDLIST pidlFolder,
  259. LPCITEMIDLIST pidlIn, LPCITEMIDLIST pidlNewIn)
  260. {
  261. // Build an absolute pidl from the folder pidl + the object pidl
  262. //
  263. LPITEMIDLIST pidl = ILCombinePriv(pidlFolder, pidlIn);
  264. if (pidl)
  265. {
  266. // If we have two pidls, call the notify with both
  267. //
  268. if (pidlNewIn)
  269. {
  270. // Build the second absolute pidl
  271. //
  272. LPITEMIDLIST pidlNew = ILCombinePriv(pidlFolder, pidlNewIn);
  273. if (pidlNew)
  274. {
  275. // Make the notification, and free the new pidl
  276. //
  277. SHChangeNotify(lEventId, SHCNF_IDLIST, pidl, pidlNew);
  278. FreeIDL(pidlNew);
  279. }
  280. }
  281. else
  282. {
  283. // Make the single-pidl notification
  284. //
  285. SHChangeNotify(lEventId, SHCNF_IDLIST, pidl, NULL);
  286. }
  287. // Always refresh, then free the newly allocated pidl
  288. //
  289. SHChangeNotifyHandleEvents();
  290. FreeIDL(pidl);
  291. }
  292. }
  293. VOID ForceRefresh(HWND hwnd)
  294. {
  295. LPSHELLBROWSER psb = FileCabinet_GetIShellBrowser(hwnd);
  296. LPSHELLVIEW psv = NULL;
  297. // Did we get the shellview?
  298. #if 0 // We can't require this, since we may need to refresh without a folder
  299. // actually being open
  300. AssertSz(psb, "FileCabinet_GetIShellBrowser failed in ForceRefresh()");
  301. #endif
  302. if (psb && SUCCEEDED(psb->QueryActiveShellView(&psv)))
  303. {
  304. // $$TODO: Flush the connection list
  305. //
  306. Assert(psv);
  307. if (psv)
  308. {
  309. psv->Refresh();
  310. psv->Release();
  311. }
  312. }
  313. else
  314. {
  315. // $$TODO: Refresh the connection list.
  316. }
  317. }
  318. //+---------------------------------------------------------------------------
  319. //
  320. // Function: HrShellView_GetSelectedObjects
  321. //
  322. // Purpose: Get the selected data objects. We only care about the first
  323. // one (we'll ignore the rest)
  324. //
  325. // Arguments:
  326. // hwnd [in] Our window handle
  327. // papidlSelection [out] Return array for selected pidls
  328. // lpcidl [out] Count of returned pidls
  329. //
  330. // Returns: S_OK if 1 or more items are selected.
  331. // S_FALSE if 0 items are selected
  332. // OLE HRESULT otherwise
  333. //
  334. // Author: jeffspr 13 Jan 1998
  335. //
  336. // Notes:
  337. //
  338. HRESULT HrShellView_GetSelectedObjects(
  339. HWND hwnd,
  340. LPCITEMIDLIST ** papidlSelection,
  341. UINT * lpcidl)
  342. {
  343. HRESULT hr = S_OK;
  344. LPCITEMIDLIST * apidl = NULL;
  345. UINT cpidl = 0;
  346. // Get the selected object list from the shell
  347. //
  348. cpidl = ShellFolderView_GetSelectedObjects(hwnd, &apidl);
  349. // If the GetSelectedObjects failed, NULL out the return
  350. // params.
  351. //
  352. if (-1 == cpidl)
  353. {
  354. cpidl = 0;
  355. apidl = NULL;
  356. hr = E_OUTOFMEMORY;
  357. }
  358. else
  359. {
  360. // If no items were selected, return S_FALSE
  361. //
  362. if (0 == cpidl)
  363. {
  364. Assert(!apidl);
  365. hr = S_FALSE;
  366. }
  367. }
  368. // Fill in the out params
  369. //
  370. *papidlSelection = apidl;
  371. *lpcidl = cpidl;
  372. TraceHr(ttidError, FAL, hr, (S_FALSE == hr),
  373. "HrShellView_GetSelectedObjects");
  374. return hr;
  375. }