Лекції з WinApi

Сайт: Державний університет "Житомирська політехніка" - Освітній портал
Курс: Системне та мережне програмування
Книга: Лекції з WinApi
Надруковано: Гість-користувач
Дата: субота 27 квітня 2024 00:37

Тема №1 Вступ

1. Windows’95 і Windows NT. Подібності і розбіжності

Бажання скоротити витрати на розробку ОС і збільшити переносимость прикладних систем на різні апаратні платформи привело до ідеї створення ОС, заснованих на мікроядрі.

Мікроядро - віртуальна машина мінімальної функціональності, на якій будується вся операційна система.

Для перенесення всієї ОС на іншу апаратну платформу досить переписати мікроядро.

Більшість сучасних ОС побудована на архітектурі мікроядра. Це ОС фірм IBM, Microsoft, Novell, Sun і більшості постачальників UNIX . Операційна система Windows NT також побудована на архітектурі мікроядра і, тому, стерпна на багато апаратних платформ. Крім того, існує Windows'95, що має ту ж базову функціональність, що і Windows NT. Розходження цих систем визначаються різними цілями, прийнятими при їхньому створенні.

Windows’95 орієнтована на малопотужні робочі станції і стерпні персональні комп'ютери. Windows NT Workstation орієнтована на високопродуктивні робочі станції. Windows NT Server використовується як сервер мережі. Для розроблювачів програмного забезпечення мається єдина платформа, що складається з Win32® (the 32-bit Windows application programming interface) і OLE.

1. Windows’95 і Windows NT. Подібность та розбіжність.
 1.1. Загальні риси Windows’95 і Windows NT.

1. Простота використання

  • Автоматичне визначення устаткування під час інсталяції і наступної конфігурації
  • Інтерфейс користувача нового покоління
  • Технологія Plug and Play

2. Потужність

  • Реальна многозадачність
  • Використання Win32® і OLE

3. Здатність спільної роботи

  • Убудована підтримка основних мережних протоколів (TCP/IP, IPX/SPX, NetBeui)
  • Відкрита мережна архітектура і здатність вибору типу мережного клієнта, транспорту, драйверів і розширюваність для підтримки додаткових мережних додатків.
  • Убудовані засоби надання вилученого доступу до робочої станції

4. Керованість

  • Відкрита архітектура керування з можливістю використання додаткових керуючих систем.
  • Підтримка стандартів системного керування
  • Незалежне настроювання робочої області екрана для кожного користувача і засобу моніторингу.

5. Підтримка додатків

  • Можливість виконання 16-розрядних Windows додатків
  • Можливість виконання 32-розрядних Windows додатків і підтримка OLE 2.0

6. Переносимість

  • Повна переносимість на платформи Intel® 386DX, 486, і Pentium®

1. Windows’95 і Windows NT. Подібності і розбіжності.
 1.2. Розбіжності Windows’95 і Windows NT

Властивість

Windows’95

Windows NT Workstation

Захист і безпека

 

 

Забезпечення повної ізоляції 16 бітних Windows - додатків шляхом надання кожному окремого адресного простору

немає

так

Надання захисту по стандарті C-2. Окремі каталоги і файли можуть бути зроблені невидимими для обраних користувачів.

Немає

так

Установка прав різних користувачів до зміни конфігурації системи.

Немає

так

Захист файлової структури

немає

так

Автоматичне відновлення після краху системи

немає

так

Підтримка додатків

 

 

MS DOS

так

більшість

підтримка файлових структур NTFS і HPFS

немає

так

Підтримка графічної бібліотеки OpenGL (тривимірна графіка)

наступна версія

так

Виконання IBM® Presentation Manager® (through 1.3) і підтримка стандарту POSIX 1003.2

Немає

так

Системні можливості.

 

 

Драйвери MS DOS

так

немає

Драйвери Win16

так

немає

Компресія диска

немає

так

Можливість виконання на PowerPC, MIPS і DEC Alpha

немає

так

Підтримка мультипроцесорных платформ

немає

так

Технічна підтримка і сервіс

 

 

Команди інженерів для рішення проблем у критичних випадках

немає

так

Щомісячні інформаційні випуски

немає

так

Щоквартальні сервісні пакети на CD і дискетах

немає

так

Тема №2 Багатозадачність

2. Багатозадачність
 2.1. Процеси і потоки

Процес - завантажена в пам'ять і готова до виконання програма.

Кожен процес має свій власний віртуальний адресний простір (4Gb). Процес складається з коду, даних і інших системних ресурсів, таких як відкриті файли, канали (pipes), що синхронізують об'єкти.

Потік (thread) - базовий об'єкт, якому операційна система розподіляє час центрального процесора.

Виконання процесу починається зі стартового потоку. Надалі він може породжувати інші потоки. Ресурси процесу доступні всім його потокам. Кожен потік використовує структуру даних, для збереженняконтексту виконання, у той час, коли в нього віднімається процесор. У контекст входять регістри процесора, перемінні оточення, стеки ядра і користувача. Усі потоки одного процесу спільно використовують його віртуальний адресний простір.

Процесорний час розподіляється по черзі між потоками, а не між процесами. Тривалість кванта виділення часу складає близько 20 мс.

2. Багатозадачність.
 2.2. Розподіл часу між потоками

Процесорний час виділяється потокам відповідно до їхнього рівня пріоритету. Потоку з більш низьким пріоритетом не виділяється час, якщо на нього претендує потік з більш високим рівнем пріоритету. Більш того, процес з більш низьким пріоритетом переривається до витікання кванта часу, якщо на процесор претендує потік з більш високим рівнем пріоритету. Необхідно пам'ятати, що в середовищі Windows основна “робота” потоку складається в чеканні події і реагуванні на нього. Це дає шанс на виконання потокам з низьким рівнем пріоритету.

Рівні пріоритетів варіюються в діапазоні від 0 (нижчий) до 31 (вищий).

Рівень пріоритету кожного потоку складається з трьох складових

  • клас пріоритету процесу (простоючий, нормальний, високий, реального часу)
  • рівень пріоритету потоку усередині класу пріоритету процесу (нижній, нижче нормального, нормальний, вище нормального, вищий)
  • динамічно встановлений рівень пріоритету.
    1. Клас пріоритету процесу

Клас

Прапор у функції CreateProcess

Числовий рівень

Idle (простоючий)

IDLE_PRIORITY_CLASS

4

Normal (нормальний)

NORMAL_PRIORITY_CLASS

7-9

High (високий)

HIGH_PRIORITY_CLASS

13

Real time(реального часу)

REALTIME_PRIORITY_CLASS

24

2.                                                        При запуску на виконання процесу йому призначається один з чотирьох класів пріоритету. Рівень Idle призначається процесу, що нічого не повинний робити у випадку активності інших процесів (наприклад, хоронитель екрана). Процесам, що запускається користувачем, привласнюється нормальний рівень. Користувач може запустити кілька процесів. Томові процесу, з яким користувач безпосередньо працює (а це може бути тільки один процес) рівень пріоритету піднімається на двох одиниць (7+2 = 9). Це робить спілкування з прикладною програмою більш “комфортабельним”. Високий клас пріоритету призначається деяким системним процесам, що простоюють до виникнення визначених подій і, тому, не заважають іншим процесам. Тільки в особливих випадках процес може відноситися до класу Real time.

      1. Рівень пріоритету потоку усередині класу пріоритетів

Ідентифікатор

Рівень пріоритету потоку

THREAD_PRIORITY_LOWEST

На 2 нижче рівні класу

THREAD_PRIORITY_BELOW_NORMAL

На 1 нижче рівня класу

THREAD_PRIORITY_NORMAL

Дорівнює рівню класу

THREAD_PRIORITY_ABOVE_NORMAL

На 1 вище рівня класу

THREAD_PRIORITY_HIGHEST

На 2 вище рівні класу

THREAD_PRIORITY_IDLE

Дорівнює 1 для процесів класу IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, і HIGH_PRIORITY_CLASS і дорівнює 16 для REALTIME_PRIORITY_CLASS

THREAD_PRIORITY_TIME_CRITICAL

Дорівнює 15 для процесів класу IDLE_PRIORITY_CLASS, NORMAL_PRIORITY_CLASS, і HIGH_PRIORITY_CLASS, і дорівнює 31 для REALTIME_PRIORITY_CLASS

      1. Динамічна зміна рівня пріоритету потоку

Клас пріоритету процесу і рівень пріоритету потоку усередині класу визначають базовий рівень пріоритету потоку. Цей рівень може динамічно змінюватися системою, а саме, підвищуватися на 2 одиниці у відповідь на надходження повідомлень у чергу потоку з наступним зниженням до базового рівня після закінчення визначеного проміжку часу. Це правило діє тільки для потоків до 15 рівня.

2. Багатозадачність.
 2.3. Робота з процесами і потоками в Win32® API.

·  Список функцій

У Win32® API визначені наступні функції роботи з процесами і потоками

Назва функції

Виконувана дія

AttachThreadInput

Переключення механізмів уведення з однієї нитки на іншу

CommandLineToArgv

Робить розбір командного рядка в Unicode

CreateProcess

Створює процес

CreateRemoteThread

Створює потік в адресному просторі іншого процесу

CreateThread

Створює потік

ExitProcess

Завершує процес і весь його потоки

ExitThread

Завершує потік

FreeEnvironmentStrings

Звільняє пам'ять області перемінні середовища

GetCommandLine

Повертає покажчик на командний рядок

GetCurrentProcess

Повертає описувач (handle) поточного процесу

GetCurrentProcessId

Повертає ідентифікатор поточного процесу

GetCurrentThread

Повертає описувач (handle) поточного потоку

GetCurrentThreadId

Повертає ідентифікатор поточного потоку

GetEnvironmentStrings

Повертає рядок перемінні середовища

GetEnvironmentVariable

Повертає значення зазначеного перемінного середовища

GetExitCodeProcess

Повертає код завершення процесу

GetExitCodeThread

Повертає код завершення потоку

GetPriorityClass

Повертає клас пріоритету процесу

GetProcessAffinityMask

Повідомляє, на яких процесорах дозволене виконання процесу

GetProcessShutdownParameters

Повідомляє параметри поводження процесу при завершенні роботи системи

GetProcessTimes

Повертає тимчасові характеристики зазначеного процесу

GetProcessVersion

Повідомляє версію Windows, для якої призначений процес

GetProcessWorkingSetSize

Повертає характеристики доступного процесу адресного простору

GetStartupInfo

