Страницы свойств
library ATLGLLib { importlib("stdole32.tlb"); importlib("stdole2.tlb"); [ uuid(6DEBB446-C43A-4AB5-BEEl-110510C7AC89) helpstring("_IOpenGLEvents Interface") ] dispinterface _IOpenGLEvents { properties: methods: }; [ uuid(5B3EF182-CD91-426F-9309-2E4869C353DB), helpstringC'OpenGL Class") ] coclass COpenGL { [default] interface IQpenGL; [default, source] dispinterface _IOpenGLEvents; }; //====== Новые элементы в библиотеке типов сервера [ uuid(3AE16CD6-4558-460F-8A7E-5AB83D40DE9A), helpstring ("_IGraphPropEvents Interface") ] dispinterface _IGraphPropEvents { properties: methods: }; [ uuid(lAOC756A-DA17-4630-91BO-72722950B8F7), helpstring("GraphProp Class") ] coclass PropDlg { interface lUnknown; [default, source] dispinterface _IGraphPropEvents; };
Убедитесь, что в составе проекта появились новые файлы (PropDlg.h, PropDlg.cpp и PropDlg.rgs). Откройте первый файл описаний и отметьте, что класс CPropDlg происходит от четырех родителей (классов ATL и одного интерфейса). Два из них (ccomObjectRootEx и CGomCoClass) мы уже встречали ранее, а два других (iPropertyPagelmpl и CDialoglmpl), как нетрудно догадаться, поддерживают функциональность диалоговой вкладки (страницы), размещаемой в блоке страниц (property sheet), и самого диалога, то есть механизм обмена данными. Оба родителя являются шаблонами, которые уже настроены на наш конкретный класс CPropDlg. Конструктор класса:
CPropDlg() { m_dwTitleID = IDSJTITLEPropDlg; m_dwHelpFileID = IDS_HELPFILEPropDlg; m_dwDocStringID = IDS_DOCSTRINGPropDlg; }
Устанавливает унаследованные переменные m_dwTitleio и идентификаторы строковых ресурсов в те значения, которые им присвоил мастер Studio .NET. Сами строки вы можете увидеть в ресурсах, если откроете узел дерева String Table. В классе изначально присутствует реакция на кнопку Apply, которая, как вы знаете, всегда сопровождает блок диалоговых вкладок (property sheet):
//====== Реакция на нажатие кнопки Apply STDMETHOD(Apply)(void) { ATLTRACE(_T("CPropDlg::Apply\n")); for (UINT i = 0; i < m_nObjects; i++) { // Do something interesting here // ICircCtl* pCirc; //m_ppUnk[i] › QueryInterface(IID_ICircCtl, (void**)SpCirc) // pCirc › put_Caption(CComBSTR("smth special")); // pCirc › Release(); } m_bDirty = FALSE; return S__OK; }
В комментарий мастер поместил подсказку, которая дает намек о том, как следует пользоваться новым классом. Как вы видите, общение между двумя классами нашего сервера (copenGL и CPropDlg) должно происходить по правилам СОМ, то есть с помощью указателя на интерфейс. Этот факт производит впечатление излишней усложненности. Если оба класса расположены в рамках одной DLL, они могли бы общаться друг с другом с помощью прямого указателя, несмотря на то, что сама DLL загружается в пространство чужого процесса.
Примечание
Имя ICircCtl, которое присутствует в подсказке, не имеет отношения к нашему проекту. Оно связано с учебным примером по созданию элементов управления с помощью библиотеки ATL. Вы можете увидеть этот пример в MSDN (Visual C++ Tutorials › Creating the Circle Control).
Переменная m_bDirty используется каркасом в качестве флага доступности кнопки Apply. Если m_bDirt у == FALSE; то кнопка недоступна. Она тотчас же должна стать доступной, если пользователь страницы диалога свойств введет изменения в органы управления на лице диалога. Конечно, этим состоянием управляет разработчик, то есть мы с вами.