- •Процессы и задачи в Microsoft Windows
- •Запуск задач
- •Управление запущенными задачами
- •Изменение приоритета задачи
- •Определение приоритета задачи
- •Приостановка и возобновление выполнения задачи
- •Временная приостановка работы задачи
- •Завершение задачи
- •Освобождение идентификатора задачи
- •Критические секции
- •Инициализация критической секции
- •Удаление критической секции
- •Вход в критическую секцию и выход из нее
- •4. Контрольные вопросы
- •5. Содержание работы
- •Создание объекта - событие
- •Открытие объекта - событие
- •Управление состоянием объекта - событие
- •Объекты – событие с автосбросом
- •Создание объекта Mutex
- •Освобождение идентификатора объекта Mutex
- •Открытие объекта Mutex
- •Как завладеть объектом Mutex
- •Освобождение объекта Mutex
- •Как работает семафор
- •Функции для работы с семафорами
- •Создание семафора
- •Уничтожение семафора •
- •Увеличение значения счетчика семафора
- •Уменьшение значения счетчика семафора
- •Определение текущего значения счетчика семафора
- •Создание и открытие ожидаемого таймера
- •Функции для работы с ожидаемым таймером
- •Контрольные вопросы
- •Содержание работы
- •Содержание отчета
- •Теоретический материал
- •7.1. Универсальные функции для работы с файлами в операционных системах Microsoft Windows
- •Функция CreateFile
- •Функция CloseHandle
- •Функции ReadFile и WriteFile
- •Механизм отображения файлов на память
- •Создание отображения файла
- •Выполнение отображения файла в память
- •Открытие отображения
- •Отмена отображения файла
- •Принудительная запись измененных данных
- •Обмен через файлы, отображаемые на память
- •Пример приложения, использующего файлы, отображаемые на память
- •Именованные и анонимные каналы
- •Имена каналов
- •Реализации каналов
- •Создание канала
- •Установка соединения с каналом со стороны сервера
- •Пример приложения, использующего каналы передачи данных Pipes
- •Создание канала Mailslot
- •Открытие канала Mailslot
- •Запись сообщений в канал Mailslot
- •Чтение сообщений из канала Mailslot
- •Определение состояния канала Mailslot
- •Изменение состояния канала Mailslot
- •Пример приложения, использующего каналы передачи данных MailSlot
- •Пример приложения, использующего передачу сообщений между процессами
Изменение состояния канала Mailslot
С помощью функции SetMailslotInfo серверный процесс может изменить время ожидания для канала Mailslot уже после его создания.
Прототип функции SetMailslotInfo приведен ниже:
BOOL SetMailslotInfo( |
|
|
|
HANDLE hMailslot |
// идентификатор канала Mailslot |
|
DWORD dwReadTimeout); |
// время ожидания |
Через параметр hMailslot функции SetMailslotInfo передается идентификатор канала Mailslot, для которого нужно изменить время ожидания.
Новое значение времени ожидания в миллисекундах задается через параметр dwReadTimeout. Вы также можете указать здесь константы 0 или MAILSLOT_WAIT_FOREVER. В первом случае функции, работающие с каналом, вернут управление немедленно, во втором - будут находиться в состоянии ожидания до тех пор, пока не завершится выполняемая операция.
Пример приложения, использующего каналы передачи данных MailSlot
Рассмотрим пример реализации каналов передачи данных MailSlot. Сначала рассмотрим серверную часть.
Объявим переменные, которые будут использоваться в программе, и присвоим им необходимее значения:
BOOL fReturnCode; // Код возврата из функций
DWORD cbMessages; // Размер сообщения в байтах
DWORD cbMsgNumber; // Количество сообщений в каналеMailslot
HANDLE hMailslot // Идентификатор канала Mailslot
LPSTR lpszMailslot Name ="\\\\.\\mailslot\\$Channel$"; // Имя создаваемого канала
char szBuf[512]; // Буфер для передачи данных
через канал
DWORD cbRead; // Количество байт данных,
Через канал
Создаем канал Mailslot, имеющий имя lpszMailslotName:
hMailslot = CreateMailslot(lpszMailslotName, 0, MAILSLOT_WAIT_FOREVER, NULL);
// Если возникла ошибка, выводим ее код и завершаем работу приложения
if(hMailslot== INVALID_HANDLE_VALUE)
{fprintf(stdout,"CreateMailslot: Error %ld\n", GetLastError ());
getch();
return 0;
}
Цикл получения команд через канал:
while(TRUE)
{ // Определяем состояние канала Mailslot
fReturnCode = GetMailslotInfo(hMailslot, NULL, &cbMessages, &cbMsgNumber, NULL);
if(!fReturnCode)
{ fprintf(stdout,"GetMailslotInfo: Error %ld\n", GetLastError ());
getch();
break;
}
// Если в канале есть Mailslot сообщения, читаем первое из них и выводим на экран
if(cbMsgNumber != 0)
{if(ReadFile(hMailslot, szBuf, 512, &cbRead, NULL))
{ printf("Received: <%s>\n", szBuf); // Выводим принятую строку на консоль
// Если пришла команда "exit", завершаем работу приложения
if(!strcmp(szBuf, "exit")) break;
}
else
{ fprintf(stdout,"ReadFile: Error %ld\n", GetLastError ()); getch();
break;
}
}
Sleep (500); // Выполняем задержку на 500 миллисекунд
}
Перед завершением приложения закрываем идентификатор канала Mailslot:
CloseHandle (hMailslot);
Рассмотрим работу клиентской части. Объявим переменные, которые будут использоваться в программе, и присвоим им необходимее значения:
HANDLE hMailslot; // Идентификатор канала Mailslot
char szMailslotName[256]= "\\\\.\\mailslot\\$Channel$"; // Буфер для имени канала
char szBuf[512]; // Буфер для передачи данных через канал
DWORD cbWritten; // Количество байт, переданных
через канал
Создаем канал с процессом MSLOTS
hMailslot = CreateFile (szMailslotName, GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
// Если возникла ошибка, выводим ее код и завершаем работу приложения
if(hMailslot == INVALID_HANDLE_VALUE)
{ fprintf(stdout,"CreateFile: Error %ld\n", GetLastError ());
getch();
return 0;
}
Цикл посылки команд через канал:
while(TRUE)
{ printf("cmd>"); // Выводим приглашение для ввода команды
gets(szBuf); // Вводим текстовую строку
// Передаем введенную строку серверному процессу в качестве команды
if(!WriteFile (hMailslot, szBuf, strlen(szBuf) + 1, &cbWritten, NULL)) break;
// В ответ на команду "exit" завершаем цикл обмена данными с серверным процессом
if(!strcmp(szBuf, "exit")) break;
}
Закрываем идентификатор канала:
CloseHandle (hMailslot);
7.5. Передача сообщений между приложениями
Метод передачи данных между процессами, основанный на использовании файлов, отображенных на виртуальную память, работает достаточно быстро, так как процессы имеют прямой доступ к общим страницам памяти. Тем не менее, при использовании этого метода необходимо заботиться о синхронизации процессов, для чего следует использовать объекты синхронизации.
Если скорость передачи данных не является критичной, можно воспользоваться удобным способом передачи данных, не требующим синхронизации. Этот метод основан на передаче сообщения WM_COPYDATA из одного приложения в другое при помощи функции SendMessage (функцию PostMessage для передачи этого сообщения использовать нельзя).
Сообщение WM_COPYDATA использует оба параметра - wParam и lParam. Через параметр wParam необходимо передать идентификатор окна, посылающего сообщение. Параметр lParam используется для передачи указателя на предварительно заполненную структуру COPYDATASTRUCT, в которой находится ссылка на передаваемые данные.
Если приложение обрабатывает сообщение WM_COPYDATA, то соответствующий обработчик должен вернуть значение TRUE, а если нет - FALSE.
Ниже мы привели формат структуры COPYDATASTRUCT:
Typede fstruct tagCOPYDATASTRUCT |
|
|
|
{ DWORD dwData; |
// 32-разрядные данные |
|
DWORD cbData; |
// размер передаваемого буфера с данными |
|
PVOID lpData;} |
// указатель на буфер с данными |
Перед посылкой сообщения WM_COPYDATA приложение должно заполнить структуру COPYDATASTRUCT.
В поле dwData можно записать произвольное 32-разрядное значение, которое будет передано вместе с сообщением.
В поле lpData вы дополнительно можете записать указатель на область данных, полученную, например, при помощи функции HeapAlloc. Размер этой области следует записать в поле cbData.
Когда функция окна принимающего приложения получит сообщение WM_COPYDATA, она должна скопировать в свой локальный буфер данные, которые были переданы вместе с сообщением. И это единственное, что можно с этими данными сделать. Их, например, нельзя изменять. Не следует также надеяться, что данные сохранятся до обработки другого сообщения, поэтому копирование следует выполнить во время обработки сообщения WM_COPYDATA.
Если вам достаточно передать из одного приложения в другое 32-разрядное значение, в поле lpData можно записать константу NULL.