Повертає параметри процесу, отримані їм при створенні

GetThreadPriority

Повідомляє пріоритет зазначеного потоку

GetThreadTimes

Повертає тимчасові характеристики зазначеного потоку

OpenProcess

Повертає описувач (handle) зазначеного процесу

ResumeThread

Зменшує лічильник затримок потоку (чи запускає його)

SetEnvironmentVariable

Установлює значення зазначеного перемінного середовища

SetPriorityClass

Установлює клас пріоритету процесу

SetProcessShutdownParameters

Установлює параметри поводження процесу при завершенні роботи системи

SetThreadAffinityMask

Установлює, на яких процесорах дозволене виконання потоку

SetThreadPriority

Установлює пріоритет зазначеного потоку

Sleep

Затримує виконання потоку на зазначену кількість мілісекунд

SleepEx

Затримує виконання до настання події введення/ чивисновку на час

SetProcessWorkingSetSize

Установлює характеристики доступного процесу адресного простору

SuspendThread

Припиняє виконання зазначеного потоку

TerminateProcess

Завершує зазначений процес

TerminateThread

Завершує зазначений потік

TlsAlloc

Розподіляє індекс локальної пам'яті потоку (thread local storage TLS)

TlsFree

Звільняє індекс TLS

TlsGetValue

Повертає дані, розміщені в TLS із зазначеним індексом

TlsSetValue

Поміщає дані в TLS із зазначеним індексом

WaitForInputIdle

Чекає, поки не почнеться введення для зазначеного процесу

WinExec

Виконує зазначений додаток

Докладний опис функцій приведений у Win32® Programmer’s Reference. Тут будуть докладно розглянуті тільки деякі функції.

·  Функція CreateProcess()

Створює новий процес і його первинний потік. Новий процес виконує зазначений файл, що виконується.

Формат функції:

BOOL CreateProcess(

LPCTSTR lpApplicationName, // ім'я файлу, що виконується

LPTSTR lpCommandLine, // командний рядок

LPSECURITY_ATTRIBUTES lpProcessAttributes, // атрибути захисту процесу

LPSECURITY_ATTRIBUTES lpThreadAttributes, // атрибути захисту

// потоку

BOOL bInheritHandles, // прапор спадкування описувачей

DWORD dwCreationFlags, // прапори створення

LPVOID lpEnvironment, // покажчик блоку перемінні середовища

LPCTSTR lpCurrentDirectory, // поточний каталог

LPSTARTUPINFO lpStartupInfo, // блок початкових параметрів

LPPROCESS_INFORMATION lpProcessInformation // покажчик

// структури, що описує породжений // процес

);

Функція повертає TRUE у випадку успіху і FALSE - у випадку невдачі.

Параметри:

lpApplicationName - покажчик на рядок, що містить ім'я програми, що виконується. Ім'я може бути повне. Якщо воно не повне, то пошук файлу виробляється в поточному каталозі. Параметру може бути привласнене значення NULL. У цьому випадку як ім'я файлу виступає перша виділена пробілами лексема з рядка lpCommandLine;

lpCommandLine - покажчик командного рядка. Якщо параметр lpApplicationName має значення NULL, то ім'я файлу, що виконується, виділяється з lpCommandLine, а пошук файлу, що виконується, виробляється відповідно до правил, що діють у системі;

lpProcessAttributes - покажчик на структуру, що описує параметри захисту процесу. Якщо параметру привласнене значення NULL, то встановлюються атрибути “за замовчуванням”;

lpThreadAttributes- покажчик на структуру, що описує параметри захисту первинного потоку. Якщо параметру привласнене значення NULL, то встановлюються атрибути “за замовчуванням”;

bInheritHandles - визначає, чи буде породжений процес успадковувати описувачі (handles) об'єктів батьківського процесу. Наприклад, якщо батьківський процес A уже до цього породжував процес B, те він одержав описувач процесу B і може їм маніпулювати. Якщо тепер він породжує процес C з параметром bInheritHandles рівним TRUE, то і процес C зможе працювати з описувачем процесу B;

dwCreationFlags - визначає деякі додаткові умови створення процесу і його клас пріоритету;

lpEnvironment- покажчик на блок перемінні середовища породженого процесу. Якщо цей параметр дорівнює NULL, то породжений процес успадковує середовище батька. Інакше він повинний указувати на блок рядків, що завершується нулем, кожна з який завершується нулем (аналогічно DOS);

lpCurrentDirectory - покажчик на рядок, що містить повне ім'я поточного каталогу породженого процесу. Якщо цей параметр дорівнює NULL, то породжений процес успадковує каталог батька;

lpStartupInfo - покажчик на структуру STARTUPINFO, що визначає параметри головного вікна породженого процесу;

lpProcessInformation - покажчик на структуру, що буде заповнена інформацією про породжений процес після повернення з функції.

Приклад: програма, що запускає Microsoft® Word

#include <windows.h>

#include <conio.h>

#include <stdio.h>

main()

{ PROCESS_INFORMATION pi ;

STARTUPINFO si ;

ZeroMemory( &si, sizeof(si)) ;

si.cb = sizeof( si ) ;

printf( "Press any key to start WinWord -- " );

getch() ;

CreateProcess( NULL, "WinWord", NULL, NULL, FALSE, 0,

NULL, NULL, &si, &pi ) ;

return 0 ;

}

·  Функція CreateThread()

Створює новий потік в адресному просторі процесу.

Формат функції:

HANDLE CreateThread(

LPSECURITY_ATTRIBUTES lpThreadAttributes, // атрибути захисту

// потоку

DWORD dwStackSize, // розмір стека в байтах

LPTHREAD_START_ROUTINE lpStartAddress, //покажчик на функцію

// потоку

LPVOID lpParameter, // аргумент, переданий у функцію

// потоку

DWORD dwCreationFlags, // прапори керування створенням потоку

LPDWORD lpThreadId // область пам'яті для повернення

// ідентифікатора потоку

);

Функція повертає описувач породженого потоку.

Параметри:

lpThreadAttributes - покажчик на структуру, що описує параметри захисту потоку. Якщо параметру привласнене значення NULL, то встановлюються атрибути “за замовчуванням”;

dwStackSize - установлює розмір стека, що приділяється потоку. Якщо параметр дорівнює нулю, то встановлюється стек, рівний стеку первинного потоку;

lpStartAddress - адреса функції, которую буде виконувати потік. Функція має один 32-бітний аргумент і повертає 32 бітне значення;

lpParameter - параметр, переданий у функцію, которую буде виконувати потік;

dwCreationFlags - додатковий прапор, що керує створенням потоку. Якщо цей параметр дорівнює CREATE_SUSPENDED, то потік після породження не запускається на виконання до виклику функціїResumeThread;

lpThreadId - покажчик на 32-бітну перемінну, котрої буде привласнене значення унікального ідентифікатора потоку.

Приклад: програма, що породжує потік

#include <stdio.h>

#include <conio.h>

#include <windows.h>

DWORD WINAPI Output( LPVOID Param )

{ while( TRUE ) {

printf( "A" ) ;

Sleep(100) ;

}

return( 0 ) ;

}

main()

{ HANDLE hThread ;

DWORD ThreadId ;

hThread = CreateThread( NULL, 0, Output, NULL, 0, &ThreadId ) ;

getch() ;

TerminateThread( hThread, 0 ) ;

return(0) ;

}

 

Тема №3 Архітектура пам'яті в Win32® API

3. Архітектура пам'яті в Win32® API
 3.1. Адресний простір процесу

У Win32® API використовується плоска 32-розрядна модель пам'яті. Кожному процесу виділяється “особисте” (private) ізольований адресний простір, розмір якого складає 4Gb. Цей простір розбивається на регіони, небагато відмінні для Windows’95 і Windows NT. У загальному для тієї й іншої системи можна сказати, що нижні 2Gb ці простори відведені процесу для вільного використання, а верхні 2Gb зарезервовані для використання операційною системою.

  1. Регіони в адресному просторі процесу Windows’95

  1. Регіони в адресному просторі процесу Windows® NT™

Код системи Windows NT краще захищений від процесу користувача, чим код Windows’95. Це обумовлює велику стійкість ОС до помилок у прикладній програмі.

  1. Приклад

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

/* Win95Killer.cpp */

#include <windows.h>

#include <iostream.h>

void main()

{ // Системна область. Старший Gb адресного простору

DWORD SystemAreaAddress = 0xC0000000 ;

while(1) {

try { // Спроба запису

ZeroMemory( (LPVOID) SystemAreaAddress, 0x1000 ) ;

}

catch(...) { // помилка запису

cout << "Exception: " << hex << SystemAreaAddress << endl;

}

SystemAreaAddress += 0x1000 ; // Перехід до наступного сторінці (4K)

}

}

Оскільки в Windows’95 відсутен захист сторінок системної області, то програма знищує цю область, що приводить до краху системи. Windows NT захищає системну область і, тому, “витримує натиск” програми.

3. Архітектура пам'яті в Win32® API.
 3.2. Керування віртуальною пам'яттю. VMM.

VMM(Virtual Memory Manager) - частина операційної системи, що займається керуванням віртуальною пам'яттю.

У Win32 використовується сторінкова організація пам'яті. Розмір сторінок для платформ Intel і MIPS складає 4K. Розмір сторінок для DEC Alpha складає 8K.

Схема сторінкового перетворення в процесорах Intel докладно вивчалася в курсі “Програмування мовою ассемблера. Частина 3”. Win32 використовує двоступінчасту схему сторінкового перетворення, підтримувану процесорами 386, 486, Pentium. Додаткові схеми, що підтримує процесор Pentium Pro, не використовуються.

Сторінкова організація пам"яті

Кожному процесу призначається свій каталог сторінок. Саме тому адресний простір кожного процесу ізольовано.

Організацією свопинга займається VMM. При генерації системи на диску утвориться спеціальний файл свопинга, куди записуються ті сторінки, яким не знаходиться місця у фізичній пам'яті. Процеси можуть захоплювати пам'ять у своєму 32-бітному адресному просторі і, потім, використовувати її. При звертанні потоку до комірки пам'яті можуть виникнути три різні ситуації:

  • Сторінка існує і знаходиться в пам'яті
  • Сторінка існує і вивантажена на диск
  • Сторінка не існує

При цьому VMM використовує наступний алгоритм організації доступу до даних:

Алгоритм роботи менеджера віртуальної пам"яті

Виділення пам'яті процесу означає виділення її у файлі підкачування.

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

