views:

372

answers:

1

I've been through all of the Stack Overflow answers search comes up with, and neither Google or Bing are showing me any love. I need to know when a network cable has been connected or disconnected on a Windows CE device, preferrably, from a Compact Framework application.

+3  A: 

I realize I'm answering my own question here, but it was actually a question asked of via email, and I actually spent quite a while finding the answer, so I'm posting it here.

So the general answer for how this is detected is that you have to call down into the NDIS driver via an IOCTL and tell it that you're interested in notifications. This is done with the IOCTL_NDISUIO_REQUEST_NOTIFICATION value (the docs say this is not supported in WinMo, but the docs are wrong). Of course receiving the notifications isn't so straightforward - you son't just get some nice callback. Instead you have to spin up a point to point message queue and send that in to the IOCTL call, along with a mask of which specific notifications you want. Then, when something changes (like the cable is pulled) you'll get an NDISUIO_DEVICE_NOTIFICATION structure (again MSDN incorrectly says this is CE-only) on the queue, which you can then parse to find the adapter that had the event and what the exact event is.

From a managed code perspective, this is actually a lot of code to have to write - CreateFile to open NDIS, all of the queueing APIs, the structures for the notifications, etc. Fortunately, I'd already been down this road and had added it to the Smart Device Framework already. So if you're using the SDF, getting the notifications looks like this:

public partial class TestForm : Form
{
    public TestForm()
    {
        InitializeComponent();

        this.Disposed += new EventHandler(TestForm_Disposed);

        AdapterStatusMonitor.NDISMonitor.AdapterNotification += 
            new AdapterNotificationEventHandler(NDISMonitor_AdapterNotification);
        AdapterStatusMonitor.NDISMonitor.StartStatusMonitoring();
    }

    void TestForm_Disposed(object sender, EventArgs e)
    {
        AdapterStatusMonitor.NDISMonitor.StopStatusMonitoring();
    }

    void NDISMonitor_AdapterNotification(object sender, 
                                         AdapterNotificationArgs e)
    {
        string @event = string.Empty;

        switch (e.NotificationType)
        {
            case NdisNotificationType.NdisMediaConnect:
                @event = "Media Connected";
                break;
            case NdisNotificationType.NdisMediaDisconnect:
                @event = "Media Disconnected";
                break;
            case NdisNotificationType.NdisResetStart:
                @event = "Resetting";
                break;
            case NdisNotificationType.NdisResetEnd:
                @event = "Done resetting";
                break;
            case NdisNotificationType.NdisUnbind:
                @event = "Unbind";
                break;
            case NdisNotificationType.NdisBind:
                @event = "Bind";
                break;
            default:
                return;
        }

        if (this.InvokeRequired)
        {
            this.Invoke(new EventHandler(delegate
            {
                eventList.Items.Add(string.Format(
                                    "Adapter '{0}' {1}", e.AdapterName, @event));
            }));
        }
        else
        {
            eventList.Items.Add(string.Format(
                                "Adapter '{0}' {1}", e.AdapterName, @event));
        }
    }
}
ctacke