Текущее объявление 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 время выполнения может и
будет распоряжаться оконными ручками
из-под вашего сообщения - вызывая все
виды неприятных проблем!
Кто-то вики задал следующий вопрос:
Вопрос: Не удается решить эту последнюю проблему
с маршалингом, конкретно пиннингом?
И кто-то ответил:
Ответ: Вы можете использовать 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
}
Это означает, что дескриптор окна может стать недействительным между временем, когда я его использую, и временем, когда метод заканчивается?
Update One
Я понимаю, что как только форма выходит из области видимости, ее дескриптор становится недействительным. e.g.:
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 link guy) в том, что форма будет сохраняться до тех пор, пока не будут получены все отправленные сообщения. CLR не знает, кому мог быть предоставлен дескриптор окна моей формы, и не может знать, кто может вызвать SendMessage () в будущем.
Другими словами, я не могу представить, что зовет:
IntPtr hWnd = this.Handle;
теперь предотвратит сборку мусора этим .
Обновление Два
Я не могу себе представить, что ручка окна будет мешать собирать мусор. i.e.:
Clipboard.AsText = this.Handle.ToString();
IntPtr theHandle = (IntPtr)(int)Clipboard.AsText;
Ответ
Но это важные моменты - первоначальный вопрос все еще таков:
Может ли среда выполнения располагать
вытащить из-под меня?
Ответ, оказывается, нет. Среда выполнения не избавится от формы из-под меня. Он будет распоряжаться не ссылочной формой, но не ссылочные формы не находятся подо мной. «Подо мной» означает, что у меня есть ссылка на форму.
С другой стороны, дескриптор окна Windows, лежащий в основе объекта Form, может быть уничтожен из-под меня (и действительно, как он мог этого не делать - дескрипторы окна не считаются ссылками - и не должны):
IntPtr hwnd = this.Handle;
this.RightToLeft = RightToLeft.Yes;
//hwnd is now invalid
Также важно отметить, что HandleRef не поможет предотвратить проблемы, вызванные созданием оберток объектов вокруг дескрипторов окон Windows:
Причина 1
Если объект формы разрушается из-за того, что у вас не было ссылки на него - тогда вы просто глупы, пытаясь поговорить с формой, которая по праву больше не должна существовать. Тот факт, что GC еще не дошел до этого, не делает вас умными - это делает вас счастливым. HandleRef - это хак, чтобы сохранить ссылку на форму. Вместо использования:
HandleRef hr = new HandleRef(this, this.Handle);
DoSomethingWithHandle(this.Handle);
Вы можете легко использовать:
Object o = this;
DoSomethingWithHandle(this.Handle);
Причина 2
HandleRef не будет препятствовать повторному созданию формой своего основного дескриптора окна, например ::1100
HandleRef hr = new HandleRef(this, this.Handle);
this.RightToLeft = RightToLeft.Yes;
//hr.Hande is now invalid
Итак, хотя оригинальный модификатор SendMessage в P / Invoke указывал на проблему, его решение не является решением.