Операционные системы. Методические указания к курсовому проектированию. К 84 Операционные системы: методические указания к курсовому проектированию / А.Ю. Кручинин.


Чтобы посмотреть этот PDF файл с форматированием и разметкой, скачайте его и откройте на своем компьютере.
М
ИНИСТЕРСТВО

ОБРАЗОВАНИЯ И НАУКИ

Р
ОССИЙСКОЙ

Ф
ЕДЕРАЦИИ

Ф
ЕДЕРАЛЬНОЕ

АГЕНТСТВО ПО ОБРАЗОВ
АНИЮ


Государственное образовательное учреждение

высшего профессионального о
б
разования

«
Оренбургский государственный ун
и
верситет»


Кафедра вычислительной те
х
ники





А.
Ю. К
РУЧИНИН







ОПЕРАЦИОННЫЕ СИ
С
ТЕМЫ



М
ЕТОДИЧЕСКИЕ

УКАЗАНИЯ


К

КУРСОВОМУ ПРОЕКТИРОВ
АНИЮ







Рекомендовано к изданию Редакционно
-
издательским сов
е
том

государственного образовательного учреждения

высшего профессионального образов
а
ния

«
Оренбургский го
сударс
т
венный университет
»










Оренбург 200
9


2

УДК
004(07)

ББК
32.81
я
7


К

84



Рецензе
н
т

к
андидат
т
ехнических наук

А.Л. Коннов



Кручинин А.Ю.

К

84

Операционные системы: методические указания к
курсовому
проектированию

/
А.Ю. Кручинин
.



Оре
н
бур
г, ГОУ ОГУ, 2009
.


59
с.






Методические указания предназначены для
выполнения курсового
проектирования

по общепрофессиональной дисциплине «Операционные
системы» для студе
н
тов специальности

230101 «Вычислительные машины,
комплексы, системы и сети».




























УДК
004(07)


ББК 32.81я7














©

А.Ю. Кручинин, 2009


©

ГОУ ОГУ, 2009


3


Соде
р
жание


Введение…………………………………………………………………………………...4

1 Э
тапы проектирования
………………………………………………………



…4

2 Задание на курсовое проектирование
……………………
…………………………

4

3 Теоретические сведения для выполнения задания
………………………
…………
...6

4 Методические указания к выполнению этапов проекта
……………………
………
10

4.1 Ознакомление со средой программирования Visual
C
++ 6.0.
Разработка


оконного пр
и
ложения Win32API
………………
…………………………………..10

4.2 Динамическое создание пунктов меню и создание формы окна средствами


Win32API

………………………………………………………………………….21

4.3 Получение сведений о компьютере в операционной среде Windows

программн
ы
ми средствами……………………………………………………………...27

4.4
Взаимодействие приложения с
System

Tray
………………………………………32

4.5 Создание и управление процессами……………………………………………….36

4.6 Обмен информацией между процессами………………………………………….42

4.7 Управление потоками и работа с файлами средствами Win32API……………...48

4.8 С
инхронизация процессов и потоков……………………………………………...51

4.9 Управление памятью………………………………………………………………..53

4.10 Дочерние окна и управление «чужим» приложением…………………………..56

4.11 Решение задачи производителя и потребителя………………………………….59

Список использованны
х источников
…………………………………………………..59





4

Введение


Выполнение курсового проектирования
по дисциплине
«
Операционные
си
с
те
мы» и
меет целью закрепить теоретические знания, полученные в процессе

изуч
е
ния лекционного курса и выполнения лабораторного практикума, а

также
привить навыки самостоятельной

раб
о
ты.


1

Э
тапы проектирования


В процессе проектирования выполняются следующие этапы:

1

Ознакомление со средой программирования Visual
C
++ 6.0.
Разработка
оконного пр
и
ложения Win32API.

2

Динамическое создание пунктов

меню и создание формы окна
средствами Win32API.

3

Получение сведений о компьютере в операционной среде Windows
программн
ы
ми средствами.

4

Взаимодействие приложения с
System

Tray
.

5

Создание и управление процессами.

6

Обмен информацией между процессами.

7

Управление потоками и работа с файлами средствами Win32API.

8

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

9

Управление памятью.

10

Дочерние окна и управление «чужим» приложением.

11

Решение задачи производителя и потребителя.

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

оформляется пояснительная
запи
с
ка объемом 25

40 страниц текста с необходимыми для изложения

графическими м
а
тери
а
лами.

Записка должна быть оформлена в соответствии с
требованиями

СТП 101
-
00

на листах формата
А4
на

одной стороне листа.


2 Задание на курсово
е проектирование


Написать комплекс программ, решающих проблему производителя и
потреб
и
теля с использованием семафоров. Имеется

N

производителей и

M

потребителей. Каждый оформлен в виде отдельного процесса. Данные процессы
работают в фон
о
вом режиме и их мо
жно наблюдать только в диспетчере задач. Так
же имеется м
е
неджер этих процессов, который:

1)

работает свернутым в системный трей;

2)

отображает процессы производителей и потребителей;

3)

имеет
пункт меню

запуска работы модели и остановки;

4)

показывает состояние буфер
а в текущий момент времени;

5)

запускает все процессы производителей и потребителей при старте менедж
е
ра;

6)

удаляет все процессы производителей и потребителей при закрытии менедж
е
ра;


5

7)

ведет счет и показывает на экране, кто сколько записал и кто сколько проч
и
тал,

взаимодействие между процессами осуществляется путем передачи с
о
общения
WM
_
COPYDATA
.

В качестве буфера используется
текстовый файл
, доступ к которому
регулируется семафорами. Скорость записи и чтения данных из буфера для
различных производителей и потреби
телей разная и задается путем п
е
редачи
параметров создаваемому процессу. В результате курсового проектирования должно
получиться 3
exe
-
файла:

Menedger
.
exe
,

Proizv
.
exe
,

Potreb
.
exe
.

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

секунд, для вт
о
рого


через 2
K
, для третьего


через 3
K

и т.д. Для потребителей:
L

секунд, 2
L
, 3
L

и т.д. Варианты задан
ий для студентов перечислены в таблице 1.


Таблица

1



Варианты заданий

№ вар
и
анта

Условия з
а
дания

Буква

1

N
=4,
M
=4,
K
=1,
L
=0.7

А

2

N
=5,
M
=3,
K
=0.8,
L
=1

Б

3

N
=3,
M
=5,
K
=1,
L
=1.2

В

4

N
=3,
M
=2,
K
=1
, L=0.4

Г

5

N=6, M=2, K=2, L=1

Д

6

N=3, M=3, K=1, L=1

Е

7

N=4, M=7, K=1.5, L=2

Ж

8

N=1, M=6, K=0.5, L=1

З

9

N=1, M=5, K=1, L=1.3

И

10

N=6, M=1, K=1.6, L=1.4

К

11

N=7, M=2, K=1, L=0.7

Л

12

N=2, M=5, K=0.3, L=0.9

М

13

N=3, M=3, K=1.2, L=1.7

Н

14

N=7, M=2, K=2, L=0.5

О

15

N=8, M=6, K=0.3, L=0.4

П

16

N=4
, M=7, K=0.4, L=0.4

Р

17

N=2, M=5, K=0.7, L=0.9

С

18

N=6, M=3, K=1, L=1.1

Т


6

Продолжение таблицы 1

19

N=4, M=8, K=1.1, L=1.7

У

20

N=1, M=9, K=0.2, L=0.7

Ф

21

N=9, M=1, K=2, L=0.5

Х

22

N=5, M=4, K=1, L=1

Ц

23

N=6, M=6, K=1.2, L=1.5

Ч

24

N=6, M=3, K=0
.8, L=0.9

Ш

25

N=3, M=5, K=1.2, L=1.4

Щ

26

N=2, M=5, K=1, L=1.7

Э

27

N=5, M=3, K=0.8, L=0.4

Ю

28

N=6, M=2, K=1, L=1.2

Я


Перед выполнением курсового проекта студент уточняет номер выполняемого
им варианта


ключом к выбору задания является начальная б
уква фамилии.
Напр
и
мер: студент Сидоров для выполнения курсового проекта в
ы
бирает 17 номер.


3 Теоретические сведения для выполнения задания


Рассмотрим некоторые примитивы межпроцессного взаимодействия,
прим
е
няющиеся вместо циклов ожидания, в которых лишь

напрасно расходуется
проце
с
сорное время. Эти примитивы блокируют процессы в случае запрета на вход
в кр
и
тическую область. Одной из простейших является пара примитивов
sleep

и
wakeup
. Примитив
sleep



системный запрос, в результате которого вызывающий
проц
есс блокируется, пока его не запустит другой процесс. У запроса
wakeup

есть
один п
а
раметр


процесс, который следует запустить. Также возможно наличие
одного п
а
раметра у обоих запросов


адреса ячейки памяти, используемой для
согласования запросов ожидания

и запуска.

Два процесса совместно используют буфер ограниченного размера. Один из
них, производитель, помещает данные в буфер, а потребитель считывает их оттуда.
Трудности начинаются в тот момент, когда производитель хочет поместить в буфер
очередную порц
ию данных и обнаруживает, что буфер полон. Для производителя
решением является ожидание, пока потребитель полностью или частично не очистит
буфер. Аналогично, если потребитель хочет забрать данные из буфера, а буфер пуст,
потребитель уходит в состояние ожи
дания и выходит из него, как только
произв
о
дитель положит что
-
нибудь в буфер и разбудит его.

Это решение кажется достаточно простым, но оно приводит к состояниям
с
о
стязания. Нам нужна переменная

count

для о
т
слеживания количества элементов в
буфере. Если ма
ксимальное число элементов, хранящихся в буфере, равно
N
,
пр
о
грамма производителя должна проверить, не равно ли
N

значение
count

прежде,
чем поместить в буфер следующую порцию данных. Если значение
count

равно
N
,
то производитель уходит в состояние ожидани
я; в противном случае производитель

7

помещает данные в буфер и увеличивает знач
е
ние
count
.

Код программы потребителя прост: сначала проверить, не равно ли значение
count

нулю. Если равно, то уйти в состояние ожидания; иначе забрать порцию
да
н
ных из буфера и

уменьшить значение
count
. Каждый из процессов также должен
проверять, не следует ли активизировать другой процесс, и в случае необходимости
проделывать это. Программы обоих процессов представлены в листинге
1
.


#
define

N

100

int

count

= 0;


void producer(
)

{

int item;

while (TRUE) {

item
=
produce
_
item
();


//
сформировать

следующий

элемент

if

(
count
==
N
)
sleep
();

//буфер полон


состояние ожидания

insert
_
item
(
item
);


//поместить элемент в буфер

count++;

if (count==1) wakeup(consumer);

}

}


void consumer()

{

i
nt item;

while (TRUE) {


if

(
count
==0)
sleep
();


//
буфер

пуст



состояние

ожидания


item
=
remove
_
item
(
item
);

//забрать элемент из буфера


count
--
;


if (count==N
-
1) wakeup(producer);

}

}

Листинг 1



Проблема производителя и потребителя с неустранимым
состоя
н
и
ем соревнования


Для описания на языке С системных вызовов
sleep

и
wakeup

мы представили
их в виде вызовов библиотечных процедур. В стандартной библиотеке С их нет, но
они будут доступны в любой системе, в которой присутствуют такие системные
в
ы
зовы. Про
цедуры
insert_item

и
remove_item

помещают элементы в буфер и
извлек
а
ют их оттуда.

В
озникновение
состояния состязания
возможно, поскольку доступ к
переме
н
ной
count

не ограничен. Может возникнуть следующая ситуация: буфер
пуст, и п
о
треб
и
тель только что счита
л значение переменной
count
, чтобы
проверить, не равно ли оно нулю. В этот момент планировщик передал управление
производителю, пр
о
изводитель поместил элемент в буфер и увеличил значение
count
, проверив, что т
е
перь оно стало равно 1. Зная, что перед этим о
но было равно
0 и потребитель нах
о
дился в состоянии ожидания, производитель акт
и
визирует его с
помощью вызова
wakeup
.


8

Но потребитель не был в состоянии ожидания, так что сигнал активизации
пропал впустую. Когда управление перейдет к потребителю, он вернетс
я к
счита
н
ному когда
-
то значению
count
, обнаружит, что оно равно 0, и уйдет в
состояние ожидания. Рано или поздно производитель наполнит буфер и также уйдет
в состо
я
ние ожидания. Оба процесса так и останутся в этом состоянии.

С
уть проблемы в данном случае
состоит в том, что сигнал активизации,
пр
и
шедший к процессу, не находящемуся в состоянии ожидания, пропадает. Если
бы не это, проблемы бы не было. Быстрым решением может быть добавление бита
ожид
а
ния активизации. Если сигнал активизации послан процессу, не

находящемуся
в с
о
стоянии ожидания, этот бит устанавливается. Позже, когда процесс пытается
уйти в состояние ожидания, бит ожидания активизации сбрасывается, но процесс
остается активным. Этот бит исполняет роль копилки сигналов активизации.

Несмотря на то

что введение бита ожидания запуска спасло положение в этом
примере, легко сконструировать ситуацию с несколькими процессами, в которой
одного бита будет недостаточно. Мы можем добавить еще один бит, или 8, или 32,
но это не решит проблему.

В 1965 году Дей
кстра (Е.
W
.
Dijkstra
) предложил использовать целую
пер
е
менную для подсчета сигналов запу
ска, сохраненных на будущее
. Им был
предложен новый тип переменных, так называемые семафоры, значение которых
может быть нулем (в случае отсутствия сохраненных сигнало
в активизации) или
н
е
которым положительным числом, соответствующим количеству отложенных
акт
и
визирующих сигналов.

Дейкстра предложил две операции,
down

и
up

(обобщения
sleep

и
wakeup
).
Операция
down

сравнивает значение семафора с нулем. Если значение семаф
ора
больше нуля, операция
down

уменьшает его (то есть расходует один из сохраненных
сигналов активации) и просто возвращает управление. Если значение семафора
ра
в
но нулю, процедура
down

не возвращает управление процессу, а процесс
переводи
т
ся в состояние о
жидания. Все операции проверки значения семафора, его
изменения и перевода процесса в состояние ожидания выполняются как единое и
неделимое элементарное действие. Тем самым гарантируется, что после начала
операции ни один процесс не получит доступа к семаф
ору до окончания или
блокирования оп
е
рации. Элементарность операции чрезвычайно важна для
разрешения проблемы синхронизации и предотвращения состояния состязания.

Операция
up

увеличивает значение семафора. Если с этим семафором связаны
один или несколько о
жидающих процессов, которые не могут завершить более
ра
н
нюю операцию
down
, один из них выбирается системой (например, случайным
о
б
разом) и ему разрешается завершить свою операцию
down
. Таким образом, после
операции
up
, примененной к семафору, связанному с
несколькими ожидающими
процессами, значение семафора так и останется равным 0, но число ожидающих
процессов уменьшится на единицу. Операция увеличения значения семафора и
а
к
тивизации процесса тоже неделима. Ни один процесс не может быть блокирован
во время

выполнения операции
up
, как ни один процесс не мог быть блокирован во
время выполнения операции
wakeup

в предыдущей модели.

В оригинале Дейкстра использовал вместо
down

и
up

