.NET WinForms: Может ли во время выполнения выбрасывайте ручку одной из форм в из-под меня?

голоса
13

В настоящее время декларация SendMessage над на Pinvoke.net является:

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

Примечание: HWND больше не IntPtr , и был заменен HandleRef . Очень рыхлое объяснение изменения Дано:

Вы можете заменить «HWND» с «IntPtr» вместо «HandleRef». Тем не менее, вы принимаете риск при этом - это может привести ваш код аварии с условиями гонки. Среда .NET может, и утилизируйте окно обрабатывает из-под вашим сообщением - вызывает все виды неприятных проблем!

Кто-то wiki'd на последующий вопрос:

Вопрос: Не может это последний вопрос должен быть рассмотрен с сортировочными, в частности , прижав?

И кто-то ответил:

Ответ: Вы можете использовать GC.KeepAlive () сразу же после SendMessage () с объектом формы в качестве параметра KeepAlive ().

Все это «распоряжаться ваша форма под вас» , кажется странной для меня. SendMessage является синхронным вызовом. Он не вернется до тех пор , пока отправленное сообщение не было обработано.

Подразумевается то, что форма ручки может быть разрушен в любое время. Например:

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
}

Это означает, что оконная ручка может стать недействительной между временем я использую это и время, метод заканчивается?


Обновление One

я понимаю идею, что когда форма выходит из области видимости, это недопустимый дескриптор. например:

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
}

Это для меня очевидно, что ручка формы не является действительной, как только DoStuff вернулся. То же самое было бы справедливо независимо от того, какой метод - если форма не в каком-нибудь объеме, она не действительна для использования.

я бы не согласен с (TODO ссылки парнем) в том , что форма будет придерживаться вокруг , пока все отправлять сообщения не были получены. CLR не знает , кто , возможно, дали ручку окна моей формы, и не имеет возможности узнать , кто может назвать SendMessage () в будущем.

Другими словами, я не могу себе представить, что призвание:

IntPtr hWnd = this.Handle;

теперь будет предотвратить это от того мусора.


Обновление Два

я не могу представить себе, что окно обрабатывать вокруг будет держать форму от сборщика мусора. то есть:

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

Ответ

Но это illevant точки - оригинальный вопрос до сих пор является:

Может ли во время выполнения выбрасывайте ручку одной из форм в из-под меня?

Нет Ответ, оказывается, нет. Среда выполнения не распорядится форму из - под меня. Она будет распоряжаться в форме без ссылок - но без ссылок формы не под меня. «Под Me» означает , что у меня есть ссылка на форму.

С другой стороны, основной дескриптор окна Windows, объект формы можно уничтожить из-под меня (и на самом деле, как бы это не - оконные ручки не подсчет ссылок - они не должны быть):

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

Важно также отметить, что HandleRef не поможет предотвратить проблемы, связанные с созданием объектов оберток вокруг окна Окна ручки:

Причина 1 Если объект форма разрушается , потому что у вас не было ссылки на него - тогда вы просто глупо пытаться говорить с формой что права больше не должны существовать. Просто потому , что GC не удосужился к нему еще не делает вас умнее - это делает вас повезло. HandleRef хак сохранить ссылку на форму. Вместо того чтобы использовать:

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

Вы можете легко использовать:

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

Причина 2 HandleRef не будет препятствовать форме от воссоздавать это основной дескриптор окна, например:

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

Таким образом, в то время как оригинальный модификатор SendMessage на P / Invoke сделал указать на проблему, его решение не является решением.

Задан 09/12/2008 в 17:27
источник пользователем
На других языках...                            


1 ответов

голоса
3

Часто , когда вы звоните SendMessage, вы делаете это из другого потока или , по крайней мере , еще один компонент отдельно от формы. Я предполагаю , что точка делается в том , что только потому , что у вас есть IntPtr , который в одной точке , содержавший действительный дескриптор окна, вы не можете предположить , что она все еще является действительным.

Допустим, у вас этот класс:

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);
   }
}

и где-нибудь еще:

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

то потому , что fвышел за рамки, его Disposeв конечном итоге получить вызывается GC финализации. Вот почему вы , возможно , придется использовать Gc.KeepAliveв такой ситуации. fдолжен остаться в живых до тех пор , mcпока не закончится с ручкой.

Ответил 09/12/2008 в 17:48
источник пользователем

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