Implémentation d’une boucle de message Win32 et création d’un object Window avec P / Invoke

Mon objective principal est d’implémenter une boucle de message appropriée uniquement avec des appels P / Invoke, capable de gérer les événements USB HID. Ses fonctionnalités doivent absolument être identiques au code suivant, qui fonctionne bien dans Windows Forms . Ce descendant de NativeWindow reçoit les événements:

public class Win32EventHandler : NativeWindow { public const int WM_DEVICECHANGE = 0x0219; public Win32EventHandler() { this.CreateHandle(new CreateParams()); } protected override void OnHandleChange() { base.OnHandleChange(); IntPtr handle = UsbHelper.RegisterForUsbEvents(this.Handle); } protected override void WndProc(ref Message m) { if (m.Msg == WM_DEVICECHANGE) { // Handle event } base.WndProc(ref m); } } 

… alimenté par cette boucle d’événement:

 Win32EventHandler handler = new Win32EventHandler(); var context = new ApplicationContext(); Application.Run(context); // Other thread calls: // context.ExitThread() 

J’ai découvert que l’implémentation de la boucle d’événement est plutôt facile:

 while (true) { res = Win32.GetMessage(out msg, IntPtr.Zero, 0, 0); if (res == 0) { break; } Win32.TranslateMessage(ref msg); Win32.DispatchMessage(ref msg); if (msg.message == WM_DEVICECHANGE) { // Handle event } } 

Mais je n’ai aucune idée de la manière dont l’object Window sous-jacent doit être créé. L’implémentation de la classe NativeWindow semble trop complexe pour moi.

Voici ma solution pour le moment:

 public void CustomLoop() { ssortingng clsName = "Class"; ssortingng wndName = "Window"; Win32.WNDCLASSEX wndClassEx = new Win32.WNDCLASSEX(); wndClassEx.cbSize = (uint)Marshal.SizeOf(wndClassEx); wndClassEx.lpszClassName = clsName; wndClassEx.lpfnWndProc = WndProc; Win32.RegisterClassEx(ref wndClassEx); IntPtr windowHandle = Win32.CreateWindowEx(0, clsName, wndName, 0, 0, 0, 0, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero); IntPtr usbEventHandle = UsbHelper.RegisterForUsbEvents(windowHandle); Win32.MSG msg; sbyte res = 0; while (true) { res = Win32.GetMessage(out msg, IntPtr.Zero, 0, 0); if (res == 0) { break; } if (msg.message == WM.DEVICECHANGE) { // Handle event (does not fire) } else { Win32.TranslateMessage(ref msg); Win32.DispatchMessage(ref msg); } } Win32.DestroyWindow(windowHandle); Win32.UnregisterClass(clsName, IntPtr.Zero); } [AllowReversePInvokeCalls] private IntPtr WndProc(IntPtr hWnd, WM msg, IntPtr wParam, IntPtr lParam) { switch (msg) { case WM.DEVICECHANGE: // Handle event (fires) break; default: return Win32.DefWindowProc(hWnd, msg, wParam, lParam); } return IntPtr.Zero; } 

C’est une boucle d’événement très sous-alimentée. Pensez à utiliser quelque chose comme MsgWaitForMultipleObjectsEx au lieu de GetMessage .

Quoi qu’il en soit, la création d’une fenêtre nécessite que vous enregissortingez d’abord une classe de fenêtre ( RegisterClassEx ), puis que vous créiez la fenêtre ( CreateWindow ). Ni l’un ni l’autre n’est particulièrement difficile. Et au lieu d’utiliser base.WndProc() , vous devrez appeler DefWindowProc .

Essayer de gérer tous les messages directement à l’intérieur de la boucle de messages va être extrêmement difficile, c’est pourquoi des procédures de fenêtre ont été créées. Et n’appelez pas TranslateMessage ou DispatchMessage pour tout message que vous choisissez de traiter directement.

Vous voudrez peut-être vérifier comment ce gars détecte les périphériques USB: Une bibliothèque USB pour détecter les périphériques USB