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

Меню

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

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

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

Все время, пока пользователь работает с приложением, работает цикл обработки сообщений этого приложения, обеспечивающий доставку сообщений окнам. В конце работы приложения этот цикл, очевидно, должен завершиться. В принципе, можно сделать так, что бы в цикле проверялось наличие окон у приложения. При закрытии всех окон цикл тоже должен завершить свою работу. Однако можно несколько упростить задачу — и в Windows именно так и сделано — вместо проверки наличия окон можно предусмотреть специальный метод завершения цикла при получении последним окном (обычно это главное окно приложения) сообщения о его уничтожении (WM_DESTROY). Для этого применяется специальное сообщение WM_QUIT, которое посылается не какому–либо окну, а всему приложению в целом. При извлечении этого сообщения из очереди цикл обработки сообщений завершается. Для посылки такого сообщения предусмотрена специальная функция — PostQuitMessage.

После завершения цикла обработки сообщений приложение уничтожает оставшиеся ненужные объекты и возвращает управление операционной системе.

Сейчас в качестве примера мы рассмотрим простейшее приложение для Windows, традиционную программу “Hello, world!”. После этого подробнее рассмотрим, как это приложение устроено. Здесь же можно заметить, что при создании практически любых, написанных на “C”, приложений для Windows этот текст может использоваться в качестве шаблона.

Пример 1A первое приложение

Файл 1a.cpp

#define STRICT
#include <windows.h>

#define  UNUSED_ARG(arg)      (arg)=(arg)
static   char    szWndClass[] = "test window";

LRESULT WINAPI _export WinProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
{
      UNUSED_ARG( wParam );
      UNUSED_ARG( lParam );
      PAINTSTRUCT    ps;

  switch ( uMsg ) {
      case WM_CREATE:
           return 0L;

  case WM_PAINT:
           BeginPaint( hWnd, &ps );
           TextOut( ps.hdc, 0, 0, "Hello, world!", 13 );
           EndPaint( hWnd, &ps );
           return 0L;

  case WM_DESTROY:
           PostQuitMessage( 0 );
           return 0L;

  default:
           break;
   }
   return DefWindowProc( hWnd, uMsg, wParam, lParam );
}

static BOOL init_instance( HINSTANCE hInstance )
{
      WNDCLASS             wc;

  wc.style =            0L;
      wc.lpfnWndProc =    WinProc;
      wc.cbClsExtra =        0;
      wc.cbWndExtra =           0;
      wc.hInstance =          hInstance;
      wc.hIcon =                 LoadIcon( NULL, IDI_APPLICATION );
      wc.hCursor =       LoadCursor( NULL, IDC_ARROW );
      wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
      wc.lpszMenuName = NULL;
      wc.lpszClassName = szWndClass;
      return RegisterClass( &wc ) == NULL ? FALSE : TRUE;
}

int PASCAL WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpszCmdLine, int nCmdShow )
{
      UNUSED_ARG( lpszCmdLine );
      MSG         msg;
      HWND     hWnd;

  if ( !hPrevInst ) {
           if ( !init_instance( hInst ) ) return 1;
      }

  hWnd= CreateWindow(
           szWndClass, "window header", WS_OVERLAPPEDWINDOW,
           CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
           NULL, NULL, hInst, NULL
      );

  if ( !hWnd ) return 1;

  ShowWindow( hWnd, nCmdShow );
      UpdateWindow( hWnd );

  while ( GetMessage( &msg, NULL, NULL, NULL ) ) {
           TranslateMessage( &msg );
           DispatchMessage( &msg );
      }

  return msg.wParam;
}

Рисунок 1. Приложение 1a.cpp в среде Windows 3.x или Windows NT 3.x (слева) или в среде Windows–95 или Windows NT 4.0 (справа).

В зависимости от платформы, на которой запускается это приложение, внешний вид окна может несколько изменяться. Это связано с изменившимся интерфейсом пользователя при переходе от Windows 3.x и Windows NT 3.x к Windows–95 и Windows NT 4.0.

Далее мы рассмотрим исходный текст более подробно. При первом взгляде на него обращают на себя внимание сразу несколько необычных (по сравнению с программами для DOS) вещей:

·   новые типы данных

·   странные имена переменных

·   обилие используемых функций и передаваемых им параметров

Примерно в таком порядке мы и рассмотрим эти вопросы.

 

Новые типы данных

Итак, еще раз рассмотрим первое Windows–приложение (1a.cpp).

Обычно в начале “С”–программы помещается директива препроцессора #include для включения файла, содержащего основные определения и прототипы функций. При написании Windows–приложений вы должны включить файл WINDOWS.H. Этот файл содержит определения типов, констант и функций, используемых в Windows[6].

В приложении перед включением WINDOWS.H определяется специальный символ STRICT:

  #define STRICT
      #include <windows.h>

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

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

Для 16ти и 32х разрядных платформ существенно различаются режимы адресации. Например, для 32х разрядных машин практически не применяются near и far модификаторы адреса (Win32 требует, что бы приложения разрабатывались в 32х разрядной flat–модели памяти, где на все про все отводится один 32х разрядный сегмент, размером до 4Г).  Кроме того, стандартом C предполагается, что тип данных int имеет длину одно слово. То есть для 16ти разрядных машин он совпадает с типом short int, а для 32х разрядных с типом long int. Это приводит к частичной непереносимости С–программ с одной платформы на другую.

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

Новое название Значение для Windows API Значение для Win32 API

