ВІКІСТОРІНКА
Навигация:
Інформатика
Історія
Автоматизація
Адміністрування
Антропологія
Архітектура
Біологія
Будівництво
Бухгалтерія
Військова наука
Виробництво
Географія
Геологія
Господарство
Демографія
Екологія
Економіка
Електроніка
Енергетика
Журналістика
Кінематографія
Комп'ютеризація
Креслення
Кулінарія
Культура
Культура
Лінгвістика
Література
Лексикологія
Логіка
Маркетинг
Математика
Медицина
Менеджмент
Металургія
Метрологія
Мистецтво
Музика
Наукознавство
Освіта
Охорона Праці
Підприємництво
Педагогіка
Поліграфія
Право
Приладобудування
Програмування
Психологія
Радіозв'язок
Релігія
Риторика
Соціологія
Спорт
Стандартизація
Статистика
Технології
Торгівля
Транспорт
Фізіологія
Фізика
Філософія
Фінанси
Фармакологія


Використання акселераторів у файлах ресурсу.

Акселератори.Акселератор дозволяє вибирати пункт меню просто поєднанням клавіш. ^

Це дуже зручно і швидко. Таблиця акселераторів є ресурсом, ім’я якого повинне збігатися з ім’ям того меню (ресурсу), пункти якого вона визначає.

Ось приклад такої таблиці. Визначається один акселератор на пункт меню MENUP, що має ідентифікатор 4.

MENUP ACCELERATORS {

VKJF5, 4, VIRTKEY

} '

Загальний вигляд таблиці акселераторів Ім’я ACCELERATORS

Клавіша 1, Ідентифікатор пункту меню (1) [,тип] [,параметр]

Клавіша 2, Ідентифікатор пункту меню (2) [,тип] [,параметр]

Клавіша 3, Ідентифікатор пункту меню (3) [,ran] [,параметр]

Клавіша N, Ідентифікатор пункту мето (N) [.тип] [.параметр]

}

Розглянемо представлену схему. Клавіша - це або символ у лапках, або код ASCII символу, або віртуальна клавіша. Якщо спочатку іде код символу, то тип задається як ASCII. Якщо використовується віртуальна клавіша, то тип визначається як віртуальний. Всі назви (макроімена) віртуальних клавіш можна знайти у файлах - (window®,h).

Параметр може приймати одне з наступних значень: NOINVERT, Alt, Control, Shift. Значення NOINVERT означає, що не підсвічується обраний за допомогою акселератора пункт меню. Значення ALT, SHIFT, CONTROL означають, що, крім клавіші, визначеної в акселераторі, повинна бути натиснута одна з керуючих клавіш. Крім цього, якщо клавіша визначається в лапках, то натискання при цьому клавіші CONTROL визначається знаком "^": "^ А". А тепер поговоримо про механізм роботи акселераторів. Для того щоб акселератори працювали, необхідно виконати дві умови: Повинна бути завантажена таблиця акселераторів. Для цього використовується функція LoadAccelerators. Повідомлення, що прийшли від акселератора, слід перетворити на повідомлення WM_COMMAND. Тут нам стане в нагоді функція TranslateAccelerator. Зупинимося докладніше на другому пункті. Функція TranslateAccelerator перетворить повідомлення WMKEYDOWN і WMJ5YSKEYDOWN в повідомлення WM COMMAND і WM_SYSCOMMAND відповідно. При цьому в старшому слові параметра WPARAM поміщається 1, як відмінність для акселератора. У молодшому слові, як Ви пам'ятаєте, міститься ідентифікатор пункту меню. Виникає питання: для чого необхідні два повідомлення WM_COMMAND і WM_SYSCOMMAND? Тут все закономірно: повідомлення WM_SYSCOMMAND генерується для пунктів системного меню або меню вікна Функція TranslateAccelerator повертає ненульове значення, якщо було вироблено перетворення повідомлення акселератора, в іншому випадку повертається 0. Природно включити виклик цієї функції в цикл повідомлень. Ось цей фрагмент.

MSG_LOOP

PUSH 0

