

25. Средства межпроцессорного взаимодействия Windows
Очень часто возникают ситуации, когда данные должны быть доступны для нескольких программ, или когда для одной программы требуются результаты работы второй программы. С развитием операционных систем, реализация обмена данными между процессами (Interprocess Communications, IPC) имеет множество форм.
Для изучения предлагается два наиболее используемых и простых механизма IPC: передача участка памяти одного процесса другому при помощи сообщения WM_COPYDATA и реализация памяти общего доступа с использованием механизма отображения файлов на оперативную память.
Приложения Windows состоят из множества объектов, которые взаимодействуют друг с другом, обмениваясь сообщениями. Источниками сообщений могут быть: пользователь, оперирующий с клавиатурой и мышью, среда Windows, посылающая сообщения приложениям, другие приложения, обменивающиеся информацией. Обмен данными при помощи сообщения заключается в послании сообщения окну другого процесса по известному идентификатору окна. Следовательно, такой способ обмена данными может быть использован при работе процессов на одном компьютере. Для передачи данных другому процессу, нужно отправить оконное сообщение WM_COPYDATA, в поле параметров которого указать адрес блока памяти для передачи и размер блока. Windows передает эти данные другому процессу в приемлемой для прочтения форме.
Это напоминает пересылку копии документа по почте. Владелец документа делает копию этого документа и пересылает ее по почте. Человек, получивший копию документа, может внести в эту копию коррективы, однако об этих изменениях не узнает владелец оригинала. Если же владелец оригинала примет решение изменить изначальный документ, получатель копии также не узнает об этих изменениях, так как будет иметь дело с копией, которая была сделана до модификации оригинала.
Механизм проецирования файла на оперативную память используется для организации памяти общего доступа. Если один процесс создает объект “проецируемый файл”, другие процессы могут открыть этот объект и использовать его для работы с этим же файлом. Таким образом, все эти процессы будут обладать сходным представлением о содержимом файла. Другими словами, если один из процессов вносит в файл изменения, эти изменения немедленно становятся заметными для всех остальных процессов, работающих с файлом.
Очевидно, что это одна из форм памяти общего доступа, однако при этом данные, к которым осуществляется совместный доступ, располагаются в файле, который хранится на жестком диске. Это существенно снижает производительность, так как любое обращение к памяти общего доступа будет сопровождаться операцией файлового ввода/вывода. Но в Windows существует механизм создания области памяти, которая может стать доступной для нескольких процессов, однако этой области не будет соответствовать конкретный дисковый файл, так как вместо него будет использоваться оперативная память.
Организация работы с сообщениями
Сообщение представляет собой структуру
Для пересылки сообщения окну другого процесса в большинстве случаев следует использовать вызов SendMessage().
Чтобы получить дескриптор окна, которому надо передать сообщение, можно воспользоваться системным вызовом FindWindow().
Функция возвращает дескриптор окна или NULL в случае неудачного поиска.
Для передачи сообщения WM_COPYDATA следует передать предать вызову SendMessage() структуру COPYDATASTRUCT.
Чтобы процесс, окну которого было отправлено сообщение, смог его обработать, нужно в код его программы включить соответствующую функцию обработки сообщения.
Для введения собственного обработчика сообщения Windows в среде C++Builder надо сделать следующее:
создать в объявлении класса карту сообщений и ввести в неё те сообщения, которые вы хотели бы обрабатывать сами;
добавить в объявлении класса объявления вводимых вами обработчиков;
описать эти обработчики в модуле.
Следует обратить внимание, что передаваемый в обработчик параметр представляет собой структуру, через которую в обработчик передаются параметры сообщения, а из обработчика возвращается значение поля Result.
Можно создавать собственные сообщения и работать с ними также как и со стандартными. Номера собственных сообщений должны отсчитываться от константы WM_USER, которая соответствует первому номеру сообщения пользователя.
Отправление сообственного сообщения:
Для принятия этого сообщения окном “Окно1” приложения нужно в программном коде приложения написать обработчик сообщения. А также соответственно сделать все необходимые объявления констант и карты сообщений.
Чтобы воспользоваться этим механизмом, необходимо создать объект “проецируемый файл” при помощи вызова CreateFileMapping().
Функция возвращает возвращает дескриптор созданного события и увеличивает счетчик числа пользователей объекта на 1. Следовательно, при завершении работы c ним надо вызвать функцию CloseHandle(). Этот вызов надо также сделать и для дескриптора файла hFile.
Можно открыть уже существующий объект “проецируемый файл” при помощи вызова OpenFileMapping(), указав при этом его имя.
Функция возвращает дескриптор объекта и увеличивают счетчик числа его пользователей на единицу. Если объект с таким именем не существует, то функция возвращает NULL.
После этого процесс может использовать полученный дескриптор для обращения к вызову MapViewOfFile(). Этот вызов возвращает адрес области памяти общего доступа. Этот адрес может быть разным для разных процессов, так как файл может проецироваться по разным адресам в адресном пространстве каждого процесса. Используя указатель на адрес области памяти общего доступа, каждый процесс имеет возможность записать или считать оттуда данные.
Последние три параметра относятся к резервированию региона адресного пространства и увязке его с памятью общего доступа. Рекомендуется их задать равными нуль, благодаря чему эти операции система выполнит сама.
Функция при успешном выполнении возвращает указатель (void*) на начало участка общей памяти, в случае неудачи - NULL.
Если область памяти общего доступа больше не нужна, ее следует освободить при помощи вызова UnmapVlewOfFile(), а затем закрыть дескриптор объекта “проецируемый файл” при помощи вызова CloseHandle
Для изучения предлагается два наиболее используемых и простых механизма IPC: передача участка памяти одного процесса другому при помощи сообщения WM_COPYDATA и реализация памяти общего доступа с использованием механизма отображения файлов на оперативную память.
Приложения Windows состоят из множества объектов, которые взаимодействуют друг с другом, обмениваясь сообщениями. Источниками сообщений могут быть: пользователь, оперирующий с клавиатурой и мышью, среда Windows, посылающая сообщения приложениям, другие приложения, обменивающиеся информацией. Обмен данными при помощи сообщения заключается в послании сообщения окну другого процесса по известному идентификатору окна. Следовательно, такой способ обмена данными может быть использован при работе процессов на одном компьютере. Для передачи данных другому процессу, нужно отправить оконное сообщение WM_COPYDATA, в поле параметров которого указать адрес блока памяти для передачи и размер блока. Windows передает эти данные другому процессу в приемлемой для прочтения форме.
Это напоминает пересылку копии документа по почте. Владелец документа делает копию этого документа и пересылает ее по почте. Человек, получивший копию документа, может внести в эту копию коррективы, однако об этих изменениях не узнает владелец оригинала. Если же владелец оригинала примет решение изменить изначальный документ, получатель копии также не узнает об этих изменениях, так как будет иметь дело с копией, которая была сделана до модификации оригинала.
Механизм проецирования файла на оперативную память используется для организации памяти общего доступа. Если один процесс создает объект “проецируемый файл”, другие процессы могут открыть этот объект и использовать его для работы с этим же файлом. Таким образом, все эти процессы будут обладать сходным представлением о содержимом файла. Другими словами, если один из процессов вносит в файл изменения, эти изменения немедленно становятся заметными для всех остальных процессов, работающих с файлом.
Очевидно, что это одна из форм памяти общего доступа, однако при этом данные, к которым осуществляется совместный доступ, располагаются в файле, который хранится на жестком диске. Это существенно снижает производительность, так как любое обращение к памяти общего доступа будет сопровождаться операцией файлового ввода/вывода. Но в Windows существует механизм создания области памяти, которая может стать доступной для нескольких процессов, однако этой области не будет соответствовать конкретный дисковый файл, так как вместо него будет использоваться оперативная память.
Организация работы с сообщениями
Сообщение представляет собой структуру
Для пересылки сообщения окну другого процесса в большинстве случаев следует использовать вызов SendMessage().
Чтобы получить дескриптор окна, которому надо передать сообщение, можно воспользоваться системным вызовом FindWindow().
Функция возвращает дескриптор окна или NULL в случае неудачного поиска.
Для передачи сообщения WM_COPYDATA следует передать предать вызову SendMessage() структуру COPYDATASTRUCT.
Чтобы процесс, окну которого было отправлено сообщение, смог его обработать, нужно в код его программы включить соответствующую функцию обработки сообщения.
Для введения собственного обработчика сообщения Windows в среде C++Builder надо сделать следующее:
создать в объявлении класса карту сообщений и ввести в неё те сообщения, которые вы хотели бы обрабатывать сами;
добавить в объявлении класса объявления вводимых вами обработчиков;
описать эти обработчики в модуле.
Следует обратить внимание, что передаваемый в обработчик параметр представляет собой структуру, через которую в обработчик передаются параметры сообщения, а из обработчика возвращается значение поля Result.
Можно создавать собственные сообщения и работать с ними также как и со стандартными. Номера собственных сообщений должны отсчитываться от константы WM_USER, которая соответствует первому номеру сообщения пользователя.
Отправление сообственного сообщения:
Для принятия этого сообщения окном “Окно1” приложения нужно в программном коде приложения написать обработчик сообщения. А также соответственно сделать все необходимые объявления констант и карты сообщений.
Организация общей памяти объектами “проецируемый файл”
Чтобы воспользоваться этим механизмом, необходимо создать объект “проецируемый файл” при помощи вызова CreateFileMapping().
Функция возвращает возвращает дескриптор созданного события и увеличивает счетчик числа пользователей объекта на 1. Следовательно, при завершении работы c ним надо вызвать функцию CloseHandle(). Этот вызов надо также сделать и для дескриптора файла hFile.
Можно открыть уже существующий объект “проецируемый файл” при помощи вызова OpenFileMapping(), указав при этом его имя.
Функция возвращает дескриптор объекта и увеличивают счетчик числа его пользователей на единицу. Если объект с таким именем не существует, то функция возвращает NULL.
После этого процесс может использовать полученный дескриптор для обращения к вызову MapViewOfFile(). Этот вызов возвращает адрес области памяти общего доступа. Этот адрес может быть разным для разных процессов, так как файл может проецироваться по разным адресам в адресном пространстве каждого процесса. Используя указатель на адрес области памяти общего доступа, каждый процесс имеет возможность записать или считать оттуда данные.
Последние три параметра относятся к резервированию региона адресного пространства и увязке его с памятью общего доступа. Рекомендуется их задать равными нуль, благодаря чему эти операции система выполнит сама.
Функция при успешном выполнении возвращает указатель (void*) на начало участка общей памяти, в случае неудачи - NULL.
Если область памяти общего доступа больше не нужна, ее следует освободить при помощи вызова UnmapVlewOfFile(), а затем закрыть дескриптор объекта “проецируемый файл” при помощи вызова CloseHandle