Mise en œuvre d'un message Win32 boucle et la création d'un objet de la Fenêtre avec P/Invoke
Mon objectif principal est de mettre en œuvre une bonne boucle de message purement avec P/Invoke appels qui est capable de gérer l'USB HID événements. Certainement sa fonctionnalité devrait être identique avec le code suivant qui fonctionne bien dans la Windows Forms. Cette NativeWindow descendant 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 trouvé que la mise en place 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 façon dont la Fenêtre sous-jacente de l'objet doit être créé. La mise en œuvre de la classe NativeWindow semble trop complexe pour moi.
C'est ma solution pour le moment:
public void CustomLoop()
{
string clsName = "Class";
string 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;
}
Par curiosité, si vous avez le code de travail, pourquoi voulez-vous le réécrire d'une façon différente?
Je veux attraper ces événements dans Silverlight 5 avec P/Invoke. Pour une bonne raison, il manque Win32 spécifique des choses complètement.
Vous êtes l'obtention de p/invoke les déclarations de pinvoke.net ?
Oui!
Je veux attraper ces événements dans Silverlight 5 avec P/Invoke. Pour une bonne raison, il manque Win32 spécifique des choses complètement.
Vous êtes l'obtention de p/invoke les déclarations de pinvoke.net ?
Oui!
OriginalL'auteur tamasf | 2012-01-24
Vous devez vous connecter pour publier un commentaire.
C'est un très sous-alimenté boucle d'événements. Envisagez d'utiliser quelque chose comme
MsgWaitForMultipleObjectsEx
au lieu deGetMessage
.De toute façon, la création d'une fenêtre vous demande de vous inscrire d'abord une classe de fenêtre (
RegisterClassEx
), puis de créer la fenêtre (CreateWindow
). Ni l'un est particulièrement difficile. Et au lieu d'utiliserbase.WndProc()
, vous aurez besoin de demanderDefWindowProc
.Essayer de gérer tous les messages directement à l'intérieur de la boucle de message va être trop difficile, c'est pourquoi les procédures de fenêtre ont été créés. Et n'appelez pas
TranslateMessage
ouDispatchMessage
pour n'importe quel message que vous choisissez de traiter directement.Avez-vous de vérifier tous vos appels d'erreurs? Si vous n'avez pas de gérer les messages correctement (en les passant à
DefWindowProc
) votreCreateWindow
appel sera de retourNULL
,RegisterDeviceNotification
échoue, et vous ne recevrez pas les messages.Vous pourriez travailler sur l'obtention de Raymond Chen squelette Win32 application et en cours d'exécution, d'abord en C, en C# avec P/Invoke.
J'ai mis à jour la question pour voir mon actuel de mise en œuvre.
Je ne vois pas de contrôle d'erreur. Avez vous franchi dans un débogueur assurez-vous que les valeurs de retour sont tous ok? Aussi, la "Classe" est un terrible nom de classe de fenêtre, il est nécessaire d'être unique. Utiliser un GUID, ou votre nom, ou quelque chose d'autre qu'un paresseux développeur n'aurait pas déjà utilisé. Aussi, des zéros pour tous les styles de fenêtre n'est pas susceptible de tourner bien.
OriginalL'auteur Ben Voigt
Vous voudrez peut-être vérifier comment ce mec détecter des périphériques USB: Une clé USB à la Bibliothèque pour Détecter les Périphériques USB
OriginalL'auteur Chris Shain