Створення системних пасток Windows на Borland C + + Builder, Різне, Програмування, статті

Перш ніж викладати матеріал я хочу зауважити, що мета даної роботи – показати як пишуться пастки Windows взагалі. Подробиці, в міру можливості, я буду опускати (їх можна знайти в поставляється з середовищем розробці довідці).

Для початку визначимо, що саме ми хочемо зробити.

Мета: написати програму, яка буде викликати хранитель екрану при переміщенні курсора миші в правий верхній кут і видавати звуковий сигнал через вбудований динамік при перемиканні мови з клавіатури.

Передбачається, що така програма повинна мати невеликий розмір. Тому будемо писати її з використанням тільки WIN API.


Поняття пастки.

Пастка (hook) – це механізм, який дозволяє проводити моніторинг повідомлень системи і обробляти їх до того як вони досягнуть цільової віконної процедури.

Для обробки повідомлень пишеться спеціальна функція (Hook Procedure). Для початку спрацьовування пастки цю функцію слід спеціальним чином “підключити” до системи.

Якщо треба відстежувати повідомлення всіх потоків, а не тільки поточного, то пастка повинна бути глобальною. В цьому випадку функція пастки повинна знаходитися в DLL.

Таким чином, завдання розбивається на дві частини:



  1. Написання DLL c функціями пастки (їх буде дві: одна для клавіатури, інша для миші).

  2. Написання програми, яке встановить пастку.

Написання DLL.


Створення порожній бібліотеки.

С + + Builder має вбудований майстер зі створення DLL. Використовуємо його, щоб створити порожню бібліотеку. Для цього треба вибрати пункт меню File-> New: У вікні треба вибрати “DLL Wizard” і натиснути кнопку “Ok”. У новому діалозі в розділі “Source Type” слід залишити значення за умовчанням – “C + +”. У другому розділі треба зняти всі прапорці. Після натискання кнопки “Ок” порожня бібліотека буде створена.


Глобальні змінні і функція входу (DllEntryPoint).

Треба визначити деякі глобальні змінні, які знадобляться в подальшому.

# Define UP 1 / / Стану клавіш
#define DOWN 2
#define RESET 3

int iAltKey; / / Тут зберігається стан клавіш
int iCtrlKey;
int iShiftKey;

int KEYBLAY ;/ / Тип перемикання мови
bool bSCRSAVEACTIVE ;/ / Чи встановлений ScreenSaver
MOUSEHOOKSTRUCT * psMouseHook; / / Для аналізу сообшеній від миші

У функції DllEntryPoint треба написати код, подібний нижчеподаному:

if (reason == DLL_PROCESS_ATTACH) / / Проектуємо на адр. витягну.
{
HKEY pOpenKey;
char * cResult = “”; / / Дізнаємося як перекл. розкладка
long lSize=2;
KEYBLAY=3;

if(RegOpenKey(HKEY_USERS,”.Defaultkeyboard layout oggle”,
&pOpenKey)==ERROR_SUCCESS)
{
RegQueryValue(pOpenKey,””,cResult,&lSize);

if(strcmp(cResult,”1″)==0)
KEYBLAY=1;
if(strcmp(cResult,”2″)==0)
KEYBLAY=2; // Ctrl+Shift

RegCloseKey(pOpenKey);
}
else
MessageBox (0, “Не можу отримати дані про спосіб”
“Перемикання розкладки клавіатури”,
“Увага!”, MB_ICONERROR);
/ / ————- Чи активний хранитель Ерана
if(!SystemParametersInfo(SPI_GETSCREENSAVEACTIVE,0,&bSCRSAVEACTIVE,0))
MessageBox (0, “Не можу отримати дані про встановлений”
“Зберігачі екрану”, “Увага!”, MB_ICONERROR);
}
return 1;

Цей код дозволяє дізнатися спосіб перемикання мови і встановити факт наявності активного хранителя екрану. Зверніть увагу на те, що цей код виконується тільки коли бібліотека проектується на адресний простір процесу – перевіряється умова (reason == DLL_PROCESS_ATTACH). Якщо вас цікавлять подробиці, то їх можна дізнатися в розділі довідки “Win32 Programmer” s Reference “в підрозділі” DllEntryPoint “.