PUSH 0

PUSH 0

PUSH OFFSET MSG

CALL GetMessageA@ 16

CMP EAX, 0

JE END_LOOP

PUSH OFFSET MSG

PUSH [ACC]

PUSH [NEWHWND]

CALL TranslateAcceleratorA@12

CMP EAX ,0

JNE MSG_LOOP

PUSH OFFSET MSG

CALL TranslateMessage@4

PUSH OFFSET MSG

CALL DispatchMessageA@4

JMP MSG_LOOP

END LOOP:

 

Ресурси. Переваги використання ресурсів у програмах.

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

Використання ресурсів дає дві цілком певні вигоди:

Ресурси завантажуються в пам'ять лише при зверненні до них. тобто реалізується економія пам'яті.

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

Опис ресурсів зберігається окремо від програми в текстовому файлі (*. RC) і компілюються (*. Res) спеціальним транслятором ресурсів.

 

Використання ресурсів при роботі з іконками, рядками, курсорами.

Почнемо з перерахування найбільш уживаних ресурсів.

- Іконки.

- Курсори.

- Бітовая картинка.

- Рядок.

- Діалогове вікно.

- Меню.

- Акселератор.

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

1. Іконки.Можуть бути описані в самому файлі ресурсів, або зберігатися в окремому файлі *. ICO. Розглянемо останній випадок.

Ось файл ресурсів resu.rc:

# define IDI ICONl 1

IDIJCOH1 ICON "CdromOl.ico"

Як бачите, файл містить лише два значущих рядка. Один рядок визначає ідентифікатор іконки, другий - асоціює ідентифікатор з файлом "CdromOl.ico". Оператор Define є Сі-оператором препроцесора.

Як використовувати цей ресурс у програмі? Тут все просто: припустимо, що ми хочемо встановити нову іконку для вікна. Ось фрагмент програми, який встановлює стандартну іконку для головного вікна.

PUSH IDІ APPLICATION

Push 0

CALL LoadlconA @ 8

MOV [WC.CLSHICON], EAX

А ось фрагмент програми для встановлення іконки, зазначеної у файлі ресурсів:

Push 1; ідентифікатор іконки

Push [HINST]; ідентифікатор процесу

CALL LoadlconA @ 8

MOV [WC.CLSHICON], EAX

2. Курсори.Підхід тут повністю ідентичний.

#define IDIICON1 1

#define IDI_CUR1 2

ID1JCON1 ICON "CdromOl.ico"

IDI_CUR1 CURSOR "4way01.cur"

А ось фрагмент програми, що викликає іконку і курсор.

;---------------------------------------Іконка вікна

Push 1; ідентифікатор іконки Push [HINST]

CALL LoadlconA @ 8

MOV [WC.CLSHICON], EAX

;---------------------------------------Курсор вікна

Push 2; ідентифікатор курсора

Push [HINST]

CALL LoadCursorA @ 8

MOV [WC.CLSHCURSOR], EAX

3. Рядки.Щоб задати рядок або декілька рядків використовується ключове слово STRINGTABLE. Нижче представлений текст ресурсу, задає два рядки. Для завантаження рядки в програму використовується функція LoadString (див. нижче). Строки, що задаються у файлі ресурсів, можуть відігравати роль констант.

#define STR1 1

#define STR2 2 STRINGTABLE

{

STR1, "Повідомлення"

STR2, "Версія 1.01"

}

Процеси. Створення процесу, Завершення процесу.

Процеси.

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

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

- Дескриптори відкриваних ним файлів.

- Список завантажених ним у його власну пам'ять динамічних модулів (DLL).

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

Простіше кажучи кожен виконуваний модуль (. ЕХЕ), запущений в операційній системі Windows, стає процесом.

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

Тепер розглянемо деякі типи багатозадачності. У старій 16-бітної Windows перемикання між завданнями відбувалося лише тоді, коли завдання віддавало управління операційною системою. Така багатозадачність називається невитисняючою. У певному сенсі це було навіть гірше, ніж в операційній системі М8 ООБ. Там елементи багатозадачність здійснювалися за допомогою так званих ТSR-програм. Такі програми називалися ще резидентні. Вони перехоплюють переривання від таймера, клавіатури або іншого пристрою і мали можливість час від часу отримувати управління.

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

