Базы данныхИнтернетКомпьютерыОперационные системыПрограммированиеСетиСвязьРазное
Поиск по сайту:
Подпишись на рассылку:

Назад в раздел

Как создавать значки в панели управления.

div.main {margin-left: 20pt; margin-right: 20pt} Как создавать значки в панели управления.

Автор: Paul DiLascia

Скачать исходник к статье - 179 Кб (Компилятор: Visual C++)

Значки, которые мы привыкли видеть в панели управления, это так называемые апплеты, которые представляют из себя обычные DLL-ки, имеющие расширение .cpl и содержащие в себе специфическую функцию CPlApplet. Каждый раз, когда запускается приложение панели управления (CONTROL.EXE), то сперва оно ищет в системной директории все файлы XXX.cpl, затем загружает каждую DLL и вызывает функцию CPlApplet с различными сообщениями. Например, когда Панель управления запускается первый раз, то функция CPlApplet вызывается с сообщением msg=CPL_INIT. Затем, если пользователь дважды кликнет по иконке аплета, то CPlApplet будет вызвана с сообщением msg=CPL_DBLCLK.

Каждая DLL-ка панели управления может поддерживать несколько иконок или апплетов. Для этого панель управления посылает сообщение CPL_GETCOUNT, и от нас требуется сообщить ей точное количество. После этого панель управления запросит информацию о каждом апплете при помощи сообщений CPL_INQUIRE или CPL_NEWINQUIRE. На рисунке показан процесс посылки сообщений панелью управления:


Рисунок 1.

Процедура общения Вашей DLL с панелью управления довольно универсальна и легко воплощается в классах. Поэтому я создал два класса CControlPanelApp и CCPApplet, которые собственно и занимаются процессом общения. Чтобы показать, как это работает, я написал собственную DLL панели управления MyPanel. Она включает в себя два апплета (Рисунок 2), один диалог (Рисунок 3) и одно окошко с закладками (Рисунок 4)


Рисунок 2.

MyPanel.cpp представляет обычное MFC Документ/Вид приложение за исключением того, что класс наследован от CControlPanelApp вместо CWinApp. А вместо InitInstance (которая обычно используется для добавления шаблонов документов) я вызываю OnInit, в которой создаю два апплета:

BOOL CMyControlPanelApp::OnInit() { AddApplet(newCCPApplet( IDR_MYAPPLET1, RUNTIME_CLASS( CMyDialog1))); AddApplet(new CCPApplet( IDR_MYAPPLET3, RUNTIME_CLASS( CMyPropSheet))); return CControlPanelApp::OnInit(); }

 

Класс апплета CCPApplet настолько универсален, что даже нет необходимости в MyPanel наследовать от него собственный. Единственное, что прийдётся дописать соственно код для диалогов. В моём случае, MyPanel включает диалог (CMyDialog) и property sheet (CMyPropSheet). Чтобы добавить свои диалоги, достаточно написать и и переопределить CControlPanelApp::OnInit как показано выше. Класс сделает всё остальное самостоятельно.


Рисунок 3.

Классы CControlPanelApp и CCPAppletBut так же заботятся о иконках, описании, функции CPlApplet а так же о всех CPL сообщениях. CPanel.cpp содержит в себе функцию CPlApplet, которая передаёт CPL сообщения в виртуальную функцию. Когда панель управления вызывает CPlApplet с сообщением CPL_INIT, то CPlApplet вызывает CControlPanelApp:: OnCplMsg, которая в свою очередь вызывает CControlPanelApp::OnInit. OnCplMsg это аналог CWnd::WindowProc, а OnInit - аналогичен обработчику сообщения OnCreate. Некоторые CPL сообщения, типа CPL_INQUIRE и CPL_ DBLCLK, имеют параметр lParam1, который содержит номер апплета (индекс), для которого предназначено сообщение. Как я уже говорил, DLL-ка панели управления может обслуживать несколько иконок или апплетов, поэтому в таких случаях CControlPanelApp::OnCplMsg направляет сообщение в виртуальную функцию в CCPApplet, а не CControlPanelApp.


Рисунок 4.

А теперь предлагаю более подробно разобраться с моим апплетом. Для создания апплета, вызывается конструктор, в который необходимо передать ID ресурса и MFC runtime class.

AddApplet(new CCPApplet(IDR_MYAPPLET3, RUNTIME_CLASS(CMyPropSheet)));

Этой информации достаточно для создания апплета. После вызова этой функции, Ваш апплет добавится к списку m_lsApplets. Дефолтовый обработчик для CPL_ GETCOUNT возвращает число апплетов, беря информацию именно из этого списка. Как только панель управления пошлёт CPL_INQUIRE или CPL_ NEWINQUIRE, то CCPApplet воспользуется идентификатором (ID) ресурса, чтобы получить иконку, имя и описание. Имя и описание, разделены на подстроки в основной строке ресурса.

  STRINGTABLE PRELOAD DISCARDABLE BEGIN IDR_MYAPPLET3 "Intergalacticn Intergalactic settings for space cadetsnn" END

