Оригинальный DVD-ROM: eXeL@B DVD !
eXeL@B ВИДЕОКУРС !

ВИДЕОКУРС ВЗЛОМ
выпущен 2 сентября!


УЗНАТЬ БОЛЬШЕ >>
Домой | Статьи | RAR-cтатьи | FAQ | Форум | Скачать | Видеокурс
Новичку | Ссылки | Программирование | Интервью | Архив | Связь

ПРОГРАММИРОВАНИЕ НА C и С++



Программисты долго мучаются с кодом прогаммы, изучают С++, WinAPI функции, MSDN. Потом пишут банальную систему защиты или навешивают банальный протектор, а крэкеры и реверсеры справляются с такой защитой за 5 минут. В итоге, продажи программы почти нулевые. Чтобы такого не допустить, тут самому надо немного поднабрать опыта отладки, реверсинга, тот же отладчик Ollydbg изучить или дизассемблер IDA Pro. Но где искать по крохам эти знания? Нет, конечно можно годами "методом тыка" разбираться, но куда быстрее видеокурс специальный посмотреть. Вот тут он есть: ссылка. Автор курса с большим опытом и объясняет понятно, я из этого курса много узнал про то как работает компьютер, процессор, про инструменты специальные и как с ними работать. Мои коллеги программисты на работе ничего такого и не знают, теперь я им нос утру.

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

Автор: 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  "Intergalactic\n
      Intergalactic settings for space
      cadets\n\n"
  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:\utils\MyPanel\MyPanel.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();
     }
  }

 



<< ВЕРНУТЬСЯ В ПОДРАЗДЕЛ

<< ВЕРНУТЬСЯ В ОГЛАВЛЕНИЕ




Материалы находятся на сайте https://exelab.ru/pro/



Оригинальный DVD-ROM: eXeL@B DVD !


Вы находитесь на EXELAB.rU
Проект ReactOS