Глава 3 об'єкти ядра

if (pWideCharStr == NULL) return (fOk);

// перетворимо нультібайтовую рядок в шірокосімвольную

MultiByteToWideChar (CP_ACP, 0, pMulti8yteStr, -1, pWideCharStr, nLenOfWideCharStr);

// викликаємо шірокосімвольную версію цієї функції для виконання цієї роботи

// перетворимо шірокосімвольную рядок назад в мультібайтовую

WideCharToMultiByte (CP_ACP, 0, pWideCharStr, -1, pMultiByteStr, strlen (pMultiByteStr), NULL, NULL);

// звільняємо пам'ять, виділену під шірокобайтовую рядок

HeapFree (GetProcessHeap (), 0, pWideCharStr);

І, нарешті, в заголовки, що поставляється разом з DLL, прототипи цих функцій були б такими:

BOOL StringReverseW (PWSTR pWideCharStr);

BOOL StringReverseA (PSTR pMultiByteStr);

#define StnngReverse StringReverseW #else

#define StringRevcrsc StringReverseA #endif // UNICODE

Вивчення Windows API ми почнемо з об'єктів ядра і їх описателей (handles). Ця глава присвячена порівняно абстрактним концепціям, т. E. ми, не заглиблюючись в специфіку тих чи інших об'єктів ядра, розглянемо їх загальні властивості.

Я б вважав за краще почати з чогось більш конкретного, але без чіткого розуміння об'єктів ядра Вам не стати справжнім професіоналом в області розробки Windows-програм. Ці об'єкти використовуються системою і нашими додатками для управління безліччю найрізноманітніших ресурсів процесами, потоками, файлами і т. Д. Концепції, представлені тут, будуть зустрічатися протягом всієї книги. Однак я чудово розумію, що частина матерiалiв не вляжеться у Вас в голові до тих пір, доки Ви не приступите до роботи з об'єктами ядра, використовуючи реальні функції. І при читанні наступних глав книги Ви, напевно, будете час від часу повертатися до цієї чолі.

Що таке об'єкт ядра

Створення, відкриття та інші операції з об'єктами ядра стануть для Вас, як розробника Windows-додатків, повсякденною рутиною. Система дозволяє створювати і

оперувати з кількома типами таких об'єктів, в тому числі, маркерами доступу

(Access token objects), файлами (file objects), проекціями файлів (file-mapping objects), портами завершення введення-виведення (I / O completion port objects), завданнями (job objects), поштовими скриньками (mailslot objects), мьютсксамі ( mutex objects), каналами (pipe objects), процесами (process objects), семафора (semaphore objects), потоками (thread objects) і

очікуваними таймерами (waitable timer objects). Ці об'єкти створюються Windowsфункціямі Наприклад, CreateFtleMapping змушує систему

сформувати об'єкт "проекція файлу". Кожен об'єкт ядра - насправді просто блок пам'яті, виділений ядром і доступний тільки йому. Цей блок представляє собою структуру даних, в елементах якої міститься інформація про об'єкт. Деякі елементи (дескриптор захисту, лічильник числа користувачів і ін.) Присутні у всіх об'єктах, але більша їх частина стосується виключно об'єктів конкретного типу. Наприклад, у об'єкта "процес" є ідентифікатор, базовий пріоритет і код завершення, а у об'єкта "файл" - зміщення в байтах, режим поділу і режим відкриття

Оскільки структури об'єктів ядра доступні тільки ядру, додаток не може самостійно знайти ці структури в пам'яті і безпосередньо модифікувати їх вміст Таке обмеження Microsoft ввела навмисно, щоб жодна програма не порушила цілісність структур об'єктів ядра. Це ж обмеження дозволяє Microsoft вводити, прибирати або змінювати елементи структур, нс порушуючи роботи будь-яких додатків.

Але от питання: якщо ми не можемо безпосередньо модифікувати ці структури, то як же наші програми оперують з об'єктами ядра? Відповідь в тому, що в Windows

передбачений набір функцій, що обробляють структури об'єктів ядра за суворо визначеними правилами. Ми отримуємо доступ до об'єктів ядра тільки через ці функції. Коли Ви викликаєте функцію, яка створює об'єкт ядра, вона повертає описувач, що ідентифікує створений об'єкт, Описувач слід розглядати як "непрозоре" значення, яке може бути використаний будь-якою потоком Вашого процесу. Цей описувач Ви передаєте Windows-функцій, повідомляючи системі, який об'єкт ядра Вас цікавить. Але про описатели ми поговоримо пізніше (в цьому розділі).

