Piszę aplikację w C#, .NET 3.0 w VS2005 z funkcją monitorowania wstawiania/wyrzucania różnych dysków wymiennych (dysków flash USB, CD-ROM itp.). Nie chciałem korzystać z WMI, ponieważ może to być czasami niejednoznaczne (np. Może zaszczepić wiele zdarzeń wstawienia dla pojedynczego dysku USB), więc po prostu przesłonię WndProc mojego mainformu, aby złapać wiadomość WM_DEVICECHANGE, zgodnie z propozycją here. Wczoraj natknąłem się na problem, gdy okazało się, że będę musiał mimo to korzystać z WMI, aby pobrać trochę niejasne szczegóły dysku, takie jak numer seryjny. Okazuje się, że wywoływanie procedur WMI z wnętrza WndProc powoduje odrzucenie Mconnected DisconnectedContext.DisconnectedContext MDA podczas wywoływania funkcji WMI w aplikacji jednowątkowej
Po pewnym kopaniu skończyłem z niewygodnym obejściem tego problemu. Kod jest następujący:
// 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();
co oznacza po prostu uruchomienie procedury związanej z WMI w oddzielnym wątku - ale potem czekanie na jej zakończenie.
Teraz pytanie brzmi: dlaczegoto działa i dlaczegoto ma być w ten sposób? (lub, czy nie?)
Nie rozumiem faktu, że pierwszeństwo otrzymałem od DisconnectedContext MDA lub RPC_E_WRONG_THREAD. W jaki sposób uruchamianie procedury GetDrives()
z obsługi zdarzeń kliknięcia przycisku różni się od wywoływania z WndProc? Czy nie dzieje się to w tym samym głównym wątku mojej aplikacji? BTW, moja aplikacja jest całkowicie jednowątkowa, więc dlaczego nagle pojawia się błąd odnoszący się do "niewłaściwej nici"? Czy użycie WMI oznacza wielowątkowość i specjalne traktowanie funkcji od System.Management?
W międzyczasie znalazłem inne pytanie związane z tym MDA, to jest here. OK, mogę przyjąć, że wywołanie WMI oznacza stworzenie oddzielnego wątku dla podstawowego składnika COM - ale nadal nie przychodzi mi do głowy, dlaczego nie jest potrzebna magia, gdy dzwonię po naciśnięciu przycisku, i do-magia jest potrzebna podczas dzwonienia to od WndProc.
Jestem naprawdę zdezorientowany i docenię pewne wyjaśnienia w tej sprawie. Istnieje tylko kilka rzeczy gorsze niż posiadanie rozwiązania, a nie wiedząc, dlaczego to działa:/
Cheers, Aleksander
Same kłopoty tutaj! Szkoda, że nie było rozwiązania. Dodam nagrodę ... może to pomoże. – Brad