Функція пастки клавіатури.

Функція пастки в загальному вигляді має наступний синтаксис:


LRESULT CALLBACK HookProc (int nCode, WPARAM wParam, LPARAM lParam), де:


HookProc – ім’я функції,


nCode – код пастки, його конкретні значення визначаються типом пастки,


wParam, lParam – параметри з інформацією про повідомленні.

У разі нашого завдання функція повинна визначати стан клавіш Alt, Ctrl і Shift (натиснуті або відпущені). Інформація про це береться з параметрів wParam і lParam (подробиці в “Win32 Programmer” s Reference ” в підрозділі “KeyboardProc”). Після визначення стану клавіш треба порівняти його зі способом перемикання мови (визначається у функції входу). Якщо поточна комбінація клавіш здатна перемкнути мову, то треба видати звуковий сигнал.

Все це реалізує приблизно такий код:

LRESULT CALLBACK KeyboardHook(int nCode,WPARAM wParam,LPARAM lParam)
{/ / Пастка клав. – Біканов при перекл. розкладки
if ((lParam >> 31) & 1) / / Якщо клавіша натиснута …
switch(wParam)
{/ / Визначаємо яка саме
case VK_SHIFT: {iShiftKey=UP; break};
case VK_CONTROL: {iCtrlKey=UP; break};
case VK_MENU: {iAltKey=UP; break};
}
else / / Якщо була відпущена …
switch(wParam)
{/ / Визначаємо яка саме
case VK_SHIFT: {iShiftKey=DOWN; break};
case VK_CONTROL: {iCtrlKey=DOWN; break};
case VK_MENU: {iAltKey=DOWN; break};
}
//————–
switch (KEYBLAY) / / В залежності від способу перемикання розкладки
{
case 1: // Alt+Shift
{
if(iAltKey==DOWN && iShiftKey==UP)
{
vfBeep();
iShiftKey=RESET;
}
if(iAltKey==UP && iShiftKey==DOWN)
{
vfBeep();
iAltKey=RESET;
}
((iAltKey==UP && iShiftKey==RESET)//(iAltKey==RESET &&

iShiftKey==UP))
{
iAltKey=RESET;
iShiftKey=RESET;
}
break;
}
//————————————
case 2: // Ctrl+Shift
{
if(iCtrlKey==DOWN && iShiftKey==UP)
{
vfBeep();
iShiftKey=RESET;
}
if(iCtrlKey==UP && iShiftKey==DOWN)
{
vfBeep();
iCtrlKey=RESET;
}
if((iCtrlKey==UP && iShiftKey==RESET)//(iCtrlKey==RESET &&

iShiftKey==UP))
{
iCtrlKey=RESET;
iShiftKey=RESET;
}
}
}

return 0;
}

Звуковий сигнал видається такий невеликий функцією:

void vfBeep()
{/ / Біканов
MessageBeep(-1);
MessageBeep (-1) ;/ / Два рази – для виразності
}

Функція пастки миші.

Ця функція відстежує рух курсора миші, отримує його координати і порівнює їх з координатами правого верхнього кута екрану (0,0). Якщо ці координати співпадають, то викликається хранитель екрану. Для відстеження руху аналізується значення параметра wParam, а для відстеження координат значення, що знаходиться в структурі типу MOUSEHOOKSTRUCT, на яку вказує lParam (подробиці можна знайти в “Win32 Programmer” s Reference “в підрозділі” MouseProc “). Код, який реалізує вищесказане, приблизно такий:

