Question

I need some help implementing asynchronous events in Powershell.

As a testbed for a larger HID project I want to use Powershell to read the data from a usb panic button that I got off amazon. The perfect solution would implement the data callback as an event that could then be registered using Register-ObjectEvent.

My current approach is to use the Hidlibrary library. I am having difficulty invoking both the Read() or ReadReport() methods. They do not appear to be typical asynccallbacks and the standard solution of using New-ScriptBlockCallback does not work.

What I have so far that works and allows me to pull a readhandle.

Add-Type -Path .\Projects\UsbPanicButton\HidLibrary.dll
$device = [HidLibrary.HidDevices]::GetDevice('\\?\hid#vid_1130&pid_0202&mi_00#7&29add023&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}')
$device.OpenDevice()

This does not work. (Cannot find an overload)

$device.ReadReport((New-ScriptBlockCallback {Write-host "HI"}))

How can I convert the ReadReport method into an event that can be registered?

Was it helpful?

Solution

The ReadReport method signature:

public delegate void ReadReportCallback(HidReport report);

Isn't a fit for New-ScriptBlockCallback. It works with methods taking an AsyncCallback parameter. IF you know the callback is called on the creating thread during the ReadReport method call you can use:

$device.ReadReport({param($hidReport) $hidReport.ReadStatus })

If it is called back on a different thread, try this modified version of the New-ScriptBlockCallback function:

function New-ScriptBlockCallback {
    param(
        [parameter(Mandatory=$true)]
        [ValidateNotNullOrEmpty()]
        [scriptblock]$Callback
    )

    if (-not ("CallbackEventBridge" -as [type])) {
        Add-Type @"
            using System;
            using HidLibrary;

            public sealed class CallbackEventBridge
            {
                public event HidDevice.ReadReportCallback CallbackComplete = delegate { };

                private CallbackEventBridge() {}

                private void CallbackInternal(HidReport report)
                {
                    CallbackComplete(report);
                }

                public HidDevice.ReadReportCallback Callback
                {
                    get { return new HidDevice.ReadReportCallback(CallbackInternal); }
                }

                public static CallbackEventBridge Create()
                {
                    return new CallbackEventBridge();
                }
            }
"@
    }
    $bridge = [callbackeventbridge]::create()
    Register-ObjectEvent -input $bridge -EventName callbackcomplete -action $callback -messagedata $args > $null
    $bridge.callback
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top