обозначения Р и V
соо
т
ветственно. Мы не будем в дальнейшем использовать оригиналь
ные

9

обозначения, поскольку тем, кто не знает датского языка, эти обозначения ничего не
говорят (да и тем, кто знает язык, говорят немного). Впервые обозначения down и up
появились в языке Algol 68.

Как показано в листинге 2
, проблему потерянных сигналов за
пуска можно
р
е
шить с помощью семафоров. Очень важно, чтобы они были реализованы
недел
и
мым образом. Стандартным способом является реализация операций down и
up в виде системных запросов, с запретом операционной системой всех прерываний
на период проверки се
мафора, изменения его значения и возможного перевода
процесса в с
о
стояние ожидания. Поскольку для выполнения всех этих действий
требуется всего лишь несколько команд процессора, запрет прерываний не приносит
никакого вр
е
да. Если используются несколько проц
ессоров, каждый семафор
необходимо защ
и
тить переменной блокировки с использованием команды TSL,
чтобы гарантир
о
вать одновременное обращение к семафору только одного
процессора. Необходимо п
о
нимать, что использование команды TSL
принципиально отличается от
активного ожидания, при котором производитель или
потребитель ждут наполнения или опу
с
тошения буфера. Операция с семафором
займет несколько микросекунд, тогда как активное ожидание может затянуться на
существенно больший промежуток врем
е
ни.


#define N 100


/* количество сегментов в буфере */

typedef int semaphore;

/* семафоры
-

особый вид целочисленных переменных */

semaphore mutex = 1;

/* контроль доступа в критическую область */

semaphore empty = N;

/* число п
устых сегментов буфера */

semaphore full = 0;

/* число полных сегментов буфера */

void producer(void)

{


int item;


while (TRUE) {

/* TRUE
-

константа, равная 1*/


item = produce_item();

/* создать данные, помещае
мые в буфер */


down(&empty);

/* уменьшить счетчик пустых сегментов буфера */


down(&mutex);

/* вход в критическую область */


insert_item(item);

/* поместить в буфер новый элемент */


up(&mutex);


/* выход из критической области */


up(&full);

/* увеличить счетчик полных сегментов буфера */


}

}

void consumer(void)

{


int item;


while

(
TRUE
) {

/*
бесконечный

цикл

*/


down
(&
full
);

/*
уменьшить

числа

полных

сегментов

буфера

*/


down
(&
mutex
);

/* вход в критическую область */


item

=
remove
_
item
();

/* удалить элемент из буфера */


up(&mutex);

/* выход из критической области */


up(&em
pty);

/* увеличить счетчик пустых сегментов буфера */


consume_item(item);

/*
обработка

элемента

*/


}

}

Листинг
2



Проблема п
роизводителя и потребителя с с
емафорами


10


В представленном решении используются три семафора: один для п
одсчета
заполненных сегментов буфера (
full
), другой для подсчета пустых сегментов
(
empty
), а третий предназначен для исключения одновременного доступа к буферу
производителя и потребителя (
mutex
). Значение счетчика
full

исходно равно нулю,
счетчик
empty

ра
вен числу сегментов в буфере, a
mutex

равен 1. Семафоры,
исхо
д
ное значение которых равно 1, используемые для исключения одновременного
н
а
хождения в критической области двух процессов, называются двоичными
семаф
о
рами. Взаимное исключение обеспечивается, есл
и каждый процесс
выполняет оп
е
рацию
down

перед входом в критическую область и
up

после выхода
из нее.


4 Методические указания к выполнению этапов проекта


4.1
Ознакомление со средой программирования Visual
C
++ 6.0.
Разработка оконного пр
и
ложения Win32API


Среда программирования Visual C++ 6.0

была разработана в 1998 году.
Одн
а
ко до сих пор ею пользуются многие разработчики консольных и написанных
на чистом Win32

API приложениях, так как она
облает отличным компилятором,
нетребовательна к компьютерам (мо
ж
но

работать даже на

Pentium

I), занимает мало
места и может работать без установки на компьютер


путѐм простого копирования.
Внешн
ий вид среды представлен на рисунке

1.


Рисунок 1


Среда программирования Visual C++ 6.0


11

Перед тем, как начать программироват
ь
,
необходимо

проверить состояние
настр
о
ек среды, которые находятся в Tools→
Options

Directories

(Рис
унок

2).



Рисунок

2



Окно настроек директорий


Пути до include и
library

файлов должны соответствовать их действительному
место
нахождению
.
Сюда же вы мож
ете добавлять и свои пути.

Для создания нового проекта выберете File→
New
, в р
е
з
у
льтате
у вас появится
окно (Рисунок

3).



Рисунок

3



Окно создания нового проекта


12

Выберете из списка пункт «Win32 Application», в графу «
Project

Name
»

внес
и
те название проект
а и выб
ерите путь до него в графе «
Location
», после этого
нажм
и
те «OK» и у вас появится следующее окно (Рис
унок

4).



Рисунок 4


Окно Шага 1 создания проекта


Нажмите «
Finish
», и у вас создастся пустой проект.

Теперь можно добавлять
файлы в проект. Выбер
ите
Project

Add to Project

New


появится

окно (Рис. 5).

Выберите «C++ Source File»

и наберите в графе
«
File

name
»

имя файла:
main
.

Затем нажмите «
OK
»


у вас добавился файл main.cpp. Аналогичным образом
д
о
бавьте «C/C++ Header File»


у вас появится

файл m
ain.h.

Для создания вашего первого приложения на Win32API заполните эти файлы
следующим ниже содержимым.


#ifndef _MAIN_

#define _MAIN_ 1


#include win; ows;&#x.h00;windows.h


HINSTANCE hInst;


//
функция

обработки

сообщений

LRESULT CALLBACK WIN32PROC(HWND hWnd,UINT Messa
ge,UINT wParam,LONG lParam);



#endif

Листинг

3


Файл

main.h



13


Рис
унок 5


Окно добавления новых файлов


#include "main.h"


//Главная функция

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,


LPSTR lpszCmdParam,int nCmd
Show)

{


hInst=hInstance;



WNDCLASS WndClass;


MSG Msg;


char ClassName[]="MYPROJECT";


HWND hWnd;



WndClass.style=CS_HREDRAW | CS_VREDRAW;


WndClass.lpfnWndProc=WIN32PROC;


WndClass.cbClsExtra=0;


WndClass.cbWndExtra=0;


WndClass.hInst
ance=hInstance;


WndClass.hIcon=NULL;


WndClass.hCursor=LoadCursor(NULL,IDC_ARROW);


WndClass.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);;


WndClass.lpszMenuName=NULL;


WndClass.lpszClassName=ClassName;



if (!RegisterClass(&WndCla
ss))


{



MessageBox(NULL,"Cannot register class","Error",MB_OK | MB_ICONERROR);



return 0;


14


}





hWnd=CreateWindowEx(0, ClassName,"Моя первая программа",


WS_OVERLAPPEDWINDOW,


CW_USEDEFAULT,CW_USEDEFAULT,



CW_USEDEFAULT,CW_USEDEFAULT,


NULL,NULL,hInstance,NULL);



if (hWnd==NULL)


{





MessageBox(NULL,"Cannot create window","Error",MB_OK | MB_ICONERROR);



return 0;


}




ShowWindow(hWnd,nCmdShow);


UpdateWindo
w(hWnd);



MSG msg;



while (1) {


while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) == TRUE)


{


if (GetMessage(&msg, NULL, 0, 0) )


{


TranslateMessage(&msg);


DispatchMessage(&m
sg);


} else {


return TRUE;


}


}




}




return

Msg
.
wParam
;


}


//функция обработки сообщений

LRESULT CALLBACK WIN32PROC(HWND hWnd,UINT Message,


UINT wParam,LONG lParam)

{


switch(Message)


{


case WM_DESTROY:





PostQuitMessage(0);



break;


}



return DefWindowProc(hWnd,Message,wParam,lParam);

}

Листинг
4



Файл main.
cpp


15

Сохраните всѐ и откомпилируйте, используя
F
7 или через пункт меню
«Build»
.

После запуска у вас д
олжно появиться чѐрное окно. Ваша первая программа на
Win32

API

готова.

Кратко опишем то, что происходит внутри функции
WinMain
. Первоначально
заполняется
структура

окна
WNDCLASS
, в которой
устанавливаются

основные
свойства окна. После этого с помощью фун
кции
RegisterClass
ваш класс
регистр
и
руется в Windows. Как вы заметили, у вашей программы отсутствует
иконка, чтобы добавить еѐ необходимо воспользоваться редактором ресурсов. Для
этого выберите
Project

Add

to

Project

New
, а там выберите

«
Resource

Script
»
и в
графе «
File

name
»


res
.
У вас должно создаться два файл:
res
.
rc

и
resource
.
h
. Ниже
списка фа
й
лов в пр
о
екте у вас должна появиться закладка «
Resource

View
».
Переключитесь на закладку и, щѐлкнув правой кнопкой на «
res

resources
», выбе
рите
«Insert»


поя
вится о
к
но (Рисунок
6).



Рисунок 6


Окно добавления ресурсов


Выберите «Icon»

и нажмите

«
New
». Отредактируйте и сохраните иконку.
Т
е
перь можно подключать еѐ к программе. Сначала подключите к проекту файл
r
e
source
.
h

с помощью
Pr
o
ject

Add

to

Project
→File
s. Добавьте в основную
программу строку:
#include "resource.h"

(ниже строки
#include "
main.h"
). Замените
строку в со
з
дании класса

WndClass
.
hIcon
=
NULL
;

на

WndClass
.
hIcon
=
LoadIcon
(
hInstance
,
MAKEINTRESOURCE
(
IDI
_
ICON
1));

Здесь
IDI_ICON1

указывает на вашу икон
ку. Компилируйте проект


иконка
присоединена. Описание остальных элементов структуры приведено ниже.


Структура

WNDCLASS.


typedef struct tagWNDCLASS

{

UINT style;

WNDPROC lpfnWndProc;

int cbClsExtra;


16

int cbWndExtra;

HINSTANCE hInstance;

HICON hIcon;

HC
URSOR hCursor;

HBRUSH hbrBackground;

LPCSTR lpszMenuName;

LPCSTR lpszClassName;

} WNDCLASS;


style



определяет

стиль

класса
.
Стили можно объединять
,

используя |. Вот какие
они бывают:

CS_BYTEALIG
NCLIENT


(по горизонтали) выравнивание рабочей области окн
а по
границе байта. Влияет на ширину окна и его горизонтально
е положение на экране;

CS_BYTEALIGNWINDOW


(по вертикали) выравниает
ся

окна по границе ба
й
та;


CS_CLASSDC


контекст устройства, который будет разделяться всеми окн
а
ми
класса. При нескольких пот
оках операционная система разрешит доступ только
о
д
ному потоку
;

CS_DBLCLKS


посылать сообщение от мыши при двойном щелчке в пред
е
лах
класса окна;

CS_GLOBALCLASS


Создавать глобальный класс, который можно поместить в
д
и
намическую библиотеку DLL;

CS_HREDRA
W


перерисовывать

всѐ окно при изменении ширины;

CS_NOCLOSE


отключить команду
«
Закрыть
»;

CS_OWNDC


у каждого окна
уникальный контекст устройства;

CS_PARENTDC


у

дочернего окна будет область отсечки от родительского.
Пов
ы
шает производительность;

CS_SAV
EBITS


п
озволяет сохранять область экрана в виде битовой матрицы
з
а
крытую в данный момент другим окном, использу
ется для восстановления экрана;

CS_VREDRAW


перерисовывать окно при изменении вертикальных размеров
.


WNDPROC



указатель на процедуру окна вы
зываемую функцией
CallWindowProc
.

cbClsExtra



объем памяти в
ыделяемый за структурой класса.

cbWndExtra



объем дополнительной памяти за экземпляром окна.

hInstance



дескриптор экземпляра.

hIcon



дескриптор и
коны окна
.


hCursor



дескриптор курсора о
кна.

hbrBackground



дескриптор для закраски фона.

lpszMenuName



имя меню в р
е
сурсах
.


lpszClassName



имя класса.


После регистрации класса окна вызывается функция
CreateWindowEx
,
пре
д
назначенная для создания окна.


Функция
CreateWindowEx


HWND CreateW
indowEx


17

(

DWORD dwExStyle,



// улучшенный стиль окна

LPCTSTR lpClassName,


// указатель на зарегистрированное имя класса

LPCTSTR lpWindowName,


// указатель на имя окна

DWORD dwStyle,



// стиль окна

int x,





// горизонтальная позиция окна

int y,





//

вертикальная позиция окна

int nWidth,




// ширина окна

int nHeight,




// высота окна

HWND hWndParent,



// дескриптор родительского или окна







// собственника

HMENU hMenu,



// дескриптор меню или идентификатор







// дочернего окна

HINSTANCE hIns
tance,


// дескриптор экземпляра прикладной







// программы


LPVOID lpParam



// указатель на данные создания окна

);

Параметры:

dwExStyle



о
пределяет расширенный стиль окна. Этот параметр может быть одно
из сл
е
дующих значений:

WS_EX_ACCEPTFILES


Оп
ределяет, что окно, созданное с этим стилем пр
и
нимает
файлы при по
мощи информационной технологии «перетащи и вставь»
.

WS_EX_APPWINDOW


Активизирует окно верхнего уровня на панель задач, когда
окно свернуто.

WS_EX_CLIENTEDGE


Определяет, что окно имеет
рамку с углубленным краем.

WS_EX_CONTEXTHELP


Включает вопросительный знак в строку заголовка окна.
Когда пользователь щелкает мышью по вопросительному знаку, курсор мен
я
ется на
вопросительный знак с указателем. Если пользователь затем щелкает мышью по
д
о
чернему окну, потомок принимает сообщение WM_HELP. Дочернее окно должно
передать сообщение родительской оконной процедуре, которая должна в
ы
зваться
функцией
WinHelp
, использующей команду HELP_WM_HELP. Прикладная
пр
о
грамма Справки показывает выскакивающее
окно, которое обычно содержит
спра
в
ку для дочернего окна. WS_EX_CONTEXTHELP не может использоваться со
ст
и
лями WS_MAXIMIZEBOX или WS_MINIMIZEBOX.

WS_EX_CONTROLPARENT


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

WS_EX_DLGMODALFRAME


Создает окно, которое имеет двойную рамку; окно
может быть создано (необязательно) со строкой заголовка, которую определяет
стиль WS_CAPTION в параметре dwStyle.

WS_EX_LEFT


Окно имее
т общеупотребительные свойс
тва «
выравнивания по
л
е
вой границе»
. Это


по умолчанию.

WS_EX_LEFTSCROLLBAR


Если язык оболочки Еврейский, Арабский или другой
язык, который придерживается иного порядка чтения, вертикальная линейка
пр
о
крутки (если появляется)


слева от рабочей области
. Для других языков, этот
стиль игнорируется и не обрабатывается как ошибка.

WS_EX_LTRREADING


Текст окна отображается, используя свойство поря
д
ка
чтения
«
Слева


Направо
»
. Это


по умолчанию.


18

WS_EX_MDICHILD


Создает MDI дочернее окно.

WS_EX_NOPARENTN
OTIFY