Теперь, если кликнуть по иконке апплета, то панель управления пошлёт сообщение CPL_DBLCKT, которое будет обработано функцией CCPApplet::OnLaunch, которая использует runtime class для создания экземпляра диалогового окошка или окна с закладками, а затем просто вызывает DoModal.

LRESULT CCPApplet::OnLaunch(CWnd* pWndCpl, LPCSTR lpCmdLine) { CWnd* pw = (CWnd*)m_pDialogClass->CreateObject(); if (pw) { if (pw->IsKindOf(RUNTIME_CLASS(CPropertySheet))) { CPropertySheet* ps = (CPropertySheet*)pw; ps->SetActivePage(lpCmdLine ? atoi(lpCmdLine) : 0); ps->DoModal(); } else if (pw->IsKindOf(RUNTIME_CLASS(CDialog))) { CDialog* pd = (CDialog*)pw; pd->DoModal(); } } return pw==NULL; }

Не забудьте объявить своё диалоговое окошко в DECLARE_DYNCREATE, иначе оно не создастся. Так же не забудьте переопределить OnPostNcDestroy чтобы "удалить его". Почему ? Объясняю. Обычно мы создаём диалог в стеке

CMyDialog dlg; dlg.DoModal();

поэтому нет необходимости его удалять. Однако, CCPApplet создаёт Ваш диалог в куче, поэтому необходимо удалять его после того, как он будет уничтожен. Иначе будет утечка памяти.

После того, как апплет будет откомпилирован, не забудьте переименовать его в .cpl и поместить в системную директорию. Однако, DLL-ку можно оставить и в своей директории, тогда необходимо в CONTROL.INI в секции MMCPL добавить следующую строчку:

[MMCPL] MyPanel=c:utilsMyPanelMyPanel.cpl

Существует маленькая проблемка, которая возникает, если Вы вдруг захотите добавить новый апплет или изменить имя или иконку. Изменения сразу не появятся в панели управления. Дело в том, что панель управления, после того как считает информацию (CPL_INQUIRE) из Вашего апплета, сражу же закэширует её на диск. Верный способ заставить панель управления поновой считать информацию из апплета, это переименовать DLL. Можно канечно просто нажать F5 (Обновить), но у меня это не дало результатов. В процессе разработки можно установить CCPApplet::m_bDynamic в TRUE, тем самым указав классу использовать CPL_NEWINQUIRE (информация не кэшируется) вместо CPL_INQUIRE (информация кэшируется). А после того, как все отладки будут закончены опять вернуть m_bDynamic=FALSE (по умолчанию).

Один из немаловажных вопросов, которые могут возникнуть при создании апплета панели управления, это как его отлаживать ? Есть два пути решения данной проблемы. Можно запустить панель управления под отладчиком, а можно воспользоваться rundll32:

rundll32 shell32.dll,Control_RunDLL mypanel.cpl

Control_RunDLL, это специальная функция в shell32.dll, которая запускает приложение панели управления. Чтобы запустить определённый апплет в Вашей DLL, наберите следующее

  rundll32 shell32.dll,Control_RunDLL mypanel.cpl,@n

где n, это номер Вашего апплета. Если добавить в конец строку, то она будет передана в CPL_ STARTWPARAMS типа командной строки (command line), которая передаётся  в стандартном приложении Windows. Обычно такая строка используется для апплетов, основанных на property sheet, чтобы сразу показать определённую страницу. Например, чтобы показать закладку Настройка (Settings) в свойствах экрана (Display Properties) наберите следующее:

  rundll32 shell32.dll,Control_RunDLL desk.cpl,,3

В моей программе, нет необходимости делать дополнительную разборку параметров. Если Ваш апплет будет основан на property sheet, то CCPApplet автоматически интерпретирует дополнительный аргумент как номер страницы.

// В CCPApplet::OnLaunch CWnd* pw = (CWnd*)m_pDialogClass->CreateObject(); if (pw) { if (pw->IsKindOf(RUNTIME_CLASS(CPropertySheet))) { CPropertySheet* ps = (CPropertySheet*)pw; ps->SetActivePage(lpCmdLine ? atoi(lpCmdLine) : 0); ps->DoModal(); } }

  • Главная
  • Новости
  • Новинки
  • Скрипты
  • Форум
  • Ссылки
  • О сайте




  • Emanual.ru – это сайт, посвящённый всем значимым событиям в IT-индустрии: новейшие разработки, уникальные методы и горячие новости! Тонны информации, полезной как для обычных пользователей, так и для самых продвинутых программистов! Интересные обсуждения на актуальные темы и огромная аудитория, которая может быть интересна широкому кругу рекламодателей. У нас вы узнаете всё о компьютерах, базах данных, операционных системах, сетях, инфраструктурах, связях и программированию на популярных языках!
     Copyright © 2001-2024
    Реклама на сайте