PageRenderTime 63ms CodeModel.GetById 9ms app.highlight 47ms RepoModel.GetById 1ms app.codeStats 1ms

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