Определяет, что дочернее окно, созданное с этим
стилем не посылает сообщение WM_PARENTNOTIFY родительскому окну, когда
оно создается или разрушается.

WS_EX_OVERLAPPEDWINDOW


Объединяет

стили

WS_EX_CLIENTEDGE
и

WS_EX_WINDOWEDGE.

WS_EX_PALETTEWIND
OW


Объединяет

стили

WS_EX_WINDOWEDGE,
WS_EX_TOOLWINDOW
и

WS_EX_TOPMOST.

WS_EX_RIGHT


Окно имеет общеупотребительные свойства
«
выравнивание по
пра
вому краю»
. Оно зависит от класса окна. Этот стиль имеет эффект только тогда,
е
с
ли язык оболочек Еврейский,

Арабский или другой язык, который поддерживает
иной порядок выравнивания для чтения; иначе, стиль игнорируется и не
обрабат
ы
вается как ошибка.

WS_EX_RIGHTSCROLLBAR


Вертикальная линейка прокрутки (если поя
в
ляется)


справа от рабочей области. Это
-

по у
молчанию.

WS_EX_RTLREADING


Если язык оболочки Еврейский, Арабский или др
у
гой
язык, который придерживается иного порядка выравнивания для чтения, текст в
о
к
не отображается, используя свойства поряд
ка чтения «Справа


Налево
»
. Для
др
у
гих языков, стиль игн
орируется и не обрабатывается как ошибка.

WS_EX_STATICEDGE


Создает окно с трехмерным стилем рамки, предпол
а
гается
использовать для элементов, которые не принимают вводимую информацию от
пользователя.

WS_EX_TOOLWINDOW


Создает окно инструментальных сре
дств; то есть окно
предполагается использовать как плавающую инструментальную панель. Окно
и
н
струментальных средств имеет строку заголовка, которая является короче, чем
но
р
мальная строка заголовка, а заголовок окна выводится, с использованием
мен
ь
шего шриф
та. Окно инструментальных средств не появляется в панели задач
или в диал
о
говом окне, которое появляется, когда пользователь нажимает
ALT+TAB.

WS_EX_TOPMOST


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

WS_EX_TRANSPARENT


Определяет, что окно, созданное с этим стилем должно
быть прозрачным. То есть любые окна, ко
торые появляются из
-
под окна, не
затен
я
ются им. Окно, созданное с этим стилем принимает WM_PAINT сообщения
только после того, как все сестринские окна под ним модифицировались.

WS_EX_WINDOWEDGE


Определяет, что окно имеет рамку с выпуклым краем.

Использ
ование стиля WS_EX_RIGHT для статического или редактируемого
элементов управления имеет тот же самый эффект как и использование стиля
SS_RIGHT или ES_RIGHT, соответственно. Использование этого стиля с
коман
д
ными кнопками имеет тот же самый эффект как и исп
ользование стилей
BS_RIGHT и BS_RIGHTBUTTON.

lpClassName



у
казывает на строку с нулевым символом в конце или на
целочи
с
ленный атом. Если
lpClassName



атом, он должен быть глобальным

19

атомом, со
з
данным предыдущим вызовом функции
GlobalAddAtom
. Атом, 16
-
ра
зрядное зн
а
чение меньше чем 0xC000, должно быть младшим словом в
lpClassName
; старшее слово должно быть нулевое. Если
lpClassName



строка, она
определяет имя класса о
к
на. Имя класса может быть любое имя, зарегистрированное
функцией
RegisterClass

или любым

из предопределенных имен класса элементов
управления.

lpWindowName



у
казывает на строку с нулевым символом в конце, которая
опр
е
деляет имя окна.

dwStyle



о
пределяет стиль создаваемого окна.
Основные стили:

WS_BORDER


Создание окна с рамкой.

WS_CAPTI
ON


Создание окна с заголовком (невозможно использовать
одновр
е
менно со стилем WS_DLGFRAME).

WS_CHILD
,
WS_CHILDWINDOW


Создание дочернего окна (невозможно
использовать одн
о
временно со стилем WS_POPUP).

WS_CLIPCHILDREN


Исключает область, занятую дочер
ним окном, при выводе в
родительское окно.

WS_CLIPSIBLINGS


Используется совместно со стилем WS_CHILD для
обрисовки

в дочернем окне областей клипа, перекрываемых другими окнами.

WS_DISABLED


Создает окно, которое недоступно.

WS_DLGFRAME


Создает окно

с двойной рамкой, без заголовка.

WS_GROUP


Позволяет объединять элементы управления в группы.

WS_HSCROLL


Создает окно с горизонтальной полосой прокрутки.

WS_MAXIMIZE


Создает окно максимального размера.

WS_MAXIMIZEBOX


Создает окно с кнопкой разв
ертывания окна.

WS_MINIMIZE

WS_ICONIC


Создает первоначально свернутое окно (используется только со
ст
и
лем WS_OWERLAPPED).

WS_MINIMIZEBOX


Создает окно с кнопкой свертывания.

WS_OVERLAPPED


Создает перекрывающееся окно (которое, как правило, имеет
за
головок и WS_TILED рамку).

WS_OVERLAPPEDWINDOW


Создает перекрывающееся окно, имеющее стили
WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME,
WS_MINIMIZEBOX, WS_MAXIMIZEBOX.

WS_POPUP


