скачать рефераты
  RSS    

Меню

Быстрый поиск

скачать рефераты

скачать рефератыУчебное пособие: Ознакомление с приложениями Windows

При нормальной работе первый вызов функции GetWindowLong вернет указатель на объект, так что следующий шаг — вызов функции–диспетчера. Таким образом дополнительные затраты ресурсов на реализацию ООП таким способом оказываются минимальными. В случае разработки классов–наследников от Win0 надо разработать собственную функцию–диспетчер, которая будет вместо процедуры DefWindowProc вызывать диспетчер класса–предка.

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

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

Основы работы с памятью

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

Хендл задачи (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 возвращают так называемый псевдодескриптор[19] процесса (потока). Псевдодескриптор — это некоторая величина, рассматриваемая в качестве дескриптора текущего процесса (потока). То есть эта величина, применяемая в контексте другого процесса (потока), будет описывать его, а не данный поток. Для получения “настоящего” хендла из псевдодескриптора надо воспользоваться функцией:

  BOOL       DuplicateHandle(
           hSourceProcess, hSourceHandle, hTargetProcess, lphTargetHandle,
           fdwAccess, fInherit, fdwOptions
      );

Хендл копии приложения (HINSTANCE) 

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

  int       GetInstanceData( hInstance, pByte, cbData );

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

В Win32 для каждого запущенного приложения (т.е. процесса) выделяется виртуальное адресное пространство в 4Г в едином сегменте. Поэтому данный хендл соответствует не сегменту данных (который описывает весь 4Г сегмент), а адресу в виртуальном пространстве, с которого был загружен данный модуль. В адресном пространстве одного процесса никаких других приложений не существует, поэтому этот хендл не может применяться для обнаружения других копий приложения и тем более для обмена данными между разными копиями приложений. В приложениях 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 3.x хендл модуля часто может быть заменен на хендл копии приложения. В Win32 хендл модуля вообще является синонимом хендла копии приложения. В документации еще встречаются оба термина, как они перекочевали из 16ти битовых Windows, хотя теперь они тождественны.

 

Подробнее о приложении (2)

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

Приложение в среде Windows, как и в среде DOS, содержит так называемую главную функцию — WinMain, вызываемую при запуске приложения.  Приложение завершается при окончании работы этой функции.

Обычно, хотя это и не обязательно, функция WinMain реализует следующую схему:

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

·   создается главное окно приложения, для чего часто регистрируется новый класс окон (оконная функция);

·   организуется цикл обработки сообщений приложения. Обычно цикл завершается при закрытии главного окна приложения;

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

Замечание 1. Если приложение содержит непродолжительные (порядка 1 сек.) операции, не требующие взаимодействия с пользователем (например, только файл–ориентированный ввод–вывод или настройка другого приложения), то эти действия могут быть выполнены непосредственно функцией WinMain без создания окон и без организации цикла обработки сообщений.

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

Замечание 3. В момент вызова функции WinMain ей, через аргументы, передается несколько параметров, например хендл копии приложения hInstance. До вызова WinMain приложение “не знает” этих данных.  Поэтому могут возникать сложности с использованием статических конструкторов объектно–ориентированных языков (C++).

!!!!!!!!Фокус ввода!!!!!!

В Windows существует определенная путаница терминов. Попробуем разобраться с некоторыми из них. Как известно, окно может находиться в нескольких состояниях:

Максимизированном, то есть быть “распахнутым” на весь экран — при этом внутренняя область окна занимает весь экран, кроме небольших полос сверху — где размещается заголовок и меню, снизу — горизонтальная полоса прокрутки и справа вертикальная полоса прокрутки; рамка окна находится за пределами экрана, мы ее не видим, перемещение окна невозможно.

Для максимизации окна мы можем воспользоваться функцией ShowWindow со следующими возможными параметрами:

  ShowWindow( hWnd, SHOW_FULLSCREEN );
      ShowWindow( hWnd, SW_SHOWMAXIMIZED );
      ShowWindow( hWnd, SW_MAXIMIZE );

максимизированное окно всегда активно и имеет фокус ввода. Когда какое–либо окно максимизируется, все остальные верхние окна получают сообщение WM_SIZE, информирующее о том, что они “закрыты” сверху максимизированным окном.

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

  BOOL  IsZoomed( hWnd );

При использовании системного меню операции максимизации окна соответствует пункт Maximize, выбор которого порождает системную команду SC_MAXIMIZE (или синоним SC_ZOOM). (см. сообщение WM_SYSCOMMAND)

Здесь вместо термина maximize может использоваться zoom.

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

  ShowWindow( hWnd, SHOW_ICONWINDOW );
      ShowWindow( hWnd, SW_SHOWMINIMIZED );
      ShowWindow( hWnd, SW_SHOWMINNOACTIVE );
      ShowWindow( hWnd, SW_MINIMIZE );
      CloseWindow( hWnd );

Разные способы, использующие ShowWindow, отличаются только правилами активации окна. SW_SHOWMINIMIZED и SHOW_ICONWINDOW отображает окно в виде пиктограммы, делая его активным; SW_SHOWMINNOACTIVE не изменяет текущего активного окна; SW_MINIMIZE (как и функция CloseWindow) делает активным следующее окно в списке Windows.  Последний способ эффективен при минимизации главного окна приложения так как минимизированное главное окно обычно обозначает передачу активности другому приложению.

Проверить состояние окна можно с помощью функции

  BOOL IsIconic( hWnd );

При использовании системного меню превращению окна в иконку соответствует пункт Minimize, порождающий системную команду SC_MINIMIZE (или синоним SC_ICON). (см. сообщение WM_SYSCOMMAND)

В этом случае используется сразу три разных термина для обозначения одного и того–же: minimize, close и iconic. При этом функция CloseWindow является единственной, интерпретирующей термин close таким способом; в остальных случаях close означает действительно закрытие (иногда уничтожение) окна. Здесь же надо, что термин open, применяемый к минимизированному окну обозначает его максимизацию или восстановление нормальных размеров.

Нормальным, то есть мы видим (или можем увидеть) его рамку, мы можем перемещать окно по экрану. Когда окно находится в нормальном состоянии, то для него определены максимально и минимально допустимый размеры. Эти размеры нельзя путать с максимизированным и минимизированным состояниями. Максимальный размер нормального окна может даже превышать размер окна в максимизированном состоянии, минимальный размер это обычно такой размер, при котором окно еще может быть корректно представлено в виде окна.

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

  OpenIcon( hWnd );

или, как из минимизированного, так и из максимизированного состояния можно пользоваться функцией ShowWindow с параметрами:

  ShowWindow( hWnd, SHOW_OPENWINDOW );
      ShowWindow( hWnd, SW_SHOWNORMAL );
      ShowWindow( hWnd, SW_RESTORE );
      ShowWindow( hWnd, SW_SHOWNOACTIVATE );

В документации (SDK Help) указано, что SW_RESTORE и SW_SHOWNORMAL эквивалентны, но это далеко не так — SW_RESTORE восстанавливает предыдущее состояние, а не нормальное. То есть, если Вы минимизировали окно из максимизированного, то SW_RESTORE вернет Вас к максимизированному окну, а SW_SHOWNORMAL к нормальному. SW_SHOWNORMAL имеет синоним SHOW_OPENWINDOW.

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

Несколько замечаний: На самом деле Windows не является настоящей объектно–ориентированной средой. Хотя окно и может быть названо объектом ООП, но лишь с достаточной натяжкой. Самое существенное отличие окна в Windows от объекта ООП заключается в том, что сообщение, обрабатываемое оконной функцией, во многих случаях не выполняет действий, а является “информационным”, указывая на то, что над окном выполняется та или иная операция какой–либо внешней функцией.

Поясним это на примере создания окна. В случае ООП для уничтожения объекта он должен получить сообщение “destroy”, обработка которого приведет к его уничтожению. В Windows сообщение WM_DESTROY не выполняет никаких функций по уничтожению окна. Оно только информирует окно о том, что в это время окно уничтожается средствами обычной функциональной библиотеки, например посредством функции DestroyWindow. Вы можете вообще игнорировать это сообщение, возвращать любое значение, вызывать или не вызывать функцию обработки по умолчанию — окно все равно будет уничтожено.

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

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

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

 

Настройка приложений

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

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

Такие файлы (обычно имеющие расширение .INI) являются обычными ASCII–файлами, разделенными на секции, начинающиеся с имени секции, заключенного в квадратные скобки. Далее следует список параметров в виде параметр=значение, каждый параметр размещается в отдельной строке. В этот файл можно вставлять комментарии строки начинающиеся с ‘;’.

Пример взят из файла WORKSHOP.INI:

  [User Controls]
      BorShade=E:\BORLANDC\WORKSHOP\BWCC.DLL

  [RWS_Bitmap]
      PercentLeft=50
      ZoomLeft=1
      ZoomRight=1
      bVert=0

  [RWS_Font]
      PercentLeft=50
      ZoomLeft=4
      ZoomRight=1
      bVert=1

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

  int GetProfileInt(lpszSection, lpszEntry, nDefault);
      int  GetProfileString(
           lpszSection, lpszEntry, lpszDefault, lpsBuffer, nMaxBuffer
      );
      BOOL WriteProfileString(lpszSection, lpszEntry, lpszString);

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

С помощью функции GetProfileString можно получить список имен всех параметров в секции, указав lpszEntry равным NULL. При этом имена параметров секции будут скопированы в буфер последовательно друг за другом, каждое имя будет заканчиваться байтом '\0' и после последнего имени будут стоять два байта '\0'.

Функция WriteProfileString позволяет не только записывать параметры, но и удалять, для чего надо указать lpszString равным NULL. Можно удалить целиком всю секцию, указав для этого lpszEntry равным NULL.

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

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

  int GetPrivateProfileInt( lpszSection, lpszEntry, nDefault, lpszIniFile );
      int GetPrivateProfileString(
           lpszSection, lpszEntry, lpszDefault, lpsBuffer, nMaxBuffer, lpszIniFile
      );
      BOOL WritePrivateProfileString( lpszSection, lpszEntry, lpszString, lpszIniFile );

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

Реестр Windows

RegOpenKey       Opens a specified key

RegCreateKey      Creates a specified key

RegCloseKey       Closes a key and releases the key's handle

RegQueryValue   Retrieves the text string for a specified key

RegSetValue        Associates a text string with a specified key

RegDeleteKey      Deletes a specified key

RegEnumKey      Enumerates the subkeys of a specified key

#include shellapi.h

LONG RegOpenKey(hkey, lpszSubKey, lphkResult);
HKEY hkey;        /* handle of an open key        */
LPCSTR lpszSubKey;  /* address of string for subkey to open     */
HKEY FAR* lphkResult;       /* address of handle of open key     */

The RegOpenKey function opens the specified key.

Parameter   Description

hkey  Identifies an open key (which can be HKEY_CLASSES_ROOT). The key opened by the RegOpenKey function is a subkey of the key identified by this parameter. This value should not be NULL.

lpszSubKey         Points to a null-terminated string specifying the name of the subkey to open.

lphkResult  Points to the handle of the key that is opened.

Returns

The return value is ERROR_SUCCESS if the function is successful. Otherwise, it is an error value.

Comments

Unlike the RegCreateKey function, the RegOpenKey function does not create the specified key if the key does not exist in the database.

Example

  char szBuff[80];
      LONG cb;
      HKEY hkStdFileEditing;

  if (
           RegOpenKey(
                 HKEY_CLASSES_ROOT,
                 "NewAppDocument\\protocol\\StdFileEditing",
                 &hkStdFileEditing
           ) == ERROR_SUCCESS
      ) {

        cb = sizeof(szBuff);
           if (
                 RegQueryValue(
                       hkStdFileEditing,
                       "handler",
                       szBuff,
                       &cb
                 ) == ERROR_SUCCESS
                 && lstrcmpi("nwappobj.dll", szBuff) == 0
           ) RegDeleteKey(hkStdFileEditing, "handler");
           RegCloseKey(hkStdFileEditing);
      }


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

[2] В принципе требования могут и нарушаться. Так приложения под Windows 3.x сравнительно легко могут получить доступ к аппаратуре, хотя делать это не рекомендуется. Приложениям Win32 уже значительно сложнее получить доступ — система лучше защищена от таких попыток, особенно Windows NT.

[3] Строго говоря, обычный DOS тоже может работать с различными файловыми системами — для CD‑ROM дисков специально спроектирована своя собственная файловая система (CDFS). При этом надо установить драйвер CD–ROM, обеспечивающий физический доступ к диску, и программу MSCDEX, которая осуществляет работу с дисками в формате CDFS.

[4] Кроме некоторых особых случаев, связанных с обработкой критичных по времени процессов, скажем некоторых операций ввода/вывода, взаимодействия с периферией и пр. Однако обычно такие задачи решаются драйверами устройств, так что приложение об этом опять–же не ведает.

[5] Точнее при уничтожении. Термин “закрытие” в Windows часто имеет другой смысл, в том числе сворачивание окна в пиктограмму.

[6] В Win32 API заголовочный файл windows.h просто включает в себя набор директив #include для включения необходимых заголовочных файлов и директив условной компиляции.

[7] Строка ASCII — строка символов таблицы ASCII, то есть обычный текст. Однако при программировании часто используются строки либо со специальным завершающим символом (в C это байт с кодом 0 — ASCIIZ), либо с указанием длины строки в виде лидирующего байта (ASCIIB) или слова (ASCIIW).

[8] При необходимости выяснить наличие других копий приложения в системе можно попробовать найти другие окна, принадлежащие тому–же классу, что и главное окно нашего приложения. Это легко делается с помощью функции FindWindow. Этот метод работает как в Windows API, так и в Win32 API.

[9] При задании хендла окна–родителя окна могут находиться либо в отношениях родительское/дочернее (parent/child), либо в отношениях владелец/используемое (owner/owned), в зависимости от наличия стиля WS_CHILD у порожденного окна.

[10] В некоторых руководствах в простейших примерах обходятся без трансляции вообще. Однако это является не совсем корректным, так как функция TranslateMessage распознает комбинацию клавиш Alt+Space как команду нажатия на кнопку системного меню. Конечно без нее приложение будет работать, но не в полной мере реализует стандартный клавиатурный интерфейс.

[11] В Windows все указатели, которые получает или передает Вам система являются 32х разрядными. В случае Windows API это будут дальние (far) указатели, а в случае Win32 это ближние (near), так как они уже являются 32х разрядными.

[12] В первых версиях Windows в результате объединения формировался новый неверный прямоугольник. В современных версиях вместо неверного прямоугольника реально формируется неверный регион, который может иметь сложную форму.

[13] Для проверки возможностей аппаратуры следует использовать функцию GetDeviceCaps.

[14] В частном случае — с верхним левым углом самого окна, включая его обрамление (см. описание функции GetWindowDC).

[15] Кроме случаев применения сохраняемых контекстов. См. стили класса окон CS_OWNDC и CS_CLASSDC.

[16] Панель диалога является родительским окном для всех элементов управления, размещенных на этой панели, включая статические — рамки, текст и прочее.

[17] Ориентировочно, начиная с компиляторов для Windows 3.0

[18] Это связано с тем, что параметр wParam имеет тип UINT — то есть он в Windows API представляет собой 16ти разрядное слово, а в Win32 API — 32х разрядное. Кроме того, в младшем или старшем слове lParam часто размещается хендл, который в Windows API 16ти разрядный. К сожалению в Win32 API хендлы 32х разрядные, так что уместить его на прежнем месте не представляется возможным.

[19] Это просто некоторая константа, используемая для обозначения «текущего потока» или «текущего процесса».


Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11


Новости

Быстрый поиск

Группа вКонтакте: новости

Пока нет

Новости в Twitter и Facebook

  скачать рефераты              скачать рефераты

Новости

скачать рефераты

Обратная связь

Поиск
Обратная связь
Реклама и размещение статей на сайте
© 2010.