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!

OriginalL'auteur tamasf | 2012-01-24