3. Архітектура пам'яті в Win32® API.
 3.3. Архітектура інтерфейсів (API) керування пам'яттю.

Диспетчер керування пам'яттю (VMM) є складовою частиною ядра операційної системи. Додатка не можуть одержати до нього прямий доступ. Для керування пам'яттю прикладним програмам надаються різні інтерфейси (API).

Керування пам"ятю

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

Memory Mapped File API - набір функцій, що дозволяє працювати з файлами, відображуваними в пам'ять. Новий механізм, наданий Win32® API для роботи з файлами і взаємодії процесів. Докладно розглядається в розділі 4.5.

Heap Memory API - набір функцій, що дозволяють працювати з областями пам'яті, що розподіляються динамічно, (купами). Докладно розглядається в розділі 4.6.

Local, Global Memory API - набір функцій роботи з пам'яттю, сумісних з 16-бітної Windows. Варто уникати їхнього використання.

CRT Memory API - функції стандартної бібліотеки мови “З” періоду виконання (runtime).

Два останніх набори функцій у дійсному курсі не розглядаються.

3. Архітектура пам'яті в Win32® API.
 3.4. Робота додатків з віртуальною пам'яттю.

Блок адрес в адресному просторі процесу може знаходитися в одному з трьох станів

  1. Виділений (committed) - блоку адрес призначені фізична пам'ять або частина файлу підкачування.
  2. Зарезервований (reserved) - блок адрес позначений як зайнятий, але фізична пам'ять не розподілена.
  3. Вільний (free) - блок адрес не виділений і не зарезервований.

Резервування і виділення пам'яті виробляється блоками. Початкова адреса блоку повинна бути вирівняна на границю 64K (округляється вниз), а розмір кратний розміру сторінки (округляється нагору). При виділенні пам'ять обнуляється.

Для резервування регіону пам'яті в адресному просторі чи процесу виділення її використовується функція VirtualAlloc, а для звільнення - функція VirtualFree.

LPVOID VirtualAlloc(

LPVOID lpAddress, // address of region to reserve or commit

DWORD dwSize, // size of region

DWORD flAllocationType, // type of allocation

DWORD flProtect // type of access protection

);

Функція повертає адресу виділеного чи регіону NULL у випадку невдачі

Параметри:

lpAddress - адреса, по якому треба чи зарезервувати виділити пам'ять. Якщо цей параметр дорівнює NULL, то система самостійно вибирає місце в адресному просторі процесу;

dwSize - розмір виділюваного регіону;

flAllocationType - тип розподілу пам'яті;

MEM_RESERVE

Резервує блок адрес без виділення пам'яті

MEM_COMMIT

Відображає раніше зарезервований блок адрес на фізичну чипам'ять файл підкачування. (Виділяє пам'ять). Може бути комбінований із прапором MEM_RESERVE для одночасного резервування і виділення.

MEM_TOP_DOWN

Виділяє пам'ять по найбільшій можливій адресі. Має сенс тільки при lpAddress = NULL. У Windows’95 ігнорується.

flProtect - тип захисту доступу виділюваного регіону;

PAGE_READONLY

допускається тільки читання

PAGE_READWRITE

допускається читання і запис

PAGE_EXECUTE

допускається тільки виконання

PAGE_EXECUTE_READ

допускається виконання і читання

PAGE_EXECUTE_READWRITE

допускається виконання читання і запис

PAGE_GUARD

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

PAGE_NOCACHE

Забороняє кэширування сторінок. Може бути корисний при розробці драйверів пристроїв (наприклад, дані у відеобуфер повинні листуватися відразу, без кэширування)

BOOL VirtualFree(

LPVOID lpAddress, // address of region of committed pages

DWORD dwSize, // size of region

DWORD dwFreeType // type of free operation

);

Повертає TRUE у випадку успіху і FALSE - у випадку невдачі.

Параметри:

lpAddress - адреса регіону, якім треба звільнити.

dwSize - розмір регіону, що звільняється;

dwFreeType - тип звільнення.

MEM_DECOMMIT

Звільнити виділену пам'ять

MEM_RELEASE

Звільнити зарезервований регіон. При використанні цього прапора параметр dwSize повинний бути дорівнює нулю.

Виділені сторінки можна заблокувати в пам'яті, тобто заборонити їхнє витиснення у файл підкачування. Для цих цілей служить пари функцій VirtualLock і VirtualUnlock. Процесу не дозволяється блокувати більш 30 сторінок.

Для зміни атрибутів захисту регіонів використовуються функції VirtualProtect і VirtualProtectEx. Причому, перша дозволяє змінювати атрибути захисту в адресному просторі поточного процесу, а друга -довільного.

Функції VirtualQuery і VirtualQueryEx дозволяють визначити статус зазначеного регіону адрес.

3. Архітектура пам'яті в Win32® API.
 3.5. Файли, проецируємі в пам'ять.

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

Цей механізм має три застосування в Win32

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

1) Запуск файлів, що виконуються, і бібліотек, що динамічно зв'язуються.

При виконанні функції CreateProcess система звертається до VMM для виконання наступних дій

  1. Створити адресний простір процесу (розміром 4Gb)
  2. Резервувати в адресному просторі процесу регіон розміром, достатнім для розміщення файлу, що виконується. Початкова адреса регіону визначається в заголовку EXE-модуля. Звичайно він дорівнює 0x00400000, але може бути змінений при побудові файлу параметром /BASE компоновщика.
  3. Відобразити файл, що виконується, на зарезервований адресний простір. Тим самим VMM розподіляє фізичні сторінки не з файлу підкачування, а безпосередньо з EXE-модуля.
  4. У такий же спосіб відобразити на адресний простір процесу необхідні йому бібліотеки, що динамічно зв'язуються. Інформація про необхідні бібліотеки знаходиться в заголовку EXE-модуля. Бажане розташування регіону адрес описано усередині бібліотеки. Visual C++, наприклад, установлює за замовчуванням адреса 0x10000000. Ця адреса може так само змінюватися параметром /BASE компоновщика. Якщо при завантаженні з'ясовується, що даний регіон зайнятий, то система спробує перемістити бібліотеку в інший регіон адрес, на основі налагоджувальної інформації, що міститься в DLL-модулі. Однак ця операція знижує ефективність системи і, крім того, якщо налагуджувальна інформація вилучена при компонуванні бібліотеки параметром /FIXED, те завантаження стає взагалі неможливою.

При одночасному запуску декількох додатків Win32® відображає той самий файл, що виконується, і бібліотеки на адресні простори різних процесів. При цьому виникає проблема незалежного використання процесами статичних перемінних і областей даних. Крім того, зміна даних програмою, що виповнюється, не повинне приводити до зміни EXE-файлу. Win32® відкладає рішення цієї проблеми на максимально можливий термін (Lazy Evaluation). При цьому використовується класичний механізм відкладеного копіювання (copy-on-write - копіювання при спробі запису). Усі сторінки адресного простору процесу одержують атрибут захистуPAGE_WRITECOPY. При спробі запису в таку сторінку виникає виключення порушення захисту і VMM копіює сторінку для процесу, що звернувся. Надалі ця сторінка буде вивантажуватися у файл підкачування. Після копіювання відбувається рестарт команди, що викликала виключення.

2) Файли даних, проецируємі в пам'ять.

Проектування файлу даних в адресний простір процесу надає могутній механізм роботи з файлами. Спроецирував файл на адресний простір процесу, програма одержує можливість працювати їм, як з масивом. Проектування файлу в пам'ять виконується в три етапи

  1. Створюється об'єкт ядра “файл”. У колишній термінології це операція відкриття файлу. Для створення об'єкта “файл” використовується функція CreateFile, аналогічна функції open() з CRT-бібліотеки.
  2. За допомогою функції CreateFileMapping створюється об'єкт ядра “проецируємий файл”. При цьому використовується описувач файлу (handle), повернутий функцією CreateFile. Тепер файл готовий до проектування.
  3. Виробляється відображення об'єкта “проецируємий файл” чи його частини на адресний простір процесу. Для цього застосовується функція MapViewOfFile.

Для відкріплення файлу від адресного простору процесу використовується функція UnmapViewOfFile, а для знищення об'єктів “файл” і “проецируємый файл” - функція CloseHandle.

Загальна схема роботи з проецируванними файлами така:

HANDLE hFile, hFileMapping;

PVOID pMassive;

hFile = CreateFile( “File Name”, ... );

hFileMapping = CreateFileMapping( hFile, ... );

CloseHandle( hFile ) ;

pMassive = MapViewOfFile( hFileMapping, ... );

/* Робота з масивом pMassive */

UnmapViewOfFile( pMassive );

3) Взаємодія процесів через загальну область даних. Когерентність.

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

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

Когерентність

Якщо один процес змінює поділювану область даних, то вона міняється і для іншого процесу. Операційна система забезпечує когерентність поділюваної області даних для всіх процесів. Але для забезпечення когерентності процеси повинні працювати з одним об'єктом “проецируємый файл”, а не з одним файлом.

Робота з пам"ятю

Тема №4 Вікна

4. Вікна
 4.1. Визначення вікна. Компоненти і параметри вікон

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

У кожен момент часу тільки одне вікно в системі може одержувати вступну інформацію. Користувач може використовувати клавіатуру, чи мишу інше пристрою введення для взаємодії з вікном.

Коли Windows® завантажується, створюється вікно займаюче весь екран (desktop window). Кожен windows-додаток створює хоча б одне вікно, називаний головним вікном додатка. Багато додатків створюють ще додаткові вікна. Вікно додатка може складатися з наступних компонентів:

Просте вікно

Додатки можуть використовувати й інші типи вікон:

  • елементи керування (controls)
  • вікна діалогу (dialog boxes)
  • вікна повідомлень (message boxes)

Для породження вікна (у тому числі і головному вікні додатка) використовується функція CreateWindowEx. Додаток для створення вікна повинний визначити наступні параметри:

  • Клас вікна (Window class )
  • Ім'я вікна (Window name)
  • Стиль вікна (Window style)
  • Батьківське чи вікно вікно-хазяїн (Parent or owner window)
  • Розміри (Size)
  • Координати лівого верхнього кута (Location)
  • Місце в порядку розташування (Position in the Z-order)
  • Ідентифікатор дочірнього чи вікна описувач меню (Child-window identifier or menu handle)
  • Описувач екземпляра програми (Instance handle)
  • Додаткові дані (Creation data)
    1. Клас вікна

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