Для більшої надійності операційної системи Microsoft зробила так, щоб значення описателей залежали від конкретного процесу. Тому, якщо Ви передасте таке значення (за допомогою будь-якого механізму межпроцессной зв'язку) потоку іншого процесу, будь-який виклик з того процесу зі значенням описателя, отриманого в Вашому процесі, дасть помилку. Але не вользуйтесь, в кінці розділу ми розглянемо три механізму коректного використання декількома процесами одного об'єкта ядра.

Облік користувачів об'єктів ядра

Об'єкти ядра належать ядру, а не процесу. Інакше кажучи, якщо Ваш процес викликає функцію, яка створює об'єкт ядра, а потім завершується, об'єкт ядра може бути не зруйнований. У більшості випадків такий об'єкт все ж руйнується; але якщо створений Вами об'єкт ядра використовується іншим процесом, ядро ​​заборонить руйнування об'єкта до тих пір, поки від нього не відмовиться і той процес.

Ядру відомо, скільки процесів використовує конкретний об'єкт ядра, посколь ку в кожному об'єкті є лічильник числа його користувачів. Цей лічильник - один з елементів даних, загальних для всіх типів об'єктів ядра. У момепт створення об'єкта лічильнику

присвоюється 1. Коли до існуючого об'єкту ядра звертається інший процес, лічильник збільшується на 1. А коли якийсь процес завершується, лічильники всіх використовуваних їм об'єктів ядра автоматично зменшуються на 1. Як тільки лічильник будь-якого об'єкта обнуляється, ядро ​​знищує цей об'єкт.

Об'єкти ядра можна захистити дескриптором захисту (security descriptor), який описує, хто створив об'єкт і хто має права на доступ до нього. Дескриптори захисту зазвичай використовують при написанні серверних додатків; створюючи клієнтську програму, Ви можете ігнорувати це властивість об'єктів ядра.

Майже всі функції, що створюють об'єкти ядра, приймають покажчик на структуру

SECURITY_ATTRIBUTES як аргумент, наприклад:

typedef struct _SECURITY_ATTRIBUTES

LPVOID lpSecurityDescriptor; BOOL bInherttHandle;

Хоча структура називається SECURITY__ATTRIBUTES, лише один cc елемент має відношення до захисту - lpSecuntyDescnptor. Якщо треба обмежити доступ до створеного Вами об'єкту ядра, створіть дескриптор захисту і Ініціалізуйте структуру

SECURITY_ATTRIBUTES наступним чином:

HANDLE hFileMapping = CreateFileMapping (INVALID_HANDLE_VALUE, sa, PAGE_REAOWRITE, 0, 1024, "MyFileMapping");

Розгляд елемента bInheritHandle я відкладу до розділу про спадкування, так як цей елемент не має нічого спільного із захистом.

Бажаючи отримати доступ до існуючого об'єкту ядра (замість того щоб створювати новий), вкажіть, які операції Ви маєте намір проводити над об'єктом. Наприклад, якби я захотів зчитувати дані з існуючої проекції файлу, то викликав би функцію

OpenFileMapping таким чином;

HANDLE hFileMapping = OpenFileMapping (FILE_MAP_READ, FALSE, "MyFileMapping");

Передаючи FILE_MAPREAD першим параметром в функцію OpenFileMapping, я повідомляю, що, як тільки мені нададуть доступ до проекції файлу, я буду зчитувати з неї дані. Функція OpenFileMapping, перш Чсм повернути дійсний описатель, перевіряє тип захисту об'єкта. Якщо мене, як зареєстрованого користувача, допускають до існуючого об'єкту ядра "проекція файлу", OpenFileMapping повертає дійсний описатель. Але якщо мені відмовляють в доступі,

повертає NULL, а виклик GetLastError дає код помилки 5 (або ERROR_ACCESS_DENIED). Але знову ж таки, в основній масі додатків захист не використовують, і тому я більше не буду затримуватися на цій темі

Уявіть, що можна запустити програму зчитує дані з якогось розділу реєстру Щоб робити це коррекчно, воно повинно викликати функцію RegOpenKeyEx, передаючи значення KEY_QUERY_VALUE, яке дозволяє операцію читання в зазначеному розділі.

Якби розробник хоч трохи подумав про захист і поміняв значення

KEY_ALL_ACCESS на KEY_QUERY_VALUE (тільки-то і всього!), Його продукт міг би працювати в обох операційних системах

Крім об'єктів ядра Ваша програма може використовувати об'єкти інших типів - меню, вікна, курсори миші, кисті і шрифти. Вони відносяться до об'єктів User або GDI Новачок в програмуванні для Windows може заплутатися, намагаючись відрізнити об'єкти User або GDI від об'єктів ядра. Як дізнатися, наприклад, чиїм об'єктом - User або ядра - є даний значок? З'ясувати, чи не належить об'єкт ядра, найпростіше так проаналізувати функцію, яка створює об'єкт. Практично у всіх функцій, що створюють об'єкти ядра, є параметр, що дозволяє вказати атрибути захисту, - як у

Схожі статті