У 32-бітних операційних системах Windows (Windows 9х, Windows NТ, Windows 2000) реалізована витісняюча схема багатозадачності, в якій перемиканням між процесами і потоками займається операційна система. Якщо процес занадто довго виконує деяку операцію, то курсор над вікном процесу перетворюється в пісочний годинник. При цьому інші процеси, як і раніше виконуватися, і Ви зможете перемикатися на них. А от доступ до вікна даного процесу може виявитися важким. Вирішити цю проблему можна вже згаданим способом, замінивши в циклі очікування GetMessage на РееkMessage. Однак більш правильним рішенням буде розбивка процесу на певну кількість потоків.

Створити процес можна за допомогою функції CreateProcess.

Параметри:

1-й параметр - вказує на ім'я завантажуваної програми. Ім'я може містити повний шлях до програми.

2- й параметр - його значення залежить від того, чи є перший параметр NULL (0) чи ні. Якщо перший параметр вказує на рядок, то цей параметр трактується як командний рядок запуску (без імені програми). Якщо перший параметр дорівнює NULL, то цей параметр розглядається як командний рядок, перший елемент якого являє собою ім'я програми. Якщо шлях до програми не зазначено, то функція CreateProcess здійснює пошук програми за певним алгоритмом:

Пошук в каталозі, звідки була запущена програма.

Пошук в поточному каталозі.

Пошук в системному каталозі (можна отримати через GetSystemDirectory). Зазвичай системним каталогом є С: \ WINDOWS \ SYSTEM.

Пошук в каталозі Windows (можна отримати через GetWindowsDirectory). Зазвичай цим каталогом є С: \ WINDOWS.

Пошук в каталогах, перерахованих в параметрі PATH оточення.

3- й і 4-й параметри. Використовуються для завдання атрибутів доступу породжуваного процесу. Зазвичай вважають рівним 0.

5- й параметр. Якщо цей параметр 0, то породжувані процес не успадковує дескриптор породжуваного процесу, в іншому випадку породжувані процес успадковує дескриптори.

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

7- й параметр. Є вказівником на буфер, який містить параметри середовища. Якщо параметр дорівнює 0, то породжуваний процес успадковує параметри середовища породжуваного процесу.

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

9- й параметр. Представляє покажчик на структуру, яка містить інформацію про вікно створюваного процесу.

10- й параметр. Вказує на структуру, заповнюється при виконанні запуск програми.

Ось ця структура:

PROCINF STRUC

liProcess DD? ; Дескриптор створеного процесу.

hThread DD? ; Дескриптор головного потоку нового процесу.

Idproc DD? ; Ідентифікатор створеного процесу.

idTlir DD? ; Ідентифікатор головного потоку нового процесу.

PROCINF ENDS

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

Розглянемо тепер структуру, на яку вказує 9-й параметр функції CreateProcess. Ось ця структура:

STARTUP STRUC

cb DD 0

IpReserved DD 0

lpDesktop DD 0

lpTitle DD 0

dwX DD 0

dwY DD 0

dwXSize DD 0

dwYSize DD 0

dwXCountChars DD 0

dwYCountChars DD 0

dwFiUAttribute DD 0

dwFlags DD 0

wShowWindow DW 0

cbReserved2 DW 0

lpReserved2 DD 0

hStdlnput DD 0

hStdOutput DD 0

hStdError DD 0

STARTUP ENDS

Отже, роберемо сенс полыв цыэъ структури

СB – розмір даної структури в байтах. Заповнюється обов’язково.

IpReserved –резерв, повинне дорівнювати 0

IpDesktop – імя робочого столу.

IpTitle – назва вікна для консольних додатків, що створюють своє вікно. Для інших повинно дорівнювати 0.

dwX - координата X лівого верхнього кута вікна.

dwY - координата Y лівого верхнього кута вікна.