LRESULT CALLBACK MouseHook(int nCode,WPARAM wParam,LPARAM lParam)
{/ / Пастка миші – включає хранитель коли в кутку
if(wParam==WM_MOUSEMOVE // wParam==WM_NCMOUSEMOVE)
{
psMouseHook=(MOUSEHOOKSTRUCT*)(lParam);
if(psMouseHook->pt.x==0 && psMouseHook->pt.y==0)
if(bSCRSAVEACTIVE)
PostMessage(psMouseHook->hwnd,WM_SYSCOMMAND,
SC_SCREENSAVE,0);
}
return 0;
}

Зверніть увагу, що команда на активізацію хранителя посилається у вікно, яка отримує повідомлення від миші: PostMessage (psMouseHook-> hwnd, WM_SYSCOMMAND, SC_SCREENSAVE, 0).

Тепер, коли функції пасток написані, треба зробити так, щоб вони були доступні з процесів, підключають цю бібліотеку. Для цього перед функцією входу слід додати такий код:

extern “C” __declspec(dllexport) LRESULT CALLBACK KeyboardHook(int,WPARAM,LPARAM);
extern “C” __declspec(dllexport) LRESULT CALLBACK MouseHook(int,WPARAM,LPARAM);

Написання програми, що встановлює пастку.


Створення порожнього програми.

Для створення пустого додатка скористатися вбудованим майстром. Для цього треба використовувати пункт меню File-> New: У вікні необхідно вибрати “Console Wizard” і натиснути кнопку “Ok”. У новому діалозі в розділі “Source Type” слід залишити значення за умовчанням – “C + +”. У другому розділі треба зняти всі прапорці. При натисканні “Ок” додаток створюється.


Створення головного вікна.

Наступний етап – це створення головного вікна програми. Спочатку треба зареєструвати клас вікна. Після цього створити вікно (подробиці можна знайти в “Win32 Programmer” s Reference “в підрозділах” RegisterClass ” і “CreateWindow”). Все це робить наступний код (описувач вікна MainWnd визначений глобально):

BOOL InitApplication(HINSTANCE hinstance,int nCmdShow)
{/ / Створення головного вікна
WNDCLASS wcx; / / Клас вікна
wcx.style=NULL;
wcx.lpfnWndProc=MainWndProc;
wcx.cbClsExtra=0;
wcx.cbWndExtra=0;
wcx.hInstance=hinstance;
wcx.hIcon=LoadIcon(hinstance,”MAINICON”);
wcx.hCursor=LoadCursor(NULL,IDC_ARROW);
wcx.hbrBackground=(HBRUSH)(COLOR_APPWORKSPACE);
wcx.lpszMenuName=NULL;
wcx.lpszClassName=”HookWndClass”;

if (RegisterClass (& wcx)) / / Реєструємо клас
{
MainWnd = CreateWindow (“HookWndClass”, “SSHook”, / * Створюємо вікно * /
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,
NULL,NULL,hinstance,NULL);
if(!MainWnd)
return FALSE;

return TRUE;
}
return false;
}

Зверніть увагу на те, яким чином було отримано значок класу: wcx.hIcon = LoadIcon (hinstance, “MAINICON”); Для того, щоб це вийшло треба включити в проект файл ресурсів (*. Res), в якому повинен знаходитися значок з ім’ям “MAINICON”.

Це вікно ніколи не з’явиться на екрані, тому воно має розміри і координати, що встановлюються за замовчуванням. Віконна процедура такого вікна незвичайно проста:

 LRESULT CALLBACK MainWndProc(HWND hwnd,UINT uMsg,WPARAM wParam,
LPARAM lParam)
{/ / Віконна процедура
switch (uMsg)
{
case WM_DESTROY:{PostQuitMessage(0); break;}
//————
case MYWM_NOTIFY:
{
if(lParam==WM_RBUTTONUP)
PostQuitMessage(0);
break; / / Правий клацання на значку – завершуємо
}
default:
return DefWindowProc(hwnd,uMsg,wParam,lParam);
}
return 0;

Розміщення значка в системній області.

Виникає природне запитання: якщо вікно додатка ніколи не з’явиться на екрані, то яким чином користувач може управляти їм (наприклад, закрити)? Для індикації роботи додатку і для управління його роботою помістимо значок в системну область панелі завдань. Робиться це наступною функцією:

void vfSetTrayIcon(HINSTANCE hInst)
{/ / Значок в Tray
char * pszTip = “Хранитель екрану і розкладка” ;/ / Це просто Hint
NotIconD.cbSize=sizeof(NOTIFYICONDATA);
NotIconD.hWnd=MainWnd;
NotIconD.uID=IDC_MYICON;
NotIconD.uFlags=NIF_MESSAGE/NIF_ICON/NIF_TIP;
NotIconD.uCallbackMessage=MYWM_NOTIFY;
NotIconD.hIcon=LoadIcon(hInst,”MAINICON”);
lstrcpyn(NotIconD.szTip,pszTip,sizeof(NotIconD.szTip));
Shell_NotifyIcon(NIM_ADD,&NotIconD);
}

Для коректної роботи функції заздалегідь потрібно визначити унікальний номер значка (параметр NotIconD.uID) і його повідомлення (параметр NotIconD.uCallbackMessage). Робимо це в області визначення глобальних змінних:

#define MYWM_NOTIFY (WM_APP+100)
#define IDC_MYICON 1006

Повідомлення значка буде оброблятися у віконній процедурі головного вікна (NotIconD.hWnd = MainWnd):

case MYWM_NOTIFY:
{
if(lParam==WM_RBUTTONUP)
PostQuitMessage(0);
break; / / Правий клацання на значку – завершуємо
}

Цей код просто завершує роботу програми по клацанню правою кнопкою миші на значку.

При завершенні роботи значок треба видалити:

void vfResetTrayIcon()
{/ / Видаляємо значок
Shell_NotifyIcon(NIM_DELETE,&NotIconD);
}

Установка і зняття пасток.


Для отримання доступу в функціям пастки треба визначити покажчики на ці функції:

LRESULT CALLBACK (__stdcall *pKeybHook)(int,WPARAM,LPARAM);
LRESULT CALLBACK (__stdcall *pMouseHook)(int,WPARAM,LPARAM);

Після цього спроеціруем написану DLL на адресний простір процесу:

hLib=LoadLibrary(“SSHook.dll”);

(HLib описаний як HINSTANCE hLib).

Після цього ми повинні отримати доступ до функцій пасток:

(void*)pKeybHook=GetProcAddress(hLib,”KeyboardHook”);
(void*)pMouseHook=GetProcAddress(hLib,”MouseHook”);

Тепер все готово до постановки пасток. Встановлюються вони за допомогою функції SetWindowsHookEx:

 hKeybHook=SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)(pKeybHook),hLib,0);
