1

I am writing an application that requires an HID card reader be connected to the system. Everything works properly when a card reader is already connected when the application is started, so I know I can find the device properly. (I am using the HID classes from PM> Install-Package hidlibrary.)

I want to add a feature where the program will display a prompt to connect a card reader if one is not found.

This is my first attempt:

public class App : Application
{
    public static List<HidDevice> HidDeviceList;

    // Block until device is plugged in
    static ManualResetEvent m_WaitForPlugin = new ManualResetEvent(false);

    // WMI Watcher for actual plug-in event
    static ManagementEventWatcher watcher = new ManagementEventWatcher();

    [STAThread()]
    static void Main()
    {
        ShowSplashScreen();

        FindCardReader();

        CloseSplashScreen();

        new App();
    }

    public App() : base()
    {

        StartupUri = new System.Uri("MainWindow.xaml", UriKind.Relative);
        Run();
    }

    private static void FindCardReader()
    {

        ShowOnSplashScreen("Searching for card reader");

        do
        {
            int VendorID = Convert.ToInt32(Settings.Default.ReaderVID, 16); // 0x0801
            int ProductID = Convert.ToInt32(Settings.Default.ReaderPID, 16); // 0x0002
            HidDeviceList = HidDevices.Enumerate(VendorID, ProductID).ToList();

            if (HidDeviceList.Count > 0) {
                break;
            }

            ShowOnSplashScreen("Please attach card reader...");
            SetupWatcher();
            m_WaitForPlugin.WaitOne();

        } while (HidDeviceList.Count == 0);
    }

    private static void SetupWatcher()
    {
        WqlEventQuery query = new WqlEventQuery("SELECT * FROM Win32_DeviceChangeEvent WHERE EventType = 2");
        watcher.EventArrived += new EventArrivedEventHandler(delegate(Object sender, EventArrivedEventArgs e)
        {
            ShowOnSplashScreen("New device detected!");
            m_WaitForPlugin.Set();
        });
        watcher.Query = query;
        watcher.Start();
    }

FindCardReader() in Main blocks as expected, but never appears to be signalled when a new device is plugged in. (I put a breakpoint in the delegate and it was never hit.)

I am not sure how to test the WMI watcher by itself (I tested the query in PowerShell and it appears to work). I also tried starting it in a new Thread, but the result was the same.

yakatz
  • 2,142
  • 1
  • 18
  • 47
  • Can you test your `WqlEventQuery` in a timed loop (say, every 2-3 seconds) to see if the `Win32_DeviceChangeEvent` actually shows up in WMI? After that, you can try testing the `ManagementEventWatcher` using something that you know changes regularly like `Select * From Win32_LocalTime`. – Moshe Katz Oct 30 '14 at 20:11
  • Have you considered a different query, perhaps based on this one: http://stackoverflow.com/questions/5278860/using-wmi-to-identify-which-device-caused-a-win32-devicechangeevent?rq=1 ? – Moshe Katz Oct 30 '14 at 20:13
  • Have you looked at how some of the [sample apps](https://github.com/mikeobrien/HidLibrary/blob/master/examples/MagtekCardReader/Program.cs#L23) handle connect/disconnect? – Moshe Katz Oct 30 '14 at 20:53

1 Answers1

0

It turns out that there is a very clear deadlock in this code. I have re-architected the entire system to avoid the issue rather than add additional threads to handle the locking.

yakatz
  • 2,142
  • 1
  • 18
  • 47