Я пишу приложение в С#,.NET 3.0 в VS2005 с функцией мониторинга вставки/извлечения различных съемных дисков (USB-флеш-дисков, компакт-дисков и т.д.). Я не хотел использовать WMI, поскольку это может быть иногда неоднозначным (например, он может порождать несколько событий вставки для одного USB-накопителя), поэтому я просто переопределяю WndProc моей основной формы, чтобы поймать сообщение WM_DEVICECHANGE, как предлагалось здесь. Вчера я столкнулся с проблемой, когда выяснилось, что мне придется использовать WMI в любом случае, чтобы получить некоторые неясные данные о диске, такие как серийный номер. Оказывается, что вызов подпрограмм WMI из WndProc вызывает DisconnectedContext MDA.
После некоторого рытья я закончил неловкое обходное решение для этого. Код выглядит следующим образом:
// 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();
что в основном означает запуск процедуры, связанной с WMI, в отдельном потоке, но затем, ожидая ее завершения.
Теперь вопрос: почему работает, а почему он должен быть таким? (или, не так ли?)
Я не понимаю факт получения DisconnectedContext MDA или RPC_E_WRONG_THREAD в первую очередь. Как работает процедура GetDrives()
от обработчика события нажатия кнопки отличается от вызова его из WndProc? Разве они не происходят в одной и той же основной теме моего приложения? BTW, мое приложение полностью однопоточное, так почему же внезапно возникает ошибка со ссылкой на какой-то "неправильный поток"? Использует ли WMI многопоточность и специальную обработку функций из System.Management?
В то же время я нашел еще один вопрос, связанный с этим MDA, здесь . Хорошо, я могу считать, что вызов WMI означает создание отдельного потока для базового COM-компонента, но мне все еще не приходит в голову, почему нет необходимости в магии при вызове его после нажатия кнопки, и требуется магия при вызове это из WndProc.
Я действительно запутался в этом и был бы признателен за некоторые разъяснения по этому вопросу. Есть только несколько худших вещей, кроме решения и не зная, почему это работает:/
Cheers, Александр