Функція вікна - спеціальна функція, що призначається класу вікна. Для посилки вікну повідомлення операційна система викликає цю функцію і передає їй як параметри код повідомлення й іншу уточнюючу інформацію.

Існує три типи класів вікна:

  1. Системні глобальні класи: класи, що реєструються при завантаженні операційної системи. До таких класів відносяться класи елементів керування (кнопки, списки, смуги прокручування і т.д.)
  2. Прикладні глобальні класи: класи, що реєструються бібліотеками, що динамічно зв'язуються, (DLL) і доступні всім додаткам системи
  3. Прикладні локальні класи: класи, що додатка реєструють для свого внутрішнього використання.

Для реєстрації класів використовується функція RegsterClass (RegisterClassEx).

1. Ім'я вікна

Ім'я вікна - послідовність символів, що іменують вікно. Ім'я вікна відображається в заголовку стандартного вікна, чи є текстом, написаним на кнопці і т.д.

2.  Стиль вікна

Кожне вікно має чи стиль кілька стилів. Стиль - це іменована константа, що задає додаткові параметри вікна усередині класу. Наприклад, вікно класу “смуга прокручування” може мати стилі SBS_HORZ чиSBS_VERT, що визначають напрямок прокручування: вертикальне чи горизонтальне. Докладний опис стилів приводиться в п.5.3.

3.Батьківське чи вікно вікно-хазяїн

Вікно може мати батьківське вікно (parent window). У такому випадку воно називається дочірнім вікном (child window) стосовно батьківського. Дочірнє вікно ніколи не виходить за границі батьківського. При згортанні батьківського вікна згортаються всі дочірні. При знищенні батьківського вікна всі дочірні знищуються. Дочірнє вікно не має меню.

Вікно може мати вікна-хазяїна. Це інший тип відносин між вікнами. Вікно завжди розташовується поверх хазяїна і звертається і знищується разом з ним.

4.Розміри і координати, місце в порядку розташування

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

5.  Ідентифікатор дочірнього чи вікна описувач меню

Дочірнє вікно може мати унікальний ідентифікатор, що дозволяє виділяти дочірнє вікно з безлічі дочірніх вікон. Не дочірньому вікну можна призначити меню.

6. Описувач екземпляра програми

Кожне процес у Windows має унікальний ідентифікатор. Цей ідентифікатор повідомляється системі при породженні вікна і може надалі використовуватися вікном.

7. Додаткові дані

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

 

4. Вікна.
 4.2. Ієрархія вікон

Ієрархія вікон

4. Вікна
 4.3. Стилі вікон

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

  1.  Вікна, що перекриваються, (Overlapped windows)

Overlapped window - це вікно верхнього рівня, що має заголовок, границю, і клієнтську область. Вікна цього типу призначені для використання як головне вікно додатка.

Вікно типу WS_OVERLAPPED має тільки заголовок і границю

Вікно типу WS_OVERLAPPEDWINDOW додатково має системне меню, кнопки мінімізації і максимізації.

  1. Спливаючі вікна (Pop-up windows)

Pop-up window - це спеціальний тип overlapped window, використовуваний для створення вікон діалогу, вікон повідомлень і інших тимчасових вікон, що відображаються поза клієнтською областю головного вікна додатка.

Для породження спливаючого вікна використовується стиль WS_POPUP. Цей стиль може комбінуватися з WS_CAPTION, для наділення вікна заголовком. Стиль WS_POPUPWINDOW використовується для наділення спливаючого вікна додатково системним меню і границею.

  1. Дочірні вікна (Child windows)

Для породження дочірнього вікна використовується стиль WS_CHILD. Дочірнє вікно відображається в межах клієнтської області батьківського. Дочірнє вікно за замовчуванням має тільки клієнтську область. Додатково можна задати будь-які елементи крім меню. Дії, вироблені з батьківським вікном спричиняють дії, вироблені з дочірнім

Батьківське вікно

Дочірнє

Знищується

Знищується перед батьківським

Ховається

Ховається перед батьківським

Переміщається

Переміщається разом з батьківським

Відображається

Відображається після батьківського

Дочірнє вікно не вирізує автоматично з клієнтської області батьківського при отрисовці. Це означає, що батьківське вікно малює поверх дочірнього. Якщо необхідно уникнути цього, батьківське вікно повинне мати стиль WS_CLIPCHILDREN. Аналогічно, щоб уникнути отрисовці з боку братів, дочірнє вікно повинне мати стиль WS_CLIPSIBLINGS.

  1. Стилі границь вікна

WS_BORDER

Тонка рамка

WS_DLGFRAME

Подвійна рамка, використовувана при створенні вікон діалогу. Вікно з подібною границею не може мати заголовка

WS_EX_DLGMODALFRAME

Аналогічно WS_DLGFRAME, але може бути комбіноване з WS_CAPTION для створення заголовка

WS_EX_STATICEDGE

Заголовок, призначений для вікон, у які не можна робити введення. Наприклад незмінний текст у вікні діалогу (static)

WS_THICKFRAME

Толста рамка, що дозволяє змінювати розміри вікна

5.        WS_OVERLAPPED і WS_POPUPWINDOW мають стиль WS_BORDER за замовчуванням. Комбінацією з іншими стилями можна одержати інший тип рамки цих вікон. Вікна типів WS_POPUP іWS_CHILD узагалі не мають рамки за замовчуванням. Вікно типу WS_OVERLAPPEDWINDOW має товсту рамку (WS_THICKFRAME).

  1. Визначення компонентів вікна, що лежать за межами клієнтської області

Для створення вікон, що мають додаткові компоненти, що лежать за межами клієнтської області, використовуються наступні прапори:

WS_CAPTION

Заголовок вікна

WS_HSCROLL

Горизонтальна смуга прокручування

WS_MAXIMIZEBOX

Кнопка максимізації

WS_MINIMIZEBOX

Кнопка мінімізації

WS_SYSMENU

Системне меню

WS_VSCROLL

Вертикальна смуга прокручування

  1. Початковий стан вікна

При породженні вікна можна задати його початковий стан

WS_DISABLED

Вікно не одержує введення

WS_MAXIMIZE

Вікно одержує максимальний розмір

WS_MINIMIZE

Вікно породжується в мінімізованому виді

WS_VISIBLE

Вікно породжується видимим. Інакше, для відображення вікна необхідно викликати функціюShowWindow.

4. Вікна.
 4.4. Повідомлення і черги повідомлень.

На відміну від традиційних “консольних” додатків, Windows додаток ніколи не очікує введення шляхом виклику спеціальних функцій типу getchar(). Операційна система сама здійснює введення і приймає рішення, якому з вікон він призначений.

За кожним вікном закріплена спеціальна функція, так називана процедура вікна. Для повідомлення вікна про призначеному йому чи введенні про яку-небудь іншу подію Windows викликає цю процедуру і передає їй як параметр код події й інших параметрів. Процедура повинна зробити необхідні дії, що відповідають даній події, і повернути керування операційній системі.

Виклик функції вікна називають передачею повідомлення цьому вікну. Як обов'язковий параметр у функцію вікна передається іменована константа, називана кодом повідомлення (message identifier)

Інші параметри визначають додаткові дані, зв'язані з даним повідомленням. Наприклад, при натисканні лівої кнопки миші в той момент, коли покажчик миші знаходиться над клієнтською областю вікна, вікну передається повідомлення WM_LBUTTONDOWN. При цьому як параметри передаються координати покажчика і стан інших кнопок миші і клавіш SHIFT і CTRL.

Windows використовує два способи для передачі повідомлень вікну

  1. Постановка повідомлення в чергу повідомлень
  2. Безпосередній виклик процедури вікна

1.   Черга повідомлень потоку

Кожен потік має свою чергу повідомлень. Потік повинний переглядати свою чергу повідомлень і направляти повідомлення на обробку відповідному вікну. Для цей потік повинний організувати цикл обробки повідомлень, що складає з функцій: GetMessage, TranslateMessage, і DispatchMessage.

while (GetMessage(&msg, (HWND) NULL, 0, 0)) {

TranslateMessage(&msg);

DispatchMessage(&msg);

}

Функція GetMessage припиняє виконання потоку до одержання їм повідомлення. Функція повертає значення FALSE, якщо отримане повідомлення WM_QUIT. В всіх інших випадках повертається TRUE. Додаток може завершити себе посилкою повідомлення WM_QUIT. Для цього призначена функція PostQuitMessage. Звичайно вона викликається у відповідь на одержання головним вікном додатка повідомлення WM_DESTROY.

При натисканні клавіш Windows посилає активному вікну повідомлення WM_KEYDOWN і WM_KEYUP. Ці повідомлення містять деякі віртуальні коди клавіш, а не символи. Для аналізу натискань і породження повідомлень WM_CHAR, що містять символьні коди клавіш, використовується функція TranslateMessage.

Для того, щоб направити повідомлення на обробку відповідному вікну, використовується функція DispatchMessage.

Для постановки повідомлень у чергу використовується функція PostMessage. Першим параметром цієї функції є описувач вікна, якому передається повідомлення. Система визначає, який потік породив це вікно і ставить повідомлення йому в чергу. Потік, що викликав функцію PostMessage не чекає обробки повідомлення, а продовжує виповнюватися. Функцією PostThreadMessage повідомлення ставиться в чергу потоку, але в якості описувача вікна встановлюється NULL. Потік не повинний відправляти такі повідомлення на обробку своїм вікнам. Для цього в циклі обробці повідомлень повинний бути передбачений відповідний аналіз описувача вікна.

2.    Безпосередній виклик процедури вікна

Для безпосереднього виклику процедури вікна призначена функція SendMessage. Потік, що викликав SendMessage припиняється до завершення обробки повідомлення.

3.   Пересилання даних за допомогою повідомлень

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

Тема №5 Взаємодія процесів

5. Взаємодія процесів
 5.1. Обмін даними між процесами

Win32® API надає багатий набір засобів обміну даними.

Interprocess communications (IPC) - складова частина Win32® API, набір засобів для організації обміну і поділу даних між процесами.

