Короткая версия
Как использовать вызов API, если я не могу гарантировать, что окно
дескриптор останется в силе?
Я могу гарантировать, что у меня есть ссылка на мою форму (поэтому форма не удаляется). Это не гарантирует, что дескриптор формы будет оставаться в силе все это время.
Как дескриптор окна формы может стать недействительным, даже если форма не опущена ?
Поскольку основное окно Windows формы было уничтожено и воссоздано.
Длинная версия
Я хочу P / Invoke API, который требует hwnd (дескриптор окна). Вот некоторые примеры вызовов API, которые требуют hWnd:
IVMRWindowlessControl :: SetVideoClippingWindow
HRESULT SetVideoClippingWindow(
HWND hwnd
);
SendMessage
SendMessage(
HWND hWnd,
UINT Msg,
WPARAM wParam,
LPARAM lParam
);
SetClipboardViewer
HWND SetClipboardViewer(
HWND hWndNewViewer
);
SetTimer
UINT_PTR SetTimer(
HWND hWnd,
UINT_PTR nIDEvent,
UINT uElapse,
TIMERPROC lpTimerFunc
);
IProgressDialog :: StartProgressDialog
HRESULT StartProgressDialog(
HWND hwndParent,
IUnknown *punkEnableModless,
DWORD dwFlags,
LPCVOID pvReserved
);
Shell_NotifyIcon
BOOL Shell_NotifyIcon(
DWORD dwMessage,
PNOTIFYICONDATA lpdata //<--hWnd in there
);
AnimateWindow
BOOL AnimateWindow(
HWND hwnd,
DWORD dwTime,
DWORD dwFlags
);
Примечание: Некоторые из этих вызовов API имеют управляемые эквиваленты, некоторые нет - но этот факт не имеет отношения к моему вопросу.
Объяснение
я могу вызвать одну из этих функций API, для которой требуется долгосрочный дескриптор окна, например ::1010*
private void TellTheGuyToDoTheThing()
{
SendMessage(this.Handle,
WM_MyCustomMessage,
paramOneForTheThing,
paramTwoForTheThing);
}
Было высказано предположение, что приведенный выше вызов SendMessage опасен из-за неуправляемого использования дескриптора окна. Они предлагают вам обернуть hwnd в объект HandleRef:
private void TellTheGuyToDoTheThing()
{
SendMessage(new HandleRef(this, this.Handle),
WM_MyCustomMessage,
paramOneForTheThing, paramTwoForTheThing);
Таким образом: дескриптор окна гарантированно остается действительным во время вызова SendMessage. Но так бывает не всегда. Следующий вызов API требует долгосрочного доступа к дескриптору окна:
private void RegisterWithTheThing()
{
this.nextClipboardViewerInChain = SetClipboardViewer(
new HandleRef(this, this.Handle));
}
Несмотря на то, что я обернул дескриптор в HandleRef, все еще возможно (в секундах, минутах, часах, днях, неделях, месяцах или годах подзапроса), чтобы дескриптор окна формы стал недействительным. Это происходит, когда основное окно Windows формы уничтожено и создано новое. И это несмотря на то, что я защищал дескриптор формы в HandleRef.
я могу назвать один способ, которым дескриптор формы становится недействительным:
this.RightToLeft = RightToLeft.Yes;
Окно формы воссоздано, и старый hwnd теперь недействителен.
Итак, вопрос: как использовать вызов API, для которого требуется дескриптор окна?
Не может быть сделано?
Я ожидаю ответа: Вы не можете сделать это. Ничего нельзя сделать, чтобы защитить дескриптор формы, чтобы она действовала до тех пор, пока вам нужно сохранить дескриптор.
Это значит, что мне нужно знать, когда дескриптор уничтожается, поэтому я могу сказать Windows, чтобы он отпустил, например ::1010 *
protected override void TheHandleIsAboutToBeDestroyed()
{
ChangeClipboardChain(this.Handle, this.nextClipboardViewerInChain);
}
и затем вам сообщат, когда будет создан новый дескриптор:
protected override void TheHandleWasJustCreated()
{
RegisterTheThing();
}
За исключением того, что такие методы-предки не существуют.
Альтернативный вопрос: Существуют ли методы, которые я могу переопределить, чтобы я знал, когда дескриптор окна собирается разрушиться, и когда он только что был создан?
Необходимость нарушать инкапсуляцию .NET WinForms для воссоздания дескрипторов ужасна, но разве это единственный способ?
Обновление Один
Обработка события Close / OnClose формы недостаточна, то же самое относится и к
- обработка IDisposable
- GC закрепляет форму
поскольку я могу сделать недействительным дескриптор основного окна формы, не закрывая и не удаляя форму. например:
private void InvalidThisFormsWindowHandleForFun()
{
this.RightToLeft = RightToLeft.Yes;
}
Примечание: Вы уничтожаете дескриптор окна Windows, вы не избавляетесь от него. Объекты в .NET - это вещи, от которых избавляются; который, если это объект Form, скорее всего, будет уничтожать дескриптор окна Windows.
Windows является продуктом Microsoft.
Окно - это вещь с циклом сообщений, которая иногда может показывать вещи на экране.
Обновление Два
me.yahoo.com / a / BrYwg было хорошее предложение по использованию объекта NativeWindow для прослушивания элементов, для которых требуется hWnd, которые используются слушать сообщения. Это может быть использовано для решения некоторых проблем, например:
- SetClipboardViewer
- SetTimer
- IProgressDialgo :: StartProgressDialog
- Shell_NotifyIcon
но не работает для
- AnimateWindow
- SendMessage
- IVMRWindowlessControl :: SetVideoClippingWindow