ShellContextMenu.cs 53 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Runtime.InteropServices;
  5. using System.Drawing;
  6. using System.Windows.Forms;
  7. using System.IO;
  8. using System.Security.Permissions;
  9. namespace GeekDesk.Util
  10. {
  11. /// <summary>
  12. /// "Stand-alone" shell context menu
  13. ///
  14. /// It isn't really debugged but is mostly working.
  15. /// Create an instance and call ShowContextMenu with a list of FileInfo for the files.
  16. /// Limitation is that it only handles files in the same directory but it can be fixed
  17. /// by changing the way files are translated into PIDLs.
  18. ///
  19. /// Based on FileBrowser in C# from CodeProject
  20. /// http://www.codeproject.com/useritems/FileBrowser.asp
  21. ///
  22. /// Hooking class taken from MSDN Magazine Cutting Edge column
  23. /// http://msdn.microsoft.com/msdnmag/issues/02/10/CuttingEdge/
  24. ///
  25. /// Andreas Johansson
  26. /// [email protected]
  27. /// http://afjohansson.spaces.live.com
  28. /// </summary>
  29. /// <example>
  30. /// ShellContextMenu scm = new ShellContextMenu();
  31. /// FileInfo[] files = new FileInfo[1];
  32. /// files[0] = new FileInfo(@"c:\windows\notepad.exe");
  33. /// scm.ShowContextMenu(this.Handle, files, Cursor.Position);
  34. /// </example>
  35. public class ShellContextMenu : NativeWindow
  36. {
  37. #region Constructor
  38. /// <summary>Default constructor</summary>
  39. public ShellContextMenu()
  40. {
  41. this.CreateHandle(new CreateParams());
  42. }
  43. #endregion
  44. #region Destructor
  45. /// <summary>Ensure all resources get released</summary>
  46. ~ShellContextMenu()
  47. {
  48. ReleaseAll();
  49. }
  50. #endregion
  51. #region GetContextMenuInterfaces()
  52. /// <summary>Gets the interfaces to the context menu</summary>
  53. /// <param name="oParentFolder">Parent folder</param>
  54. /// <param name="arrPIDLs">PIDLs</param>
  55. /// <returns>true if it got the interfaces, otherwise false</returns>
  56. private bool GetContextMenuInterfaces(IShellFolder oParentFolder, IntPtr[] arrPIDLs, out IntPtr ctxMenuPtr)
  57. {
  58. int nResult = oParentFolder.GetUIObjectOf(
  59. IntPtr.Zero,
  60. (uint)arrPIDLs.Length,
  61. arrPIDLs,
  62. ref IID_IContextMenu,
  63. IntPtr.Zero,
  64. out ctxMenuPtr);
  65. if (S_OK == nResult)
  66. {
  67. _oContextMenu = (IContextMenu)Marshal.GetTypedObjectForIUnknown(ctxMenuPtr, typeof(IContextMenu));
  68. return true;
  69. }
  70. else
  71. {
  72. ctxMenuPtr = IntPtr.Zero;
  73. _oContextMenu = null;
  74. return false;
  75. }
  76. }
  77. #endregion
  78. #region Override
  79. /// <summary>
  80. /// This method receives WindowMessages. It will make the "Open With" and "Send To" work
  81. /// by calling HandleMenuMsg and HandleMenuMsg2. It will also call the OnContextMenuMouseHover
  82. /// method of Browser when hovering over a ContextMenu item.
  83. /// </summary>
  84. /// <param name="m">the Message of the Browser's WndProc</param>
  85. /// <returns>true if the message has been handled, false otherwise</returns>
  86. protected override void WndProc(ref Message m)
  87. {
  88. #region IContextMenu
  89. if (_oContextMenu != null &&
  90. m.Msg == (int)WM.MENUSELECT &&
  91. ((int)ShellHelper.HiWord(m.WParam) & (int)MFT.SEPARATOR) == 0 &&
  92. ((int)ShellHelper.HiWord(m.WParam) & (int)MFT.POPUP) == 0)
  93. {
  94. string info = string.Empty;
  95. if (ShellHelper.LoWord(m.WParam) == (int)CMD_CUSTOM.ExpandCollapse)
  96. info = "Expands or collapses the current selected item";
  97. else
  98. {
  99. info = "";
  100. }
  101. }
  102. #endregion
  103. #region IContextMenu2
  104. if (_oContextMenu2 != null &&
  105. (m.Msg == (int)WM.INITMENUPOPUP ||
  106. m.Msg == (int)WM.MEASUREITEM ||
  107. m.Msg == (int)WM.DRAWITEM))
  108. {
  109. if (_oContextMenu2.HandleMenuMsg(
  110. (uint)m.Msg, m.WParam, m.LParam) == S_OK)
  111. return;
  112. }
  113. #endregion
  114. #region IContextMenu3
  115. if (_oContextMenu3 != null &&
  116. m.Msg == (int)WM.MENUCHAR)
  117. {
  118. if (_oContextMenu3.HandleMenuMsg2(
  119. (uint)m.Msg, m.WParam, m.LParam, IntPtr.Zero) == S_OK)
  120. return;
  121. }
  122. #endregion
  123. base.WndProc(ref m);
  124. }
  125. #endregion
  126. #region InvokeCommand
  127. private void InvokeCommand(IContextMenu oContextMenu, uint nCmd, string strFolder, Point pointInvoke)
  128. {
  129. CMINVOKECOMMANDINFOEX invoke = new CMINVOKECOMMANDINFOEX();
  130. invoke.cbSize = cbInvokeCommand;
  131. invoke.lpVerb = (IntPtr)(nCmd - CMD_FIRST);
  132. invoke.lpDirectory = strFolder;
  133. invoke.lpVerbW = (IntPtr)(nCmd - CMD_FIRST);
  134. invoke.lpDirectoryW = strFolder;
  135. invoke.fMask = CMIC.UNICODE | CMIC.PTINVOKE |
  136. ((System.Windows.Forms.Control.ModifierKeys & Keys.Control) != 0 ? CMIC.CONTROL_DOWN : 0) |
  137. ((System.Windows.Forms.Control.ModifierKeys & Keys.Shift) != 0 ? CMIC.SHIFT_DOWN : 0);
  138. invoke.ptInvoke = new POINT(pointInvoke.X, pointInvoke.Y);
  139. invoke.nShow = SW.SHOWNORMAL;
  140. oContextMenu.InvokeCommand(ref invoke);
  141. }
  142. #endregion
  143. #region ReleaseAll()
  144. /// <summary>
  145. /// Release all allocated interfaces, PIDLs
  146. /// </summary>
  147. private void ReleaseAll()
  148. {
  149. if (null != _oContextMenu)
  150. {
  151. Marshal.ReleaseComObject(_oContextMenu);
  152. _oContextMenu = null;
  153. }
  154. if (null != _oContextMenu2)
  155. {
  156. Marshal.ReleaseComObject(_oContextMenu2);
  157. _oContextMenu2 = null;
  158. }
  159. if (null != _oContextMenu3)
  160. {
  161. Marshal.ReleaseComObject(_oContextMenu3);
  162. _oContextMenu3 = null;
  163. }
  164. if (null != _oDesktopFolder)
  165. {
  166. Marshal.ReleaseComObject(_oDesktopFolder);
  167. _oDesktopFolder = null;
  168. }
  169. if (null != _oParentFolder)
  170. {
  171. Marshal.ReleaseComObject(_oParentFolder);
  172. _oParentFolder = null;
  173. }
  174. if (null != _arrPIDLs)
  175. {
  176. FreePIDLs(_arrPIDLs);
  177. _arrPIDLs = null;
  178. }
  179. }
  180. #endregion
  181. #region GetDesktopFolder()
  182. /// <summary>
  183. /// Gets the desktop folder
  184. /// </summary>
  185. /// <returns>IShellFolder for desktop folder</returns>
  186. private IShellFolder GetDesktopFolder()
  187. {
  188. IntPtr pUnkownDesktopFolder = IntPtr.Zero;
  189. if (null == _oDesktopFolder)
  190. {
  191. // Get desktop IShellFolder
  192. int nResult = SHGetDesktopFolder(out pUnkownDesktopFolder);
  193. if (S_OK != nResult)
  194. {
  195. throw new ShellContextMenuException("Failed to get the desktop shell folder");
  196. }
  197. _oDesktopFolder = (IShellFolder)Marshal.GetTypedObjectForIUnknown(pUnkownDesktopFolder, typeof(IShellFolder));
  198. }
  199. return _oDesktopFolder;
  200. }
  201. #endregion
  202. #region GetParentFolder()
  203. /// <summary>
  204. /// Gets the parent folder
  205. /// </summary>
  206. /// <param name="folderName">Folder path</param>
  207. /// <returns>IShellFolder for the folder (relative from the desktop)</returns>
  208. private IShellFolder GetParentFolder(string folderName)
  209. {
  210. if (null == _oParentFolder)
  211. {
  212. IShellFolder oDesktopFolder = GetDesktopFolder();
  213. if (null == oDesktopFolder)
  214. {
  215. return null;
  216. }
  217. // Get the PIDL for the folder file is in
  218. IntPtr pPIDL = IntPtr.Zero;
  219. uint pchEaten = 0;
  220. SFGAO pdwAttributes = 0;
  221. int nResult = oDesktopFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, folderName, ref pchEaten, out pPIDL, ref pdwAttributes);
  222. if (S_OK != nResult)
  223. {
  224. return null;
  225. }
  226. IntPtr pStrRet = Marshal.AllocCoTaskMem(MAX_PATH * 2 + 4);
  227. Marshal.WriteInt32(pStrRet, 0, 0);
  228. nResult = _oDesktopFolder.GetDisplayNameOf(pPIDL, SHGNO.FORPARSING, pStrRet);
  229. StringBuilder strFolder = new StringBuilder(MAX_PATH);
  230. StrRetToBuf(pStrRet, pPIDL, strFolder, MAX_PATH);
  231. Marshal.FreeCoTaskMem(pStrRet);
  232. pStrRet = IntPtr.Zero;
  233. _strParentFolder = strFolder.ToString();
  234. // Get the IShellFolder for folder
  235. IntPtr pUnknownParentFolder = IntPtr.Zero;
  236. nResult = oDesktopFolder.BindToObject(pPIDL, IntPtr.Zero, ref IID_IShellFolder, out pUnknownParentFolder);
  237. // Free the PIDL first
  238. Marshal.FreeCoTaskMem(pPIDL);
  239. if (S_OK != nResult)
  240. {
  241. return null;
  242. }
  243. _oParentFolder = (IShellFolder)Marshal.GetTypedObjectForIUnknown(pUnknownParentFolder, typeof(IShellFolder));
  244. }
  245. return _oParentFolder;
  246. }
  247. #endregion
  248. #region GetPIDLs()
  249. /// <summary>
  250. /// Get the PIDLs
  251. /// </summary>
  252. /// <param name="arrFI">Array of FileInfo</param>
  253. /// <returns>Array of PIDLs</returns>
  254. protected IntPtr[] GetPIDLs(FileInfo[] arrFI)
  255. {
  256. if (null == arrFI || 0 == arrFI.Length)
  257. {
  258. return null;
  259. }
  260. IShellFolder oParentFolder = GetParentFolder(arrFI[0].DirectoryName);
  261. if (null == oParentFolder)
  262. {
  263. return null;
  264. }
  265. IntPtr[] arrPIDLs = new IntPtr[arrFI.Length];
  266. int n = 0;
  267. foreach (FileInfo fi in arrFI)
  268. {
  269. // Get the file relative to folder
  270. uint pchEaten = 0;
  271. SFGAO pdwAttributes = 0;
  272. IntPtr pPIDL = IntPtr.Zero;
  273. int nResult = oParentFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, fi.Name, ref pchEaten, out pPIDL, ref pdwAttributes);
  274. if (S_OK != nResult)
  275. {
  276. FreePIDLs(arrPIDLs);
  277. return null;
  278. }
  279. arrPIDLs[n] = pPIDL;
  280. n++;
  281. }
  282. return arrPIDLs;
  283. }
  284. /// <summary>
  285. /// Get the PIDLs
  286. /// </summary>
  287. /// <param name="arrFI">Array of DirectoryInfo</param>
  288. /// <returns>Array of PIDLs</returns>
  289. protected IntPtr[] GetPIDLs(DirectoryInfo[] arrFI)
  290. {
  291. if (null == arrFI || 0 == arrFI.Length)
  292. {
  293. return null;
  294. }
  295. IShellFolder oParentFolder = GetParentFolder(arrFI[0].Parent.FullName);
  296. if (null == oParentFolder)
  297. {
  298. return null;
  299. }
  300. IntPtr[] arrPIDLs = new IntPtr[arrFI.Length];
  301. int n = 0;
  302. foreach (DirectoryInfo fi in arrFI)
  303. {
  304. // Get the file relative to folder
  305. uint pchEaten = 0;
  306. SFGAO pdwAttributes = 0;
  307. IntPtr pPIDL = IntPtr.Zero;
  308. int nResult = oParentFolder.ParseDisplayName(IntPtr.Zero, IntPtr.Zero, fi.Name, ref pchEaten, out pPIDL, ref pdwAttributes);
  309. if (S_OK != nResult)
  310. {
  311. FreePIDLs(arrPIDLs);
  312. return null;
  313. }
  314. arrPIDLs[n] = pPIDL;
  315. n++;
  316. }
  317. return arrPIDLs;
  318. }
  319. #endregion
  320. #region FreePIDLs()
  321. /// <summary>
  322. /// Free the PIDLs
  323. /// </summary>
  324. /// <param name="arrPIDLs">Array of PIDLs (IntPtr)</param>
  325. protected void FreePIDLs(IntPtr[] arrPIDLs)
  326. {
  327. if (null != arrPIDLs)
  328. {
  329. for (int n = 0; n < arrPIDLs.Length; n++)
  330. {
  331. if (arrPIDLs[n] != IntPtr.Zero)
  332. {
  333. Marshal.FreeCoTaskMem(arrPIDLs[n]);
  334. arrPIDLs[n] = IntPtr.Zero;
  335. }
  336. }
  337. }
  338. }
  339. #endregion
  340. #region InvokeContextMenuDefault
  341. private void InvokeContextMenuDefault(FileInfo[] arrFI)
  342. {
  343. // Release all resources first.
  344. ReleaseAll();
  345. IntPtr pMenu = IntPtr.Zero,
  346. iContextMenuPtr = IntPtr.Zero;
  347. try
  348. {
  349. _arrPIDLs = GetPIDLs(arrFI);
  350. if (null == _arrPIDLs)
  351. {
  352. ReleaseAll();
  353. return;
  354. }
  355. if (false == GetContextMenuInterfaces(_oParentFolder, _arrPIDLs, out iContextMenuPtr))
  356. {
  357. ReleaseAll();
  358. return;
  359. }
  360. pMenu = CreatePopupMenu();
  361. int nResult = _oContextMenu.QueryContextMenu(
  362. pMenu,
  363. 0,
  364. CMD_FIRST,
  365. CMD_LAST,
  366. CMF.DEFAULTONLY |
  367. ((System.Windows.Forms.Control.ModifierKeys & Keys.Shift) != 0 ? CMF.EXTENDEDVERBS : 0));
  368. uint nDefaultCmd = (uint)GetMenuDefaultItem(pMenu, false, 0);
  369. if (nDefaultCmd >= CMD_FIRST)
  370. {
  371. InvokeCommand(_oContextMenu, nDefaultCmd, arrFI[0].DirectoryName, System.Windows.Forms.Control.MousePosition);
  372. }
  373. DestroyMenu(pMenu);
  374. pMenu = IntPtr.Zero;
  375. }
  376. catch
  377. {
  378. throw;
  379. }
  380. finally
  381. {
  382. if (pMenu != IntPtr.Zero)
  383. {
  384. DestroyMenu(pMenu);
  385. }
  386. ReleaseAll();
  387. }
  388. }
  389. #endregion
  390. #region ShowContextMenu()
  391. /// <summary>
  392. /// Shows the context menu
  393. /// </summary>
  394. /// <param name="files">FileInfos (should all be in same directory)</param>
  395. /// <param name="pointScreen">Where to show the menu</param>
  396. public void ShowContextMenu(FileInfo[] files, Point pointScreen)
  397. {
  398. // Release all resources first.
  399. ReleaseAll();
  400. _arrPIDLs = GetPIDLs(files);
  401. this.ShowContextMenu(pointScreen);
  402. }
  403. /// <summary>
  404. /// Shows the context menu
  405. /// </summary>
  406. /// <param name="dirs">DirectoryInfos (should all be in same directory)</param>
  407. /// <param name="pointScreen">Where to show the menu</param>
  408. public void ShowContextMenu(DirectoryInfo[] dirs, Point pointScreen)
  409. {
  410. // Release all resources first.
  411. ReleaseAll();
  412. _arrPIDLs = GetPIDLs(dirs);
  413. this.ShowContextMenu(pointScreen);
  414. }
  415. /// <summary>
  416. /// Shows the context menu
  417. /// </summary>
  418. /// <param name="arrFI">FileInfos (should all be in same directory)</param>
  419. /// <param name="pointScreen">Where to show the menu</param>
  420. private void ShowContextMenu(Point pointScreen)
  421. {
  422. IntPtr pMenu = IntPtr.Zero,
  423. iContextMenuPtr = IntPtr.Zero,
  424. iContextMenuPtr2 = IntPtr.Zero,
  425. iContextMenuPtr3 = IntPtr.Zero;
  426. try
  427. {
  428. if (null == _arrPIDLs)
  429. {
  430. ReleaseAll();
  431. return;
  432. }
  433. if (false == GetContextMenuInterfaces(_oParentFolder, _arrPIDLs, out iContextMenuPtr))
  434. {
  435. ReleaseAll();
  436. return;
  437. }
  438. pMenu = CreatePopupMenu();
  439. int nResult = _oContextMenu.QueryContextMenu(
  440. pMenu,
  441. 0,
  442. CMD_FIRST,
  443. CMD_LAST,
  444. CMF.EXPLORE |
  445. CMF.NORMAL |
  446. ((System.Windows.Forms.Control.ModifierKeys & Keys.Shift) != 0 ? CMF.EXTENDEDVERBS : 0));
  447. Marshal.QueryInterface(iContextMenuPtr, ref IID_IContextMenu2, out iContextMenuPtr2);
  448. Marshal.QueryInterface(iContextMenuPtr, ref IID_IContextMenu3, out iContextMenuPtr3);
  449. _oContextMenu2 = (IContextMenu2)Marshal.GetTypedObjectForIUnknown(iContextMenuPtr2, typeof(IContextMenu2));
  450. _oContextMenu3 = (IContextMenu3)Marshal.GetTypedObjectForIUnknown(iContextMenuPtr3, typeof(IContextMenu3));
  451. uint nSelected = TrackPopupMenuEx(
  452. pMenu,
  453. TPM.RETURNCMD,
  454. pointScreen.X,
  455. pointScreen.Y,
  456. this.Handle,
  457. IntPtr.Zero);
  458. DestroyMenu(pMenu);
  459. pMenu = IntPtr.Zero;
  460. if (nSelected != 0)
  461. {
  462. InvokeCommand(_oContextMenu, nSelected, _strParentFolder, pointScreen);
  463. }
  464. }
  465. catch
  466. {
  467. throw;
  468. }
  469. finally
  470. {
  471. //hook.Uninstall();
  472. if (pMenu != IntPtr.Zero)
  473. {
  474. DestroyMenu(pMenu);
  475. }
  476. if (iContextMenuPtr != IntPtr.Zero)
  477. Marshal.Release(iContextMenuPtr);
  478. if (iContextMenuPtr2 != IntPtr.Zero)
  479. Marshal.Release(iContextMenuPtr2);
  480. if (iContextMenuPtr3 != IntPtr.Zero)
  481. Marshal.Release(iContextMenuPtr3);
  482. ReleaseAll();
  483. }
  484. }
  485. #endregion
  486. #region Local variabled
  487. private IContextMenu _oContextMenu;
  488. private IContextMenu2 _oContextMenu2;
  489. private IContextMenu3 _oContextMenu3;
  490. private IShellFolder _oDesktopFolder;
  491. private IShellFolder _oParentFolder;
  492. private IntPtr[] _arrPIDLs;
  493. private string _strParentFolder;
  494. #endregion
  495. #region Variables and Constants
  496. private const int MAX_PATH = 260;
  497. private const uint CMD_FIRST = 1;
  498. private const uint CMD_LAST = 30000;
  499. private const int S_OK = 0;
  500. private const int S_FALSE = 1;
  501. private static int cbMenuItemInfo = Marshal.SizeOf(typeof(MENUITEMINFO));
  502. private static int cbInvokeCommand = Marshal.SizeOf(typeof(CMINVOKECOMMANDINFOEX));
  503. #endregion
  504. #region DLL Import
  505. // Retrieves the IShellFolder interface for the desktop folder, which is the root of the Shell's namespace.
  506. [DllImport("shell32.dll")]
  507. private static extern Int32 SHGetDesktopFolder(out IntPtr ppshf);
  508. // Takes a STRRET structure returned by IShellFolder::GetDisplayNameOf, converts it to a string, and places the result in a buffer.
  509. [DllImport("shlwapi.dll", EntryPoint = "StrRetToBuf", ExactSpelling = false, CharSet = CharSet.Auto, SetLastError = true)]
  510. private static extern Int32 StrRetToBuf(IntPtr pstr, IntPtr pidl, StringBuilder pszBuf, int cchBuf);
  511. // The TrackPopupMenuEx function displays a shortcut menu at the specified location and tracks the selection of items on the shortcut menu. The shortcut menu can appear anywhere on the screen.
  512. [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
  513. private static extern uint TrackPopupMenuEx(IntPtr hmenu, TPM flags, int x, int y, IntPtr hwnd, IntPtr lptpm);
  514. // The CreatePopupMenu function creates a drop-down menu, submenu, or shortcut menu. The menu is initially empty. You can insert or append menu items by using the InsertMenuItem function. You can also use the InsertMenu function to insert menu items and the AppendMenu function to append menu items.
  515. [DllImport("user32", SetLastError = true, CharSet = CharSet.Auto)]
  516. private static extern IntPtr CreatePopupMenu();
  517. // The DestroyMenu function destroys the specified menu and frees any memory that the menu occupies.
  518. [DllImport("user32", SetLastError = true, CharSet = CharSet.Auto)]
  519. private static extern bool DestroyMenu(IntPtr hMenu);
  520. // Determines the default menu item on the specified menu
  521. [DllImport("user32", SetLastError = true, CharSet = CharSet.Auto)]
  522. private static extern int GetMenuDefaultItem(IntPtr hMenu, bool fByPos, uint gmdiFlags);
  523. #endregion
  524. #region Shell GUIDs
  525. private static Guid IID_IShellFolder = new Guid("{000214E6-0000-0000-C000-000000000046}");
  526. private static Guid IID_IContextMenu = new Guid("{000214e4-0000-0000-c000-000000000046}");
  527. private static Guid IID_IContextMenu2 = new Guid("{000214f4-0000-0000-c000-000000000046}");
  528. private static Guid IID_IContextMenu3 = new Guid("{bcfce0a0-ec17-11d0-8d10-00a0c90f2719}");
  529. #endregion
  530. #region Structs
  531. [StructLayout(LayoutKind.Sequential)]
  532. private struct CWPSTRUCT
  533. {
  534. public IntPtr lparam;
  535. public IntPtr wparam;
  536. public int message;
  537. public IntPtr hwnd;
  538. }
  539. // Contains extended information about a shortcut menu command
  540. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
  541. private struct CMINVOKECOMMANDINFOEX
  542. {
  543. public int cbSize;
  544. public CMIC fMask;
  545. public IntPtr hwnd;
  546. public IntPtr lpVerb;
  547. [MarshalAs(UnmanagedType.LPStr)]
  548. public string lpParameters;
  549. [MarshalAs(UnmanagedType.LPStr)]
  550. public string lpDirectory;
  551. public SW nShow;
  552. public int dwHotKey;
  553. public IntPtr hIcon;
  554. [MarshalAs(UnmanagedType.LPStr)]
  555. public string lpTitle;
  556. public IntPtr lpVerbW;
  557. [MarshalAs(UnmanagedType.LPWStr)]
  558. public string lpParametersW;
  559. [MarshalAs(UnmanagedType.LPWStr)]
  560. public string lpDirectoryW;
  561. [MarshalAs(UnmanagedType.LPWStr)]
  562. public string lpTitleW;
  563. public POINT ptInvoke;
  564. }
  565. // Contains information about a menu item
  566. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
  567. private struct MENUITEMINFO
  568. {
  569. public MENUITEMINFO(string text)
  570. {
  571. cbSize = cbMenuItemInfo;
  572. dwTypeData = text;
  573. cch = text.Length;
  574. fMask = 0;
  575. fType = 0;
  576. fState = 0;
  577. wID = 0;
  578. hSubMenu = IntPtr.Zero;
  579. hbmpChecked = IntPtr.Zero;
  580. hbmpUnchecked = IntPtr.Zero;
  581. dwItemData = IntPtr.Zero;
  582. hbmpItem = IntPtr.Zero;
  583. }
  584. public int cbSize;
  585. public MIIM fMask;
  586. public MFT fType;
  587. public MFS fState;
  588. public uint wID;
  589. public IntPtr hSubMenu;
  590. public IntPtr hbmpChecked;
  591. public IntPtr hbmpUnchecked;
  592. public IntPtr dwItemData;
  593. [MarshalAs(UnmanagedType.LPTStr)]
  594. public string dwTypeData;
  595. public int cch;
  596. public IntPtr hbmpItem;
  597. }
  598. // A generalized global memory handle used for data transfer operations by the
  599. // IAdviseSink, IDataObject, and IOleCache interfaces
  600. [StructLayout(LayoutKind.Sequential)]
  601. private struct STGMEDIUM
  602. {
  603. public TYMED tymed;
  604. public IntPtr hBitmap;
  605. public IntPtr hMetaFilePict;
  606. public IntPtr hEnhMetaFile;
  607. public IntPtr hGlobal;
  608. public IntPtr lpszFileName;
  609. public IntPtr pstm;
  610. public IntPtr pstg;
  611. public IntPtr pUnkForRelease;
  612. }
  613. // Defines the x- and y-coordinates of a point
  614. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
  615. private struct POINT
  616. {
  617. public POINT(int x, int y)
  618. {
  619. this.x = x;
  620. this.y = y;
  621. }
  622. public int x;
  623. public int y;
  624. }
  625. #endregion
  626. #region Enums
  627. // Defines the values used with the IShellFolder::GetDisplayNameOf and IShellFolder::SetNameOf
  628. // methods to specify the type of file or folder names used by those methods
  629. [Flags]
  630. private enum SHGNO
  631. {
  632. NORMAL = 0x0000,
  633. INFOLDER = 0x0001,
  634. FOREDITING = 0x1000,
  635. FORADDRESSBAR = 0x4000,
  636. FORPARSING = 0x8000
  637. }
  638. // The attributes that the caller is requesting, when calling IShellFolder::GetAttributesOf
  639. [Flags]
  640. private enum SFGAO : uint
  641. {
  642. BROWSABLE = 0x8000000,
  643. CANCOPY = 1,
  644. CANDELETE = 0x20,
  645. CANLINK = 4,
  646. CANMONIKER = 0x400000,
  647. CANMOVE = 2,
  648. CANRENAME = 0x10,
  649. CAPABILITYMASK = 0x177,
  650. COMPRESSED = 0x4000000,
  651. CONTENTSMASK = 0x80000000,
  652. DISPLAYATTRMASK = 0xfc000,
  653. DROPTARGET = 0x100,
  654. ENCRYPTED = 0x2000,
  655. FILESYSANCESTOR = 0x10000000,
  656. FILESYSTEM = 0x40000000,
  657. FOLDER = 0x20000000,
  658. GHOSTED = 0x8000,
  659. HASPROPSHEET = 0x40,
  660. HASSTORAGE = 0x400000,
  661. HASSUBFOLDER = 0x80000000,
  662. HIDDEN = 0x80000,
  663. ISSLOW = 0x4000,
  664. LINK = 0x10000,
  665. NEWCONTENT = 0x200000,
  666. NONENUMERATED = 0x100000,
  667. READONLY = 0x40000,
  668. REMOVABLE = 0x2000000,
  669. SHARE = 0x20000,
  670. STORAGE = 8,
  671. STORAGEANCESTOR = 0x800000,
  672. STORAGECAPMASK = 0x70c50008,
  673. STREAM = 0x400000,
  674. VALIDATE = 0x1000000
  675. }
  676. // Determines the type of items included in an enumeration.
  677. // These values are used with the IShellFolder::EnumObjects method
  678. [Flags]
  679. private enum SHCONTF
  680. {
  681. FOLDERS = 0x0020,
  682. NONFOLDERS = 0x0040,
  683. INCLUDEHIDDEN = 0x0080,
  684. INIT_ON_FIRST_NEXT = 0x0100,
  685. NETPRINTERSRCH = 0x0200,
  686. SHAREABLE = 0x0400,
  687. STORAGE = 0x0800,
  688. }
  689. // Specifies how the shortcut menu can be changed when calling IContextMenu::QueryContextMenu
  690. [Flags]
  691. private enum CMF : uint
  692. {
  693. NORMAL = 0x00000000,
  694. DEFAULTONLY = 0x00000001,
  695. VERBSONLY = 0x00000002,
  696. EXPLORE = 0x00000004,
  697. NOVERBS = 0x00000008,
  698. CANRENAME = 0x00000010,
  699. NODEFAULT = 0x00000020,
  700. INCLUDESTATIC = 0x00000040,
  701. EXTENDEDVERBS = 0x00000100,
  702. RESERVED = 0xffff0000
  703. }
  704. // Flags specifying the information to return when calling IContextMenu::GetCommandString
  705. [Flags]
  706. private enum GCS : uint
  707. {
  708. VERBA = 0,
  709. HELPTEXTA = 1,
  710. VALIDATEA = 2,
  711. VERBW = 4,
  712. HELPTEXTW = 5,
  713. VALIDATEW = 6
  714. }
  715. // Specifies how TrackPopupMenuEx positions the shortcut menu horizontally
  716. [Flags]
  717. private enum TPM : uint
  718. {
  719. LEFTBUTTON = 0x0000,
  720. RIGHTBUTTON = 0x0002,
  721. LEFTALIGN = 0x0000,
  722. CENTERALIGN = 0x0004,
  723. RIGHTALIGN = 0x0008,
  724. TOPALIGN = 0x0000,
  725. VCENTERALIGN = 0x0010,
  726. BOTTOMALIGN = 0x0020,
  727. HORIZONTAL = 0x0000,
  728. VERTICAL = 0x0040,
  729. NONOTIFY = 0x0080,
  730. RETURNCMD = 0x0100,
  731. RECURSE = 0x0001,
  732. HORPOSANIMATION = 0x0400,
  733. HORNEGANIMATION = 0x0800,
  734. VERPOSANIMATION = 0x1000,
  735. VERNEGANIMATION = 0x2000,
  736. NOANIMATION = 0x4000,
  737. LAYOUTRTL = 0x8000
  738. }
  739. // The cmd for a custom added menu item
  740. private enum CMD_CUSTOM
  741. {
  742. ExpandCollapse = (int)CMD_LAST + 1
  743. }
  744. // Flags used with the CMINVOKECOMMANDINFOEX structure
  745. [Flags]
  746. private enum CMIC : uint
  747. {
  748. HOTKEY = 0x00000020,
  749. ICON = 0x00000010,
  750. FLAG_NO_UI = 0x00000400,
  751. UNICODE = 0x00004000,
  752. NO_CONSOLE = 0x00008000,
  753. ASYNCOK = 0x00100000,
  754. NOZONECHECKS = 0x00800000,
  755. SHIFT_DOWN = 0x10000000,
  756. CONTROL_DOWN = 0x40000000,
  757. FLAG_LOG_USAGE = 0x04000000,
  758. PTINVOKE = 0x20000000
  759. }
  760. // Specifies how the window is to be shown
  761. [Flags]
  762. private enum SW
  763. {
  764. HIDE = 0,
  765. SHOWNORMAL = 1,
  766. NORMAL = 1,
  767. SHOWMINIMIZED = 2,
  768. SHOWMAXIMIZED = 3,
  769. MAXIMIZE = 3,
  770. SHOWNOACTIVATE = 4,
  771. SHOW = 5,
  772. MINIMIZE = 6,
  773. SHOWMINNOACTIVE = 7,
  774. SHOWNA = 8,
  775. RESTORE = 9,
  776. SHOWDEFAULT = 10,
  777. }
  778. // Window message flags
  779. [Flags]
  780. private enum WM : uint
  781. {
  782. ACTIVATE = 0x6,
  783. ACTIVATEAPP = 0x1C,
  784. AFXFIRST = 0x360,
  785. AFXLAST = 0x37F,
  786. APP = 0x8000,
  787. ASKCBFORMATNAME = 0x30C,
  788. CANCELJOURNAL = 0x4B,
  789. CANCELMODE = 0x1F,
  790. CAPTURECHANGED = 0x215,
  791. CHANGECBCHAIN = 0x30D,
  792. CHAR = 0x102,
  793. CHARTOITEM = 0x2F,
  794. CHILDACTIVATE = 0x22,
  795. CLEAR = 0x303,
  796. CLOSE = 0x10,
  797. COMMAND = 0x111,
  798. COMPACTING = 0x41,
  799. COMPAREITEM = 0x39,
  800. CONTEXTMENU = 0x7B,
  801. COPY = 0x301,
  802. COPYDATA = 0x4A,
  803. CREATE = 0x1,
  804. CTLCOLORBTN = 0x135,
  805. CTLCOLORDLG = 0x136,
  806. CTLCOLOREDIT = 0x133,
  807. CTLCOLORLISTBOX = 0x134,
  808. CTLCOLORMSGBOX = 0x132,
  809. CTLCOLORSCROLLBAR = 0x137,
  810. CTLCOLORSTATIC = 0x138,
  811. CUT = 0x300,
  812. DEADCHAR = 0x103,
  813. DELETEITEM = 0x2D,
  814. DESTROY = 0x2,
  815. DESTROYCLIPBOARD = 0x307,
  816. DEVICECHANGE = 0x219,
  817. DEVMODECHANGE = 0x1B,
  818. DISPLAYCHANGE = 0x7E,
  819. DRAWCLIPBOARD = 0x308,
  820. DRAWITEM = 0x2B,
  821. DROPFILES = 0x233,
  822. ENABLE = 0xA,
  823. ENDSESSION = 0x16,
  824. ENTERIDLE = 0x121,
  825. ENTERMENULOOP = 0x211,
  826. ENTERSIZEMOVE = 0x231,
  827. ERASEBKGND = 0x14,
  828. EXITMENULOOP = 0x212,
  829. EXITSIZEMOVE = 0x232,
  830. FONTCHANGE = 0x1D,
  831. GETDLGCODE = 0x87,
  832. GETFONT = 0x31,
  833. GETHOTKEY = 0x33,
  834. GETICON = 0x7F,
  835. GETMINMAXINFO = 0x24,
  836. GETOBJECT = 0x3D,
  837. GETSYSMENU = 0x313,
  838. GETTEXT = 0xD,
  839. GETTEXTLENGTH = 0xE,
  840. HANDHELDFIRST = 0x358,
  841. HANDHELDLAST = 0x35F,
  842. HELP = 0x53,
  843. HOTKEY = 0x312,
  844. HSCROLL = 0x114,
  845. HSCROLLCLIPBOARD = 0x30E,
  846. ICONERASEBKGND = 0x27,
  847. IME_CHAR = 0x286,
  848. IME_COMPOSITION = 0x10F,
  849. IME_COMPOSITIONFULL = 0x284,
  850. IME_CONTROL = 0x283,
  851. IME_ENDCOMPOSITION = 0x10E,
  852. IME_KEYDOWN = 0x290,
  853. IME_KEYLAST = 0x10F,
  854. IME_KEYUP = 0x291,
  855. IME_NOTIFY = 0x282,
  856. IME_REQUEST = 0x288,
  857. IME_SELECT = 0x285,
  858. IME_SETCONTEXT = 0x281,
  859. IME_STARTCOMPOSITION = 0x10D,
  860. INITDIALOG = 0x110,
  861. INITMENU = 0x116,
  862. INITMENUPOPUP = 0x117,
  863. INPUTLANGCHANGE = 0x51,
  864. INPUTLANGCHANGEREQUEST = 0x50,
  865. KEYDOWN = 0x100,
  866. KEYFIRST = 0x100,
  867. KEYLAST = 0x108,
  868. KEYUP = 0x101,
  869. KILLFOCUS = 0x8,
  870. LBUTTONDBLCLK = 0x203,
  871. LBUTTONDOWN = 0x201,
  872. LBUTTONUP = 0x202,
  873. LVM_GETEDITCONTROL = 0x1018,
  874. LVM_SETIMAGELIST = 0x1003,
  875. MBUTTONDBLCLK = 0x209,
  876. MBUTTONDOWN = 0x207,
  877. MBUTTONUP = 0x208,
  878. MDIACTIVATE = 0x222,
  879. MDICASCADE = 0x227,
  880. MDICREATE = 0x220,
  881. MDIDESTROY = 0x221,
  882. MDIGETACTIVE = 0x229,
  883. MDIICONARRANGE = 0x228,
  884. MDIMAXIMIZE = 0x225,
  885. MDINEXT = 0x224,
  886. MDIREFRESHMENU = 0x234,
  887. MDIRESTORE = 0x223,
  888. MDISETMENU = 0x230,
  889. MDITILE = 0x226,
  890. MEASUREITEM = 0x2C,
  891. MENUCHAR = 0x120,
  892. MENUCOMMAND = 0x126,
  893. MENUDRAG = 0x123,
  894. MENUGETOBJECT = 0x124,
  895. MENURBUTTONUP = 0x122,
  896. MENUSELECT = 0x11F,
  897. MOUSEACTIVATE = 0x21,
  898. MOUSEFIRST = 0x200,
  899. MOUSEHOVER = 0x2A1,
  900. MOUSELAST = 0x20A,
  901. MOUSELEAVE = 0x2A3,
  902. MOUSEMOVE = 0x200,
  903. MOUSEWHEEL = 0x20A,
  904. MOVE = 0x3,
  905. MOVING = 0x216,
  906. NCACTIVATE = 0x86,
  907. NCCALCSIZE = 0x83,
  908. NCCREATE = 0x81,
  909. NCDESTROY = 0x82,
  910. NCHITTEST = 0x84,
  911. NCLBUTTONDBLCLK = 0xA3,
  912. NCLBUTTONDOWN = 0xA1,
  913. NCLBUTTONUP = 0xA2,
  914. NCMBUTTONDBLCLK = 0xA9,
  915. NCMBUTTONDOWN = 0xA7,
  916. NCMBUTTONUP = 0xA8,
  917. NCMOUSEHOVER = 0x2A0,
  918. NCMOUSELEAVE = 0x2A2,
  919. NCMOUSEMOVE = 0xA0,
  920. NCPAINT = 0x85,
  921. NCRBUTTONDBLCLK = 0xA6,
  922. NCRBUTTONDOWN = 0xA4,
  923. NCRBUTTONUP = 0xA5,
  924. NEXTDLGCTL = 0x28,
  925. NEXTMENU = 0x213,
  926. NOTIFY = 0x4E,
  927. NOTIFYFORMAT = 0x55,
  928. NULL = 0x0,
  929. PAINT = 0xF,
  930. PAINTCLIPBOARD = 0x309,
  931. PAINTICON = 0x26,
  932. PALETTECHANGED = 0x311,
  933. PALETTEISCHANGING = 0x310,
  934. PARENTNOTIFY = 0x210,
  935. PASTE = 0x302,
  936. PENWINFIRST = 0x380,
  937. PENWINLAST = 0x38F,
  938. POWER = 0x48,
  939. PRINT = 0x317,
  940. PRINTCLIENT = 0x318,
  941. QUERYDRAGICON = 0x37,
  942. QUERYENDSESSION = 0x11,
  943. QUERYNEWPALETTE = 0x30F,
  944. QUERYOPEN = 0x13,
  945. QUEUESYNC = 0x23,
  946. QUIT = 0x12,
  947. RBUTTONDBLCLK = 0x206,
  948. RBUTTONDOWN = 0x204,
  949. RBUTTONUP = 0x205,
  950. RENDERALLFORMATS = 0x306,
  951. RENDERFORMAT = 0x305,
  952. SETCURSOR = 0x20,
  953. SETFOCUS = 0x7,
  954. SETFONT = 0x30,
  955. SETHOTKEY = 0x32,
  956. SETICON = 0x80,
  957. SETMARGINS = 0xD3,
  958. SETREDRAW = 0xB,
  959. SETTEXT = 0xC,
  960. SETTINGCHANGE = 0x1A,
  961. SHOWWINDOW = 0x18,
  962. SIZE = 0x5,
  963. SIZECLIPBOARD = 0x30B,
  964. SIZING = 0x214,
  965. SPOOLERSTATUS = 0x2A,
  966. STYLECHANGED = 0x7D,
  967. STYLECHANGING = 0x7C,
  968. SYNCPAINT = 0x88,
  969. SYSCHAR = 0x106,
  970. SYSCOLORCHANGE = 0x15,
  971. SYSCOMMAND = 0x112,
  972. SYSDEADCHAR = 0x107,
  973. SYSKEYDOWN = 0x104,
  974. SYSKEYUP = 0x105,
  975. TCARD = 0x52,
  976. TIMECHANGE = 0x1E,
  977. TIMER = 0x113,
  978. TVM_GETEDITCONTROL = 0x110F,
  979. TVM_SETIMAGELIST = 0x1109,
  980. UNDO = 0x304,
  981. UNINITMENUPOPUP = 0x125,
  982. USER = 0x400,
  983. USERCHANGED = 0x54,
  984. VKEYTOITEM = 0x2E,
  985. VSCROLL = 0x115,
  986. VSCROLLCLIPBOARD = 0x30A,
  987. WINDOWPOSCHANGED = 0x47,
  988. WINDOWPOSCHANGING = 0x46,
  989. WININICHANGE = 0x1A,
  990. SH_NOTIFY = 0x0401
  991. }
  992. // Specifies the content of the new menu item
  993. [Flags]
  994. private enum MFT : uint
  995. {
  996. GRAYED = 0x00000003,
  997. DISABLED = 0x00000003,
  998. CHECKED = 0x00000008,
  999. SEPARATOR = 0x00000800,
  1000. RADIOCHECK = 0x00000200,
  1001. BITMAP = 0x00000004,
  1002. OWNERDRAW = 0x00000100,
  1003. MENUBARBREAK = 0x00000020,
  1004. MENUBREAK = 0x00000040,
  1005. RIGHTORDER = 0x00002000,
  1006. BYCOMMAND = 0x00000000,
  1007. BYPOSITION = 0x00000400,
  1008. POPUP = 0x00000010
  1009. }
  1010. // Specifies the state of the new menu item
  1011. [Flags]
  1012. private enum MFS : uint
  1013. {
  1014. GRAYED = 0x00000003,
  1015. DISABLED = 0x00000003,
  1016. CHECKED = 0x00000008,
  1017. HILITE = 0x00000080,
  1018. ENABLED = 0x00000000,
  1019. UNCHECKED = 0x00000000,
  1020. UNHILITE = 0x00000000,
  1021. DEFAULT = 0x00001000
  1022. }
  1023. // Specifies the content of the new menu item
  1024. [Flags]
  1025. private enum MIIM : uint
  1026. {
  1027. BITMAP = 0x80,
  1028. CHECKMARKS = 0x08,
  1029. DATA = 0x20,
  1030. FTYPE = 0x100,
  1031. ID = 0x02,
  1032. STATE = 0x01,
  1033. STRING = 0x40,
  1034. SUBMENU = 0x04,
  1035. TYPE = 0x10
  1036. }
  1037. // Indicates the type of storage medium being used in a data transfer
  1038. [Flags]
  1039. private enum TYMED
  1040. {
  1041. ENHMF = 0x40,
  1042. FILE = 2,
  1043. GDI = 0x10,
  1044. HGLOBAL = 1,
  1045. ISTORAGE = 8,
  1046. ISTREAM = 4,
  1047. MFPICT = 0x20,
  1048. NULL = 0
  1049. }
  1050. #endregion
  1051. #region IShellFolder
  1052. [ComImport]
  1053. [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
  1054. [Guid("000214E6-0000-0000-C000-000000000046")]
  1055. private interface IShellFolder
  1056. {
  1057. // Translates a file object's or folder's display name into an item identifier list.
  1058. // Return value: error code, if any
  1059. [PreserveSig]
  1060. Int32 ParseDisplayName(
  1061. IntPtr hwnd,
  1062. IntPtr pbc,
  1063. [MarshalAs(UnmanagedType.LPWStr)]
  1064. string pszDisplayName,
  1065. ref uint pchEaten,
  1066. out IntPtr ppidl,
  1067. ref SFGAO pdwAttributes);
  1068. // Allows a client to determine the contents of a folder by creating an item
  1069. // identifier enumeration object and returning its IEnumIDList interface.
  1070. // Return value: error code, if any
  1071. [PreserveSig]
  1072. Int32 EnumObjects(
  1073. IntPtr hwnd,
  1074. SHCONTF grfFlags,
  1075. out IntPtr enumIDList);
  1076. // Retrieves an IShellFolder object for a subfolder.
  1077. // Return value: error code, if any
  1078. [PreserveSig]
  1079. Int32 BindToObject(
  1080. IntPtr pidl,
  1081. IntPtr pbc,
  1082. ref Guid riid,
  1083. out IntPtr ppv);
  1084. // Requests a pointer to an object's storage interface.
  1085. // Return value: error code, if any
  1086. [PreserveSig]
  1087. Int32 BindToStorage(
  1088. IntPtr pidl,
  1089. IntPtr pbc,
  1090. ref Guid riid,
  1091. out IntPtr ppv);
  1092. // Determines the relative order of two file objects or folders, given their
  1093. // item identifier lists. Return value: If this method is successful, the
  1094. // CODE field of the HRESULT contains one of the following values (the code
  1095. // can be retrived using the helper function GetHResultCode): Negative A
  1096. // negative return value indicates that the first item should precede
  1097. // the second (pidl1 < pidl2).
  1098. // Positive A positive return value indicates that the first item should
  1099. // follow the second (pidl1 > pidl2). Zero A return value of zero
  1100. // indicates that the two items are the same (pidl1 = pidl2).
  1101. [PreserveSig]
  1102. Int32 CompareIDs(
  1103. IntPtr lParam,
  1104. IntPtr pidl1,
  1105. IntPtr pidl2);
  1106. // Requests an object that can be used to obtain information from or interact
  1107. // with a folder object.
  1108. // Return value: error code, if any
  1109. [PreserveSig]
  1110. Int32 CreateViewObject(
  1111. IntPtr hwndOwner,
  1112. Guid riid,
  1113. out IntPtr ppv);
  1114. // Retrieves the attributes of one or more file objects or subfolders.
  1115. // Return value: error code, if any
  1116. [PreserveSig]
  1117. Int32 GetAttributesOf(
  1118. uint cidl,
  1119. [MarshalAs(UnmanagedType.LPArray)]
  1120. IntPtr[] apidl,
  1121. ref SFGAO rgfInOut);
  1122. // Retrieves an OLE interface that can be used to carry out actions on the
  1123. // specified file objects or folders.
  1124. // Return value: error code, if any
  1125. [PreserveSig]
  1126. Int32 GetUIObjectOf(
  1127. IntPtr hwndOwner,
  1128. uint cidl,
  1129. [MarshalAs(UnmanagedType.LPArray)]
  1130. IntPtr[] apidl,
  1131. ref Guid riid,
  1132. IntPtr rgfReserved,
  1133. out IntPtr ppv);
  1134. // Retrieves the display name for the specified file object or subfolder.
  1135. // Return value: error code, if any
  1136. [PreserveSig()]
  1137. Int32 GetDisplayNameOf(
  1138. IntPtr pidl,
  1139. SHGNO uFlags,
  1140. IntPtr lpName);
  1141. // Sets the display name of a file object or subfolder, changing the item
  1142. // identifier in the process.
  1143. // Return value: error code, if any
  1144. [PreserveSig]
  1145. Int32 SetNameOf(
  1146. IntPtr hwnd,
  1147. IntPtr pidl,
  1148. [MarshalAs(UnmanagedType.LPWStr)]
  1149. string pszName,
  1150. SHGNO uFlags,
  1151. out IntPtr ppidlOut);
  1152. }
  1153. #endregion
  1154. #region IContextMenu
  1155. [ComImport()]
  1156. [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
  1157. [GuidAttribute("000214e4-0000-0000-c000-000000000046")]
  1158. private interface IContextMenu
  1159. {
  1160. // Adds commands to a shortcut menu
  1161. [PreserveSig()]
  1162. Int32 QueryContextMenu(
  1163. IntPtr hmenu,
  1164. uint iMenu,
  1165. uint idCmdFirst,
  1166. uint idCmdLast,
  1167. CMF uFlags);
  1168. // Carries out the command associated with a shortcut menu item
  1169. [PreserveSig()]
  1170. Int32 InvokeCommand(
  1171. ref CMINVOKECOMMANDINFOEX info);
  1172. // Retrieves information about a shortcut menu command,
  1173. // including the help string and the language-independent,
  1174. // or canonical, name for the command
  1175. [PreserveSig()]
  1176. Int32 GetCommandString(
  1177. uint idcmd,
  1178. GCS uflags,
  1179. uint reserved,
  1180. [MarshalAs(UnmanagedType.LPArray)]
  1181. byte[] commandstring,
  1182. int cch);
  1183. }
  1184. [ComImport, Guid("000214f4-0000-0000-c000-000000000046")]
  1185. [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
  1186. private interface IContextMenu2
  1187. {
  1188. // Adds commands to a shortcut menu
  1189. [PreserveSig()]
  1190. Int32 QueryContextMenu(
  1191. IntPtr hmenu,
  1192. uint iMenu,
  1193. uint idCmdFirst,
  1194. uint idCmdLast,
  1195. CMF uFlags);
  1196. // Carries out the command associated with a shortcut menu item
  1197. [PreserveSig()]
  1198. Int32 InvokeCommand(
  1199. ref CMINVOKECOMMANDINFOEX info);
  1200. // Retrieves information about a shortcut menu command,
  1201. // including the help string and the language-independent,
  1202. // or canonical, name for the command
  1203. [PreserveSig()]
  1204. Int32 GetCommandString(
  1205. uint idcmd,
  1206. GCS uflags,
  1207. uint reserved,
  1208. [MarshalAs(UnmanagedType.LPWStr)]
  1209. StringBuilder commandstring,
  1210. int cch);
  1211. // Allows client objects of the IContextMenu interface to
  1212. // handle messages associated with owner-drawn menu items
  1213. [PreserveSig]
  1214. Int32 HandleMenuMsg(
  1215. uint uMsg,
  1216. IntPtr wParam,
  1217. IntPtr lParam);
  1218. }
  1219. [ComImport, Guid("bcfce0a0-ec17-11d0-8d10-00a0c90f2719")]
  1220. [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
  1221. private interface IContextMenu3
  1222. {
  1223. // Adds commands to a shortcut menu
  1224. [PreserveSig()]
  1225. Int32 QueryContextMenu(
  1226. IntPtr hmenu,
  1227. uint iMenu,
  1228. uint idCmdFirst,
  1229. uint idCmdLast,
  1230. CMF uFlags);
  1231. // Carries out the command associated with a shortcut menu item
  1232. [PreserveSig()]
  1233. Int32 InvokeCommand(
  1234. ref CMINVOKECOMMANDINFOEX info);
  1235. // Retrieves information about a shortcut menu command,
  1236. // including the help string and the language-independent,
  1237. // or canonical, name for the command
  1238. [PreserveSig()]
  1239. Int32 GetCommandString(
  1240. uint idcmd,
  1241. GCS uflags,
  1242. uint reserved,
  1243. [MarshalAs(UnmanagedType.LPWStr)]
  1244. StringBuilder commandstring,
  1245. int cch);
  1246. // Allows client objects of the IContextMenu interface to
  1247. // handle messages associated with owner-drawn menu items
  1248. [PreserveSig]
  1249. Int32 HandleMenuMsg(
  1250. uint uMsg,
  1251. IntPtr wParam,
  1252. IntPtr lParam);
  1253. // Allows client objects of the IContextMenu3 interface to
  1254. // handle messages associated with owner-drawn menu items
  1255. [PreserveSig]
  1256. Int32 HandleMenuMsg2(
  1257. uint uMsg,
  1258. IntPtr wParam,
  1259. IntPtr lParam,
  1260. IntPtr plResult);
  1261. }
  1262. #endregion
  1263. }
  1264. #region ShellContextMenuException
  1265. public class ShellContextMenuException : Exception
  1266. {
  1267. /// <summary>Default contructor</summary>
  1268. public ShellContextMenuException()
  1269. {
  1270. }
  1271. /// <summary>Constructor with message</summary>
  1272. /// <param name="message">Message</param>
  1273. public ShellContextMenuException(string message)
  1274. : base(message)
  1275. {
  1276. }
  1277. }
  1278. #endregion
  1279. #region Class HookEventArgs
  1280. public class HookEventArgs : EventArgs
  1281. {
  1282. public int HookCode; // Hook code
  1283. public IntPtr wParam; // WPARAM argument
  1284. public IntPtr lParam; // LPARAM argument
  1285. }
  1286. #endregion
  1287. #region Enum HookType
  1288. // Hook Types
  1289. public enum HookType : int
  1290. {
  1291. WH_JOURNALRECORD = 0,
  1292. WH_JOURNALPLAYBACK = 1,
  1293. WH_KEYBOARD = 2,
  1294. WH_GETMESSAGE = 3,
  1295. WH_CALLWNDPROC = 4,
  1296. WH_CBT = 5,
  1297. WH_SYSMSGFILTER = 6,
  1298. WH_MOUSE = 7,
  1299. WH_HARDWARE = 8,
  1300. WH_DEBUG = 9,
  1301. WH_SHELL = 10,
  1302. WH_FOREGROUNDIDLE = 11,
  1303. WH_CALLWNDPROCRET = 12,
  1304. WH_KEYBOARD_LL = 13,
  1305. WH_MOUSE_LL = 14
  1306. }
  1307. #endregion
  1308. #region Class LocalWindowsHook
  1309. public class LocalWindowsHook
  1310. {
  1311. // ************************************************************************
  1312. // Filter function delegate
  1313. public delegate int HookProc(int code, IntPtr wParam, IntPtr lParam);
  1314. // ************************************************************************
  1315. // ************************************************************************
  1316. // Internal properties
  1317. protected IntPtr m_hhook = IntPtr.Zero;
  1318. protected HookProc m_filterFunc = null;
  1319. protected HookType m_hookType;
  1320. // ************************************************************************
  1321. // ************************************************************************
  1322. // Event delegate
  1323. public delegate void HookEventHandler(object sender, HookEventArgs e);
  1324. // ************************************************************************
  1325. // ************************************************************************
  1326. // Event: HookInvoked
  1327. public event HookEventHandler HookInvoked;
  1328. protected void OnHookInvoked(HookEventArgs e)
  1329. {
  1330. if (HookInvoked != null)
  1331. HookInvoked(this, e);
  1332. }
  1333. // ************************************************************************
  1334. // ************************************************************************
  1335. // Class constructor(s)
  1336. public LocalWindowsHook(HookType hook)
  1337. {
  1338. m_hookType = hook;
  1339. m_filterFunc = new HookProc(this.CoreHookProc);
  1340. }
  1341. public LocalWindowsHook(HookType hook, HookProc func)
  1342. {
  1343. m_hookType = hook;
  1344. m_filterFunc = func;
  1345. }
  1346. // ************************************************************************
  1347. // ************************************************************************
  1348. // Default filter function
  1349. protected int CoreHookProc(int code, IntPtr wParam, IntPtr lParam)
  1350. {
  1351. if (code < 0)
  1352. return CallNextHookEx(m_hhook, code, wParam, lParam);
  1353. // Let clients determine what to do
  1354. HookEventArgs e = new HookEventArgs();
  1355. e.HookCode = code;
  1356. e.wParam = wParam;
  1357. e.lParam = lParam;
  1358. OnHookInvoked(e);
  1359. // Yield to the next hook in the chain
  1360. return CallNextHookEx(m_hhook, code, wParam, lParam);
  1361. }
  1362. // ************************************************************************
  1363. // ************************************************************************
  1364. // Install the hook
  1365. public void Install()
  1366. {
  1367. m_hhook = SetWindowsHookEx(
  1368. m_hookType,
  1369. m_filterFunc,
  1370. IntPtr.Zero,
  1371. (int)AppDomain.GetCurrentThreadId());
  1372. }
  1373. // ************************************************************************
  1374. // ************************************************************************
  1375. // Uninstall the hook
  1376. public void Uninstall()
  1377. {
  1378. UnhookWindowsHookEx(m_hhook);
  1379. }
  1380. // ************************************************************************
  1381. #region Win32 Imports
  1382. // ************************************************************************
  1383. // Win32: SetWindowsHookEx()
  1384. [DllImport("user32.dll")]
  1385. protected static extern IntPtr SetWindowsHookEx(HookType code,
  1386. HookProc func,
  1387. IntPtr hInstance,
  1388. int threadID);
  1389. // ************************************************************************
  1390. // ************************************************************************
  1391. // Win32: UnhookWindowsHookEx()
  1392. [DllImport("user32.dll")]
  1393. protected static extern int UnhookWindowsHookEx(IntPtr hhook);
  1394. // ************************************************************************
  1395. // ************************************************************************
  1396. // Win32: CallNextHookEx()
  1397. [DllImport("user32.dll")]
  1398. protected static extern int CallNextHookEx(IntPtr hhook,
  1399. int code, IntPtr wParam, IntPtr lParam);
  1400. // ************************************************************************
  1401. #endregion
  1402. }
  1403. #endregion
  1404. #region ShellHelper
  1405. internal static class ShellHelper
  1406. {
  1407. #region Low/High Word
  1408. /// <summary>
  1409. /// Retrieves the High Word of a WParam of a WindowMessage
  1410. /// </summary>
  1411. /// <param name="ptr">The pointer to the WParam</param>
  1412. /// <returns>The unsigned integer for the High Word</returns>
  1413. public static uint HiWord(IntPtr ptr)
  1414. {
  1415. if (((uint)ptr & 0x80000000) == 0x80000000)
  1416. return ((uint)ptr >> 16);
  1417. else
  1418. return ((uint)ptr >> 16) & 0xffff;
  1419. }
  1420. /// <summary>
  1421. /// Retrieves the Low Word of a WParam of a WindowMessage
  1422. /// </summary>
  1423. /// <param name="ptr">The pointer to the WParam</param>
  1424. /// <returns>The unsigned integer for the Low Word</returns>
  1425. public static uint LoWord(IntPtr ptr)
  1426. {
  1427. return (uint)ptr & 0xffff;
  1428. }
  1429. #endregion
  1430. }
  1431. #endregion
  1432. }