Символы (#define)
FAR
NEAR
PASCAL
LONG
VOID
NULL
WINAPI
CALLBACK


far
near
pascal
long
void
0
pascal far
pascal far




pascal
long
void
0
pascal
pascal

Типы (typedef)
BOOL
BYTE
WORD
DWORD
UINT
NPSTR
PSTR
LPSTR
LPCSTR
WPARAM
LPARAM
LRESULT
FARPROC
HANDLE
HFILE
HWND
HINSTANCE
HDC


int
unsigned char
unsigned short int
unsigned long int
unsigned int
char near*
char *
char far*
const char far*
UINT
LONG
LONG
(far pascal *)(void)
unsigned int
HANDLE
HANDLE
HANDLE
HANDLE


int
unsigned char
unsigned short int
unsigned long int
unsigned int
char *
char *
char *
const char *
UINT
LONG
LONG
(pascal *)( void )
unsigned int
HANDLE
HANDLE
HANDLE
HANDLE

Практически для всех определенных типов существуют типы “указатель на...”. Ближние указатели строятся с помощью префикса NP, а дальние — LP, указатели, соответствующие принятой модели памяти, строятся с помощью префикса P. Например, BYTE тип, представляющий отдельный байт, LPBYTE дальний указатель на байт, а NPBYTE ближний указатель. Исключение — тип VOID, он имеет только дальний указатель LPVOID.

Внимательнее разберемся с типом HANDLE (и со всеми производными” от него): Дело в том, что Windows создает специальные структуры данных, описывающих требуемые объекты (например окно). Эта структура данных зачастую принадлежит не вашему приложению, а самой системе. Для того, что бы этот объект можно было идентифицировать, вводится специальное понятие хендл (дескриптор, handle). Хендл в Windows это просто целое число, иногда номер, присвоенный данному объекту, причем значение NULL указывает на несуществующий объект. Единственное исключение — HFILE, для которого определено специальное значение — HFILE_ERROR, равное -1 (это связано с тем, что хендл файла первоначально был заимствован у DOS, где хендл 0 обозначает стандартное устройство вывода stdout). Понятие хендла в Windows используется очень широко, а для облегчения контроля типов используется большое количество производных от хендла типов.

Win32

Здесь же надо еще раз отметить, что для Win32 API всегда применяется 32х разрядная flat–модель памяти. В этом случае модификаторы far и near не применяются. Кроме того хендл, соответствующий типу unsigned int, становится 32х разрядным. Это на самом деле приводит к изрядным сложностям при переходе с платформы на платформу. Дело в том, что в Windows API хендл часто объединяется с какими–либо дополнительными данными и размещается в одном двойном слове, передаваемом в качестве параметра функции или сообщения, а в Win32 такое уже не получится — хендл сам занимает все двойное слово.

Кроме того, в Win32 API для работы с файлами используется опять–таки хендл, но уже не типа HFILE, а HANDLE. При этом нулевое значение по–прежнему является допустимым и обозначает стандартное устройство вывода, а значение -1 — неверный хендл. Для обозначения неверного хендла файла определен символ INVALID_HANDLE_VALUE, равный -1. Для других хендлов, кроме хендлов файлов, этот символ не применяется, так как для индикации ошибки применяется значение 0. При этом тип HFILE и символ HFILE_ERROR определены также, как и в 16ти разрядных Windows — в виде 16ти разрядного целого числа. В принципе допустимо простое приведение типов, однако в будущих реализациях Windows API ситуация может измениться, так как тип HANDLE соответствует 32х разрядному числу.

Венгерская нотация

При чтении текстов C—программ и документации Вы обратите внимание на несколько странное написание имен переменных и функций.  Например:

  lpszFileName, wNameLength

Разработчики Windows рекомендуют применять специфичные правила описания имен переменных, которые получили название “венгерская нотация” по национальности программиста Charles Simonyi из Microsoft, предложившего ее. Применение венгерской нотации улучшает читаемость программ и уменьшает вероятность ошибки. Хотя, конечно, это дается ценой увеличения длины имен переменных.

Хорошим программистским правилом является использование мнемонических имен переменных.  Венгерская нотация предполагает не только применение мнемоники для определения смысла переменной (как, например, FileSize), но и включение ее типа в имя. Например lpszFileName обозначает дальний указатель на ASCIIZ[7] строку символов, содержащую имя файла.

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

обозначающий символ название обозначаемого типа пояснение
c char символ
by BYTE байт
n int целое число
x short координата или размер
y short координата или размер
i int целое число
f, b BOOL логическая величина
w WORD слово без знака
h HANDLE хендл
l LONG длинное целое со знаком
dw DWORD длинное целое без знака
e FLOAT число с плавающей запятой
*fn функция
s строка
sz строка, оканчивающаяся '\0' (ASCIIZ)
p * указатель на ...
lp far* дальний указатель на ...
np near* ближний указатель на ...

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

Так, в качестве примера можно привести название поля cbWndExtra в структуре WNDCLASS. В данном случае префикс cb расшифровывается как Count of Bytes.

 


Структура приложения Windows

Итак, еще раз посмотрим на приложение 1a.cpp и вспомним, что надо сделать для написания приложения:

·   написать оконную функцию;

·   зарегистрировать эту функцию в Windows;

·   создать окно, принадлежащее данному классу;

·   обеспечить работу приложения, обрабатывая поступающие окну сообщения.

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

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

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

2.  Управление передается специально написанному разработчиками компиляторов startup–коду, который инициализирует приложение, получает необходимую информацию (как, например, командная строка, хендл копии приложения и пр.), запускает конструкторы статических объектов.

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


Новости

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

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

Пока нет

Новости в Twitter и Facebook

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

Новости

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

© 2010.