Share via


Если в результате операции генерируются какие-либо оконные сообщения, то для того, чтобы эта операция выполнилась, целевое окно, разумеется, должно обрабатывать оконные сообщения

Есть операция включает в себя генерацию оконных сообщений, то для того, чтобы операция выполнилась, целевое окно, разумеется, должно обрабатывать оконные сообщения (или, точнее, поток, который владеет целевым окном, должен обрабатывать оконные сообщения). Почему? Потому что обработка оконных сообщений — это единственный способ, при помощи которого окно может получать сообщения!

Получилась некоторого рода тавтология, но, тем не менее, это утверждение очевидно не для всех.

В общем случае, вы сталкиваетесь с такой проблемой тогда, когда пытаетесь управлять окном из другого потока, отличного от того, в котором было создано окно. Поскольку окно привязано к своему потоку, операциям вне этого потока, обычно, нужно попасть внутрь этого потока, потому что именно там и "живет" это окно.

Оконный менеджер, зачастую, пытается определить, что можно сделать в данной ситуации, не прибегая к маршалингу (передаче данных между потоками — прим. переводчика), но когда дело касается оконных сообщений, у него просто нет другого выбора. Доставка сообщений в окно производится только в том потоке, которому принадлежит данное окно, и никак иначе.

Встречаются такие коварные ситуации, в которых функция, вызванная в другом потоке, может генерировать оконные сообщения. В общем случае, вы просто должны предполагать, что каждая операция для работы с окном может генерировать сообщения: если она не делает этого сейчас, то может начать делать это в будущем. К примеру, изменение стиля окна не генерировало оконное сообщение в ранних версиях Windows, но в Windows 95 оно начало генерировать сообщения WM_STYLECHANGING и WM_STYLECHANGED. Об этом нет явного упоминания в документации к функции SetWindowLong, но оно подразумевается документацией для сообщений WM_STYLECHANGING и WM_STYLECHANGED.

Почему в документации к SetWindowLong нет этого упоминания? В то время, когда писалась документация для функции SetWindowLong, сообщений WM_STYLECHANGING и WM_STYLECHANGED еще не существовало. Таким образом, документация была полной на момент ее написания. В системах, которые использовали функцию SetWindowLong, появились вторичные побочные эффекты, но никто не удосуживался обновить документацию, потому что, вероятно, никто просто не сталкивался с ними. А затем вторичные побочные эффекты привели к третичным побочным эффектам: функция SetScrollInfo может изменять внешний вид окна, добавляя или удаляя стили WS_HSCROLL или WS_VSCROLL, что в результате приводит к вызову функции SetWindowLong, которая, в свою очередь, генерирует сообщения WM_STYLECHANGING и WM_STYLECHANGED. Далее последовали четвертичные побочные эффекты, вместе с функциями, вроде FlatSB_SetScrollInf, поскольку они в ходе своей работы вызывают SetScrollInfo. И так далее, и так далее. Отследить полностью этот волновой эффект, вызванный двумя новыми сообщениями, вероятно, просто невозможно.

Но основная причина всех этих волновых эффектов — это работа с окном (в частности, модификация окна) из потока, отличного от того, которое владеет окном. Избегайте таких ситуаций, и вы избежите проблем, связанных с делением вызовов на операции, генерирующие оконные сообщения, и операции, которым удается выполниться украдкой, без генерации сообщений (по крайней мере, пока).