При розробці додатка в середовищі Win32® необхідно задатися питанням, необхідно чи передбачити можливість обміну даними цього додатка з іншими додатками і якими додатковими умовами накладаються на спосіб цього обміну.

  1. Чи буде додаток спілкуватися з іншими тільки на локальному чи комп'ютері необхідно передбачити взаємодію в мережі?
  2. Чи буде додаток спілкуватися з іншими, працюючими під керуванням іншої операційної системи (interoperable - інтероперабельність)?
  3. Чи буде користувач мати можливість вибору, з яким додатком буде взаємодіяти даний чи додаток додаток саме зробить пошук тих додатків, з якими воно повиннео і може взаємодіяти?
  4. Чи буде додаток взаємодіяти з великою кількістю інших додатків загальноприйнятими способами (типу вирізувати/уставити з буфера обміну) чи буде взаємодіяти своїми специфічними методами?
  5. Чи важлива продуктивність для додатка? Використання складних механізмів взаємодії веде до додаткового і дуже істотним накладним витратам.
  6.  Чи буде додаток Windows-based чи йому досить бути консольним? Багато механізмів взаємодії працюють тільки з Windows-based додатками.

Існують наступні способи поділу даних між процесами:

1.                                                             Відображення проецируємиых файлів (File mapping).

Два процеси відображають той самий об'єкт “проецируємий файл” на свій адресний простір. Цей механізм докладно описаний у п. 4.5.3.

2.                                                             Поділювана пам'ять (Shared Memory).

Відрізняється від попереднього способу тільки тим, що як поділюваний файл використовується частина файлу підкачування. Так само описано в пункті 4.5.3.

3.                                                             Безіменні транспортери (Anonymous Pipe).

Один із класичних способів взаємодії процесів, відомий ще в UNIX. За допомогою функції CreatePipe процес створює два описувача: один - для читання, іншої - для запису. Ці описувачі аналогічні описувачам файлів у тім змісті, що з ними можна працювати файловими функціями ReadFile і WriteFile. Якщо породити дочірній процес так, що б він успадковував описувачі, то можна використовувати описувачі транспортера для взаємодії процесів. Можна запропонувати наступну схему взаємодії:

/* Дочірній процес */

#include <stdio.h>

#include <string.h>

int main( void )

{ char WorkString[80] ;

while( strcmp( WorkString, "end" )) {

scanf( "%s", WorkString );

printf( "%s\n", WorkString ) ;

}

return 0 ;

}

/* Батьківський процес */

#include <windows.h>

#include <stdio.h>

#include <conio.h>

int main(void)

{ HANDLE hStandardInput ;

HANDLE hPipeInput ;

HANDLE hPipeOutput ;

PROCESS_INFORMATION pi ;

STARTUPINFO si ;

char WorkString[80] ;

DWORD NumberOfBytesWritten ;

ZeroMemory( &si, sizeof(si)) ;

si.cb = sizeof( si ) ;

hStandardInput = GetStdHandle( STD_INPUT_HANDLE ) ;

CreatePipe( &hPipeInput, &hPipeOutput, NULL, 0 ) ;

SetStdHandle( STD_INPUT_HANDLE, hPipeInput ) ;

CreateProcess( NULL, "Child", NULL, NULL, TRUE, CREATE_NEW_CONSOLE,

NULL, NULL, &si, &pi ) ;

SetStdHandle( STD_INPUT_HANDLE, hStandardInput ) ;

CloseHandle( hPipeInput ) ;

while( strcmp( WorkString, "end\n" )) {

scanf( "%s", WorkString ) ;

strcat( WorkString, "\n" ) ;

WriteFile( hPipeOutput, WorkString, strlen(WorkString),

&NumberOfBytesWritten, NULL ) ;

}

return 0 ;

}

4.                                                             Іменовані транспортери (Named Pipes).

Аналогічні попередніми за винятком того, що при створенні транспортеру привласнюється унікальне глобальне ім'я. Процес, що породив транспортер називається сервером. Процес, що приєднується до цього транспортера, називається клієнтом. Клієнт може приєднуватися до сервера, що знаходиться на вилученому комп'ютері в мережі. Для обслуговування одночасно декількох клієнтів необхідно породжувати кілька потоків.

5.                                                             Поштові скриньки (MailSlots).

Аналогічні іменованим транспортерам, але надають більш простий і односпрямований інтерфейс. Процес-сервер може завести поштова скринька і дати йому ім'я, глобальне в мережі. Любою клієнт може за допомогою операцій роботи з файлами відправити дані в цю шухляду. Сервер, у міру необхідності, може читати передані йому дані. Крім цього, можливо широкомовна передача інформації клієнтом усім серверам домена.

6.                                                             Буфер обміну (Clipboard).

Широко застосовуваний у Windows механізм обміну інформацією з використанням спеціального системного глобального буфера. При цьому реалізується модель cut-copy-paste. Будь-який додаток може помістити дані в буфер обміну й одержати дані з нього.

7.                                                             Динамічний обмін даними (DDE - Dynamic Data Exchange).

Механізм, вивчений раніше (див. Методичні вказівки до лабораторної роботи “Використання протоколу DDE при розробці додатків”).

8.                                                             Приєднання і впровадження об'єктів (OLE - Object linking and embedding).

Протокол спочатку призначений для створення складених документів. З його допомогою можна, наприклад, уставити таблицю MS Excel® у документ MS Word. При цьому можливо як уставити таблицю цілком (embedding), так і вставити тільки посилання на цю таблицю (linking). В даний час протокол OLE розвився до набору технологій, що лежать в основі побудови сучасних інформаційних систем.

9.                                                             Динамічно компонуємі бібліотеки (DLL - dynamic link libraries).

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

10.                                                          Вилучений виклик процедур (RPC - Remote Procedure Call).

RPC - природний розвиток ідеології процедурного програмування.

Перші програми писалися з використанням операторів goto. Фактично, саме поява таких процедурно орієнтованих мов як З, поклало цьому кінець. Підпрограма стала розглядатися як чорну шухляду з документованими параметрами. Природно спробувати уможливити виконання цієї процедури на вилученому комп'ютері. Механізм здійснення цієї ідеї наступний: з додатком компонується не сама процедура, а лише деяка заглушка, що передає по мережі параметри процедури і приймає результат обчислень. У додатка створюється ілюзія роботи з локальною процедурою. Можливе виконання процедури і зухвалої програми під керуванням різних операційних систем.

5. Взаємодія процесів.
 5.2. Синхронізація потоків.

У середовищі, що дозволяє виконувати одночасно кілька потоків, дуже важливо синхронізувати їхня діяльність. Інакше потоки не зможуть коректно працювати з поділюваними областями даних. Загальна проблематика цього питання вивчена в частині 1 курсу.

  1. Критичні секції

У Win32® API реалізований класичний механізм критичної секції. Для роботи з критичною секцією необхідно завести структуру CRITICAL_SECTION і ініціалізувати її викликом функціїInitializeCriticalSection. Тепер усі потоки можуть використовувати функції EnterCriticalSection і LeaveCriticalSection для огородження критичного розділу коду. Істотно, що механізм критичних секцій може використовуватися тільки в рамках одного процесу.

  1. Синхронізація потоків різних процесів.

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

  • WaitForMultipleObjects
  • WaitForMultipleObjectsEx
  • WaitForSingleObject
  • WaitForSingleObjectEx

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

  • Mutex (mutually exclusive - взаємне виключення)
  • Семафори
  • Події

1.                                                             Об'єкти Mutex

Mutex - глобальний іменований об'єкт, що може належати тільки одному потоку. Якщо об'єкт Mutex належить якому-небудь потоку, то інші потоки не можуть захопити його. За допомогою об'єктів Mutex так само реалізується класичний алгоритм критичної секції. Загальна схема така: один з потоків породжує об'єкт Mutex і привласнює йому глобальне ім'я за допомогою функції CreateMutex. Інші потоки можуть використовувати функцію OpenMutex для одержання описувач об'єкта. Перед входом у критичну секцію потік викликає одну з функцій чекання, передаючи їй як параметр описувач об'єкта Mutex. Якщо об'єкт Mutex уже захоплений, то потік блокується до звільнення об'єкта. Якщо не захоплений, то виконання потоку продовжується, а об'єкт Mutex захоплюється. Для звільнення об'єкта Mutex використовується функціяReleaseMutex.

2.                                                             Семафори

За допомогою об'єктів типу семафор реалізується класичний механізм семафорів. При цьому як примітив P(S) виступає одна з функцій чекання, а як примітив V(S) – функція ReleaseSemaphore. При створенні семафора функцією CreateSemaphore можна визначити максимально припустиме значення перемінної S.

3.                                                             Події

Події – самий примітивний різновид синхронізуючих об'єктів. Вони породжуються функцією CreateEvetnt і бувають двох типів “зі скиданням вручну” і “з автоматичним скиданням”. Об'єкт подія може знаходитися в двох станах: “зайнятий” (non-signaled) і “вільний” (signaled). Для перекладу об'єкта подія у вільний стан використовується функція SetEvent, а для перекладу в зайняте – ResetEvent. За допомогою кожної з функцій чекання можна перевести потік, що викликав, у стан блокування до звільнення об'єкта подія. Якщо об'єкт подія є об'єктом “з автоматичним скиданням” то функція чекання автоматично переведе його в стан зайнятого.

Тема №6 Структурна обробка виключень

6. Структурна обробка виключень
 6.1. Загальний порядок обробки виключень

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

Апаратні виключення виникають у випадку спроби виконання неприпустимої послідовності команд (наприклад, розподіл на 0). Програми можуть самостійно викликати програмні виключення, використовуючи існуючі в Win32® механізми.

Структурна обробка виключень (SEH-Structured Exception Handling) - спеціальний механізм, що існує в Win32®, що надає можливість визначати дії програми у випадку виникнення виключень.

Компілятори, розроблені для середовища Win32® надають спеціальні кошти, призначені для структурної обробки виключень. У компіляторах Microsoft® - це ключові слова tryfinallyexcept. Ключове слово try визначає обгороджена ділянка коду. Якщо при виконанні цієї ділянки виникає виключення, то керування передається ділянці коду, визначеній словом finally чи except.

try {

// захищений блок

}

except (filter-expression) {

// оброблювач виключення

}

try {

// захищений блок

}

finally {

// оброблювач завершення

}

У випадку виникнення виключення ОС запам'ятовує середовище потоку, що виповнюється, у структурі CONTEXT і заповнює структуру EXCEPTION_RECORD інформацією про виключення.