Создает popup
-
окно (невозможно использовать совместно со стилем
WS_CHILD.

WS_POPUPWINDOW


Создает popup
-
окно, имеющее стили WS_BORDER,
WS_POPUP, WS_SYSMENU.

WS_SYSMENU


Создает окно с кнопкой системного меню (можно использовать
только с окнами имеющими строку заголовка).

WS_TABSTOP


Определяет элементы управления
, переход к которым может быть
выполнен по клавише TAB.

WS_THICKFRAME


Создает окно с рамкой, используемой для изменения размера
окна.

WS_VISIBLE


Создает первоначально неотображаемое окно.

WS_VSCROLL


Создает окно с вертикальной полосой прокрутки.


20

x



о
пределяет начальную горизонтальную позицию окна. Для перекрывающего или
выскакивающего окна параметр
x



начальная x
-
координата левого верхнего угла
окна, в экранных координатах устройства. Для дочернего окна
x



x
-
координата
л
е
вого верхнего угла окна
относительно левого верхнего угла рабочей области
род
и
тельского окна. Если
x

установлен как CW_USEDEFAULT, Windows выбирает
з
а
данную по умолчанию позицию для левого верхнего угла окна и игнорирует
y

пар
а
метр. Стиль CW_USEDEFAULT допустим только для перекры
вающих окон;
если он определен для всплывающего или дочернего окна параметры
x

и
y

устанавлив
а
ются в нуль.

y



о
пределяет начальную вертикальную позицию окна. Для перекрывающего или
выскакивающего окна, параметр
y



начальная y
-
координата левого верхнего
угла
окна, в экранных координатах устройства. Для дочернего окна,
y



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



начальная y
-
координата левого ве
рхнего угла рабочей области окна со списком относительно
л
е
вого верхнего угла рабочей области родительского окна. Если перекрывающее
окно создано в стиле WS_VISIBLE с набором битов, а параметр
x

установлен как
CW_USEDEFAULT, Windows игнорирует параметр
y
.

nWidth



о
пределяет ширину окна в единицах измерения устройства. Для
перекр
ы
вающих окон
nWidth



ширина окна в экранной системе координат или
CW_USEDEFAULT. Если
nWidth



CW_USEDEFAULT, Windows выбирает
зада
н
ную по умолчанию ширину и высоту для окна; зада
нная по умолчанию
ширина пр
о
стирается от начальных x
-
координат до правого края экрана; заданная
по умолч
а
нию высота простирается от начальной y
-
координаты до верхней части
области значка. Стиль CW_USEDEFAULT допустим только для перекрывающих
окон; если CW_
USEDEFAULT определен для выскакивающего или дочернего окна,
параметры
nWidth

и
nHeight

устанавливаются в нуль.

nHeight



о
пределяет высоту окна в единицах измерения устройства. Для
перекр
ы
вающих окон,
nHeight



высота окна в экранной системе координат. Ес
ли
параметр
nWidth

установлен как CW_USEDEFAULT, Windows игнорирует
nHeight
.

hWndParent



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

перекрывающее
о
к
но, к
о
торое разрушается, когда окно его владельца разрушено или скрыто, когда
его владелец свернут; оно всегда отображается на верхн
ей части окна его владельца.
Несмотря на то, что этот параметр должен определять правильный дескриптор, если
параметр
dwStyle

включает в себя стиль WS_CHILD, это необязательно, если
dwStyle

включ
а
ет в себя стиль WS_POPUP.

hMenu



и
дентифицирует меню или,
в зависимости от стиля окна, определяет
иде
н
тифик
а
тор дочернего окна. Для перекрывающего или выскакивающего окна,
hMenu

иде
н
тифицирует меню, которое будет использоваться окном; этот параметр
может быть значением
NULL
, если меню класса будет использовано. Д
ля доче
р
него
окна,
hMenu

определяет идентификатор дочернего окна, целочисленное знач
е
ние,
используемое элементом управления диалогового окна, что
-
бы сообщать род
и
телю

21

о событиях. Прикладная программа определяет идентификатор дочернего о
к
на; он
должно быть
уникальным для всех дочерних окон того же самого родител
ь
ского
о
к
на.

hInstance



и
дентифицирует экземпляр модуля, который будет связан с окном.

lpParam



у
казывает на значение, переданное окну через структуру
CREATESTRUCT
, в
ы
званную параметром

lParam

соо
бщения WM_CREATE. Если
прикладная программа вызвала
CreateWindow
, чтобы создать пользовательское
о
к
но многодок
у
ментной среды,
lpParam

должен указывать на структуру
CLIENTCREATESTRUCT
.

Возвращаемые значения

Если функция успешно завершила работу, возвращаем
ое значение


дескри
п
тор для созданного окна. Если функция потерпела неудачу, возвращаемое
значение


NULL
.


После успешного создания окна вызываются функции включения
отображ
е
ния окна
ShowWindow

и обновления окна
UpdateWindow
. Затем
происходит вход в цик
л обработки сообщений. Сообщения обрабатываются в
функции
WIN32PROC
, которую предварительно указали в классе окна.


Задание:

1. Ознакомиться со средой программирования Visual C++ 6.0.

2. Ра
зработать программу соз
дающую окно с иконкой средствами Win32 API.


Контрольные вопросы:

1. Каково назначение структуры
WNDCLASS?

2. Какие операции производит функция
CreateWindowEx?

3. Зачем нужен цикл по приѐму сообщений?

4. Что происходит в функции обработки сообщений?


Для самостоятельного изучения:

1. Различные спосо
бы построения циклов обработки сообщений.


4.2

Динамическое создание пунктов меню и созда
ние формы окна
средствами Win32
A
PI


Те, кто программировал на
Borland

C++

Builder

или
Delphi

знают, как легко
там создавать

меню (изменять его) и внешний вид главного
окна, перетаскивая туда
кнопки, списки и другие элементы.

Однако, средствами Win32

API это делается
немного по
-
другому.

Создать меню статически просто


это можно сделать по аналогии с
присоединением иконки к окну.
Но как вы будете менять элементы окна, д
обавлять
и удалять пункты меню?

Для этого надо знать, как работать с меню динамически.
Основные функции для с
оздания

меню перечислены ниже.


Функция

CreateMenu


22

HMENU CreateMenu (VOID);


Функция

CreateMenu

создает

меню
.
Изначально меню пустое, но оно может
быть заполнено пунктами меню, используя функции
InsertMenuItem
,
AppendMenu

и
InsertMenu
.

В случае успеха возвращается дескриптор созданного меню. В с
лучае
неудачи возвращается NULL
.


Функция AppendMenu


BOOL AppendMenu

(


HMENU

hMe
nu
,


// дескриптор меню,
которое будет изменен
о


UINT

uFlags
,



// флажки пункта меню


UINT

uIDNewItem
,


// идентификатор пункта меню или дескриптор






//
«выскакивающего»

меню






// или подменю


LPCTSTR

lpNewItem

// пункт контекстного меню

);


Функция
AppendMenu

добавляет в
конец определяемой строки меню,
«
выскакивающе
го»

меню, подменю или контекстного меню новый пункт. Вы
можете использовать эту функцию, чтобы определить содержание, внешний вид и
характеристики пункта меню.

Параметры:

hMenu



идентифицирует строку меню, «выс
какивающее»

меню, подменю или
контекстное меню, которое будет изменено.

uFlags



определяет флажки, которые управляют внешним видом и
характеристиками нового пункта меню. Этот параметр

может быть комбинация
значений
.

uIDNewItem



о
пределяет или идентификат
ор нового пункта меню или, если
параметр

uFlags

уст
ановлен в MF_POPUP, дескриптор «выскакивающего»

меню
или подменю.

lpNewItem



о
пределяет содержание нового пункта меню. Интерпретация
lpNewItem

зависит от того, включает ли параметр
uFlags

в себя флажок
MF
_BITMAP, MF_OWNERDRAW или MF_STRING, как указано ниже:

MF_BITMAP


Содержит дескриптор растрового рисунка.

MF_OWNERDRAW


Содержит 32
-
разрядное значение, предоставленное
прикладной программой, которое может быть использовано, чтобы утвердить, что
дополни
тельные данные касаются пункта меню. Значение является членом
itemData

структуры, указываемой параметром
lParam

при помощи передачи сообщения
WM_MEASURE или WM_DRAWITEM, когда создается меню, или его внешний вид
модифицируется.

MF_STRING



Содержит указат
ель на строку с символом нуля в конце.

Возвращаемые значения

Если функция завершается успешно, величина возвращаемого значения


не
ноль.

Если функция не выполняет задачу, величина возвращаемого значения


ноль.

23

Чтобы получать расширенные данные об ошибка
х, вызовите
.


Функция CreatePopupMenu


HMENU CreatePopupMenu (VOID
);


Функция
CreatePopupMenu

создает выпадающее м
еню (drop
-
down menu),
подменю (
submenu
) или меню быстрого вызова (
shortcut menu). Меню изначально
пустое. Вы можете вставить или
добавить пункты меню, используя функцию
InsertMenuItem
. Вы также можете использовать функцию
InsertMenu

для вставки
пунктов меню и функцию
AppendMenu

для добавления пунктов меню.

В случае
успеха возвращается дескриптор созданного меню. В с
лучае неудачи воз
вращается
NULL
.


Функция SetMenuItemInfo


BOOL WINAPI SetMenuItemInfo

(


HMENU hMenu,


UINT uItem,


BOOL fByPosition,


LPMENUITEMINFO lpmii

);


Функция


изменяет информацию о пункте меню.

Параметры:

hMenu



д
ескриптор меню, которое содержит
пункт меню.

uItem



и
дентификатор или позиция пункта меню, который измениться.
Предназначение этого параметра зависит от значения
fByPosition
.

fByPosition



з
начение, определяющее предназначение
uItem
. Если этот параметр


FALSE
, то
uItem



идентификатор п
ункта меню. Иначе, он
-

позиция пункта меню.

lpmii



у
казатель на структуру MENUITEMINFO, которая содержит информацию о
пункте меню и определяет, какие атрибуты пункта меню изменятся.

Возвращаемые значения

Если функция завершается успешно, величина возвращ
аемого значения


не
ноль.

Если функция не выполняет задачу, величина возвращаемого значения


ноль.
Чтобы получать расширенные данные об ошибках, используйте функцию
.


Функция SetMenu


BOOL SetMenu

(


HWND hWnd,

// дескриптор окна


HMENU hMen
u

// дескриптор меню

);



24

Функция

связывает новое меню с заданным окном.

Параметры:

hWnd



и
дентифицирует окно, с которым должно быть связано меню.

hMenu



и
дентифицирует новое меню. Если этот параметр имеет значение
NULL
,
текущее меню окна удаляетс
я.

Возвращаемые значения

Если функция завершается успешно, величина возвращаемого значения


не
ноль.

Если функция не выполняет задачу, величина возвращаемого значения


ноль.
Чтобы получать расширенные данные об ошибках, вызовите
.


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


//
Создание

меню

int i;

HMenu=CreateMenu();

if (HMenu==NULL) return 1;


//
Добавить

"File"

i=AppendMenu(HMenu,MF_POPUP,M_FILE,"File");

if (i==0) return 1;


//
Создать

подменю

"File"

HME
NU h;


h=CreatePopupMenu();


i=AppendMenu(h,MFT_STRING,M_FILE1,"
Новый
");

if (i==0) return 1;


i=AppendMenu(h,MFT_STRING,M_FILE2,"
Выход
");

if (i==0) return 1;


//
Добавить

к

меню

MENUITEMINFO

mi
;

mi.cbSize=sizeof(mi);

mi.fMask=MIIM_SUBMENU;

mi.hSubMenu=h;

i=
SetMenuItemInfo(HMenu,M_FILE,false,&mi);

if (i==0) return 1;


//Добавление меню к окну

i
=
SetMenu
(
hWnd
,
HMenu
);

if

(
i
==0)
return

1;

Листинг

5



Динамическое добавление меню к окну


Создание меню должно происходить во время обработки сообщения
WM_CREATE.
В пр
ограмме

hWnd



это дескриптор окна

(HWND)
.

M
_
FILE
,
M
_
FILE
1,
M
_
FILE
2 и
HMenu

должны быть объявлены ранее, например как
показано в листинге 6.


#
define

M
_
FILE

10001


25

#
define

M
_
FILE
1

10002

#define M_FILE2

10003

HMENU HMenu=NULL;

Листинг

6



Объявление определе
ний и переменных


Меню добавлено, однако надо получать сигналы о выборах пунктов меню.

Для этого в функции обработки сообщений вы должны отлавливать сообщение
WM_COMMAND

и просматривать параметр
wParam

(листинг 7).


int wID = LOWORD(wParam);


switch (wID
)

{

case M_FILE2:


DestroyWindow(hWnd);


break;

case M_FILE1:




break;

}

Листинг

7



Обработка выбора пункта меню


Теперь перейдѐм к созданию формы. Для этого на
до перейти к редактору
ресурсов и добавить диалоговое окно.

Нажмите правой кнопкой на диалогов
ом окне
и выберите «Prop
erties
» (Рис
унок

7).



Рисунок 7


Изменение свойств диалогового окна


В программе нужно, чтобы это диалоговое окно работало, как форма (Builder

26

или Delphi). Поэтому переходим во вкладку «
Styles
»

и меняем
свойства:
в пункте
«Style»

на

«
Child
»
, в пункте «
Border
»

на
«
None
»
.
Не забываем ставить флажок в
More Stules→
Visible
.

Автоматически созданное соде
ржимое диалогового окна удаляем и переносим
туда компонент «
Edit

Box
».

Открываем

его

свойства

и

помечаем

галочкой

следующие

пункты
:

Visi
ble
,
Tab

stop
,
Multiline
,
Horizontal

scroll
,
Auto

HScroll
,
Vertical

scroll
,
Auto

VScroll
,
No

hide

selection
,
Border
,
Read
-
only
,
Static

edge
.

А также
растягиваем «
Edit

Box
»

до размеров окна.

Заготовка готова, теперь надо еѐ натянуть на главное окно.

Первон
ачально
изменяем класс окна:

WndClass.hbrBackground=(HBRUSH)NULL;

А затем также при обработке сообщения WM_CREATE создаѐм диалоговое
окно

(Листинг 8)
.


hEdit=CreateDialog(hInst,MAKEINTRESOURCE(IDD_DIALOG1),hWnd,(DLGPROC) WIN32DIAL);

if (hEdit==NULL)

{


ret
urn 1;

}

Листинг

8



Создание немодального диалогового окна


Перед вызовом
hEdit

должен быть у вас объявлен как
HWND
, а также должна
существовать функция обработки сообщения диалогового окна (Листинг 9).


LRESULT CALLBACK WIN32DIAL(HWND hWnd,UINT Message,


UINT wParam,LONG lParam)

{


return DefWindowProc(hWnd,Message,wParam,lParam);

}

Листинг

9



Функция обработки сообщений диалогового окна


Компилируем


картинка не очень хорошая, т.к. диалоговое окно не
растягивается самостоятель
но. Для этого нужно написать свою функцию (Листинг
10).


int SizeEdit(HWND hWnd)

{


RECT Rect;


//получаем размер клиентской области окна


GetClientRect(hWnd,&Rect);


//меняем размеры окон


SetWindowPos(hEdit,hWnd,0,0,Rect.right
-
Rect.left,Rect.bottom
-
Rect.
top,SWP_NOZORDER);


HWND h=GetDlgItem(hEdit,IDC_EDIT1);


GetClientRect(hEdit,&Rect);


SetWindowPos(h,hEdit,0,0,Rect.right
-
Rect.left,Rect.bottom
-
Rect.top,SWP_NOZORDER);


return 0;

}

Листинг

10



Функция установки размеров


27

Добавьте вызов этой функции в двух
местах


непосредственно после
создания диалогового окна и во время обработке сообщения
WM_SIZE

главного
окна.

Теперь другое дело. Ваша простейшая форма готова.
П
ростейший приме
р
добавления текста в Edit Box:


char new_str[3]={ 0x0d, 0x0a,0 };

char buf[256
];

lstrcpy(buf,"Привет!");

lstrcat(buf,new_str);

lstrcat(buf,"Это моя первая программа!");

SetDlgItemText(hEdit,IDC_EDIT1,buf);

Листинг

1
1



Добавление текста


Задание:

1. Ознакомиться с динамическим способом добавления меню.

2.
Ознакомиться с элементами с
оздания формы рабочего окна.

3.
Разработать программу, в которой есть несколько пунктов меню и форма с
«
Edit
Box
»
. Названия пунктов меню должны загружаться из файла.

По нажатию пунктов
должен появляться и удаляться текст с формы.


Контрольные вопросы:

1.
Ч
ем отличается статическое и динамическое присоединение меню к окну
?

2. Какие операции производит функция
AppendMenu
?

3.
Как обрабатывается выбор пункта меню
?

4.
Чем отличается модальное окно от немодального
?

5.
Объясните назначения свойств диалогового окна
.

6.
Каким образом осуществляется изменение размеров формы?


Для самостоятельного изучения:

1.
Функции работы с меню
InsertMenuItem и InsertMenu.

2. Статистически
й

способ добавления меню.

3. Удаление пунктов меню.

4. Использование различных элементов диало
гового окна на форме.


4.3

Получение сведений о компьютере в операционной среде Windows
программн
ы
ми средствами


Сведения об устройствах компьютера нужны в ряде случаев, когда параметры
важны для выполнения программы. Сведения об устройствах компьютера в
W
indows 2000, ME, XP хранятся в реестре. Сведения о BIOS материнской платы и
видеокарте хранятся в реестре в ключе

(Табл. 2)
:

HKEY_LOCAL_MACHINE
\
HARDWARE
\
DESCRIPTION
\
System
.

Сведения о процессоре содержаться в реестре в ключе
:

HKEY_LOCAL_MACHINE
\
HARDWARE
\
DE
SCRIPTION
\
System
\
CentralProcessor
\
0
.

Параметры:
Identifier
,
ProcessorNameString



соответственно сведения об
идентификаторе и имени процессора.

Т
ип этих параметров можно посмотреть в

28

реестре, используя приложение
regedit
.

Для доступа к ключам реестра из
пр
ограммы можно воспользоваться функциями
RegOpenKeyEx
,
RegQueryValueEx

и
RegCloseKey
.


Таблица

2



Сведения реестра о BIOS и видеокарте

Параметр

Тип

Описание

SystemBiosDate

Строка

Дата Bios

SystemBiosVersio
n

Несколько строк

Версия Bios

VideoBiosDate

Стро
ка

Дата видеокарты


Функция
RegOpenKeyEx


LONG RegOpenKeyEx

(

HKEY hKey,

LPCTSTR lpSubKey,

DWORD ulOptions,

REGSAM samDesired,

PHKEY phkResult

);


Функция открывает раздел

реестра
.

Параметры
:

hKey



о
писатель открываемого раздела, который может быть п
олучен функциями
RegCreateKeyEx

и
RegOpenKey
. Действуют стандартные описатели
:




HKEY_CLASSES_ROOT



HKEY_CURRENT_CONFIG



HKEY_CURRENT_USER



HKEY_LOCAL_MACHINE



HKEY_USERS



Для

Windows Me/98/95
также
:
HKEY_DYN_DATA.

lpSubKey



у
казатель

на

строку
,
зав
ершающуюся

нулевым

байтом, которая
содержит имя открываемого раздела. Этот раздел должен быть подразделом,
идентифицируемого описателем раздела. Если этот параметр NULL, то функция
вернет описатель самого раздела, т. е. раздела, идентифицируемого описателе
м.

ulOptions



зарезервировано и равно нулю
.

samDesired



о
пределяет права доступа (действия, которые будет проделывать с
разделом программист). Как уже упоминалось, раздел реестра является системным
объектом, а следовательно он имеет дескриптор защиты,
именно в нем
перечисляются права пользователей на объект. Определены следующие
стандартные макросы:



KEY_ALL_ACCESS



р
азрешаются любые действия над разделом
;



KEY_ENUMERATE_SUB_KEYS



р
азрешается перечисление подразделов
данного раздела
;



KEY_READ


р
а
зрешается чтение раздела
;


29



KEY_SET_VALUE


р
азрешается создавать, удалять параметр или
устанавливать его значение
;



KEY_QUERY_VALUE


р
азрешается запрос параметра раздела
.

phkResult



у
казатель на переменную, получающую описатель открытого раздела.

Если

открытие произошло успешно, функция вернет ERROR_SUCCESS, в
противном случае вернет ненулевой код ошибки, определенный в Winerror.h


Функция
RegQueryValueEx


LONG RegQueryValueEx

(

HKEY hKey,

LPCTSTR lpValueName,

LPDWORD lpReserved,

LPDWORD lpType,

LP
BYTE lpData,

LPDWORD lpcbData

);


Функция возвращает информацию о параметре раздела и значение этого
параметра.

Параметры:

hKey



о
писатель открытого раздела. Раздел должен быть открыт с правами
KEY_QUERY_VALUE.

lpValueName



у
казатель на строку, содержа
щую название параметра, о котором
получается информация. Если параметр


NULL или пустая строка, то возвращается
информация о параметре по умолчанию.

lpReserved



зарезервирован и равен

NULL.

lpType



у
казатель на переменную, которая получает тип данных,

сохраненных в
параметре. Если равен NULL, то соответственно, информация не возвращается.

lpData



у
казатель на массив, получающий данные параметра. Если параметр


NULL, то данные не возвращаются. Если данные


это строка, то функция проверяет
наличие ну
левого символа.

lpcbData



у
казатель на переменную, которая определяет размер буфера,
принимающего данные из параметра, в байтах. После того, как функция вернет
значение, эта переменная будет содержать размер данных, скопированных в буфер.
Если данные нос
ят текстовый характер (REG_xxx_SZ), то также включается и
нулевой символ (нулевые символы для REG_MULTI_SZ). Если размер буфера,
недостаточен для сохранения данных, то функция вернет ERROR_MORE_DATA и
сохранит требуемый размер буфера в переменную, на котор
ую указывает этот
параметр. Если

lpData



NULL, а параметр
lpcbData

не нулевой, функция
возвращает ERROR_SUCCESS и сохраняет размер данных в переменной, на
которую указывает
lpcbData
.

Если функция выполнена успешно, возвращается ERROR_SUCCESS, в
противном

случае возвращается ненулевой код ошибки, определенный в Winerror.h



30

Функция
RegCloseKey


LONG RegCloseKey(HKEY hKey);


Функция закрывает описатель раздела реестра.

Параметры:

hKey



о
писатель открытого раздела, который подлежит закрытию.

Если описатель

успешно освобожден, функция возвращает
ERROR_SUCCESS, в противном случае вернет ненулевой код ошибки,
определенный в Winerror.h


Пример использования описанных функций для получения информации о дате
BIOS представлен в листинге 12.


HKEY hKeyResult = 0;

DWORD dwType;

DWORD dwBytes=256;

char buf[256];


LONG lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
"HARDWARE
\
\
DESCRIPTION
\
\
System" ,0, KEY_ALL_ACCESS, &hKeyResult );


lResult=RegQueryValueEx( hKeyResult, "SystemBiosDate", 0, &dwType,(BYTE*)buf, &dwBytes );


RegCloseKey(hKeyResult);

Листинг

12



Получение информации из ключа реестра


При типе «несколько строк» в буфер

buf

возвращается массив строк, конец
которого определяется двумя нулевыми символами.

Информацию о памяти и еѐ текущем состоянии можно получить с помощью
функции (winbase
.
h
)
:


Функция
GlobalMemoryStatus


void GlobalMemoryStatus(LPMEMORYSTATUS lpBuffer);


После вызова функции информацией о состоянии памяти заполняется
структура
MEMORYSTATUS.


Структура

MEMORYSTATUS


typedef

struct

_
MEMORYSTATUS


{

DWORD

dwLength
;


// раз
мер структуры

DWORD dwMemoryLoad;

// процент занятой памяти (0
-
100)

SIZE_T dwTotalPhys;

// объѐм физической памяти в байтах

SIZE_T dwAvailPhys;

// свободный объѐм физической памяти в байтах

SIZE_T dwTotalPageFile;

// объѐм в байтах файла подкачки


31

S
IZE_T dwAvailPageFile;

// свободный объѐм файла подкачки

SIZE_T dwTotalVirtual;

// объѐм в байтах текущего адресного пространства

SIZE_T dwAvailVirtual;

// свободный объѐм в байтах адресного пространства

} MEMORYSTATUS, *LPMEMORYSTATUS;


Получить имя
компьютера в сети и имя пользователя можно с помощью
описанных ниже функций.


Функция


BOOL GetComputerName

(


LPTSTR lpBuffer,


// указатель на буфер


LPDWORD lpnSize


// указатель на размер буфера

);


П
арам
етр
lpBuffer

указывает буфер, в

который будет записано имя
компьютера.
lpnSize



максимальное количество символов. Это значение должно
быть не менее
MAX_COMPUTERNAME_LENGTH
+1.

Если функция успешно
выполнена, она возвращает true.


Функция



BOOL GetUserName

(

LPTSTR lpBuffer,

LPDWORD nSize

);


П
арам
етр
lpBuffer

указывает буфер, в который

будет записано имя
пользовател
я.

nSize



максимальное количество символов.


Задание:

1.

Написать
функцию
, которая будет выводить информацию:



д
ата Bios
;



версия Bios;



дата видеокарты;



ид
ентификатор процессора;



производитель процессора;



объѐм физической памяти;



процент занятой памяти;



объѐм файла подкачки;



свободный объѐм файла подкачки;



адресное пространство;



имя компьютера;



имя пользователя.



32

Контрольные вопросы:

1.
Для ч
его предназначен реестр
?

2.
Какие основные разделы реестра?

3.
Каким образом можно работать со списком строк, получаемых из реестра?


Для самостоятельного изучения:

1. Функции работы с
реестром RegOpenKey, RegCreateKeyEx,
R
egQueryInfoKey,
RegEnumKeyEx, Reg
EnumValue, RegSetValueEx
.


4.4

Взаимодействие приложения с
System

Tray


Область
System

Tray

представляет собой часть полосы задач, размещается в
правом нижнем углу и содержит значки, такие как часы и т.п. Эту область активно
используют программы, работающи
е в процессе всего сеанса
Windows
. Обычно при
этом программы делают себя невидимыми в полосе задач. Для этого при создании
необходимо вызвать функцию

(
Handle



указатель на ваше окно)
:


Функция



LONG SetWindowLong

(

HWND

hWnd
,


// дескриптор
окна

int nIndex,



// значение смещения, которое устанавливается

LONG dwNewLong


//новое значение

);


Функция SetWindowLong изменяет атрибуты определяемого окна. Функция
также устанавливает 32
-
разрядное (длинное) значение при заданном смещении в
дополните
льном пространстве памяти об окне.

Параметры:

hWnd



и
дентифицирует окно и, косвенно, класс, которому окно принадлежит.

nIndex



о
пределяет значение смещения, отсчитываемое от нуля, которое будет
установлено. Допустимые значения находятся в диапазоне от н
уля до числа байтов
дополнительного пространства в памяти, минус 4; например, если бы Вы
установили 12 или большее количество байтов памяти дополнительного
пространства, значение 8 было бы индексом к третьему 32
-
разрядному целому
числу. Чтобы установить лю
бое другое значение, определите одно из следующих
значений:

GWL_EXSTYLE


Устанавливает новый расширенный стиль окна.

GWL_STYLE


Устанавливает новый стиль окна.

GWL_WNDPROC


Устанавливает новый адрес для оконной процедуры.

GWL_HINSTANCE


Устанавлива
ет новый дескриптор экземпляра прикладной
программы.

GWL_ID


Устанавливает новый идентификатор окна.

GWL_USERDATA


Устанавливает 32
-
разрядное значение, связанное с окном.
Каждое окно имеет соответствующее 32
-
разрядное значение, предназначенное для

33

использования прикладной программой, которая создала окно.

Следующие значения также доступны, когда параметр hWnd идентиф
ицирует
диалоговое окно:

DWL_DLGPROC


Устанавливает новый адрес процедуры диалогового окна.

DWL_MSGRESULT


Устанавливает возвращаемое значение сообщения,
обработанного в процедуре диалогового окна.

DWL_USER


Устанавливает новую дополнительную информа
цию, которая
является частной для прикладной программы, типа дескрипторов или указателей.

dwNewLong



у
станавливает восстановленное значение.

Возвращаемые значения

Если функция завершается успешно, возвращаемое значение
-

предыдущее
значение заданного 32
-
разрядного целого числа. Если функция не выполняет задачу,
возвращаемое значение нулевое. Чтобы получать расширенные данные об ошибках,
вызовите
.


Функция

Shell_NotifyIcon


WINSHELLAPI BOOL WINAPI Shell_NotifyIcon

(

DWORD dwMessage,

PNOTIFYI
CONDATA pnid

);


Используется для
добавления и удаления иконки в
System

Tray
.

Параметры:

dwMessage


должен содержать одно из следующих значений:

NIM_ADD
-

добавить значок в область состояния,

NIM_DEL
-

удалить значок из области состояния,

NIM_MODIFY
-

изм
енить значок в области состояния.

pnid



указывает на структуру типа NOTIFYICONDATA, значения полей которой
зависят от параметра dwMessage.

Функция
Shell_NotifyIcon

возвращает ненулевое значение, если операция
прошла успешно, и ноль в случае ошибки.


Струк
тура NOTIFYICONDATA


typedef struct _NOTIFYICONDATA

{

DWORD cbSize;

HWND hWnd;

UINT uID;

UINT uFlags;

UINT uCallbackMessage;

HICON hIcon;

WCHAR szTip[64];

} NOTIFYICONDATA, *PNOTIFYICONDATA;



34

И ее поля имеют следующий смысл:

cbSize



размер структу
ры NOTIFYICONDATA.

hWnd



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

uID



идентификатор значка. Это значение передается приложению в качестве
первого парамет
ра (WPARAM) сообщения от значка.

uFlags



набор флагов, кот
орые определяют, какие поля структуры заданы
корректно. Могут использоваться следующие значения или их комбин
ации с
помощью логического «ИЛИ»: NIF_ICON


поле
hIcon

корректно, NIF_MESSAGE


поле
uCallbackMessage

корректно, NIF_TIP


поле
szTip

корректно.

u
CallbackMessage



идентификатор сообщения, посылаемого окну
hWnd

при
возникновении события «мыши»

над значком в области состояния. Можно
использовать значения WM_USER+
N
, где
N



неотрицательное число;

hIcon



манипулятор иконки, которую нужно разместить (и
зменить, удалить) в
S
ystem
T
ray.

szTip



ASCIIZ
-
строка, которая б
удет использоваться в качестве «
всплыва
ющего»
текста, когда указатель «мыши»

остановится над значком. Если текст отсутствует,
первый байт строки должен быть нулевым.


Перед вызовом функции
Sh
ell_NotifyIcon

нужно подготовить экземпляр
структуры NOTIFYICONDATA. Поля
cbSize
,
hWnd

и
uID

нужно заполнять всегда,
остальные


по мере необходимости. В соответствии с заполнением полей
uCallbackMessage
,
hIcon

и
szTip

формируется поле флагов
uFlags
.

Чтобы

добавить значок в область состояния, нужно вызвать функцию
Shell_NotifyIcon
, передав ей в качестве параметра

dwMessage

значение NIM_ADD,
а в качестве
pnid



указатель на инициализированный экземпляр структуры
NOTIFYICONDATA. Если все выполнено правильно,
функция вернет ненулевое
значение, а в
S
ystem
T
ray появится новая иконка. Если планируется, что окно
должно принимать сообщения от значка, следует обратить внимание, чтобы поле
hWnd

перед вызовом
Shell_NotifyIcon

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

над ним остановится указатель «мыши»

Если было инициализировано поле
uCallbackMessage
, система будет посылать окну
hWnd сообщения
о событиях «мыши»

над
значком. При этом параметр сообщения
WPARAM будет содержать идентификатор значка
uID
, а параметр LPARAM


тип
сообщения.

При
ложение, разместившее значок в
S
ystem
T
ray, может в любой момент
изменить иконку или всплывающую подсказку. Для этого нужно внести и
зменения
в соответствующие поля структуры NOTIFYICONDATA, поправить значение
uFlags

(значения
cbSize
,
hWnd

и
uId
изменяться не должны
) и вызвать функцию
Shell_NotifyIcon

со значением NIM_MODIFY в качестве параметра
dwMessage
.

Для уда
ления значка из
S
ystem
T
ray достаточно правильно заполнить поля
cbSize
,
hWnd
,
uId

и вызвать функцию
Shell_NotifyIcon

со

значением параметра
dwMessage

равным

NIM_DELETE.

Пример добавления иконки к о
к
н
у представлен в
листинге 13.


35


const TrayIcon = WM_USER + 1;


NOTIFYICONDATA NID;

NID.cbSize = sizeof(NOTIFYICONDATA );

NID.hWnd = hWnd;

NID.uID = 1;

NID.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;

NID.uCallbackMessage = TrayIcon; //указатель на создаваемое событие от иконки

NID.hIcon = LoadIcon(hInst,MAKEINTRESOURCE(IDI_ICON1));

strcpy
(NID.szTip,"
Имя

приложения
");

Shell_NotifyIcon(NIM_ADD,&NID);

Листинг

13



Добавление иконки программы в System Tray


Теперь необходимо написать обработку сообщения

TrayIcon

в функции
обработки сообщений главного окна.

Так в листинге 14 показано как
обраба
тывается сообщение о нажатии на иконку и разворачивании окна

после этого.


//
Ч
асть

функции обработки сообщений

case TrayIcon:


OnTray(hWnd,wParam,lParam);


break;


//

Функция обработ
ки сообщений от иконки

int OnTray(HWND hWnd,UINT wParam,LONG lParam)

{


s
witch(lParam)


{


case 514://WM_LBUTTONDBLCLK:



ShowWindow(hWnd,SW_SHOWNORMAL);



SetForegroundWindow(hWnd);



break;


}


return 0;

}

Листинг

14



Обработка нажатия на иконку в

System Tray


Задание:

1.

Модифицировать программу для работы с
System Tray
:



удаление собственной иконки из
System

Tray
;




добавление иконки в
System

Tray
;




добавление меню к иконке;




обработка нажатия левой и правой кнопок на меню;




обработка выбора пункта меню.

2. Удалить программу из Панели задач.


Контрольные вопросы:

1.

Для чего предназначен System Tray
?

2.
Для чего нужно сообщение

WM
_
USER
?


36

3.
Какие операции по работе с иконками существуют
?

4. Как удалить программу из Панели задач?

5. Как обработать нажатие правой кнопки мыши на икон
ке
?


Для самостоятельного изучения:

1.

Удаление, добавление и модификация иконок в
System Tray.

2. Присоединение меню к
System Tray.


4.5

Создание и управление процессами


Процессом обычно называют экземпляр выполняемой программы.

Хотя на первый взгляд кажется что программа и процесс понятия п
рактически
одинаковые, они фундаментально отличаются друг от друга. Программа
представляет собой статический набор команд, а процесс это набор ресурсов и
данных, использу
ю
щихся при выполнении программы. Процесс в Windows состоит
из следующих комп
о
нентов:



с
труктура данных, содержащая всю информацию о процессе, в том числе
сп
и
сок открытых дескрипторов различных системных ресурсов, уникальный
идентифик
а
тор процесса, различную статистическую информацию и т.д.;



а
дресное пространство


диапазон адресов виртуально
й памяти, которым
м
о
жет пользоваться процесс;



и
сполняемая программа и данные, проецируемые на виртуальное
адресное пространство процесса.

Поток (thread)

сущность внутри процесса, получающая пр
о
цессорное время
для выполнения. В каждом процессе есть минимум

один поток. Этот первичный
поток со
з
дается системой автоматически при создании процесса. Далее этот поток
может пор
о
дить другие потоки, те в свою очередь новые и т.д. Таким образом, один
процесс может владеть несколькими потоками, и тогда они одновременно

исполняют код в адресном пространстве процесса. Каждый поток имеет:



у
никальный идентификатор потока;



с
одержимое набора регистров процессора, отражающих состояние
процесс
о
ра;



д
ва стека, один из которых используется потоком при выполнении в режиме
ядра, а д
ругой


в пользовательском режиме;



з
акрытую область памяти, называемую локальной памятью потока (thread
local storage, TLS) и используемую подсистемами, run
-
time библиотеками и DLL.

Чтобы все потоки работали, операционная система отводит каждому из них
опр
е
деленное процессорное время. Тем самым создается иллюзия одновременного
выполн
е
ния потоков (разумеется, для многопроцессорных компьютеров возможен
истинный п
а
раллелизм). В Windows реализована система вытесняющего
планирования на основе приоритетов, в к
о
то
рой всегда выполняется поток с
наибольшим приоритетом, готовый к выполнению. В
ы
бранный для выполнения
поток работает в течение некоторого периода, называемого квантом. Квант
определяет, сколько времени будет выполняться поток, п
о
ка операцио
н
ная система

37

не
прервет его. По окончании кванта операционная система проверяет, готов ли к
выполнению другой поток с таким же (или большим) уровнем пр
и
оритета. Если
т
а
ких потоков не оказалось, текущему потоку выделяется еще один квант. Однако
поток может не полностью исп
ользовать свой квант. Как только другой поток с
более высоким приоритетом готов к выполнению, текущий поток вытесняется, даже
если его квант еще не истек

Для

создания процессов
используется функция
CreateProcess



это основная
функция запуска процесса, все

остальные функции такие как
WinExec

и
LoadModule оставлены для совместимости и используют
CreateProcess
.



Функция CreateProcess


BOOL CreateProcess

(

LPCTSTR lpApplicationName,




//
имя

исполняемого

модуля

LPTSTR lpCommandLine,






//
Командная

строка

LPSECURITY_ATTRIBUTES lpProcessAttributes,

//
Указатель

на

структуру










//
SECURITY_ATTRIBUTES

LPSECURITY_ATTRIBUTES lpThreadAttributes,

//
Указатель

на

структуру


//
SECURITY_ATTRIBUTES

BOOL bInheritHandles,




// Флаг наследования текущего процесса

DWORD dwCreationFlags,



// Флаги способов создания процесса

LPVOID lpEnvironment,



// Указатель на блок среды

LPCTSTR lpCurrentDirectory,



// Теку
щий диск или каталог

LPSTARTUPINFO lpStartupInfo,



// Указатель нас структуру STARTUPINFO

LPPROCESS_INFORMATION lpProcessInformation

//
Указатель

нас

структуру










//
PROCESS_INFORMATION

);


Параметры:

pApplicationName



ук
азатель на

строку которая заканчивается нулем и содержит
имя выполняемого модуля. Этот параметр может быть NULL тогда имя модуля
должно быть в
lpCommandLine

самым первым элементом. Если операционная
система NT и модуль 16 разрядов этот параметр NULL обязательно. имя

модуля
может быть абсолютным или относительным. Если относительное то будет
использована информация из
lpCurrentDirectory

или текущий каталог.

lpCommandLine



к
омандная строка. Здесь передаются параметры. Она может быть
NULL. Здесь можно указать и путь и

имя модуля.

lpProcessAttributes



з
десь определяются атрибуты защиты для нового приложения.
Если указать NULL то система сделает это по умолчанию.

lpThreadAttributes



з
десь определяются атрибуты защиты для первого потока
созданного приложением. NULL оп
ять приводит к установке по умолчанию.

bInheritHandles



ф
лаг наследования от процесса производящего запуск. Здесь
наследуются дескрипторы. Унаследованные дескрипторы имеют те же значения и
права доступа, что и оригиналы.

dwCreationFlags
.

Флаг способа соз
дание процесса и его

приоритет
:

CREATE
_
DEFAULT
_
ERROR
_
MODE



Новый процесс не наследует режим ошибок

38

(
error

mode
) вызывающего процесса.

CREATE
_
NEW
_
CONSOLE



Новый процесс получает новую консоль вместо того,
чтобы унаследовать родительскую.

CREATE
_
NEW
_
PRO
CESS
_
GROUP



Создаваемый процесс
-

корневой процесс
новой группы.

CREATE
_
SEPARATE
_
WOW
_
VDM



Т
олько
Windows

NT
: Если этот флаг
установлен, новый процесс запускается в собственной
Virtual

DOS

Machine

(
VDM
).

CREATE
_
SHARED
_
WOW
_
VDM



Т
олько
Windows

NT
: Этот

флаг указывает
функции
CreateProcess

запустит новый процесс в разделяемой
Virtual

DOS

Machine
.

CREATE
_
SUSPENDED



Первичная нить процесса создается в спящем (
suspended
)
состоянии и не выполняется до вызова функции
.

CREATE
_
UNICODE
_
ENVIRONMEN
T



Если этот флаг установлен, блок
переменных окружения, указанный в параметре
lpEnvironment
, использует
кодировку
Unicode
. Иначе


кодировку
ANSI
.

DEBUG
_
PROCESS



Если этот флаг установлен, вызывающий процесс считается
отладчиком, а новый процесс
-

отла
живаемым.

DEBUG
_
ONLY
_
THIS
_
PROCESS



Если

этот флаг не установлен и вызывающий
процесс находится под отладкой, новый процесс так же становится отлаживаемым
тем же отладчиком.

DETACHED
_
PROCESS



Создаваемый процесс не имеет доступа к родительской
консоли.

Этот флаг нельзя использовать с флагом
CREATE
_
NEW
_
CONSOLE
.

HIGH
_
PRIORITY
_
CLASS



Указывает на то, что процесс выполняет критичные по
времени задачи

.

IDLE
_
PRIORITY
_
CLASS



Указывает процесс, выполняются только когда система

находится в состоянии ожидания
.

NORMAL
_
PRIORITY
_
CLASS



Указывает на процесс, без каких либо специальных
требований к выполнению.

REALTIME
_
PRIORITY
_
CLASS



Указывает процесс имеющий наивысший
возможный приоритет.

lpEnvironment



у
казывает на блок среды. Если
NULL
, то будет использован

блок
среды родительского процесса. Блок среды это список переменных имя

=

значение в
виде строк с нулевым окончанием.

lpCurrentDirectory



Указывает текущий диск и каталог. Если
NULL
,

то будет
использован диск и каталог процесса родителя.

lpStartupInfo



Указатель на структуру
STARTUPINFO,

которая определяет
пар
а
метры главного окна порожденного процесса;

lpProcessInformation



У
казатель на
структуру
PROCESS
INFO,

которая будет
з
а
полнена информацией о порожденном процессе после возврата из функции.

В резуль
тате выполнение функций вернет FALSE или TRUE. В случае успеха
TRUE.
Пример использования функции представлен в листинге 15.


STARTUPINFO cif;

ZeroMemory(&cif,sizeof(STARTUPINFO));

PROCESS_INFORMATION pi;

if (CreateProcess("c:
\
\
windows
\
\
notepad.exe",NULL,


39

NULL,NULL,FALSE,NULL,NULL,NULL,&cif,&pi)==TRUE)

{


cout "process" endl;


cout "handle " pi.hProcess endl;


Sleep(1000);




//
подождать


TerminateProcess(pi.hProcess,NO_ERROR);

//
убрать

процесс

}

Листинг

15



Пример использования функции
Cr
eateProcess


Для удаления процесса используется функция:


Функция

TerminateProcess


BOOL TerminateProcess

(


HANDLE hProcess,

//
Указатель

процесса


UINT uExitCode

// Код возврата процесса

);


Параметры:

hProcess



Дескриптор процесса, который завершает ра
боту.

uExitCode



Код выхода, который использует процесс и потоки, чтобы завершить
работу в результате этого вызова. Используйте функцию
,
чтобы извлечь значение выхода процесса. Используйте функцию
, чтобы извлечь значен
ие выхода потока.

Возвращаемые значения

Если функция завершается успешно, величина возвращаемого значения


не
ноль. Если функция завершается с ошибкой, в
еличина возвращаемого значения


ноль. Чтобы получать расширенные данные об ошибках, вызовите
rror
.


При удалении процесса, открытого не нашим приложением, необходимо
получить информацию об окне и открыть процесс. Сначала необходимо найти окно
с помощью функции:


Функция
FindWindowEx


HWND FindWindowEx

(

HWND hwndParent ,

// дескриптор родительс
кого окна

HWND hwndChildAfter ,

// дескриптор дочернего окна

LPCTSTR lpszClass ,

// указатель на имя класса

LPCTSTR lpszWindow

// указатель на имя окна

);


Функция
FindWindowEx

извлекает дескриптор окна, чье имя класса и имя
окна совпадают с указан
ными строками. Функция также просматривает дочерние
окна, начиная с того, дескриптор которого передан функции в ка
честве параметра
hwndChildAfter
.


40

Параметры:

hwndParent



идентифицирует родительское окно, среди дочерних окон которого
будет проводиться поис
к. Если значение параметра
hwndParent

равно NULL,
функция использует рабочий стол Windows в качестве родительского окна. Функция
проводит поиск среди окон, являющимися дочерними окнами рабочего стола.

hwndChildAfter



идентифицирует дочернее окно. Поиск н
ачинается со
следующего окна в

Z
-
последовательности. Окно, указанное параметром
hwndChildAfter
, должно быть прямым дочерним окном указанного параметром
hwndParent

окна, а не порожденным окном. Если значение параметра
hwndChildAfter

равно NULL, поиск начина
ется с первого дочернего окна.

lpszClass



указывает на завершающуюся нулем строку, определяющую имя класса
или атом, идентифицирующий строку


имя класса. Если этот параметр является
атомом, он должен быть глобальным атомом, созданным предыдущим вызовом
функции
GlobalAddAtom
.

lpszWindow



указывает на завершающуюся нулем строку, определяющую имя окна
(заголовок окна). Если значение этого параметра равно NULL, то совпадающими со
строкой считаются все имена окон.

Возвращаемые значения

В случае успеха воз
вращается дескриптор окна, которое имеет заданные имя
класса и имя окна. В случае неудачи возвращается NULL. Для получения
дополнительной информации об ошибке вызовите функцию
.


Данная функция позволяет искать окно по названию класса окна или
по
названию титула окна. После получения
HWND

искомого приложения, необходимо
получить номер (
ID
)

процесса, например с помощью функции:


Функция GetWindowThreadProcessId


DWORD GetWindowThreadProcessId

(

HWND hWnd,


// дескриптор окна

LPDWORD lpdwProcessId


// адрес переменной для идентификатора процесса

);


Параметры:

hWnd



и
дентифицирует окно.

lpdwProcessId



у
казывает на 32
-
разрядное значение, которое принимает
идентификатор процесса. Если этот параметр


не NULL,

копирует идент
ификатор процесса в 32
-
разрядное
значение; иначе, она этого не делает.

Возвращаемое значение


идентификатор потока, который создает окно.


Для того, чтобы завершить процесс, его необходимо открыть с
использованием функции:


Функция

OpenProcess


41


HANDLE Ope
nProcess

(

DWORD

dwDesiredAccess
,


// флажок доступа

BOOL

bInheritHandle
,


// параметр дескриптора

наследования

DWORD

dwProcessId



// идентификатор процесса

);


Параметры
:

dwDesiredAccess



у
станавливает уровень доступа к объекту процесса. Этот
па
раметр может состоять из одного нескольких прав доступа к процессу.

Windows
NT /200/XP: Это право доступа проверяется у любого дескриптора безопасности для
процесса.

bInheritHandle



е
сли этот параметр является TRUE, дескриптор наследуем. Если
этот парамет
р является
FALSE
, дескриптор не может наследоваться.

dwProcessId



и
дентификатор процесса, который открыт.

Возвращаемые значения

Если функция завершается успешно, величина возвращаемого значения


открытый дескриптор заданного процесса.

Если функция заверш
ается с ошибкой,
величина возвращаемого значения NULL. Чтобы получить дополнительные данные
об ошибке, вызовите
.


Полезной функцией, необходимой для получения сведений о выполнении
процессов, является:


Функция



BOOL GetProcess
Times

(

HANDLE

hProcess
,


// дескриптор процесса


// время создания процесса



// время выхода из работы процесса


// время, работы процесса в режиме ядра

erTime


// время, работы процесса в режиме пользователя

);


Параметры
:

hProcess



д
ескриптор процесса, информация о распределении интервалов времени
которого разыскивается. Этот дескриптор должен быть создан с правами доступа
PROCESS_QUERY_INFORMATION.

Для получения дополнительной информации,
см. статью Защита процесса и права доступа.

lpCreationTime



у
казатель на структуру FILETIME, которая принимает время
создания процесса.

Так как время возвращается по количеству интервалов по 100нс.,
отсчитанных с
полуночи 1 января 1601 года, то для получения нормального времени
необходимо воспользоваться функцией
.

lpExitTime



у
казатель на структуру FILETIME, которая принимает время выхода
из работы процесса. Если процесс не вышел из работы, со
держание этой структуры

42

не определенное.

lpKernelTime



у
казатель на структуру FILETIME, которая принимает величину
времени, в течение которого процесс выполнялся в привилегированном режиме
(режиме ядра). Чтобы получить это значение, определяется время, в
ходе которого
каждый из потоков процесса выполнялся в режиме ядра, а затем все эти периоды
суммируются вместе.

lpUserTime



у
казатель на структуру FILETIME, которая принимает величину
времени, в течение которого процесс выполнялся в непривилегированном
(по
льзовательском) режиме. Чтобы получить это значение, определяется время, в
ходе которого каждый из потоков процесса выполнялся в режиме ядра, а затем все
эти периоды суммируются вместе.

Возвращаемые значения

Если функция завершается успешно, величина возвр
ащаемого значения


не
ноль.

Если функция завершается с ошибкой, величина возвращаемого значения


ноль. Чтобы получать расширенные данные об ошибках, вызовите
.


Задание:

1.

Модифицировать программу
:



запустить процесс калькулятора из приложе
ния;



запустить из приложения процесс команды
ping

с параметрами
запрашиваемого
IP
-
адреса соседнего компьютера;



получить информацию о времени выполнения дочерних процессах
калькулятора и
ping
;



удалить оба дочерних процесса;



запустив через меню «Пуск
» программы калькулятора и графического
редактора
Paint
, найти и удалить их с помощью вашего приложения.


Контрольные вопросы:

1.
Из чего состоят процесс и поток в среде Windows?

2.
Создание и завершение процесса.

3.
Каковы параметры функции CreateProcess?

4. Назначение и состав структуры PROCESS_INFORMATION.

5. Назначение и состав структуры STARTUP_INFO.

6. Назначение и состав структуры LPSECURITY_ATTRIBUTES.


Для самостоятельного изучения:

1.
Функции

ocessVersion
,
.


4.6

Обм
ен информацией между процессами


Параллельно работающие процессы часто должны обмениваться данными.

Н
а
данном этапе необходимо осуществить взаимодействие между двум
я процессами
через файл и путѐм использования
API

сообщения
WM_COPYDATA
.

Для того, чтобы два приложения обменивались данными через файл

43

необходимо, чтобы один процесс записывал туда, к примеру, текстовую строку, а
другой считывал. При этом, осуществлялся п
оочередный доступ к файлу


только
один процесс может работать с ним. Для работы с файлами средствами
API

предназначена функция:


Функция

CreateFile


HANDLE CreateFile

(



LPCTSTR

lpFileName
,



// имя файла



DWORD

dwDesiredAcc
ess
,



// режим доступа



DWORD

dwShareMode
,



// совместный доступ



LPSECURITY
_
ATTRIBUTES

lpSecurityAttributes
,

//
SD

(дескр. защиты)



DWORD

dwCreationDisposition
,


// как действоват
ь



DWORD

dwFlagsAndAttributes
,


// атрибуты файла



HANDLE hTemplateFile



// дескр.шаблона файла

);


Функция
CreateFile

создает или открывает каталог, физический диск, том,
буфер консоли (CONIN$ или CONOUT$),
устройство на магнитной ленте,
коммуникационный ресурс, почтовый слот или именованный канал. Функция
возвращает дескриптор, который может быть использован для доступа к объекту.

П
араметр
lpFileName



адрес строки, содержащей имя файла, который вы
собираете
сь создать или открыть. Параметр
dwDesiredAccess

определяет тип
доступа, который должен быть предоставлен к открываемому файлу.

С помощью параметра
dwShareMode

задаются режимы совместного
использования открываемого или создаваемого файла.

Через параметр
lpSecurityAttributes

необходимо передать указатель на
дескриптор защиты или значение
NULL
, если этот дескриптор не используется.
Параметр
dwCreationDistribution

определяет действия, выполняемые функцией
CreateFile
, если приложение пытается создать файл, ко
торый уже существует.

Параметр
dwFlagsAndAttributes

задает атрибуты и флаги для файла.

И, наконец, последний параметр
hTemplateFile

предназначен для доступа к
файлу шаблона с расширенными атрибутами создаваемого файла.

В случае успешного завершения функц
ия
CreateFile

возвращает
идентификатор созданного или открытого файла (или каталога).

При ошибке возвращается значение
INVALID
_
HANDLE
_
VALUE

(а не
NULL
,
как можно было бы предположить). Код ошибки можно определить при помощи
функции
.

Закрытие ф
айла осуществляется с использование функции
CloseHandle
.
Запись и чтение из файла осуществляется с помощью функций
ReadFile

и
WriteFile
:


Функция

ReadFile


BOOL ReadFile

(


44



HANDLE

hFile
,



// дескриптор файла



LPVOID

lpBuffer
,




// буфер данных



DWORD

nNumberOfBytesToRead
,

// число байтов для чтения



LPDWORD

lpNumberOfBytesRead
,

// число прочитанных байтов



LPOVERLAPPED

lpOverlapped



// асинхронный буфер

);


Функция
ReadFile

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

вывода, приложение должно переместить позицию указателя
файла после операции чтения.

Параметры:

hFile


д
ескриптор файла, который читается. Дескриптор файла должен быть, создан
с правом доступа GENERIC_READ.

lpBuffer


у
казатель н
а буфер, который принимает прочитанные данные из файла.

nNumberOfBytesToRead


ч
исло байтов, которые читаются из файла.

lpNumberOfBytesRead


у
казатель на переменную, которая получает число
прочитанных байтов. Функция
ReadFile

устанавливает это значение
в нуль перед
началом любой работы или проверкой ошибок.

lpOverlapped


у
казатель на структуру OVERLAPPED. Эта структура требуется
тогда, если параметр
hFile

создавался с флажком FILE_FLAG_OVERLAPPED.

Возвращаемые значения

Функция
ReadFile

возвращает знач
ение тогда, когда выполнено одно из ниже
перечисленных условий:



операция записи завершается на записывающем конце канала,



затребованное число байтов прочитано,



или происходит ошибка.

Если функция завершается успешно, величина возвращаемого значен
ия


не
ноль.

Если функция завершается с ошибкой, величина возвращаемого значения


ноль. Чтобы получить дополнительные сведения об ошибке, вызовите
.


Функция

Write
File


BOOL WriteFile

(



HANDLE

hFile
,



// дескриптор фай
ла



LPCVOID

lpBuffer
,


// буфер данных



DWORD

nNumberOfBytesToWrite
,

// число байтов для записи



LPDWORD

lpNumberOfBytesWritten
,

// число записанных байтов



LPOVERLAPPED

lpOverlapped


// асинхронный буфер

);


Функция
W
riteFile

пишет данные в файл с места, обозначенного указателем
позиции в файле. Эта функция предназначена и для синхронной, и для асинхронной

45

операции.

Параметры:

hFile


д
ескриптор файла. Дескриптор файла, должен быть создан с правом доступа
GENERIC_WRITE
.

lpBuffer


у
казатель на буфер, содержащий данные, которые будут записаны в файл.

nNumberOfBytesToWrite


ч
исло байтов, которые будут записаны в файл.

lpNumberOfBytesWritten


у
казатель на переменную, которая получает число
записанных байтов. Функция
Wr
iteFile

устанавливает это значение в нуль перед
выполнением какой
-
либо работы или выявлением ошибок.

lpOverlapped


у
казатель на структуру OVERLAPPED. Эта структура требуется
тогда, если параметр
hFile

создавался с флажком FILE_FLAG_OVERLAPPED.

Возвращаем
ые значения

Если функция завершается успешно, величина возвращаемого значения


не
ноль.

Если функция завершается с ошибкой, величина возвращаемого значения


ноль. Чтобы получить дополнительные сведения об ошибке, вызовите
.


В листинге 16 при
ведѐн пример открытия файла для чтения.


void CreateBMPFile(HWND hwnd, LPTSTR pszFile, PBITMAPINFO pbi,


HBITMAP hBMP, HDC hDC)


{


HANDLE hf; // file handle


BITMAPFILEHEADER hdr; // bitmap file
-
header



PBITMAPINFOHEADER pbih; // bitmap info
-
header


LPBYTE lpBits; // memory pointer


DWORD dwTotal; // total count of bytes


DWORD cb; // incremental count of bytes


BYTE *hp;
// byte pointer


DWORD dwTmp;



pbih = (PBITMAPINFOHEADER) pbi;


lpBits = (LPBYTE) GlobalAlloc(GMEM_FIXED, pbih
-
�biSizeImage);



if (!lpBits)


errhandler("GlobalAlloc", hwnd);



// Retrieve the color table (RGBQUAD array) and th
e bits




if (!GetDIBits(hDC, hBMP, 0, (WORD) pbih
-
�biHeight, lpBits, pbi,


DIB_RGB_COLORS))


{


errhandler("GetDIBits", hwnd);


}



// Create the .BMP file.


hf = CreateFile(
pszFile,


GENERIC_READ | GENERIC_WRITE,


(DWORD) 0,


46


NULL,


CREATE_ALWAYS,


FILE_ATTRIBUTE_NORMAL,


(HANDLE) NULL);


if (hf == INVALID_HA
NDLE_VALUE)


errhandler("CreateFile", hwnd);


hdr.bfType = 0x4d42; // 0x42 = "B" 0x4d = "M"


// Compute the size of the entire file.


hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) +


pbih
-
�biSize + pbih
-
�biClrUs
ed


* sizeof(RGBQUAD) + pbih
-
�biSizeImage);


hdr.bfReserved1 = 0;


hdr.bfReserved2 = 0;



// Compute the offset to the array of color indices.


hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) +


pbih
-
�b
iSize + pbih
-
�biClrUsed


* sizeof (RGBQUAD);



// Copy the BITMAPFILEHEADER into the .BMP file.


if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER),