hMouseHook=SetWindowsHookEx(WH_MOUSE,(HOOKPROC)(pMouseHook), hLib,0);
(HKeybHook і hMouseHook описані як HHOOK hKeybHook; HOOK hMouseHook;)

Перший параметр – тип пастки (в даному випадку перша пастка для клавіатури, друга – для миші). Другий – адреса процедури пастки. Третій – описувач DLL-бібліотеки. Останній параметр – ідентифікатор потоку, для якого буде встановлена ​​пастка. Якщо цей параметр дорівнює нулю (як у нашому випадку), то пастка встановлюється для всіх потоків.


Після установки пасток вони починають працювати. При виході з слід їх зняти і відключити DLL. Робиться це так:

UnhookWindowsHookEx(hKeybHook);
UnhookWindowsHookEx (hMouseHook); / / Завершуємо
FreeLibrary(hLib);

Функція WinMain.

Останній етап – написання функції WinMain в якій буде створюватися головне вікно, встановлюватися значок в системну область панелі завдань, ставитися і зніматися пастки. Код її повинен бути приблизно такою:

WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
//—————-
hLib=LoadLibrary(“SSHook.dll”);
if(hLib)
{
(void*)pKeybHook=GetProcAddress(hLib,”KeyboardHook”);
hKeybHook=SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)(pKeybHook),
hLib, 0) ;/ / Ставимо пастки
(void*)pMouseHook=GetProcAddress(hLib,”MouseHook”);
hMouseHook=SetWindowsHookEx(WH_MOUSE,(HOOKPROC)(pMouseHook),
hLib,0);
//——————————-
if (InitApplication (hInstance, nCmdShow)) / / Якщо створили головне вікно
{
vfSetTrayIcon (hInstance) ;/ / Встановили значок
while (GetMessage(&msg,(HWND)(NULL),0,0))
{/ / Цикл обробки повідомлень
TranslateMessage(&msg);
DispatchMessage(&msg);
}
/ / ———————————- Все – фінал
UnhookWindowsHookEx (hKeybHook); / / Знімаємо пастки
UnhookWindowsHookEx(hMouseHook);
FreeLibrary (hLib) ;/ / Відключаємо DLL
vfResetTrayIcon () ;/ / Видаляємо значок
return 0;
}
}
return 1;
}

Після написання цієї функції можна сміливо запускати повністю готове додаток.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*