views:

41

answers:

0

hi there.

I write an app in C#, .NET 3.0 in VS2005 with a feature of monitoring insertion/ejection of various removable drives (USB flash disks, CD-ROMs etc.). I did not want to use WMI, since it can be sometimes ambiguous (e.g. it can spawn multiple insertion events for a single USB drive), so I simply override the WndProc of my mainform to catch the WM_DEVICECHANGE message, as proposed here. Yesterday I run into a problem when it turned out that I will have to use WMI anyway to retrieve some obscure disk details like a serial number. It turns out that calling WMI routines from inside the WndProc throws the DisconnectedContext MDA.

After some digging I ended with an awkward workaround for that. The code is as follows:

    // the function for calling WMI 
    private void GetDrives()
    {
        ManagementClass diskDriveClass = new ManagementClass("Win32_DiskDrive");
        // THIS is the line I get DisconnectedContext MDA on when it happens:
        ManagementObjectCollection diskDriveList = diskDriveClass.GetInstances();
        foreach (ManagementObject dsk in diskDriveList)
        {
            // ...
        }
    }

    private void button1_Click(object sender, EventArgs e)
    {
        // here it works perfectly fine
        GetDrives();
    }


    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);

        if (m.Msg == WM_DEVICECHANGE)
        {
            // here it throws DisconnectedContext MDA 
            // (or RPC_E_WRONG_THREAD if MDA disabled)
            // GetDrives();
            // so the workaround:
            DelegateGetDrives gdi = new DelegateGetDrives(GetDrives);
            IAsyncResult result = gdi.BeginInvoke(null, "");
            gdi.EndInvoke(result);
        }
    }
    // for the workaround only
    public delegate void DelegateGetDrives();

which basically means running the WMI-related procedure on a separate thread - but then, waiting for it to complete.

Now, the question is: why does it work, and why does it have to be that way? (or, does it?)

I don't understand the fact of getting the DisconnectedContext MDA or RPC_E_WRONG_THREAD in the first place. How does running GetDrives() procedure from a button click event handler differs from calling it from a WndProc? Don't they happen on the same main thread of my app? BTW, my app is completely single-threaded, so why all of the sudden an error referring to some 'wrong thread'? Does the use of WMI imply multithreading and special treatment of functions from System.Management?

In the meantime I found another question related to that MDA, it's here. OK, I can take it that calling WMI means creating a separate thread for the underlying COM component - but it still does not occur to me why no-magic is needed when calling it after a button is pressed and do-magic is needed when calling it from the WndProc.

I'm really confused about that and would appreciate some clarification on that matter. There are only a few worse things than having a solution and not knowing why it works :/

Cheers, Aleksander