(LPDWORD) &dwTmp, NULL))


{


errhandler("WriteFile"
, hwnd);


}



// Copy the BITMAPINFOHEADER and RGBQUAD array into the file.


if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER)


+ pbih
-
�biClrUsed * sizeof (RGBQUAD),


(LPDWORD) &dwTmp, ( NULL))



errhandler("WriteFile", hwnd);



// Copy the array of color indices into the .BMP file.


dwTotal = cb = pbih
-
�biSizeImage;


hp = lpBits;


if (!WriteFile(hf, (LPSTR) hp, (int) cb, (LPDWORD) &dwTmp,NULL))


errhandler("WriteFile"
, hwnd);



// Close the .BMP file.


if (!CloseHandle(hf))


errhandler("CloseHandle", hwnd);



// Free memory.


GlobalFree((HGLOBAL)lpBits);

}

Листинг

16



Функция для открытия BMP файла (MSDN)


Сообщение WM_COPYDATA передается т
огда, когда одна программа
пересылает данные в другую программу.

С
интаксис:

wParam = (WPARAM) (HWND) h
W
nd; // дескриптор передающего окна

lParam = (LPARAM) (PCOPYDATASTRUCT) pcds; // указатель на структуру с данными


47

Принимающий данные процесс должен обраба
тывать сообщение
WM
_
COPYDATA

