Смекни!
smekni.com

Окна приложений в среде Windows (стр. 2 из 5)

Если окно восстанавливается или максимизируется из минимизированного состояния, то Ваше окно получит сообщение WM_QUERYOPEN - обрабатывая которое Вы можете разрешить или запретить дальнейшие действия. Если Вы возвращаете TRUE, то окно будет раскрыто, а если Вы вернете FALSE, то окно останется минимизированным.

Замечание 7. Дополнительно надо разобраться с несколькими терминами Windows, которые постоянно применяются, но никак в документации не описаны. Речь идет о хендлах копии приложения (HINSTANCE), модуля (HMODULE) и задачи (HTASK). Все эти хендлы используются разными функциями, причем разница между ними никак не поясняется. Поэтому нам надо рассмотреть эти хендлы более подробно:

· HTASK описывает задачу.

В Windows 3.x под задачей подразумевается конкретный запущеный процесс, для которого определены командная строка, текущая выполняемая инструкция, указатель на стек, переменные окружения, PDB (эквивалент префикса задачи (PSP) в среде DOS) и пр. Хендл задачи можно получить с помощью функции

HTASK GetCurrentTask( void );

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

HANDLE GetCurrentProcess( void );

HANDLE OpenProcess( fdwAccess, fInherit, dwIDProccess );

DWORD GetCurrentProcessId( void );

HANDLE GetCurrentThread( void );

DWORD GetCurrentThreadId( void );

Функции GetCurrentProcess и GetCurrentThread возвращаюттакназываемыйпсевдодескрипторпроцесса (потока). Псевдодескриптор – это некоторая величина, рассматриваемая в качестве дескритора текущего процесса (потока). То есть эта величина, применяемая в контексте другого процесса (потока), будет описывать его, а не данный поток. Для получения “настоящего” хендла надо воспользоваться функцией:

BOOL DuplicateHandle(

hSourceProcess, hSourceHandle, hTargetProcess, lphTargetHandle,

fdwAccess, fInherit, fdwOptions

);

· HINSTANCE описывает копию приложения.

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

int GetInstanceData( hInstance, pByte, cbData );

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

В Win32 для каждого запущенного приложения (т.е. процесса) выделяется виртуальное адресное пространство в 4G в едином сегменте. Поэтому данный хендл описывает не сегмент данных (который описывает весь 4G сегмент), а адрес в виртуальном пространстве, с которого был загружен данный модуль. В адресном пространстве одного процесса никаких других приложений не существует, поэтому этот хендл не может применяться для обнаружения других копий приложения и тем более для обмена данными между разными копиями приложений. В приложениях Win32 hPrevInstance всегда равен NULL, а хендл текущей копии приложения в большинстве случаев совпадает. При необходимости обнаружения других копий приложения надо использовать какие–либо иные методы, например функцию:

HWND FindWindow( lpszClassName, lpszWindowTitle );

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

Для обмена данными между приложениями (процессами) приходится передавать данные из адресного пространства одного процесса в адресное пространство другого. Для выполнения этих операций предусмотрено сообщение WM_COPYDATA. Когда Вы посылаете это сообщение окну, созданному другим процессом, указанные Вами данные копируются в адресное пространство другого процесса и могут быть прочитаны оконной процедурой окна–получателя. Этот механизм может применяться и для обмена данными между 16-ти и 32-х битовыми приложениями, однако для этого необходимо определить номер сообщения WM_COPYDATA и специальную структуру COPYDATASTRUCT для 16-ти битовой платформы – так как файл windows.h не содержит этих определений:

#define WM_COPYDATA 0x004A

typedef struct tagCOPYDATASTRUCT {

DWORD dwData;

DWORD cbData;

LPVOID lpData;

} COPYDATASTRUCT, FAR* PCOPYDATASTRUCT;

· HMODULE описывает отдельный модуль.

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

HMODULE GetModuleHandle( lpszFileName );

int GetModuleFileName( hInstance, lpsBuffer, cbMaxSize );

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

В Win32 хендл модуля является синонимом хендла копии приложения. В документации встречаются оба термина, как они перекочевали из 16-ти битовых Windows, хотя они тождественны.

Сообщения. Посылка и передача сообщений

Ранее, на первых лекциях, мы рассматривали метод передачи сообщений, называемый “посылкой” сообщений (post). При использовании этого метода сообщение ставится в очередь приложения и позже извлекается из нее. Однако этот механизм не всегда удобен, так как не позволяет получить результата обработки сообщения, или дождаться его завершения. Точнее, позволяет, но очень громоздким способом.

Для решения этих задач вводится альтернативный механизм, называемый передачей сообщений. При этом сообщение в очередь не попадает и направляется непосредственно оконной функции. По сути его можно рассматривать как непосредственный вызов оконной функции с передачей ей указанных параметров. Это накладывает некоторые ограничения; так, например, нельзя передавать сообщение WM_QUIT - оно обязательно должно пройти через очередь сообщений, иные сообщения (скажем, клавиатуры) дополнительно обрабатываются в цикле обработки сообщений и их тоже надо посылать а не передавать и т.д.

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

Для посылки и передачи сообщений могут применяться следующие функции:

BOOL PostMessage( hWnd, wMsg, wPar, lPar );

Посылает указанное сообщение окну (через очередь сообщений).

LONG SendMessage( hWnd, wMsg, wPar, lPar );

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

BOOL PostAppMessage( hTask, wMsg, wPar, lPar ); // Windows 3.x

BOOL PostAppMessage( dwProccessId, wMsg, wPar, lPar ); // Win32 API

BOOL PostThreadMessage( dwThreadId, wMsg, wPar, lPar ); // Win32 API

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

Хендл задачи hTask не является хендлом копии приложения. Вы можете использовать функцию GetCurrentTask для получения хендла задачи в среде Windows 3.x, а также функции GetCurrentThreadId и GetCurrentProcessId в Win32 API.

для получения этого хендла.

BOOL PostQuitMessage( wPar );

Посылает сообщение WM_QUIT с заданным параметром wPar вашему приложению. Сообщение WM_QUIT используется для завершения главного цикла обработки сообщений.

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

Сейчас мы займемся изучением основных сообщений, используемых окном. При этом мы рассмотрим несколько типичных последовательностей сообщений, получаемых окном. Так, например, мы рассмотрим последовательность сообщений, получаемых окном при его создании. При этом надо считать, что приводимые сообщения в последовательности являются как бы “скелетом”, а реальная последовательность может иметь большее число сообщений, или некоторые могут отсутствовать. Это определяется характеристиками окна, его свойствами и выполняемой дополнительной обработкой сообщений. (Так, например, последовательности сообщений, получаемых “скрытыми” окнами или окнами в минимизированном состоянии могут существенно отличаться).

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