dwXSize - розмір вікна з X.

dwYSize - розмір вікна з Y.

dwXCountChars - розмір буфера консолі по X.

dwYCountChars - розмір буфера консолі по Y.

dwFillUAttribute – початковий колір тексту. Має значення тільки для консольних додатків.

dwFlags –прапор значення полів.

 

Ось значення цього прапора.

STARTF USESHOWWINDOW lh // Дозволити поле dwShowWindow

STARTF USESIZE 2h //Дозволити dwXSize та dwYSize.

STARTFJJSEPOSITION 4h //Дозволити dwX та dwX

STARTF_USECOUNTCHARS 8h // Дозволити dwXCountChars та dwYCountChars

STARTF_USEFILLATTR1BUTE lOh // Дозволити dwFillUAttribute

STARTF_FORCEONFEEDBACK 40h // Включити повернення курсору

STARTF FORCEOFFFEEDBACK 80h // Вимкнути повернення курсору

STARTFJJSESTDHANDLES lOOh // Дозволити hStdInput

dwShowWindow –визначає спосіб відображення вікна

cbReserved2 –резерв, повинно бути рівно 0

hStdInput –дескриптор введення (для консолі)

hStdOutput –дескриптор виводу (для консолі)

hStdError -дескриптор виводу повідомлення про помилку (для консолі)

 

Потоки, взаємодія потоків.

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

1- Й параметр. Покажчик на структуру атрибутів доступу. Має значення тільки для Windows NT. Зазвичай покладається NULL.

2- Й параметр. Розмір стека потоку. Якщо параметр дорівнює нулю, то береться розмір стека за замовчуванням, що дорівнює розміру стека батьківського потоку.

3- Й параметр. Покажчик на потокових функцію, з виклику якої починається виконання потоку.

4- й параметр. Параметр для потокової функції.

5- й параметр. Прапор, який визначає стан потоку. Якщо прапор дорівнює 0, то виконання потоку починається негайно. Якщо значення прапора потоку CREATESUSPENDED — (4Н), то потік знаходиться в стан очікування і запускається при виконання функції ResumeThread. .

6- й параметр. Покажчик на змінну, куди буде поміщений дескриптор потоку.

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

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

Часто трапляється, що дані неможливо отримувати періодично. Вони можуть, наприклад, залежатиме від діяльності третього процесу. Як же другий процес дізнається, що дані вже готові для передачі? На перший погляд проблема вирішується введенням додаткової змінної, назвемо її Flag. Приймемо, що при Flag = 0 дані не готові, а при Flag — 1 дані готові. Далі діє дуже проста схема.

 

NO_DAT:

CMP FLAG, 1 JNE NO_DAT ... ; передача даних

MOV FLAG, 0

 

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

А що буде, якщо процес передачі даних повинен здійснюватися багаторазово. Легко передбачити, що дана схема буде працювати і в більш складному випадку. Важливо, щоб другий процес міняв вміст Flag тільки після того, як він візьме дані, а перший процес - після того, як звільнить дані. Якщо порушити це правило, то може виникнути колізія, коли, наприклад, другий процес ще не взяв дані, а вони вже змінилися.

Такий підхід можна здійснити і в більш загальному випадку, коли два потоку (або - два процеси) повинні почергово одержувати доступ до одного ресурсу. Даний підхід припускає, що ресурс відкритий або для одного, або для іншого процесу. Якщо б поставити задачу трохи іншим чином - процес або відкрито, або закритий для доступу, то виникло б деяке ускладнення. Дійсно, імовірна така ситуація, коли обидва потоку очікують відкриття ресурсу. Іншими словами, вони безперервно здійснюють перевірку змінної Flag (CMP FLAG, 1). Може статися, що вони обидва майже одночасно звернуться до ресурсу. Цілком зрозуміло, що тут виникає необхідність в "третій силі", яка б займалася розподілом доступу до ресурсу. Наприклад, посилала б повідомлення спочатку одному потоку і, якщо він очікує доступу, давала доступ саме йому, а потім подібний процес повторюється з другим потоком.

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

 

 