в главном окне.
Данные получаются в виде структуры:

Структура COPYDATASTRUCT


typedef struct tagCOPYDATASTRUCT

{

DWORD dwData;

DWORD cbData;

PVOID lpData;

} COPYDATASTRUCT;


dwData



устанавливает до 32 битов данных, кото
рые будут переданы в
принимающую прикладную программу,
cbData



устанавливает размер, в байтах,
данных, указанных элементом структуры
lpData
,
lpData



указывает на данные,
которые будут переданы в принимающую прикладную программу. Этот элемент
структуры мо
жет быть значением
NULL
.


Чтобы послать сообщение из процесса в процесс нужно воспользоваться
API
-
функцией
SendMessage:


Функция SendMessage


LRESULT SendMessage(


HWND hWnd,

UINT message,

WPARAM wParam = 0,

LPARAM lParam = 0

);


Параметры
:

hWnd



деск
риптор


окна, которому посылается сообщение.

message



о
пределяет сообщение которое будет послано.

wParam



о
пределяет дополнительную зависимую от сообщения информацию.

pParam



о
пределяет дополнительную зависимую от сообщения информацию.

Возвращаемое знач
ение

Результат обработки сообщения, значение зависит от посланного сообщения.


Для этого необходимо знать
HWND

окна, в который вы будете посылать
сообщение. Его вы можете получить с помощью функции
FindWindowEx
.


