Программирование на Visual C++. Архив рассылки
Шрифт:
Теперь
…
Это необходимо для того, чтобы отобразить самую первую закладку.
Как вариант можно просто вызвать OnSelchangeTab1(0,0); но тогда из OnSelchangeTab1 нужно удалить последнюю строку (*pResult=0).
Можете вволю поэксперементировать со свойствами и стилями CTabCtrl. Мне, например, очень нравятся закладки, надписи на которых подсвечиваются при наведении курсора мыши, кстати это имеет место в MS Access 97 (стиль TCS_HOTTRACK).
И еще: не забудьте, если диалог у вас немодальный, вы должны обеспечить корректный обмен данными между активным диалогом в Tab Control и вашим приложением. Это делается точно так же, как и обычный обмен данными с немодальным диалогом.
Небезызвестный вам Борис Бердичевский (см. выпуск №3) делится своим решением часто возникающей проблемы с сериализацией.
Приветствую!
Случилось так, что мне пришлось потратить целый рабочий день на поиск одного решения в области сериализации; готов поделиться.
Как я уже отмечал недавно, при сериализации данных нужно решать проблему совместимости старых структур сохраняемых данных, т.е. если вы добавили новое поле в какой-то класс, подлежащий сериализации, будьте добры, обеспечьте чтение этого класса, ранее сохраненного без этого поля.
Способ, который я приводил (ReadClass/WriteClass), вполне хорош. Но закавыка-то в том, что в предыдущей версии я по какой-то причине (просто по неопытности) сохранял без WriteClass! А имплементация сериализации была описана как IMPLEMENT_SERIAL(MyClass, CObject, 0)
Итак, подобным образом сериализованный класс надо было успешно прочитать. Понятное дело, ReadClass на такую сериализацию вызывает CArchiveException с кодом CArchiveException::badIndex (=5, для справки)
Казалось бы, лови CArchiveException и обрабатывай себе, но не тут-то было! Вроде незначительная проблема: указатель архива продвигается, и невозможно уже прочитать данные из-за смещения. Никакого средства для возврата указателя на место для CArchive не существует! (Я бы мог попросить уважаемых читателей порыться, но заранее заявляю: бессмысленно! Говорите, можно манипулировать с функцией Seek принадлежащего
CArchive классу CFile? – пробовал, не работает.)
По счастью, нашлась недокументированная возможность. Выяснилось, и это очень важный нюанс, который не разъяснен в MSDN: У функции CReadClass есть 3 параметра, 2 последних имеют умолчание NULL:
Первый параметр – RuntimeClass для проверки на соответствие загружаемого класса.
Второй параметр – поинтер на UINT – версию сериализуемого класса.
Третий параметр, и это самое интересное (кстати, в MSDN записано, что, он предназначен для внутреннего использования в функции ReadClass и обычно задается как NULL) – если не задан нулем, возвращает в младших 2-х байтах значение, сериализованное из архива, а CArchiveException при этом не вырабатывается! Версия при этом не заполняется.
Отсюда решение, которое проиллюстрировано во фрагменте кода:
…
Здравствуйте Алекс!
Только что подписался на вашу рассылку, и прочитал все выпуски из архива. Мне показался интересным вопрос из выпуска N2 про возможность структурного сохранения данных в MFC.
На мой взгляд опубликованные ответы были не очень точны, т.к. в MFC все-таки имеются некоторые способы такого хранения, хотя конечно не совсем до конца доделанные.
Прежде всего существует класс COleDocument, который позволяет хранить данные в compound file – в которых как раз и хранятся иерархические данные.
У этого класса есть, к сожалению не документированный, член m_lpRootStg который представляет из себя корневой storage документа. К сожалению в MFC нет стандартных средств работы со storage, но никто не мешает пользоваться его собственным интерфейсом.
Зато есть класс COleStreamFile который инкапсулируют в себе IStream являясь в то же время потомком CFile, что делает возможным его использования для CArchive и соответственно serialize.
И наконец последнее замечание. К сожалению, модель MFC такова, что при использовании своих IStorage объектов, их НЕОБХОДИМО записывать в функции serialize, иначе они могут потеряться при команде Save As.
Вот и все что я хотел напистаь. Может немного сумбурно и поздновато, но может кому-нибудь пригодиться.
С уважением,
Спасибо Нику за ответ и полезную информацию. Я просто хочу заметить, что все-таки вместо "недоделанных" способов чаще предпочитаю использовать свои, хоть с потом и кровью созданные, но доделанные, удобные, не основывающиеся на недокументированных возможностях, досконально известные и работающие на все 100%.
Но это вопрос философский, конечно… Иногда действительно это приводит к изобретению велосипеда. Программирование – это все-таки больше искусство, чем наука ;) Каждый творит по-своему.
Пришло дополнение к прошлому выпуску:
Hello!
Маленькое замечание. После Shell_NotifyIcon( NIM_ADD, &nid); надо еще добавить ::DestroyIcon(nid.hIcon);
Я как-то делал анимацию иконки в трэе (типа как TheBat крылышками там машет) и долго не мог понять, почему после нескольких часов работы прога вешает всю систему, а никакой утечки памяти нет.
Огромное спасибо, Андрей! Действительно, если делать такие анимации в tray, то своевременное уничтожение иконки становится критичным.
И еще на тему прошлого выпуска:
В 11 выпуске был вопрос, касаемо часов и реестра. Дело не в тебе, а в авторе сообщения. Дело в том, что windoza ставит в этот ключ что-то только если user что-то поменял в разделе "язык и стандарты". Если же там всё по умолчанию, то в реестре у тебя будет по этому пути только параметр Locale, указывающий код страны, правила записи даты, времени и т.п. которой используются для вывода системной даты.
Что ж, видимо так оно и есть. Я дописал нужные параметры и все заработало. Но только после того, как я изменил региональный стандарт с русского на английский(США). Те два параметра, в которых вы записывали свое имя – на самом деле это метки "до полудня" и "после полудня", по умолчанию равные "AM" и "PM". В русском стандарте эти метки не используются.
Это последний выпуск рассылки в этом сезоне. К сожалению, я не знаю никого, кому мог бы доверить вести рассылку на время моего отпуска (и кто бы горел желанием это делать), поэтому рассылка также уходит в отпуск до конца лета .