Тотальная неудачница и убийца жёстких дисков.
#post-id: 2797-04-18
#original-date: 23.03.2008 Sun
#original-time: 4:18 AM
#original-day:  2797
#original-host: WinXP Prof SP2 (Build 2600)

Открытие месяца. До этого всю жизнь думала, что VB для каждого экземпляра User Control создаёт отдельную копию глобальных переменных. Оказалось, что это если они в разных нитях живут, а так переменные очень даже расшарены. Иными словами, если в модуле есть такой код:

Global AnyData As Long



То если один экземпляр User Control установит туда 69, то второй прочитает тоже самое. А из этого следует, что у меня был баг в SysTray Control, который я сейчас исправляю, а ещё (возможно) в субклассировщике.

Нет, в нём нет.

Зато поюзала Window Properties, тоесть оконные свойства. Есть в Win32 такая фича ,когда для окна можно задать свойство с любым именем и присовоить ему DWORD. В моём случае это будет указатель на контрол для вызова событий в самом элементе из оконной функции. Это особенность VB - там функции обратного вызова должны быть в модуле, поэтому приходится так извращаться. Субклассируем форму, а код выносим в модуль, а там уже получаем указатель на объект формы и как-то на неё воздействуем. Да. А ещё будет адрес предыдущей оконной процедуры.

Чего это я вообще затеяла? Дело в том, что у меня давно назрела идея автоматизировать обработку сообщения TaskbarCreated, которое рассылается всем окнам верхнего уровня при создании панели задач (если, скажем, залогинился пользователь или воскрес вылетевший Explorer). Первоначальная идея и заключалась в использовании локального хука, которая в тесте работала классно, но провалилась когда на форме оказалось два контрола. Проект вёл себя странно, и когда я поняла, что дело в вышеописанном баге, мне не хотелось возвращаться, ибо возможны другие ошибки, если нить будет уничтожена, но хук не будет снят.

Вторая идея заключалась в проверке очереди сообщений циклом и PeekMessage(). Поскольку PeekMessage() не ждёт сообщений, начались тормоза. Тогда я взяла GetMessage() и DispatchMessage(). Стало лучше, но форма упорно не хотела выгружаться из-за цикла, да и были проблемы с обработкой таблиц акселераторов, которой не было ^^ Тоесть все горячие клавиши ушли безвозвратно.

Тогда я добралась до третьей идеи, на которой и нашла баг. Идея в том, чтобы создать невидимую форму верхнего уровня и положиться на VB. Я могла бы создать лёгкое окно через CreateWindowEx(), но тогда много чего пришлось бы делать ручками, и в процессе отладки некоторые окна могли остаться в памяти и обратиться к несуществующей функции... И вот, я начала реализовывать план, обнаружила, что для второго контрола функция создания этого окна не выполняется, поскольку переменная, которая содержит ссылку на окно, чем-то заполнена. Я потестировала, и поняла, что тремя глобальными переменными обойтись нельзя - они расшарены... Тут же я поняла, что мои программы не летают толкьо потому что при уничтожении контролов им в качестве предыдущей оконной процедуры присваивается хоть и не родная процедура, но по сути одна и таже.

Что делать? Как оконной процедуре передать целых три значения? Вообще, обычно при субклассировании предыдущее значение алдреса оконной процедуры пишется функцией SetWindowLong() в GWL_USERDATA. Но там один Long, а у меня три ^^ Использовать структуры я, конечно же, не догадалась, поэтому нашла альтернативный способ - через оконные свойства.

Вот ^^

#music: Noir OST II\Original SoundTrack\A Farewell Song