/Application/GUI/Utilities.cs

http://yet-another-music-application.googlecode.com/ · C# · 792 lines · 416 code · 129 blank · 247 comment · 96 complexity · 5adac6eafb4d56feb561359897f2415f MD5 · raw file

  1. /**
  2. * Utilities.cs
  3. *
  4. * An extension of the Utilities class in Core that provides
  5. * various GUI related utilities for the Windows 7 GUI.
  6. *
  7. * * * * * * * * *
  8. *
  9. * This code is part of the Stoffi Music Player Project.
  10. * Visit our website at: stoffiplayer.com
  11. *
  12. * This program is free software; you can redistribute it and/or
  13. * modify it under the terms of the GNU General Public License
  14. * as published by the Free Software Foundation; either version
  15. * 3 of the License, or (at your option) any later version.
  16. *
  17. * See stoffiplayer.com/license for more information.
  18. **/
  19. using System;
  20. using System.Collections.Generic;
  21. using System.Windows.Controls;
  22. using System.Diagnostics;
  23. using System.Globalization;
  24. using System.Linq;
  25. using System.Text;
  26. using System.Runtime.InteropServices;
  27. using System.Runtime.CompilerServices;
  28. using System.Windows;
  29. using System.Windows.Data;
  30. using System.Windows.Input;
  31. using System.Windows.Media;
  32. using System.Windows.Media.Imaging;
  33. using System.Media;
  34. namespace Stoffi
  35. {
  36. /// <summary>
  37. /// A utilities class with helper method for GUI related stuff
  38. /// </summary>
  39. static partial class Utilities
  40. {
  41. /// <summary>
  42. /// Extracts a specific image from an ico
  43. /// file given it's size.
  44. /// If no exact size is matched, the largest
  45. /// image will be returned.
  46. /// </summary>
  47. /// <param name="path">The path to the ico</param>
  48. /// <param name="width">The prefered width</param>
  49. /// <param name="height">The prefered height</param>
  50. /// <returns>An image from inside the ico file</returns>
  51. public static BitmapFrame GetIcoImage(string path, int width, int height)
  52. {
  53. var iconUri = new Uri(path, UriKind.RelativeOrAbsolute);
  54. try
  55. {
  56. var iconDecoder = new IconBitmapDecoder(iconUri,
  57. BitmapCreateOptions.None, BitmapCacheOption.Default);
  58. // no image found
  59. if (iconDecoder.Frames.Count == 0) return null;
  60. BitmapFrame largest = iconDecoder.Frames[0];
  61. foreach (BitmapFrame frame in iconDecoder.Frames)
  62. {
  63. if (frame.PixelHeight == height &&
  64. frame.PixelWidth == width)
  65. {
  66. return frame;
  67. }
  68. if (frame.PixelWidth * frame.PixelHeight >
  69. largest.PixelWidth * frame.PixelHeight)
  70. largest = frame;
  71. }
  72. return largest;
  73. }
  74. catch (Exception)
  75. {
  76. return null;
  77. }
  78. }
  79. /// <summary>Finds a parent of a given item on the visual tree.</summary>
  80. /// <typeparam name="T">The type of the queried item.</typeparam>
  81. /// <param name="iChild">A direct or indirect child of the queried item.</param>
  82. /// <returns>The first parent item that matches the submitted type parameter. If not matching item can be found, a null reference is being returned.</returns>
  83. public static T TryFindParent<T>(this DependencyObject iChild)
  84. where T : DependencyObject
  85. {
  86. // Get parent item.
  87. DependencyObject parentObject = GetParentObject(iChild);
  88. // We've reached the end of the tree.
  89. if (parentObject == null)
  90. return null;
  91. // Check if the parent matches the type we're looking for.
  92. // Else use recursion to proceed with next level.
  93. T parent = parentObject as T;
  94. return parent ?? TryFindParent<T>(parentObject);
  95. }
  96. /// <summary>
  97. /// This method is an alternative to WPF's <see cref="VisualTreeHelper.GetParent"/> method, which also
  98. /// supports content elements. Keep in mind that for content element, this method falls back to the logical tree of the element!
  99. /// </summary>
  100. /// <param name="iChild">The item to be processed.</param>
  101. /// <returns>The submitted item's parent, if available. Otherwise null.</returns>
  102. public static DependencyObject GetParentObject(this DependencyObject iChild)
  103. {
  104. if (iChild == null)
  105. {
  106. return null;
  107. }
  108. // Handle content elements separately.
  109. ContentElement contentElement = iChild as ContentElement;
  110. if (contentElement != null)
  111. {
  112. DependencyObject parent = ContentOperations.GetParent(contentElement);
  113. if (parent != null) return parent;
  114. FrameworkContentElement frameworkContentElement = contentElement as FrameworkContentElement;
  115. return frameworkContentElement != null ? frameworkContentElement.Parent : null;
  116. }
  117. // Also try searching for parent in framework elements (such as DockPanel, etc).
  118. FrameworkElement frameworkElement = iChild as FrameworkElement;
  119. if (frameworkElement != null)
  120. {
  121. DependencyObject parent = frameworkElement.Parent;
  122. if (parent != null) return parent;
  123. }
  124. // If it's not a ContentElement/FrameworkElement, rely on VisualTreeHelper.
  125. return VisualTreeHelper.GetParent(iChild);
  126. }
  127. /// <summary>Tries to locate a given item within the visual tree, starting with the dependency object at a given position.</summary>
  128. /// <typeparam name="T">The type of the element to be found on the visual tree of the element at the given location.</typeparam>
  129. /// <param name="iReference">The main element which is used to perform hit testing.</param>
  130. /// <param name="iPoint">The position to be evaluated on the origin.</param>
  131. public static T TryFindFromPoint<T>(this UIElement iReference, Point iPoint) where T : DependencyObject
  132. {
  133. DependencyObject element = iReference.InputHitTest(iPoint) as DependencyObject;
  134. if (element == null)
  135. {
  136. return null;
  137. }
  138. else if (element is T)
  139. return (T)element;
  140. else
  141. return TryFindParent<T>(element);
  142. }
  143. /// <summary>
  144. /// Tries to locate a child of a given item within the visual tree
  145. /// </summary>
  146. /// <typeparam name="T">The type of the element to be found on the visual tree of the parent to the element</typeparam>
  147. /// <param name="referenceVisual">A direct or indirect parent of the element to be found</param>
  148. /// <returns>The first child item that matches the submitted type parameter. If not matching item can be found, a null reference is being returned.</returns>
  149. public static T GetVisualChild<T>(Visual referenceVisual) where T : Visual
  150. {
  151. Visual child = null;
  152. for (Int32 i = 0; i < VisualTreeHelper.GetChildrenCount(referenceVisual); i++)
  153. {
  154. child = VisualTreeHelper.GetChild(referenceVisual, i) as Visual;
  155. if (child != null && (child.GetType() == typeof(T)))
  156. {
  157. break;
  158. }
  159. else if (child != null)
  160. {
  161. child = GetVisualChild<T>(child);
  162. if (child != null && (child.GetType() == typeof(T)))
  163. {
  164. break;
  165. }
  166. }
  167. }
  168. return child as T;
  169. }
  170. }
  171. #region Description converters
  172. /// <summary>
  173. ///
  174. /// </summary>
  175. class OpenFileAddDescriptionConverter : IValueConverter
  176. {
  177. private string OpenFile_NoAdd = U.T("GeneralAddPolicyDont", "Content");
  178. private string OpenFile_Add2Lib = U.T("GeneralAddPolicyLibrary", "Content");
  179. private string OpenFile_Add2Pl = U.T("GeneralAddPolicyBoth", "Content");
  180. /// <summary>
  181. ///
  182. /// </summary>
  183. /// <param name="value"></param>
  184. /// <param name="targetType"></param>
  185. /// <param name="parameter"></param>
  186. /// <param name="culture"></param>
  187. /// <returns></returns>
  188. public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  189. {
  190. if (value == null)
  191. return null;
  192. OpenAddPolicy source = (OpenAddPolicy)Enum.Parse(typeof(OpenAddPolicy), value.ToString());
  193. string target;
  194. switch (source)
  195. {
  196. case OpenAddPolicy.DoNotAdd:
  197. target = OpenFile_NoAdd;
  198. break;
  199. case OpenAddPolicy.Library:
  200. default:
  201. target = OpenFile_Add2Lib;
  202. break;
  203. case OpenAddPolicy.LibraryAndPlaylist:
  204. target = OpenFile_Add2Pl;
  205. break;
  206. }
  207. return target;
  208. }
  209. /// <summary>
  210. ///
  211. /// </summary>
  212. /// <param name="value"></param>
  213. /// <param name="targetType"></param>
  214. /// <param name="parameter"></param>
  215. /// <param name="culture"></param>
  216. /// <returns></returns>
  217. public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  218. {
  219. if (value == null)
  220. return null;
  221. string source = value.ToString();
  222. if (source == OpenFile_NoAdd)
  223. return OpenAddPolicy.DoNotAdd;
  224. else if (source == OpenFile_Add2Pl)
  225. return OpenAddPolicy.LibraryAndPlaylist;
  226. else
  227. return OpenAddPolicy.Library;
  228. }
  229. }
  230. /// <summary>
  231. ///
  232. /// </summary>
  233. class OpenFilePlayDescriptionConverter : IValueConverter
  234. {
  235. private string OpenFile_Play = U.T("GeneralPlayPolicyPlay", "Content");
  236. private string OpenFile_DoNotPlay = U.T("GeneralPlayPolicyDont", "Content");
  237. private string OpenFile_BackOfQueue = U.T("GeneralPlayPolicyBack", "Content");
  238. private string OpenFile_FrontOfQueue = U.T("GeneralPlayPolicyFront", "Content");
  239. /// <summary>
  240. ///
  241. /// </summary>
  242. /// <param name="value"></param>
  243. /// <param name="targetType"></param>
  244. /// <param name="parameter"></param>
  245. /// <param name="culture"></param>
  246. /// <returns></returns>
  247. public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  248. {
  249. if (value == null)
  250. return null;
  251. OpenPlayPolicy source = (OpenPlayPolicy)Enum.Parse(typeof(OpenPlayPolicy), value.ToString());
  252. string target;
  253. switch (source)
  254. {
  255. case OpenPlayPolicy.BackOfQueue:
  256. default:
  257. target = OpenFile_BackOfQueue;
  258. break;
  259. case OpenPlayPolicy.FrontOfQueue:
  260. target = OpenFile_FrontOfQueue;
  261. break;
  262. case OpenPlayPolicy.DoNotPlay:
  263. target = OpenFile_DoNotPlay;
  264. break;
  265. case OpenPlayPolicy.Play:
  266. target = OpenFile_Play;
  267. break;
  268. }
  269. return target;
  270. }
  271. /// <summary>
  272. ///
  273. /// </summary>
  274. /// <param name="value"></param>
  275. /// <param name="targetType"></param>
  276. /// <param name="parameter"></param>
  277. /// <param name="culture"></param>
  278. /// <returns></returns>
  279. public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  280. {
  281. if (value == null)
  282. return null;
  283. string source = value.ToString();
  284. if (source == OpenFile_Play)
  285. return OpenPlayPolicy.Play;
  286. else if (source == OpenFile_FrontOfQueue)
  287. return OpenPlayPolicy.FrontOfQueue;
  288. else if (source == OpenFile_DoNotPlay)
  289. return OpenPlayPolicy.DoNotPlay;
  290. else
  291. return OpenPlayPolicy.BackOfQueue;
  292. }
  293. }
  294. /// <summary>
  295. ///
  296. /// </summary>
  297. class UpgradePolicyDescriptionConverter : IValueConverter
  298. {
  299. private string UpgradePolicy_Automatic = U.T("GeneralUpgradePolicyAuto", "Content");
  300. private string UpgradePolicy_Notify = U.T("GeneralUpgradePolicyNotify", "Content");
  301. private string UpgradePolicy_Manual = U.T("GeneralUpgradePolicyManual", "Content");
  302. /// <summary>
  303. ///
  304. /// </summary>
  305. /// <param name="value"></param>
  306. /// <param name="targetType"></param>
  307. /// <param name="parameter"></param>
  308. /// <param name="culture"></param>
  309. /// <returns></returns>
  310. public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  311. {
  312. if (value == null)
  313. return null;
  314. UpgradePolicy source = (UpgradePolicy)Enum.Parse(typeof(UpgradePolicy), value.ToString());
  315. string target;
  316. switch (source)
  317. {
  318. case UpgradePolicy.Automatic:
  319. default:
  320. target = UpgradePolicy_Automatic;
  321. break;
  322. case UpgradePolicy.Notify:
  323. target = UpgradePolicy_Notify;
  324. break;
  325. case UpgradePolicy.Manual:
  326. target = UpgradePolicy_Manual;
  327. break;
  328. }
  329. return target;
  330. }
  331. /// <summary>
  332. ///
  333. /// </summary>
  334. /// <param name="value"></param>
  335. /// <param name="targetType"></param>
  336. /// <param name="parameter"></param>
  337. /// <param name="culture"></param>
  338. /// <returns></returns>
  339. public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  340. {
  341. if (value == null)
  342. return null;
  343. string source = value.ToString();
  344. if (source == UpgradePolicy_Notify)
  345. return UpgradePolicy.Notify;
  346. else if (source == UpgradePolicy_Manual)
  347. return UpgradePolicy.Manual;
  348. else
  349. return UpgradePolicy.Automatic;
  350. }
  351. }
  352. /// <summary>
  353. ///
  354. /// </summary>
  355. class SearchPolicyDescriptionConverter : IValueConverter
  356. {
  357. private string SearchPolicy_Global = U.T("GeneralSearchPolicyGlobal", "Content");
  358. private string SearchPolicy_Partial = U.T("GeneralSearchPolicyPartial", "Content");
  359. private string SearchPolicy_Individual = U.T("GeneralSearchPolicyIndividual", "Content");
  360. /// <summary>
  361. ///
  362. /// </summary>
  363. /// <param name="value"></param>
  364. /// <param name="targetType"></param>
  365. /// <param name="parameter"></param>
  366. /// <param name="culture"></param>
  367. /// <returns></returns>
  368. public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
  369. {
  370. if (value == null)
  371. return null;
  372. SearchPolicy source = (SearchPolicy)Enum.Parse(typeof(SearchPolicy), value.ToString());
  373. string target;
  374. switch (source)
  375. {
  376. case SearchPolicy.Global:
  377. default:
  378. target = SearchPolicy_Global;
  379. break;
  380. case SearchPolicy.Partial:
  381. target = SearchPolicy_Partial;
  382. break;
  383. case SearchPolicy.Individual:
  384. target = SearchPolicy_Individual;
  385. break;
  386. }
  387. return target;
  388. }
  389. /// <summary>
  390. ///
  391. /// </summary>
  392. /// <param name="value"></param>
  393. /// <param name="targetType"></param>
  394. /// <param name="parameter"></param>
  395. /// <param name="culture"></param>
  396. /// <returns></returns>
  397. public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
  398. {
  399. if (value == null)
  400. return null;
  401. string source = value.ToString();
  402. if (source == SearchPolicy_Partial)
  403. return SearchPolicy.Partial;
  404. else if (source == SearchPolicy_Individual)
  405. return SearchPolicy.Individual;
  406. else
  407. return SearchPolicy.Global;
  408. }
  409. }
  410. #endregion
  411. /// <summary>
  412. /// Listens keyboard globally.
  413. ///
  414. /// <remarks>Uses WH_KEYBOARD_LL.</remarks>
  415. /// </summary>
  416. public class KeyboardListener : IDisposable
  417. {
  418. #region Constructor
  419. /// <summary>
  420. /// Creates global keyboard listener.
  421. /// </summary>
  422. public KeyboardListener()
  423. {
  424. // We have to store the HookCallback, so that it is not garbage collected runtime
  425. hookedLowLevelKeyboardProc = (InterceptKeys.LowLevelKeyboardProc)LowLevelKeyboardProc;
  426. // Set the hook
  427. hookId = InterceptKeys.SetHook(hookedLowLevelKeyboardProc);
  428. // Assign the asynchronous callback event
  429. hookedKeyboardCallbackAsync = new KeyboardCallbackAsync(KeyboardListener_KeyboardCallbackAsync);
  430. }
  431. #endregion
  432. #region Destructor
  433. /// <summary>
  434. /// Destroys global keyboard listener.
  435. /// </summary>
  436. ~KeyboardListener()
  437. {
  438. Dispose();
  439. }
  440. #endregion
  441. #region Methods
  442. /// <summary>
  443. /// Check if the handlers are present
  444. /// </summary>
  445. /// <returns>true if both handlers are not null, otherwise false</returns>
  446. public bool CheckHandlers()
  447. {
  448. return (KeyDown != null && KeyUp != null);
  449. }
  450. #endregion
  451. #region Events
  452. /// <summary>
  453. /// Fired when any of the keys is pressed down.
  454. /// </summary>
  455. public event RawKeyEventHandler KeyDown;
  456. /// <summary>
  457. /// Fired when any of the keys is released.
  458. /// </summary>
  459. public event RawKeyEventHandler KeyUp;
  460. #endregion
  461. #region Inner workings
  462. /// <summary>
  463. /// Hook ID
  464. /// </summary>
  465. private IntPtr hookId = IntPtr.Zero;
  466. /// <summary>
  467. /// Asynchronous callback hook.
  468. /// </summary>
  469. /// <param name="keyEvent"></param>
  470. /// <param name="vkCode"></param>
  471. private delegate void KeyboardCallbackAsync(InterceptKeys.KeyEvent keyEvent, int vkCode);
  472. /// <summary>
  473. /// Actual callback hook.
  474. ///
  475. /// <remarks>Calls asynchronously the asyncCallback.</remarks>
  476. /// </summary>
  477. /// <param name="nCode"></param>
  478. /// <param name="wParam"></param>
  479. /// <param name="lParam"></param>
  480. /// <returns></returns>
  481. [MethodImpl(MethodImplOptions.NoInlining)]
  482. private IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam)
  483. {
  484. if (nCode >= 0)
  485. if (wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_KEYDOWN ||
  486. wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_KEYUP ||
  487. wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_SYSKEYDOWN ||
  488. wParam.ToUInt32() == (int)InterceptKeys.KeyEvent.WM_SYSKEYUP)
  489. hookedKeyboardCallbackAsync.BeginInvoke((InterceptKeys.KeyEvent)wParam.ToUInt32(), Marshal.ReadInt32(lParam), null, null);
  490. return InterceptKeys.CallNextHookEx(hookId, nCode, wParam, lParam);
  491. }
  492. /// <summary>
  493. /// Event to be invoked asynchronously (BeginInvoke) each time key is pressed.
  494. /// </summary>
  495. private KeyboardCallbackAsync hookedKeyboardCallbackAsync;
  496. /// <summary>
  497. /// Contains the hooked callback in runtime.
  498. /// </summary>
  499. private InterceptKeys.LowLevelKeyboardProc hookedLowLevelKeyboardProc;
  500. /// <summary>
  501. /// HookCallbackAsync procedure that calls accordingly the KeyDown or KeyUp events.
  502. /// </summary>
  503. /// <param name="keyEvent">Keyboard event</param>
  504. /// <param name="vkCode">vkCode</param>
  505. void KeyboardListener_KeyboardCallbackAsync(InterceptKeys.KeyEvent keyEvent, int vkCode)
  506. {
  507. switch (keyEvent)
  508. {
  509. // KeyDown events
  510. case InterceptKeys.KeyEvent.WM_KEYDOWN:
  511. if (KeyDown != null)
  512. KeyDown(this, new RawKeyEventArgs(vkCode, false));
  513. break;
  514. case InterceptKeys.KeyEvent.WM_SYSKEYDOWN:
  515. if (KeyDown != null)
  516. KeyDown(this, new RawKeyEventArgs(vkCode, true));
  517. break;
  518. // KeyUp events
  519. case InterceptKeys.KeyEvent.WM_KEYUP:
  520. if (KeyUp != null)
  521. KeyUp(this, new RawKeyEventArgs(vkCode, false));
  522. break;
  523. case InterceptKeys.KeyEvent.WM_SYSKEYUP:
  524. if (KeyUp != null)
  525. KeyUp(this, new RawKeyEventArgs(vkCode, true));
  526. break;
  527. default:
  528. break;
  529. }
  530. }
  531. #endregion
  532. #region IDisposable Members
  533. /// <summary>
  534. /// Disposes the hook.
  535. /// <remarks>This call is required as it calls the UnhookWindowsHookEx.</remarks>
  536. /// </summary>
  537. public void Dispose()
  538. {
  539. InterceptKeys.UnhookWindowsHookEx(hookId);
  540. }
  541. #endregion
  542. }
  543. /// <summary>
  544. /// Raw KeyEvent arguments.
  545. /// </summary>
  546. public class RawKeyEventArgs : EventArgs
  547. {
  548. #region Members
  549. /// <summary>
  550. /// vkCode of the key.
  551. /// </summary>
  552. public int vkCode;
  553. /// <summary>
  554. /// WPF key of the key.
  555. /// </summary>
  556. public Key key;
  557. /// <summary>
  558. /// Is the hitted key system key.
  559. /// </summary>
  560. public bool isSysKey;
  561. #endregion
  562. #region Constructor
  563. /// <summary>
  564. /// Create raw keyevent arguments.
  565. /// </summary>
  566. /// <param name="vkCode"></param>
  567. /// <param name="isSysKey"></param>
  568. public RawKeyEventArgs(int VKCode, bool isSysKey)
  569. {
  570. this.vkCode = VKCode;
  571. this.isSysKey = isSysKey;
  572. this.key = System.Windows.Input.KeyInterop.KeyFromVirtualKey(VKCode);
  573. }
  574. #endregion
  575. }
  576. /// <summary>
  577. /// Raw keyevent handler.
  578. /// </summary>
  579. /// <param name="sender">sender</param>
  580. /// <param name="args">raw keyevent arguments</param>
  581. public delegate void RawKeyEventHandler(object sender, RawKeyEventArgs args);
  582. /// <summary>
  583. /// Exception for an unknown column
  584. /// </summary>
  585. class UnknownColumnException : ApplicationException
  586. {
  587. #region Constructor
  588. /// <summary>
  589. ///
  590. /// </summary>
  591. /// <param name="name"></param>
  592. public UnknownColumnException(string name)
  593. : base("The list view doesn't contain the column '" + name + "'")
  594. {
  595. }
  596. #endregion
  597. }
  598. #region WINAPI Helper class
  599. /// <summary>
  600. /// Winapi key interception helper class.
  601. /// </summary>
  602. internal static class InterceptKeys
  603. {
  604. #region Members
  605. public static int WH_KEYBOARD_LL = 13;
  606. #endregion
  607. #region Delegates
  608. /// <summary>
  609. ///
  610. /// </summary>
  611. /// <param name="nCode"></param>
  612. /// <param name="wParam"></param>
  613. /// <param name="lParam"></param>
  614. /// <returns></returns>
  615. public delegate IntPtr LowLevelKeyboardProc(int nCode, UIntPtr wParam, IntPtr lParam);
  616. #endregion
  617. #region Enums
  618. /// <summary>
  619. ///
  620. /// </summary>
  621. public enum KeyEvent : int
  622. {
  623. /// <summary>
  624. ///
  625. /// </summary>
  626. WM_KEYDOWN = 256,
  627. /// <summary>
  628. ///
  629. /// </summary>
  630. WM_KEYUP = 257,
  631. /// <summary>
  632. ///
  633. /// </summary>
  634. WM_SYSKEYUP = 261,
  635. /// <summary>
  636. ///
  637. /// </summary>
  638. WM_SYSKEYDOWN = 260
  639. }
  640. #endregion
  641. #region Statics
  642. public static IntPtr SetHook(LowLevelKeyboardProc proc)
  643. {
  644. using (Process curProcess = Process.GetCurrentProcess())
  645. using (ProcessModule curModule = curProcess.MainModule)
  646. {
  647. return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
  648. GetModuleHandle(curModule.ModuleName), 0);
  649. }
  650. }
  651. [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  652. public static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
  653. [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  654. [return: MarshalAs(UnmanagedType.Bool)]
  655. public static extern bool UnhookWindowsHookEx(IntPtr hhk);
  656. [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  657. public static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, UIntPtr wParam, IntPtr lParam);
  658. [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
  659. public static extern IntPtr GetModuleHandle(string lpModuleName);
  660. #endregion
  661. }
  662. #endregion
  663. }