Побочные эффекты вызова RegisterWindow несколько раз с одним и тем же классом окна? - PullRequest
3 голосов
/ 30 сентября 2008

Сейчас я работаю над небольшим тестовым приложением, и у меня есть несколько объектов окна, плавающих вокруг, и каждый из них вызывает RegisterWindowEx с одинаковой структурой WNDCLASSEX (главным образом потому, что все они являются экземплярами одного класса).

Первый из них регистрируется нормально, затем несколько из них терпят неудачу, говоря, что класс уже зарегистрирован - как и ожидалось.

Мой вопрос - это плохо? Я думал об использовании хеш-таблицы для хранения результатов ATOM, чтобы посмотреть перед вызовом RegisterWindow, но, похоже, Windows уже это делает?

Ответы [ 5 ]

4 голосов
/ 30 сентября 2008

Если ваш класс окон определен в DLL

Возможно, вам следует позвонить на RegisterClass() в PROCESS_ATTACH-части DllMain и позвонить на UnregisterClass() в PROCESS_DETACH-части DllMain

Если ваш класс окон определен в исполняемом файле

Возможно, вам следует позвонить на RegisterClass() в основном, до цикла сообщений, и позвонить в UnregisterClass() в основном, после цикла сообщений.

Регистрация в конструкторе объектов была бы ошибкой

Потому что вы бы рефлекторно очистили его в деструкторе. Если одно из ваших окон будет уничтожено, будет вызван деструктор и ... Если у вас есть другие окна, плавающие вокруг ...

А для использования глобальных данных для подсчета количества активных регистраций потребуется правильная синхронизация, чтобы убедиться, что ваш код ориентирован на многопоточность, если не поточнобезопасен.

Почему в основном / DllMain?

Потому что вы регистрируете какой-то глобальный объект (по крайней мере, для вашего процесса). Поэтому имеет смысл инициализировать его «глобальным способом», то есть в основном или в DllMain.

Почему это не так зло?

Потому что Windows не выйдет из строя только потому, что вы зарегистрировали ее более одного раза.

Чистый код использовал бы GetClassInfo(), чтобы спросить, был ли класс уже зарегистрирован.

Но, опять же, Windows не будет зависать (по крайней мере, по этой причине).

Вы даже можете избежать отмены регистрации класса окна, так как Windows удалит их после завершения процесса. Я видел противоречивую информацию в блогах MSDN на эту тему (два года назад ... не просите меня снова найти эту информацию).

Почему это все равно зло?

Моя личная точка зрения заключается в том, что вы должны аккуратно обращаться со своими ресурсами, то есть выделять их один раз, а освобождать - один раз. То, что Win32 удалит утечку памяти, не должно помешать вам освободить динамически выделенную память. То же самое касается оконных классов.

3 голосов
/ 30 сентября 2008

Вы можете проверить, был ли ранее зарегистрирован класс окна, вызвав GetClassInfoEx .

Если функция находит соответствующий класс и успешно копирует данные, возвращаемое значение отлично от нуля.

http://msdn.microsoft.com/en-us/library/ms633579(VS.85).aspx

Таким образом, вы можете условно зарегистрировать класс окна на основе возврата GetClassInfoEx .

2 голосов
/ 30 сентября 2008

Вам нужно всего лишь один раз вызвать RegisterWindowEx и затем использовать полученный ATOM при создании ваших окон. Нет проблем в повторном использовании этого ATOM для нескольких окон.

0 голосов
/ 30 сентября 2008

У меня недавно была эта проблема. Чтобы обойти это и сохранить весь код в соответствующем классе, а не распространять его по программе, у меня был статический счетчик классов, который я увеличил перед вызовом RegisterClass (). Затем я проигнорировал возвращаемые значения ERROR_CLASS_ALREADY_EXISTS и вызывал UnregisterClass () в dtor только тогда, когда счетчик ссылок был равен 0.

Это не требует какой-либо блокировки (используйте InterlockedIncrement () и InterlockedDecrement () для управления счетчиком ссылок) и означает, что при использовании класса не нужно знать или заботиться о том, чтобы внутри класса использовалось скрытое окно.

0 голосов
/ 30 сентября 2008

Что ж, вы могли бы избежать вызова в ядро ​​- кажется, что RegisterClass нужно туда попасть - но классы окон для каждого процесса и для модуля, так что вам не нужно ничего вредить, регистрируя класс несколько раз.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...