22. Семафори блять! Події нахуй!

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

CreateSemaphore - створює глобальний об'єкт-семафор. Повертає дескриптор семафор.

Параметри функції:

1- й параметр. Покажчик на структуру, яка визначає атрибути доступу. Може мати значення для Windows NT. Зазвичай цей параметр вважається рівним NULL.

2- й параметр. Початкове значення лічильника семафор. Визначає, скільки завдань мають доступ до ресурсу спочатку.

3- й параметр. Кількість завдань, які мають одночасний доступ до ресурсу.

4- й параметр. Покажчик на рядок, що містить ім'я семафор.

OpenSemaphore - відкрити вже створений семафор. Повертає дескриптор семафор. Цю функцію використовують не так часто. Зазвичай створюють семафор і присвоюють його дескриптор глобальної змінної, а потім використовують цей дескриптор в породжуванні потоків.

Параметри функції:

1- й параметр. Визначає бажаний рівень доступу до семафору. Можливі значення: SEMAPHORE_MODIFY_STATE =2Н, дозволити використовувати функцію ReleaseSemaphore,

Synchronize = 100000Н, дозволити використання будь-якої функції очікування, тільки для Windows NT,

SEMAPHORE_ALL_ACCESS = OFOOOOh + Synchronize + ЗН, специфікує всі можливі прапори доступу до семафору.

2- й параметр. Вказує, чи можо наслідувати дескриптор семафору, створюваний функцією CreateProcess; 0 - не може.

3- й параметр. Покажчик на ASCII Z-рядок, що містить ім'я семафор.

WaitForSingleObject - очікувати відкриття семафору. При успішному завершенні, тобто відкриття доступу до об'єкта, функція повертає 0.

Параметри функції:

1- й параметр. Дескриптор семафор.

2- й параметр. Час очікування в мілісекунд.

Якщо параметр дорівнює Infinite = OFFFFFFFFh, то час очікування не обмежено.

ReleaseSemaphore - звільнити семафор і дозволити отримати доступ до ресурсу іншим процесам.

Параметри функції:

1- й параметр. Дескриптор семафор.

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

3- й параметр. Покажчик на змінну, куди має бути поміщено попереднє значення лічильника.

Розглянемо алгоритм роботи з семафором.

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

3а допомогою Семафору можна регулювати кількість потоків, які одночасно можуть мати доступ до ресурсу.

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

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

Розглянемо функції для роботи з подіями.

CreateEvent - створює об’єкт -подія параметри функції.

1-й параметр Має той же зміст, що й перший параметр функції CreateSemaphore. Зазвичай покладається рівним NULL.

2-й параметр якщо параметр не дорівнює нулю то, то подія може бути скинута за допомогою функції ResetEvent. Інакше подія скидається при доступі до нього будь-якого процесу.

3-й параметр якщо параметр дорівнює 0, то подія ініціалізується як скинута в іншому випадку відразу ж подається сигнал про настання відповідної ситуації

4-й параметр. Покажчик на рядок, що містить ім'я події.

Очікування події здійснюється, як і у випадку з семафору, функцією WaitForSingleObject.

Функція OpenEvent аналогічна функції OpenSemaphore.

SetEvent - подати сигнал про настання події.

Параметри функції.

1-й параметр. Дескриптор події.

 

 

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

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

Розглянемо функції для роботи з критичною секцією.

InitializeCriticalSection - дана функція створює об'єкт під назвою критична секція

Параметри функції

1-й параметр. Покажчик на структуру. Поля даної структури викорисговуються

тільки внутрішніми процедурами сенс довільний.

CRITICAL_SECTION STRUCT

DebugInfo DWORD?

LockCount LONG?

RecursionCount LONG?

OwningThread HANDLE?

LockSemaphore HANDLE?

SpinCount DWORD?

CRITICAL_SECTION ENDS

 

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

 

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

DeleteCriticalSection –видалити об’єкт «критична секція». Параметр аналогічний попереднім.

 

 

 

© 2013 wikipage.com.ua - Дякуємо за посилання на wikipage.com.ua | Контакти