Чтение онлайн

ЖАНРЫ

Программирование на Visual C++. Архив рассылки

Jenter Алекс

Шрифт:

Переписываем функцию – обработчик следующим образом:

UINT CAboutDlg::OnNcHitTest(CPoint point) {

 UINT ret = CDialog::OnNcHitTest(point);

 // если обработчик по умолчанию говорит нам что мышка

 // над клиентской областью окна, заменяем возвращаемое

 // значение на HTCAPTION – мышка над заголовком окна,

 // а за заголовок перемещать окно можно!

 if (ret == HTCLIENT) return HTCAPTION;

 return ret;

}

Второй способ проще, первый потенциально гибче, используйте

тот, что лучше подходит к вашему конкретному случаю.

Если у вас есть вопрос по программированию, вы можете задать его одном из форумов на RSDN.

Это все на сегодня. Не забывайте заходить на RSDN. До встречи! 

Алекс Jenter jenter@rsdn.ru Красноярск, 2001. Рассылка является частью Проекта RSDN

Программирование на Visual C++

Выпуск №42 от 29 апреля 2001 г.

Всем привет!

СТАТЬЯ 

Сериализация в MFC

Скорость, гибкость, типонезависимость

Автор: Джим Биверидж

Перевод: Олег Быков

Источник: www.ddj.com

Опубликовано: 17.04.2001

Версия текста: 1.0 

Я следил за разработкой многих коммерческих программных продуктов от начального проектирования до выпуска рабочей версии, поэтому я скептически отношусь к концепции "компонент – черный ящик", так как следовать ей все труднее и труднее по мере развития и усложнения проекта. Когда я впервые познакомился с механизмом сериализации в библиотеке MFC [адекватного перевода английского слова "serialization" нет, поэтому здесь я использовал транслитерацию. В статье этот термин применяется для обозначения процесса сохранения/восстановления данных – прим.пер.], мне стало интересно, насколько этот механизм гибок и производителен для коммерческого применения. В процессе исследования я обнаружил, что, несмотря на некоторые ограничения, механизм сериализации в MFC основан на современной теории объектно-ориентированного проектирования и более того, этот механизм не привязан к какому-то определенному типу и допускает свое дальнейшее развитие.

Использовать MFC-сериализации несложно. Любой класс, производный от CObject, может переопределить функцию Serialize, принимающую в качестве параметра объект класса CArchive. В этой функции Вы можете добавить свой код для сохранения и восстановления любых данных Вашего класса.

Сериализация данных производится с помощью операторов operator<< и operator>>, совсем как в случае с классом iostream. Разница в том, что CArchive подразумевает только двоичный формат данных. Подобно iostream, в CArchive реализованы операторы для чтения и записи фундаментальных типов данных, таких как long и char. Отсутствие типа данных int упрощает переносимость между 16– и 32-битными платформами. Встроенные операторы также реализуют перестановку байтов для типов, которые это поддерживают. (За дополнительной информацией о совместимости между платформами с прямой и обратной записью байтов [Little-Endian и Big-Endian] обратитесь к книге "Endian-Neutral Software," by James R. Gillig, DDJ, October/November 1994).

Реализация сериализации в MFC выглядела очевидной и неинтересной до того момента, когда мне понадобилось создать несколько типов документов в одном приложении. Я заметил, что когда я открывал в программе файл, MFC корректно создавала объект документа нужного типа и вызывала соответствующую функцию Serialize. Это происходило, несмотря на то, что я не написал ни строчки кода, чтобы помочь MFC в создании документов. По крайней

мере, я так считал:

Проблемы, всюду проблемы

Чтобы создавать документ или любой другой вид объектов "на лету", MFC должна решить три проблемы:

Проблема 1. По мере необходимости должны создаваться объекты произвольных типов, но оператор new может работать только с явно указанным типом, поэтому для CObject нужно реализовать некое подобие "виртуальных конструкторов".

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

Проблема 3. Необходим механизм сопоставления для создания объекта нужного типа по информации, прочитанной из файла. Этот механизм не может быть жестко зашит в MFC, потому что разработчики все время добавляют новые типы данных.

Как будет продемонстрировано далее, MFC элегантно решает эти проблемы, используя реестр с автоматической регистрацией типов [здесь и далее под реестром понимается программная структура, а не реестр WIndows – прим.пер.] и реализуя виртуальные конструкторы на основе зарегистрированных типов. Идентификация типов во время исполнения (RTTI) библиотеки MFC – вот краеугольный камень этой архитектуры.

Реестр типов

Чтобы осуществить идентификацию объектов во время выполнения, MFC создает в приложении реестр классов, унаследованных от CObject. Этот реестр никак не связан с OLE-реестром, но их концепции схожи. Реестр типов представляет собой связанный список структур CRuntimeClass, в котором каждая структура описывает один класс-наследник CObject. На листинге 1 показано внутреннее устройство структуры CRuntimeClass.

Листинг 1

struct CRuntimeClass {

 // Attributes

 LPCSTR m_lpszClassName;

 int m_nObjectSize;

 UINT m_wSchema; // номер схемы загруженного класса

 void (PASCAL* m_pfnConstruct)(void* p); // NULL => abstract class

 CRuntimeClass* m_pBaseClass;

 // Operations

 CObject* CreateObject;

 // Implementation

 BOOL ConstructObject(void* pThis);

 void Store(CArchive& ar);

 static CRuntimeClass* PASCAL Load(CArchive& ar, UINT* pwSchemaNum);

 // объекты CRuntimeClass, связанные в простой список

 CRuntimeClass* m_pNextClass;// список зарегистрированных классов

};

Весь фокус в том, что типы из этого реестра не прописаны ни в одной таблице. Первый ключ к разгадке этого феномена находится в начале файла SCRIBDOC.H из MFC-примера "Scribble". Начало объявления класса выглядит так, как показано в примере 1(a).

Пример 1: (a) Начало объявления класса; (b) после обработки препроцессором макрос DECLARE_DYNCREATE разворачивается в несколько новых членов класса.

(a)

class CScribDoc : public CDocument {

protected:

 // создавать только при сериализации

 CScribDoc;

 DECLARE_DYNCREATE(CScribDoc)

 ...

};

(b)

protected:

Поделиться с друзьями: