.NET WinForm: Czy środowisko wykonawcze zbywać uchwyt w formie spod mnie?

głosy
13

Obecna deklaracja SendMessage na co PInvoke.net jest:

[DllImport(user32.dll, CharSet = CharSet.Auto, SetLastError = false)]
static extern IntPtr SendMessage(HandleRef hWnd, uint Msg, 
      IntPtr wParam, IntPtr lParam);

Uwaga: HWND nie jest już IntPtr i został zastąpiony HandleRef . Bardzo luźna wyjaśnienie zmian jest podana:

Można zastąpić „hWnd” z „IntPtr” zamiast „HandleRef”. Jednak pacjent przyjmuje ryzyko w ten sposób - może to spowodować awarię kod z warunków wyścigowych. Runtime .NET mogą i będą wyrzucać okno uchwyty spod wiadomości - powodując różnego rodzaju nieprzyjemnych problemów!

Ktoś wiki'd pytanie obserwacji:

Pytanie: Nie mogę ten ostatni problem można rozwiązać za pomocą Organizowanie, specjalnie przypinanie?

I ktoś odpowiedział:

Odpowiedź: Można użyć GC.KeepAlive () zaraz po SendMessage () z obiektu formularza jako parametr keepalive ().

Wszystko to „rozstrzygających swoją formę pod tobą” wydaje się dziwne dla mnie. SendMessage jest synchroniczne wywołanie. To nie wróci aż do momentu wysłana wiadomość została przetworzona.

Konsekwencją jest to, że wtedy uchwyt forma może zostać zniszczona w dowolnym czasie. Na przykład:

private void DoStuff()
{
   //get the handle
   IntPtr myHwnd = this.Handle;


   //Is the handle still valid to use?
   DoSomethingWithTheHandle(myHwnd); //handle might not be valid???


   //fall off the function
}

Oznacza to, że uchwyt okna mogą stać się nieważne pomiędzy czasem używam go a czas metoda kończy?


aktualizacja One

rozumiem pojęcia, że ​​kiedyś to forma wykracza poza zakres, to uchwyt jest nieprawidłowy. na przykład:

private IntPtr theHandle = IntPtr.Zero;

private void DoStuff()
{
   MyForm frm = new MyForm())

   theHandle = frm.Handle;

   //Note i didn't dispose of the form.
   //But since it will be unreferenced once this method ends
   //it will get garbage collected,
   //making the handle invalid
}

Jest dla mnie oczywiste, że uchwyt formie nie jest ważna po powrócił DoStuff. To samo byłoby prawdą, bez względu na technikę - jeśli formularz nie jest utrzymywana w pewnym zakresie, to nie jest ważne, aby użyć.

chciałbym zgadzam się z (brak łącza guy) tym, że forma będzie trzymać się aż wszystkie komunikaty wysyłane zostały otrzymane. CLR nie wie, kto może nadano uchwyt okna mojego formularza, a nie ma możliwości dowiedzenia się, kto może zadzwonić SendMessage () w przyszłości.

Innymi słowy, nie mogę sobie wyobrazić, że powołanie:

IntPtr hWnd = this.Handle;

będzie teraz zapobiec tego przed śmieci zebrane.


aktualizacja Two

Nie mogę sobie wyobrazić okno obsłużyć około zachowa formę przed śmieci zebrane. to znaczy:

Clipboard.AsText = this.Handle.ToString();
IntPtr theHandle = (IntPtr)(int)Clipboard.AsText;

Odpowiedź

Ale to są illevant punktów - oryginalne pytanie nadal jest:

Można runtime rozporządzania uchwyt w formie spod mnie?

Odpowiedź, jak się okazuje, nie jest. Środowisko wykonawcze nie będą wyrzucać formie spod mnie. To będzie likwidować przypisań formie - ale bez odnośników formy nie są pode mną. „Pod Me” oznacza, że mają odniesienie do formy.

Z drugiej strony, podkreślając uchwyt okna Okna obiektu formularza można zniszczyć spod mnie (i naprawdę, jak to może nie - klamki okienne są liczone należy odwoływać - nie powinny one być):

IntPtr hwnd = this.Handle;
this.RightToLeft = RightToLeft.Yes;
//hwnd is now invalid

Ważne jest również, aby pamiętać, że HandleRef nie pomoże uniknąć problemów spowodowanych przez tworzenie owijarki obiekt wokół okna Windows obsługuje:

Powód 1 Jeśli obiekt forma jest zniszczona, ponieważ nie mają odniesienia do niej - to jesteś po prostu głupi, próbując rozmawiać z postaci, która przez prawa nie powinny już istnieć. Tylko dlatego, że GC nie ma zdobyć wokół niej jeszcze nie sprawi, że mądry - to sprawia, że jesteś szczęśliwy. HandleRef jest hack zachować odniesienie do formularza. Zamiast używać:

HandleRef hr = new HandleRef(this, this.Handle);
DoSomethingWithHandle(this.Handle);

można łatwo używać:

Object o = this;
DoSomethingWithHandle(this.Handle);

Powód 2 HandleRef nie przeszkodzi formę z ponownego tworzenia to uchwyt okna bazowego, np:

HandleRef hr = new HandleRef(this, this.Handle);
this.RightToLeft = RightToLeft.Yes;
//hr.Hande is now invalid

Tak więc, podczas gdy oryginalny modyfikator SendMessage P / Invoke nie podkreślić problem, jego rozwiązanie nie jest rozwiązaniem.

Utwórz 09/12/2008 o 17:27
źródło użytkownik
W innych językach...                            


1 odpowiedzi

głosy
3

Często, kiedy dzwonisz SendMessage, robisz to z innego wątku lub przynajmniej inny składnik oddzielony od formularza. Zakładam, że punktem odniesienia jest to, że tylko dlatego, że masz IntPtr, które w pewnym momencie zawarty poprawny uchwyt okna, nie można zakładać, że nadal jest aktualne.

Powiedzmy, że miałem tę klasę:

class MyClass {
   IntPtr hwnd;
   public MyClass(IntPtr hwnd) {
      this.hwnd = hwnd;
   }
   ...

   private void DoStuff()
   {
       //n.b. we don't necessarily know if the handle is still valid
       DoSomethingWithTheHandle(hwnd);
   }
}

i gdzie indziej:

 private void DoOtherStuff() {
     Form f = new Form();
     mc = new MyClass(f.Handle);
 }

Następnie, ponieważ fupadł poza zakresem jego Disposekońcu sprawdzony przez finalizatora GC. Dlatego może być konieczne do korzystania Gc.KeepAlivez tego typu sytuacji. fmusi pozostać przy życiu, aż mczakończy się z uchwytu.

Odpowiedział 09/12/2008 o 17:48
źródło użytkownik

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more