Якщо при виникненні виключення виконувався прикладний процес (user-mode code) , то система виконує наступні дії:

  1. Намагається звернеться до відладчику, що обслуговує даний процес. Відладчик повинний знаходитися в стані чекання після виклику функції WaitForDebugEvent.
  2. Якщо процес чи не налагоджується відтладчик не обробляє це виключення, система передає керування блоку обробки виключення, визначеному ключовими словами finally чи except.
  3. Якщо оброблювач не визначений, чи він не обробляє дане виключення, керування передається відтладчику вдруге.
  4. Якщо знову відладчик не обробляє дане виключення, використовується обробка виключення за замовчуванням. У більшості випадків - це виклик функції ExitProcess.

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

6. Структурна обробка виключень.
 6.2. Оброблювачі завершення. Локальне і глобальне розкручування.

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

Захищений код усередині блоку try може завершитися будь-яким способом: операторами returngoto чи навіть викликом функції longjump. Оброблювач завершення буде викликаний у будь-якому випадку.

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

Приклад:

DWORD Function1( void )

{ /* Робота із семафором */

WaitForSingleObject( g_hSem, INFINITE ) ; /* Вхід у критичну секцію */

/* Робота з поділюваними даними */

ReleaseSemaphore( g_hSem, 1, NULL ) ; /* Вихід із критичної секції */

return( RetValue ) ;

}

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

DWORD Function1( void )

{ /* Робота із семафором */

try {

WaitForSingleObject( g_hSem, INFINITE ) ; /* Вхід у критичну секцію */

/* Робота з поділюваними даними */

return( RetValue ) ;

}

finally {

ReleaseSemaphore( g_hSem, 1, NULL ) ; /* Вихід із критичної секції */

}

}

Поза залежністю від ходу робіт з поділюване даними, звільнення семафора гарантовано відбудеться.

Однак, у приведеного приклада є істотний недолік. Необхідно уникати використання операторів, що штучно переривають захищений блок. Спроба виходу з захищеного блоку до його закінчення, включає механізм глобального чи локального розкручування, що вимагає великої кількості накладних витрат через те, що операційна система бере на себе обробку подібної ситуації.

Локальне розкручування виникає у випадку, коли відбувається спроба передчасного завершення захищеного блоку операторами returnbreak і т.д. Глобальне розкручування виникає в тому випадку, коли передчасне завершення виникає поза захищеним блоком, наприклад, при виконанні викликаної з блоку функції. Для передчасного завершення захищеного блоку без додаткових витрат призначене ключове слово leave. Приведений нижче приклад приводить до того ж результату, що і попередній, але має значно більшу ефективність:

DWORD Function1( void )

{ /* Робота із семафором */

try {

WaitForSingleObject( g_hSem, INFINITE ) ; /* Вхід у критичну секцію */

/* Робота з поділюваними даними */

}

finally {

ReleaseSemaphore( g_hSem, 1, NULL ) ; /* Вихід із критичної секції */

}

return( RetValue ) ;

}

6. Структурна обробка виключень.
 6.3. Фільтри й оброблювачі виключень.

У випадку виникнення виключення можна визначити тип виключення, використовуючи функцію DWORD GetExceptionCode(VOID). Функція повертає код виключення. Визначені 16 кодів. От деякі з них:

EXCEPTION_ACCESS_VIOLATION

Спроба звертання до комірки пам'яті, доступ до якої заборонений (наприклад, пам'ять не виділена)

EXCEPTION_FLT_DIVIDE_BY_ZERO

Розподіл на нуль із крапкою, що плаває

EXCEPTION_INT_DIVIDE_BY_ZERO

Розподіл на нуль з фіксованою крапкою

EXCEPTION_INT_OVERFLOW

Цілочисельне переповнення

EXCEPTION_PRIV_INSTRUCTION

Спроба виконання привілейованої команди

Синтаксична конструкція try-except, використовується для опису блоку обробки, що виповнюється у випадку виникнення виключення усередині захищеного блоку. Перед початком виконання блоку обробки виробляється обчислення значення фільтра. Значення фільтра визначає реакцію програми на виключення.

Можливі три значення фільтра

EXCEPTION_EXECUTE_HANDLER

Викликає виконання оброблювача виключення

EXCEPTION_CONTINUE_SEARCH

Викликає передачу обробки виключення більш ранньому з вкладених блоків try-except чи операційній системі

EXCEPTION_CONTINUE_EXECUTION

Викликає продовження виконання перерваного блоку

Приклад:

LPTSTR SafeStrcpy(LPTSTR lpszString1, LPTSTR lpszString2) {

try {

return strcpy(string1, string2);

}

except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?

EXCEPTION_EXECUTE_HANDLER :

EXCEPTION_CONTINUE_SEARCH ) {

return NULL;

}

}

Функція SafeStrcpy працює аналогічно функції strcpy за винятком одного моменту. Якщо при операції копіювання виникає помилка звертання до пам'яті, то ця помилка обробляється усередині тіла функції і її програмі, що викликав, повертається значення NULL. Переривання програми, що викликала, не відбувається. Приклад демонструє використання прапорів EXCEPTION_EXECUTE_HANDLER іEXCEPTION_CONTINUE_SEARCH. Прапор EXCEPTION_CONTINUE_EXECUTION використовується якщо при обчисленні значення фільтра можна усунути причину виключення і продовжити виконання перерваної програми.

Тема №7 Системний реєстр

7. Системний реєстр
 7.1. Загальна структура системного реєстру

Системний реєстр (registry) - спеціальна системна база даних, у якій додатки й операційна система можуть зберігати інформацію про конфігурацію.

Операційна система використовує системний реєстр у такий спосіб:

  1. При запуску програми установки Windows (Windows setup), додаванні нового обладнання через панель чи керування запуску програм установки устаткування, операційна система (Configuration manager) додає до реєстру інформацію об устаткування. У реєстрі міститься повний список пристроїв.
  2. При установці Windows “поверх” попередньої версії до реєстру переноситься інформація з INI файлів.
  3. При чи додаванні видаленні пристроїв, що підтримують специфікацію Plug and Play, що відповідає інформація заноситься в registry.
  4. Драйвери пристроїв зчитують з реєстру настроювання, подібно тому, як це робиться при використанні рядка device= файлу CONFIG.SYS.
  5. З реєстром працюють різні адміністративні програми, наприклад Панель Керування (Control Panel).

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

Дані в реєстрі організовані у виді дерева. Вузли цього дерева називаються ключами (key). Кожен ключ може містити будь-яку кількість підключей і значень (values). Кожен ключ має ім'я складається з одного чи декількох символів. Ім'я не може містити в собі пробіли, зворотну косу рису, символи “*” і “?”. Імена ключів, що починаються з крапки зарезервовані. Ім'я підключа повинне бути унікальним відносно выщележачого ключа.

Додаток повинний відкрити ключ перед тим як додавати в нього дані. Для того, щоб відкрити новий ключ, додаток повинний надати системі уже відкритий раніше ключ. Для того, щоб це було можливе система завжди надає два відкритих ключі (HKEY_LOCAL_MACHINE і HKEY_USERS). Перший містить інформацію описваючу можливі конфігурації комп'ютера, другий - усіх користувачів. Додаток використовує ці ключі, як крапки входу до реєстру. Крім цього завжди визначені два інших ключі, що містять посилання на актуальні підключи цих ключів. Один з них, HKEY_CLASSES_ROOT, описує актуальну конфігурацію програмного забезпечення комп'ютера з HKEY_LOCAL_MACHINE, інший, HKEY_CURRENT_USER, посилається на працюючого користувача з HKEY_USERS. Значення інших ключів системно залежно. Як приклад розглянемо реєстр Windows’95.

7. Системний реєстр.
 7.2. Системний реєстр Windows’95.

Системний реєстр Windows’95 має наступну структуру:

Ключ

Збережена інформація

HKEY_LOCAL_MACHINE