Задание:

1. Написать программу «Источник да
нных» со следующими функциями:




запись строки в файл средствами
API
, блокируя доступ к записи и чтению
файла другими программами;




передача текстовой строки с помощью сообщения
WM_COPYDATA

другому приложению.


48

2. Написать программу «Приѐмник данных» со
следующими функциями:




опрос по таймеру файла, на наличие в нѐм сообщений;




приѐм и обработка сообщения
WM_COPYDATA

от «Источника данных».


Контрольные вопросы:

1
. Каковы параметры функции CreateProcess?

2
.
Каковы режимы чтения и записи файлов?

3
.
Како
й формат сообщения
WM_COPYDATA
?

4
.
Как осуществляется приѐм и обработка сообщения WM_COPYDAT
A
?


Для

самостоятельного

изучения
:

1.
Другие способы сообщения между независимыми процессами.


4.7 Управление потоками и работа с файлами средствами Win32API


Для с
оздания дополнительных потоков в программе используется функция:


Функция CreateThread



(

LPSECURITY_ATTRIBUTES lpThreadAttributes,

//
дескриптор

защиты

SIZE_T dwStackSize,




// начальный размер стека

LPTHREAD_S
TART_ROUTINE lpStartAddress,

//
функция

потока




//
параметр

потока

DWORD

dwCreationFlags
,



// опции создания

LPDWORD

lpThreadId




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

);


Функ
ция

создает поток, который выполняется в пределах
виртуального адресного пространства вызывающего процесса.

Чтобы создавать
поток, который запускается в виртуальном адресном пространстве другого
процесса, используется функция
d
.

Параметры:

lpThreadAttributes



у
казатель на структуру SECURITY_ATTRIBUTES, которая
обуславливает, может ли возвращенный дескриптор быть унаследован дочерними
процессами. Если
lpThreadAttributes

является значением
NULL
, дескриптор не
может быть унаследо
ван.

dwStackSize



н
ачальный размер стека, в байтах. Система округляет это значение до
самой близкой страницы памяти. Если это значение нулевое, новый поток
использует по умолчанию размер стека исполняемой программы.

lpStartAddress



у
казатель на определя
емую программой функцию типа
LPTHREAD_START_ROUTINE, код которой исполняется потоком и обозначает
начальный адрес потока. Для получения дополнительной информации о функции
потока, см.
ThreadProc
.




у
казатель на переменную, которая передается в
поток.


49

dwCreationFlags



ф
лажки, которые управляют созданием потока. Если установлен
флажок CREATE_SUSPENDED, создается поток в состоянии ожидания и не
запускается до тех пор, пока не будет вызвана функция
. Если это
значение нулевое, поток зап
ускается немедленно после создания.

lpThreadId



ук
азатель на переменную, которая принимает идентификатор потока.

Возвращаемые значения

Если функция завершается успешно, величина возвращаемого значения


дескриптор нового потока.

Если функция завершается
с ошибкой, величина
возвращаемого значения



NULL
. Чтобы получать дополнительные данные об
ошибках, вызовите
.


При успешном выполнении функция создаѐт поток, возвращает его
дескриптор, а в переменную, на которую указывает параметр

lpThreadId
,
заносится
идентификатор потока. Выполнение потока начинается с выполнения функции,
адрес которой указывает параметр
lpStartAddress
. Это любая функция, в которую
передается один аргумент, являющийся указателем на любую величину


. Если передават
ь ничего не надо, то надо присваивать значение
NULL
.
Формат функции:

DWORD WINAPI Название_функции(LPVOID);

Работа потока завершается оператором

в конце функции. Пример
создания потока представлен в листинге 17.

Здесь

Func



указывает на функцию, с
которой выполняется новый поток.


DWORD lpT;

HANDLE h=CreateThread(NULL,0,Func,NULL,0,&lpT);

CloseHandle(h);

Листинг

17



Создание нового потока


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


доступ к другим функциям программы
будет недоступен до окончания операции.

Одной из распространенных задач, является поиск файлов в заданном
каталоге. Для поиска файлов используются д
ве функции
FindFirstFile

и
FindNextFile
. Алгоритм работы следующий


создается рекурсивная функция,
например
FindFile
. В неѐ передается начальный каталог, в котором необходимо
найти все входящие файлы и каталоги. Первоначально вызывается функция:


Функция
FindFirstFile


HANDLE FindFirstFile

(

LPCTSTR lpFileName,


// адрес пути для поиска

LPWIN32_FIND_DATA lpFindFileData);

//
адрес

структуры

// LPWIN32_FIND_DATA, куда будет записана

// информация о файлах


50

)
;


Через параметр
lpFileName

вы дол
жны передать функции адрес строки,
содержащей путь к каталогу и шаблон для поиска. В шаблоне можно использовать
символы «?» и «*»
.

Через параметр
lpFindFileData

следует передать адрес
структуры типа WIN32_FIND_DATA, в которую будет записана информация о
на
йденных файлах. Эта структура определена следующим образом:


Структура

WIN32_FIND_DATA


typedef struct _WIN32_FIND_DATA

{

DWORD dwFileAttributes;


//
атрибуты

файла



//
время

создания

файла

ime;


//
время

доступа



//
время

записи

DWORD nFileSizeHigh;


//
размер

файла

(
старшее

слово
)

DWORD nFileSizeLow;


//
размер

файла

(
младшее

слово
)

DWO
RD dwReserved0;


// зарезервирова
но

DWORD dwReserved1;


// зарезервировано

TCHAR

cFileName
[
MAX
_
PATH
];

// имя файла

TCHAR cAlternateFileName[14];


// альтернативное имя файла

} WIN32_FIND_DATA;


Е
сли поиск завершился успешно, функция
FindFirstFile

возвращает
идент
ификатор поиска, который будет затем использован в цикле при вызове
функции
FindNextFile
. При

ошибке

возвращается

значение

INVALID
_
HANDLE
_
VALUE
.

После вызова функции
FindFirstFile

вы должны
выполнять в цикле вызов функции
FindNextFile
:


Функция
FindNextFil
e


BOOL FindNextFile

(

HANDLE hFindFile,


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

LPWIN
32_
FIND
_
DATA

lpFindFileData
);

// адрес структуры






// WIN32_FIND_DATA

);


Через параметр
hFindFile

этой функции следует передать идентификатор
по
иска, полученный от функции
FindFirstFile
. Что же касается параметра
lpFindFileData
, то через него вы должны передать адрес той же самой структуры
типа WIN32_FIND_DATA, что была использована при вызове функции
FindFirstFile
.

Если функция
FindNextFile

завер
шилась успешно, она возвращает значение
TRUE. При ошибке возвращается значение FALSE. Код ошибки вы можете
получить от функции
. В том случае, когда были просмотрены все
файлы в каталоге, эта функция возвращает значение ERROR_NO_MORE_FILES. Вы

51

должны использовать такую ситуацию для завершения цикла просмотра
содержимого каталога.

После завершения цикла просмотра необходимо закрыть идентификатор
поиска, выз
вав для этого функцию

FindClose
:


Функция

FindClose


BOOL FindClose(HANDLE hFindFile);


Зад
ание:

1. Написать программу:




создающую отдельный поток, которому передается название каталога, в
котором будут искаться файлы;




имеющую рекурсивную функцию
FindFile
, строящую «дерево» файлов и
каталогов от выбранного каталога.


Контрольные вопросы:

1.

Для чего необходимо использование потоков
?

2.
Приведите пример многопоточного приложения.

3
. Как

работает функция
?

4
.
Объясните принцип рекурсивного поиска файлов.


Для

самостоятельного

изучения
:

1.
Функции

ExitProcess
,
ExitThread
,
CreateRemo
.

2.
Существующие компоненты для автоматизированного поиска файлов.


4.8

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


Семафор


объект синхронизации, который может регулировать доступ к
некоторому ресурсу. Мьютекс


переменная, которая может находиться в одн
ом из
двух состояний: блокированном или неблокированном. Мьютекс может охранять
неразделенный ресурс, к которому в каждый момент времени допускается только
один поток, а семафор может охранять ресурс, с которым может одновременно
работать не более
N

потоко
в.

Мьютексный объект создаѐтся функцией:


Функция
CreateMutex


HANDLE CreateMutex

(


LPSECURITY_ATTRIBUTES lpMutexAttributes,


//
атрибут

безопастности


BOOL

bInitialOwner
,






// флаг начального владельца


LPCTSTR

lpName






// имя объекта

);


Функция в
озвращает дескриптор мьютексного объекта с именем, заданным

52

параметром
lpName
. Имя мьютекса не должно совпадать с именем уже
существующего события, семафора и других объектов межпроцессной
синхронизации.

Функция

при вызове будет выдавать
ERROR
_ALREADY_EXISTS.

Для открытия существующего мьютекса используется функция
OpenMutex
,
освобождения


ReleaseMutex
.

Семафор создаѐтся функцией:


Функция
CreateSemaphore


HANDLE CreateSemaphore

(


LPSECURITY_ATTRIBUTES lpSemaphoreAttributes,

//
атрибут

доступ
а


LONG lInitialCount,






// инициализированное начальное










//
состояние счетчика


LONG lMaximumCount,





// максимальное количество










//
обращений


LPCTSTR lpName






// имя объекта

);


При успешном выполнении функция вернет идентифика
тор семафора, в
противном случае
NULL
. После того как необходимость в работе с объектом отпала
нужно вызвать функцию
ReleaseSemaphore
, чтобы освободить счетчик.

Для
открытия существующего

семафора

используется функция
OpenSemaphore
.