Специфічна для даного комп'ютера інформація, що використовується всіма користувачами комп'ютера. Використовуються наступні підключи (папки)

  • Config - всі альтернативні конфігурації, можливі для даного комп'ютера. Наприклад, для docking station
  • Enum - інформація про все устаткування комп'ютера
  • Hardware - інформація про послідовні порти і модеми
  • Network - інформація про підключення до мережі, (напр. ім'я користувача в мережі)
  • Security - інформація про захист і можливості вилученого доступу й адміністрування
  • Software - інформація про програмне забезпечення, установленому на комп'ютері. Використовується програмним забезпеченням для установки власної конфігурації
  • System - описує конфігурацію драйверів і сервісів, доступних операційній системі

HKEY_CURRENT_CONFIG

Указує на актуальний підключ ключаHKEY_LOCAL_MACHINE\Config

HKEY_DYN_DATA

Містить посилання на частину інформації вHKEY_LOCAL_MACHINE, що відноситься до пристроїв Plug and Play, Ця інформація змінюється при підключенні і відключенні пристроїв.

HKEY_CLASSES_ROOT

Містить посилання на частину інформації вHKEY_LOCAL_MACHINE, що відноситься до програмного забезпечення.

HKEY_USERS

Містить інформацію про всіх користувачів, що працюють на даному комп'ютері. Кожному користувачу виділяється підключ.

HKEY_CURRENT_USER

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

7. Системний реєстр.
 7.3. Робота додатків із системним реєстром.

Формально, додатки можуть зберігати в реєстрі будь-які дані, однак вони повинні дотримувати наступних “правил поведінки”:

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

Перед записом інформації до реєстру необхідно визначити, до чого відноситься ця інформація: чи є вона загальної для всіх користувачів чи комп'ютера специфічна для кожного окремого користувача

Інформація загальна для всіх користувачів повинна заноситися в ключ виду:

HKEY_LOCAL_MACHINE\Software\MyCompany\MyProduct\1.0

Інформація специфічна для користувача повинна заноситися в ключ виду:

HKEY_CURRENT_USER\Software\MyCompany\MyProduct\1.0\...

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

Функція

Виконувана дія

RegCreateKey

RegCreateKeyEx

Створення підключа

RegOpenKey

RegOpenKeyEx

Одержання описувача існуючого ключа (відкриття ключа)

RegSetValue

RegSetValueEx

Запис нового імені даних у ключі і запис цих даних

RegQueryValue

RegQueryValueEx

Читання значення з ключа по імені даних

RegEnumValue

Читання значення з ключа по номері даних

RegCloseKey

Закриття ключа і відновлення реєстру

RegNotifyChangeKeyValue

Визначення події, що повинне відбутися при зміні заданого значення в реєстрі (див. 6.2.5).

Приклад програми, що працює з реєстром

#include <windows.h>

#include <stdio.h>

main()

{ HKEY MyKey ;

LONG ErrorCode ;

char Value[80] ;

char Name[80] ;

DWORD NameSize ;

DWORD ValueSize ;

int і ;

/* Створення нового підключа */

ErrorCode = RegCreateKey(HKEY_CURRENT_USER,

"\\Software\\MyCompany\\MyProduct\\1.0\\aaa",

&MyKey );

if ( ERROR_SUCCESS != ErrorCode )

return 1 ;

/* Запис у підключ десятьох нових даних з ім'ям Namex і значенням Valuex */

for ( i = 0 ; i < 10 ; i++ ) {

sprintf( Name, "Name%d", i ) ;

sprintf( Value, "Value%d", i ) ;

ErrorCode = RegSetValueEx( MyKey,Name,0,REG_SZ,

Value,strlen(Value)+1);

if ( ERROR_SUCCESS != ErrorCode )

return 2 ;

}

/* Читання з підключа всіх записаних значень по номеру і й їх друк */

for ( i = 0 ; ; i++ ) {

NameSize = sizeof( Name );

ValueSize = sizeof( Value );

ErrorCode = RegEnumValue( MyKey, i, Name, &NameSize,

0,NULL, Value, &ValueSize ) ;

if ( ErrorCode != ERROR_SUCCESS )

break ;

printf( "%d: %s -- %s\n", i, Name, Value ) ;

}

RegCloseKey( MyKey ) ;

return 0 ;

}

Тема №8 Робота з файлами

8. Робота з файлами
 8.1. Файлові структури

Windows 95 підтримує роботу з файловими структурами FAT і CDFS. При цьому Windows 95 працює з розширеним варіантом FAT, що підтримує імена довжиною до 255 символів. CDFS - файлова структура призначена для компакт-дисків.

На додаток до цьому Windows NT підтримує роботу ще з двома файловими структурами NTFS і HPFS.

NTFS (New Technology File System) - структура призначена для організації даних на твердому диску. NTFS надає всі можливості FAT, значно розширюючи їх. Доступ до файлів у NTFS, як правило, більш швидкий ніж у FAT. NTFS файлова система, що самовідновлюється. Вона стійка до краху додатків, системи, операцій введення-висновку і розроблена таким чином, щоб відновлювати коректність даних без використання спеціальних сервісних програм перевірки дисків. NTFS підтримує розмежування доступу до файлів, імена файлів у довільному алфавіті. Докладно вивчається в розділі 9.5.

HPFS (High-Performance File System) - так само організує дані на твердому диску. У порівнянні з FAT вона підвищує продуктивність системи за рахунок використання кэширування. Підтримується Windows з метою сумісності. По можливості рекомендується заміняти HPFS на NTFS.

8. Робота з файлами

 8.2. Робота з томами і каталогами

Для з'ясування того, які логічні диски існують у системі, використовується функція

DWORD GetLogicalDrives( void )

Кожен установлений біт значення, що повертається, відповідає існуючому в системі логічному пристрою. Наприклад, якщо в системі існують диски A:, C: і D:, те значення, що повертається функцією, дорівнює 10(10).

Функція

DWORD GetLogicalDrivesStrings( DWORD cchBuffer, LPTSTR lpszBuffer)

заповнює lpszBuffer інформацією про кореневий каталог кожного логічного диска в системі. У приведеному вище прикладі буфер буде заповнений символами

A:\<null>C:\<null>D:\<null><null>

параметр cchBuffer визначає довжину буфера. Функція повертає реальну довжину буфера, необхідну для розміщення всієї інформації. Якщо необхідна довжина буфера заздалегідь невідома (а вона ніколи заздалегідь невідома), то можна скористатися наступним класичним прийомом:

DWORD dw = GetLogicalDrivesStrings( 0, NULL ) ;

LPSTR lpDriveStrings = HeapAlloc( GetProcessHeap(), 0, dw*sizeof(TCHAR));

GetLogicalDrivesStrings( dw, lpDriveStrings );

Для визначення типу диска призначена функція

UINT GetDriveType( LPTSTR lpszRootPathName )

Як параметр їй передається символічне ім'я кореневого каталогу (напр. A:\), а значення, що повертається, може бути одне з наступних:

Ідентифікатор

Опис

0

Тип пристрою визначити не можна

1

Корнєвої каталог не існує

DRIVE_REMOVABLE

Гнучкий диск

DRIVE_FIXED

Твердий диск

DRIVE_REMOTE

Мережний диск

DRIVE_CDROM

Компакт диск

DRIVE_RAMDISK

RAM диск (емуліруємий в оперативній пам'яті)

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

Функція GetDiskFreeSpace повідомляє інформацію про розміри сектора і кластера і про наявність вільних кластерів.

Функція DeviceIoControl дозволяє прикладній програмі звертатися прямо до драйвера пристрою і виконувати велику кількість дій, серед яких: форматування чи доріжок роздягнула, виштовхування носія з приводу, розбивка диска на розділи і багато хто інші.

Для роботи з каталогами і файлами, як з об'єктами, призначені наступні функції:

Функція

Виконувана дія

GetCurrentDirectory

Одержання поточного каталогу

SetCurrentDirectory

Зміна поточного каталогу

GetSystemtDirectory

Одержання системного каталогу

GetWindowstDirectory

Одержання основного каталогу системи

CreateDirectory

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

RemoveDirectory

Видалення каталогу

CopyFile

Копіювання файлу

MoveFile

MoveFileEx

 Чи переміщення перейменування файлу

DeleteFile

Видалення файлу

8. Робота з файлами.
 8.3. Синхронна робота з файлами.

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

У Win32 перед ухваленням рішення про використання операцій синхронної роботи з файлами настійно рекомендується розглянути питання про можливість використання файлів, відображуваних у пам'ять.

Для того, щоб чи створити відкрити файл використовується функція

HANDLE CreateFile(

LPCTSTR lpFileName, // pointer to name of the file

DWORD dwDesiredAccess, // access (read-write) mode

DWORD dwShareMode, // share mode

LPSECURITY_ATTRIBUTES lpSecurityAttributes, // pointer to security descriptor

DWORD dwCreationDistribution, // how to create

DWORD dwFlagsAndAttributes, // file attributes

HANDLE hTemplateFile // handle to file with attributes to copy

);

Параметр lpFileName визначає ім'я файлу.

Параметр dwDesiredAccess задає тип доступу до файлу. Можна визначити прапори GENERIC_READ і GENERIC_WRITE а так само їхню комбінацію для дозволу чи читання запису у файл.

Параметр dwShareMode визначає режим спільного використання файлу різними процесами. Якщо цей параметр дорівнює нулю, то ніякий інший потік не зможе відкрити цей же файл. Прапори FILE_SHARE_READ іFILE_SHARE_WRITE а так само їхня комбінація дозволяють іншим потокам здійснювати доступ до файлу для чи читання запису.

Параметр lpSecurityAttributes указує на структуру, що описує захист створюваного об'єкта ядра. Йому може бути привласнене значення NULL.

Параметр dwCreationDistribution визначає дії функції в залежності від того, чи існує уже файл із зазначеним ім'ям.

Ідентифікатор

Файл вже існує

Файл ще не існує

CREATE_NEW

Помилка

Створює файл

CREATE_ALWAYS

Знищує існуючий файл і створює новий

Створює файл

OPEN_EXISTING

Відкриває файл

Помилка

OPEN_ALWAYS

Відкриває файл

Створює файл

TRUNCATE_EXISTING

Відкриває файл і урізує його до нульової довжини

Помилка

Параметр dwFlagsAndAttributes визначає атрибути файлу, якщо він створюється і задає режим роботи з файлом.

Константа

Атрибут файлу

FILE_ATTRIBUTE_ARCHIVE

Архівний

FILE_ATTRIBUTE_HIDDEN

Схований

FILE_ATTRIBUTE_NORMAL

Немає ніяких атрибутів

FILE_ATTRIBUTE_READONLY

Тільки для читання

FILE_ATTRIBUTE_SYSTEM

Системний

FILE_ATTRIBUTE_TEMPORARY

Тимчасовий (збережений у пам'яті, але видаляє не при закритті)

Атрибути файлу можуть комбінуватися за винятком FILE_ATTRIBUTE_NORMAL, що завжди використовується на самоті.

Разом з атрибутами можуть комбінуватися і прапори, що задають режим роботи з файлом.

Прапор

Режим роботи з файлом

FILE_FLAG_NO_BUFFERING

Не здійснювати кэширування і випереджальне читання

FILE_FLAG_RANDOM_ACCESS

Кэширувати як файл довільного доступу

FILE_FLAG_SEQUENTIAL_SCAN

Кэширувати як файл послідовного доступу

FILE_FLAG_WRITE_TROUGH

Не буферизувати операцію запису. Робити запис на диск негайно.

FILE_FLAG_DELETE_ON_CLOSE

Знищити файл при закритті. Корисно комбінувати з атрибутомFILE_ATTRIBUTE_TEMPORARY.

FILE_FLAG_OVERLAPPED

Робота з файлом буде здійснюватися асинхронно. Докладно вивчається в п. 9.4.

Параметр hTemplateFile або дорівнює NULL, або задає описувач відкритого файлу. В другому випадку параметр dwFlagsAndAttributes ігнорується, а зазначений файл використовується як шаблон, тобто використовуються його прапори й атрибути.

У випадку удачі функція CreateFile повертає описувач відкритого файлу як об'єкта ядра. Істотно, що в противному випадку вона повертає не NULL, а INVALID_HANDLE_VALUE.

Для роботи з файлами використовуються наступні функції

Функція

Виконувана дія

ReadFile

Читання. Докладно розглянута в п. 9.4

WriteFile

Запис. Докладно розглянута в п. 9.4

SetFilePointer

Позиціонірування покажчика

SetEndOfFile

Зміна розміру файлу

FlushFileBuffers

Примусовий запис буферів кэширування на диск

LockFile

LockFileEx

Блокування частини файлу від запису іншими потоками.

UnlockFile

UnlockFileEx

Розблокування раніше заблокованої частини файлу

8. Робота з файлами.
 8.4. Асинхронна робота з файлами.

При асинхронній роботі з файлами прикладна програма, запустивши операцію уведення висновку, не очікує її завершення а продовжує виповнюватися.

Windows’95 не дозволяє організувати асинхронну роботу з файлами, але той же самий асинхронний механізм може використовуватися при роботі з послідовними портами, транспортерами і поштовими скриньками.

Для організації асинхронної роботи з файлами необхідно при виклику функції CreateFile установити прапор FILE_FLAG_OVERLAPPED у параметрі dwFlagsAndAttributes. Після цього функції ReadFile і WriteFile будуть працювати асинхронно, тобто тільки запускати операції уведення висновку і не очікувати їхнього завершення.

BOOL ReadFile(

HANDLE hFile, // handle of file to read

LPVOID lpBuffer, // address of buffer that receives data

DWORD nNumberOfBytesToRead, // number of bytes to read

LPDWORD lpNumberOfBytesRead, // address of number of bytes read

LPOVERLAPPED lpOverlapped // address of structure needed for overlapped I/O

);

BOOL WriteFile(

HANDLE hFile, // handle to file to write to

LPCVOID lpBuffer, // pointer to data to write to file

DWORD nNumberOfBytesToWrite, // number of bytes to write

LPDWORD lpNumberOfBytesRead, // pointer to number of bytes written

LPOVERLAPPED lpOverlapped // address of structure needed for overlapped I/O

);

Параметри функції ReadFile мають наступне призначення:

  1. hFile - описувач об'єкта ядра “файл”, отриманий у результаті виклику функції CreateFile
  1. LpBuffer - адреса буфера, у который буде вироблятися читання
  1. nNumberOfBytesToRead - кількість байт, який необхідно прочитати
  1. lpNumberOfBytesRead - адреса перемінної, у якій буде розміщена кількість реальна прочитаних байт. Істотно, що відразу після виконання функції ReadFile, цей параметр не може бути встановлений, тому що операція читання тільки почалася.
  1. lpOverlapped - покажчик на структуру OVERLAPPED, що керує асинхронним уведенням висновком.

typedef struct _OVERLAPPED {

DWORD Internal;

DWORD InternalHigh;

DWORD Offset;

DWORD OffsetHigh;

HANDLE hEvent;

} OVERLAPPED;

Елементи структури мають наступне значення

Назва елемента

Призначення

Internal

Використовується операційною системою. Зберігає статус завершення операції.

InternalHigh

Використовується операційною системою. Зберігає кількість переданих байт.

Offset

Позиція у файлі, починаючи з який необхідно робити операцію читання (запису)

OffsetHigh

Кількість байт для передачі

HEvent

Описувач події, що відбудеться при завершенні операції читання (запису)

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

Параметри функції WriteFile аналогічні параметрам функції ReadFile.

Схем організації асинхронні читання і записи може бути кілька.

  1. Перед запуском операції створюється об'єкт ядра “подія” (див. п. 6.2.5) і його описувач передається у функцію RedFile (WriteFile) як елемент hEvent параметра lpOverlapped. Програма, виконавши необхідні дії одночасно з операцією передачі даних, викликає одну з функцій чекання (напр. WaitForSingleObject), передаючи їй як параметр описувач події. Виконання програми при цьому припиняється до завершення операції виводу-введення-висновку.
  2. Подія не створюється. Як очікуваний об'єкт виступає сам файл. Його описувач передається у функцію WaitForSingleObject. Цей метод простий і коректний, але не дозволяє робити паралельно кілька операцій виводу-введення-висновку з тим самим файлом.
  3. “Тривожний” асинхронний висновок^-вивід-введення-висновок. Схема побудована на використанні функцій ReadFileEx і WriteFileEx. Як додатковий параметр у ці функції передається адреса функції завершення, що буде викликатися всякий раз при завершенні операції виводу-введення-висновку. Істотно, що ці функції виконуються в тім же самому потоці що і функції файлового введення/висновку. Це значить, що потік, що запустив операції читання запису повинний звернутися функцію чекання, щоб дозволити системі викликати функцію завершення.

8. Робота з файлами.
 8.5. Файлова структура NTFS.

·  Системні файли NTFS

Файлова структура NTFS розроблена на зміну системам FAT і HPFS з метою підвищення продуктивності, надійності і сумісності. Вона так само підтримує механізми захисту, необхідні для використання на файлі-сервері мережі.

Любою розподілений сектор NTFS належить якому-небудь файлу. Це відноситься навіть до внутрішніх структур даних. Системою використовуються наступні файли:

Master File Table

$Mft

Список умісту тому

Master File Table2

$MftMirr

Дзеркальне відображення Master File Table

Log File

$LogFile

Протокол останніх операцій з файловою структурою

Volume

$Volume

Ім'я, версія й інша інформація про том

Attribute Definitions

$AttrDef

Таблиця імен, номерів і опису атрибутів

Root Filename Index

$.

Корнєвої каталог

Cluster Bitmap

$Bitmap

Бітова карта розподілу кластерів

Boot File

$Boot

Завантажувальний запис тому

Bad Cluster File

$BadClus

Файл, що складається зі збійних кластерів

·  Master File Table (MFT)

Для кожного файлу на томі NTFS існує спеціальний запис у MFT. Перші 16 записів MFT зарезервовані для спеціального використання. Перший запис описує саму MFT, а друга - її копію MFT2. Початок області даних MFT і MFT2 записано в завантажувальному секторі, розташованому на початку диска. Копія завантажувального сектора зберігається в середині диска. Третій запис визначає Log File (див.п.9.5.3), використовуваний для відновлення файлової структури у випадку збоїв. Починаючи із сімнадцятого запису в MFT міститься інформація про каталоги і файли тому.

Кожен запис у MFT займає досить велике місце. Невеликі файли (до 1500 байт) містяться усередині цього запису і не вимагають для збереження додаткового місця на диску.

Такий спосіб збереження файлів значно прискорює доступ до них. У випадку, якщо файл не міститься усередині одного запису, у MFT міститься інформація про розташування файлу. Невеликі каталоги так само розміщаються усередині одного запису MFT. У противному випадку вони організуються у виді B-дерева.

·  Цілісність даних і здатність до самовідновлення.

Існує три види файлових структур

·  1. Careful-write file systems - файлові системи, у яких для підтримки цілісності запис на диск відбувається негайно з появою запиту на запис. Приклад FAT у MS DOS.

·  2. Lazy-write file systems - файлові системи, у яких для підвищення продуктивності виробляється кеширування даних. У випадку краху системи дані в кеш можуть бути загублені, а цілісність файлової структури - порушена. Приклад: FAT у Windows NT і більшість структур у UNIX.

·  3. Recoverable file systems - файлові системи, що поряд з кешируванням, що підвищує продуктивність, застосовують спеціальні засоби підтримки цілісності даних і здатні до самовідновлення після краху системи. До таких систем відноситься NTFS.

Кожна операція, що змінює вміст тому NTFS розглядається як транзакція і може бути розбита на послідовність елементарних дій. Коли виробляється операція зміни вмісту будь-якого файлу, у файл протоколу (Log file)заноситься наступна інформація:

·  Яким образом можна повторити транзакцію (redo)

·  Яким образом можна скасувати транзакцію (undo)

Крім цього, кожних кілька секунд Windows NT перевіряє дисковий кеш на предмет виконання операцій запису і заносить відповідні мітки в Log file.

При кожнім завантаженні операційної системи відбувається перевірка коректності завершення її роботи. У випадку, якщо робота системи завершилася крахом, виробляються дії по відновленню файлової структури. При цьому використовується інформація, записана в Log file.

·  Організація і керування дисками

При організації і керуванні дисками в Windows NT можна використовувати наступні можливості:

·  Можливість використання декількох фізичних дисків. При цьому допускається як розбивка кожного фізичного диска на розділи (volume sets), так і розміщення одного роздягнула вроздріб на декількох фізичних дисках (stripe sets).

·  Можливість використання спеціальних механізмів захисту від збоїв (fault-tolerance options)

·  Можливість використання сервісу збереження, відновлення даних і взаємодії з джерелами безперебійного харчування.

Кожен фізичний диск може бути розбитий максимум на чотири розділи. Розділи можуть бути основними (primary) і розширеними (extended). Основний розділ може містити код завантаження операційної системи. Розширений розділ може бути додатково розбитий на підрозділи. Кожному розділу і підрозділу операційна система ставить у відповідність логічний диск і призначає своє ім'я (C:, D:, E: і т.д.)

Крім розбивки фізичного диска на розділи, система дозволяє один логічний диск вроздріб на декількох фізичних. Розділи різних фізичних дисків збираються в один логічний диск. Це збільшує продуктивність дискової підсистеми.

Наступні прийоми використовуються для захисту від збоїв:

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

·  Подвоєння дисків (disk duplexing) цілком аналогічно дзеркальному відображенню, за винятком того, що використовуються не тільки різні фізичні диски, але і різні контролери. Для Windows NT дзеркальне відображення і подвоєння дисків нерозрізнені.

·  Розміщення одного роздягнула на декількох дисках з контролем парності (Disk striping with parity). Цей метод побудований на основі простого розміщення одного роздягнула на декількох дисках і відрізняється тим, що один розділ на кожнім фізичному диску виділяється для збереження контрольних сум.

Тема №9 Безпека

9. Безпека
 9.1. Загальна модель безпеки в Microsoft Windows NT

Механізми безпеки (security) діють автоматично для всіх додатків, що працюють під керуванням Windows NT. У більшості випадків цього досить. На додаток до цього функції безпеки Win32® API дозволяють додаткам вибірково чи надавати забороняти доступ до окремих об'єктів.

Windows NT розроблена таким чином, щоб задовольняти рівню безпеки C2 міністерства оборони США (див.п.2.2). Основні вимоги рівня C2 наступні:

  • Повинне здійснюватися керування доступом до ресурсів. Повинно бути можливим чи дозволяти забороняти доступ до зазначених ресурсів як окремим користувачам, так і групам користувачів.
  • Пам'ять повинна бути захищена таким чином, щоб неможливо було прочитати інформацію навіть після звільнення пам'яті процесом.
  • Користувачі повинні реєструвати себе в системі і мати унікальні ідентифікатори. Усі дії користувачів, контрольовані системою, повинні бути персоніфіковані.
  • Системний адміністратор і тільки він повинний мати можливість контролювати виконання дій, що відносяться до безпеки.
  • Система повинна бути захищена від утручання, наприклад, від модифікації системного коду в чи пам'яті системних файлів на диску.

Всі об'єкти в Windows NT можуть бути захищені. Атрибути захисту кожного об'єкта описані в його дескрипторі захисту (security descriptor). Дескриптор захисту містить інформацію про власника об'єкта і список керування доступом (ACL - access control list). Список керування доступом складається з елементів (ACE - access control entry), кожний з який відповідає користувачу і групі користувачів, яким дозволений чи заборонений доступ до об'єкта.

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