Объекты синхронизации и
спользуются совместно с функциями ожидания. Эти
функции связываются с одним или несколькими синхронизирующими объектами и
ждут, когда эти объекты перейдут в сигнальное состояние. В результате выполнение
процесса приостанавливается до тех пор, пока в систем
е не произойдѐт некоторое
событие. Ожидание одного события организуется функцией:


Функция

WaitForSingleObject


DWORD WaitForSingleObject

(

HANDLE hHandle,

DWORD dwMilliseconds

);


Здесь первый параметр


дескриптор объекта синхронизации, а второй


время

ожидания в миллисекундах. Для ожидания нескольких синхронизирующих объектов
используется функция
WaitForMultipleObjects
.


В листинге 18 приведен пример программы использования мьютекса.
При
запуске программы она создает объект с именем
«MMM»
, если захвати
ть е
го
удается
WaitForSingleObject
, то программа выполняется якобы, ждет пока введете
число и нажмете Enter. Если захватить его не удается, то выходит с надписью fail.
Если Вы попробуете, то Вы сможете запустить только одну копию.


53


#include "windows.h"

#in
clude "iostream.h"


void main()

{


HANDLE mut;


mut = CreateMutex(NULL, FALSE, "
MMM
");


DWORD result;


result = WaitForSingleObject(mut,0);


if (result == WAIT_OBJECT_0)


{



cout "programm running" endl;



int i;



c��in i;



ReleaseMutex(mut);


}


else



cout "fail programm running" endl;


CloseHandle(mut);

}

Листинг

1
8



Пример
использовани
я мьютекса


Задание:

1.
Написать программы с требованиями:




может запуститься только один экземпляр приложения, для определения
запущено приложение или

нет использовать мьютекс (проверка, не создан ли
мьютекс предыдущим экземпляром);




запускаются два экземпляра программы, при нажатии на кнопку первого
экземпляра эмулируется захват ресурса и устанавливается мьютекс, второй
экземпляр, при нажатии на кноп
ку ожидает с использованием функции
WaitForMultipleObjects

освобождение ресурса в течении 3 секунд и, если ресурс
освобождается, то он захватывается 2
-
ым экземпляром, в противном случае
выводится на экран невозможность захвата ресурса;




может запуститься

только 4 экземпляра одного приложения, реализация с
использованием семафора.


Контрольные вопросы:

1. Для чего
нужны объекты синхронизации
?

2.
Чем отличается мьютекс от семафора?

3. Как работает функция
Create
Semaphor
e
?

4.
Д
ля чего нужны функции ожидания?

5.
Чем

отличаются

функции

WaitFor
SingleObject

и

WaitForMultipleObjects?


Для

самостоятельного

изучения
:

1.
Функции

OpenMutex
,
OpenSemaphore
,
WaitForMultipleObjects
.

2.

Объекты событий
.

3. Таймеры ожидания.


54


4.9

Управление памятью


Для
управления памятью в

операционной системе Windows предусмотрен ряд
функций.


Функция GlobalAlloc


HGLOBAL GlobalAlloc

(

UINT uFlags,

SIZE_T dwBytes

);


Функция в
ыделя
ет из глобальной кучи память
запрошенного
размера
.


Параметры:

uFlags



м
аска флагов.

dwBytes



р
азмер выдел
яемой памяти

Возвpащаемое значение:

Идентификатоp выделенного блока глобальной памяти; 0
-

если ошибка.


В листинге 19

пример вызова функции Windows для выделения блок
а памяти
для указателя на целые.


DWORD dwSize = 1024;

UINT uiFlags = 0;

p = (int *)Globa
lAlloc(uiFlags, dwSize);

Листинг

19



Выделение памяти с помощью GlobalAlloc


За исключением одной, для каждой функции, начинающейся со слова Global,
существует другая, начинающаяся со слова Local. Эти два набора функций в
Windows идентичны. Два различных
слова сохранены для совместимости с
предыдущими версиями Windows, где функции Global возвращали дальние
указат
ели, а функции Local


ближние.

Если первый параметр задать нулевым, то
это эквивалентно использованию флага GMEM_FIXED. Такой вызов функции
Globa
lAlloc

эквивалентен вызову функции
malloc
.

Следующий пример демонстрирует использование функции изменения
размера блока памяти:

p = (int *)GlobalReAlloc(p, dwSize, uiFlags);

Д
ля определения размера выделенного блока памяти используется функция
GlobalSize
:

dwSize = GlobalSize(p);

Функция освобождения памяти:

GlobalFree(p);

Функция
GlobalAlloc

поддерживает флаг GMEM_MOVEABLE и
комбинированный флаг для дополнительного обнуления блока памяти (описано в
заголовочных файлах Windows):


55

#define GHND (GMEM_MOVEABLE
| GMEM_ZEROINIT)

Флаг GMEM_MOVEABLE позволяет перемещать блок памяти в виртуальной
памяти, при этом функция возвращает не адрес выделенного блока, а 32
-
разрядный
описатель (дескриптор) блока памяти. Это необязательно означает, что блок памяти
будет перемещ
ен в физической памяти, но адрес, которым пользуется программа
для чтения и записи, может измениться. Для фик
сации блока используется вызов:

p

=(
int

*)
GlobalLock
(
hGlobal
);

Эта функция преобразует описатель памяти в указатель. Пока блок
зафиксирован, Window
s не изменяет его виртуальный адрес. Когда работа с блоком
заканчивается, для снятия фиксации вызывается функция:

GlobalUnlock(hGlobal);

Этот вызов дает Windows свободу перемещать блок в виртуальной памяти.
Для того чтобы правильно осуществлять этот процес
с следует фиксировать и
снимать фиксацию блока памяти в ходе обработки одного сообщения. Когда нужно
освободить перемещаемую память, надо вызывать функцию
GlobalFree

с
описателем, но не с указателем на блок памяти.

Если в данный момент нет доступа к описа
телю, то необходимо и
спользовать
функцию
:

hGlobal = GlobalHandle(p);

Для преднамеренного удаления блока памяти можно использовать следующий
вызов:

GlobalDiscard(hGlobal);

Другим доступным для использования в функции
GlobalAlloc

является флаг
GMEM_SHARE или

GMEM_DDESHARE (ид
ентичны
). Как следует из его имени,
этот флаг предназначен для динамического обмена данными. Функции
GlobalAlloc

и
GlobalReAlloc

могут также включать флаги GMEM_NODISCARD и
GMEM_NOCOMPACT. Эти флаги дают указание Windows не удалять и не
п
еремещать блоки памяти для удовлетворения запросов памяти.

Функция
GlobalFlags

возвращает комбинацию флагов
GMEM_DISCARDABLE, GMEM_DISCARDED и GMEM_SHARE. Наконец, вы
можете вызвать функцию
GlobalMemoryStatus

(для этой функции нет функции


двойника со сл
овом Local) с указателем на структуру типа MEMORYSTATUS для
определения количества физической и виртуальной памяти, доступной
приложению.

Windows также поддерживает некоторые функции, реализованные
программистом или дублирующие библиотечные функции C. Это

функции
FreeMemory
(заполнение конкретным байтом),

ZeroMemory

(обнуление памяти),
CopyMemory и
MoveMemory



обе копируют данные из одной области памяти в
другую. Если эти области перекрываются, то функция
CopyMemory

может работать
некорректно. Вместо нее
используйте функцию

MoveMemory
.

W
indows поддерживает ряд функций, начинающихся со слова Virtual. Эти
функции предоставляют значительно больше возможностей управления памятью.
Однако, только очень необычные приложения требуют использования этих
функций.

По
следняя группа функций работы с памятью


это функции, имена которых

56

начинаются со слова Heap. Эти функции создают и поддерживают непрерывный
блок виртуальной памяти, из которого можно выделять память более мелкими
блоками. Следует начинать с вызова функци
и
HeapCreate
. Затем, использовать
функции
HeapAllocate
,
HeapReAllocate

и
HeapFree

для выделения и освобождения
блоков памяти в рамках «кучи».


Задание:

1. Написать программу:




средствами
Win
32
API

выделяющая память для массива размерностью
M

на
N
, размер
ность вво
дится с клавиатуры;




случайным образом заполняется весь массив информацией;




н
еобходимо в каждой строке найти элемент с наименьшим значением, а
затем среди этих чисел найти наибольшее. На экран вывести индексы этого
э
лемента, а также все элеме
нты матрицы.


Контрольные вопросы:

1.
Какие средства поддерживает язык
C
/
C
++ для управления памятью
?

2.
Назовите основные флаги функции GlobalAlloc и их назначение
?

3.
Чем отличаются функции Global и Local
?

4.
Какими функциями предпочтительнее выделять пам
ять
для функций
Win
32
API
?


Для

самостоятельного

изучения
:

1.
Методы C/C++ выделения памяти
.


4.10

Дочерние окна и управление «чужим» приложением


Некоторые из окон
Windows

являются дочерними


т.е. помещаются в
клиентской области другого, родительского окн
а. Если известен дескриптор
некоторого окна, то можно получить указатель на его родительское окно с помощью
функции:


Функция GetParent


HWND GetParent

(

HWND hWnd


// дескриптор дочернего окна

);


Параметры:

hWnd



и
дентифицирует окно, дескриптор родитель
ского окна которого должен
быть найден.

Возвращаемые значения

Если функция завершилась успешно, возвращаемое значение


дескриптор
родительского окна. Если у окна нет родительско
го окна, возвращаемое значение


NULL. Чтобы получить более подробную информа
цию об ошибке, вызовите
.


57


Добраться до родительского окна можно с помощью следующей операции:

while (H=GetParent(hWnd)) hWnd=H;

где сначала в
hWnd

заносится дочернее окно, а после выполнения


остаѐтся
родительское.

Перебрать все дочерние окна

некоторого родительского окна можно с
помощью функции:


Функция
EnumChildWindows


BOOL EnumChildWindows

(

HWND hWndParent,



// дескриптор родительского окна

WNDENUMPROC lpEnumFunc,

// указатель на функцию обратного вызова

LPARAM lParam



// значение, опр
еделяемое программой

);


Параметры:

hWndParent



и
дентифицирует родительское окно, чьи дочерние окна должны
перечисляться.

lpEnumFunc



у
казывает на определяемую программой функцию повторного
вызова. Для получения дополнительной информации относительно фун
кции
повторного вызова, см. функцию повторного вызова
EnumChildProc
.

lParam



у
станавливает 32
-
разрядное, определяемое программой значение, которое
будет передано в функцию повторного вызова.

Возвращаемые значения

Если функция завершилась успешно, возвраща
ется значение отличное от
нуля. Если функция потерпела неудачу, возвращаемое значение


ноль.


Пользовательская функция объявляется следующим образом:

BOOL __stdcall EnumChild(HWND hWnd, LPARAM lParam);

Эту функцию объявляет и обрабатывает пользователь, пр
и этом первым
параметром приходит дескриптор дочернего окна.

Для получения имени дочернего окна можно воспользоваться функцией
SendMessage
, например так:


где
buf
, должен быть объявлен ранее,
например, так:

char

buf
[256];

Для получения класса окна, необходимо воспользоваться функцией
.

Для полного контроля над чужим приложением необходимо получить доступ
в меню, это можно сделать с помощью функции:

HMENU GetMenu(IN HWND hWnd);

Опред
елив дескриптор меню, легко узнать количество его разделов:

int GetMenuItemCount(IN HMENU hMenu);

А тексты разделов получаются с помощью функции:

int GetMenuString(IN HMENU hMenu, IN UINT uIDItem, OUT LPSTR lpString, IN int nMaxCount,


58

IN UINT uFlag);

или

с

помощью

функции
:

BOOL GetMenuItemInfo(IN HMENU hMenu, IN UINT uItem, IN BOOL fByPosition,

IN OUT LPMENUNITEMINFO lpmii);

Следующая функция позволяет получить дескриптор выпадающего окна:

HMENU GetSubMenu(IN MENU hMenu, IN int nPos);

Для имитации щелчка
на кнопке достаточно проделать следующую операцию:

SendMessage(hWnd, WM_LBUTTONDOWN,0,0);

SendMessage(hWnd, WM_LBUTTONUP,0,0);

где, естественно
hWnd

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

Для имитации щелчка в разделе меню необходим
о сделать следующее:

SendMessage(hWnd, WM_COMMAND,*(UINT*)Param,0);

где
param



номер пункта меню.

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


#include "windows.h"

#include "iostream.h"


void main()

{

HWND hwnd;

hwnd=FindWindow("
SciCalc","
Калькулятор
");

if (hwnd!=NULL)

{



HMENU hMenu;

hMenu=GetMenu(hwnd);



if (hMenu!=NULL)



{




int iCount;





Count=GetMenuItemCount(hMenu);




cout "Menu Item
-

" iCount endl;



}



else cout " Error Loading Menu" endl;

}

else c
out " Error Find Windows" endl;

}

Листинг

20



По
лучения доступа к меню программы

«Калькулятор»


Задание:

1. Написать программу:




запускающую «Калькулятор» и получающую список его дочерних окон и
пунктов меню;




эмулировать программно нажатия пунк
тов меню и кнопок.


Контрольные вопросы:

1.
Как

можно в операционной системе Windows найти запущенную программу
?

2.
Что такое дочернее окно и как к нему получить доступ из внешней программы
?

3.
Как, зная информацию о дочернем окне, найти главное окно
?


59

4.
К
ак получить доступ к кнопке
?

4. Как получить доступ к пункту меню?


Для

самостоятельного

изучения
:

1.
Управление сообщениями основного цикла главного окна из внешнего
приложения.


4.11

Решение задачи производителя и потребителя


На данном этапе необходимо
воспользоваться накопленными в ходе
выполнения предыдущих этапов знаниями для решения задачи производителя и
потребителя, подро
бно описанной в параграфах

2
-
3.





С
писок использованных источников


1

Архангельский, А.Я. Приѐмы программирования в C++ Builder
. М
е
ханизмы
Windows, сети / А.Я. Архангельский, М.А. Тагин.


М. : ООО «Бином
-
Пресс», 2004.


656 с.

2 Баженова, И.Ю Visual C++ 6.0. Уроки программирование / И.Ю. Баженова.


М. :
Диалог
-
МИФИ, 1999.


416 с.

3

Операционные си
стемы. Основы и принципы. 3
-
е и
зд.
/

Х.М.

Дейтел, П.Дж.

Де
й
тел
.


М. : Бином, 2006.


1024

с.

4

Саймон, Р. Windows 2000 API. Энциклопедия программиста
:

п
ер. с англ. / Р.
Са
й
мон.


СПб. : ООО «ДиаСофтЮП», 2002.


1088 с.

5

Сетевые операционные системы / В.Г. Олифер, Н.А. Олифер.


СПб.

: Питер, 2001.


544 с.

6

Таненбаум
,

Э.
Современные операционные сист
емы

:

пер. с англ. / Э.
Таненбаум
.



СПб.

: Питер,

2002.


2
изд.

1040 с.

7

Щупак
,
Ю
.
А
.
Win
32
API
.
Эффективная разработка приложений
/ Ю. А. Щупак.


CПб. : Питер, 2007.


572 с.


Приложенные файлы

  • pdf 4407508
    Размер файла: 840 kB Загрузок: 0

Добавить комментарий