Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Операционная система Windows 95 для программиста

© Александр Фролов, Григорий Фролов
Том 22, М.: Диалог-МИФИ, 1993, 271 стр.

[Назад] [Содеожание] [Дальше]

1.3. Первое приложение для Microsoft Windows 95

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

Итак, перейдем к практике. Поставим перед собой задачу создать простейшее приложение Win32 с одним главным окном, пока без меню, линейки инструментов Toolbar и других элементов пользовательского интерфейса, специфических для Microsoft Windows 95.

Приложение Window Application

За основу мы возьмем приложение WINDOW из 11 тома "Библиотеки системного программиста".

Внешний вид главного окна 32-разрядного варианта приложения WINDOW, запущенного в среде Microsoft Windows 95, показан на рис. 1.16.

Рис. 1.16. Внешний вид приложения Window Application

Если сделать щелчок левой клавишей мыши по внутренней области окна, на экране появится сообщение (рис. 1.17).

Рис. 1.17. Сообщение, которое появляется после щелчка левой клавишей мыши внутри окна приложения Window Application

Если вы обратили внимание на внешний вид системного меню окон Microsoft Windows 95, то заметили, что вместо ни о чем не говорящей горизонтальной черточки в левой части заголовка окна отображается маленькая пиктограмма. По внешнему виду этой пиктограммы пользователь сможет легко узнать окно вашего приложения.

Надпись на заголовке окна выровнена влево, а не отцентрирована, как это было раньше в Microsoft Windows версии 3.1.

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

Пиктограмма Назначение
Минимизация окна приложения
Восстановление нормального размера окна
Удаление окна, которое приведет к завершению работы приложения (если удаляется главное окно)

Исходные тексты приложения Window Application

Теперь мы перейдем к исходным текстам приложения Window Application. Основной файл исходного текста приложения приведен в листинге 1.1.

Листинг 1.1. Файл window\window.c


#include <windows.h>
#include <windowsx.h>
#include "afxres.h"
#include "resource.h"

// -----------------------------------------------------
// Описание функций
// -----------------------------------------------------

// Функция главного окна
LRESULT WINAPI
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);

// Функция для обработки сообщения WM_CREATE
BOOL WndProc_OnCreate(HWND hWnd, 
  LPCREATESTRUCT lpCreateStruct);

// Функция для обработки сообщения WM_LBUTTONDOWN
void WndProc_OnLButtonDown(HWND hWnd, BOOL fDoubleClick, 
  int x, int y, UINT keyFlags);

// Функция для обработки сообщения WM_DESTROY
void WndProc_OnDestroy(HWND hWnd);

// -----------------------------------------------------
// Глобальные переменные
// -----------------------------------------------------

// Идентификатор приложения
HINSTANCE hInst;

// Название приложения
char szAppName[] = "Window";

// Заголовок главного окна приложения
char szAppTitle[] = "Window Application";

// -----------------------------------------------------
// Функция WinMain
// -----------------------------------------------------
int APIENTRY 
WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
        LPSTR lpCmdLine, int nCmdShow)
{
  WNDCLASSEX wc;
  HWND hWnd;
  MSG msg;
  
  hInst = hInstance;

  // Преверяем, не было ли это приложение запущено ранее
  hWnd = FindWindow(szAppName, NULL);
  if(hWnd)
  {
    // Если окно приложения было свернуто в пиктограмму,
    // восстанавливаем его
    if(IsIconic(hWnd))
      ShowWindow(hWnd, SW_RESTORE);

    // Выдвигаем окно приложения на передний план
    SetForegroundWindow(hWnd);
    return FALSE;
  }

  // Регистрируем класс окна
  memset(&wc, 0, sizeof(wc));
  
  // Поля wc.cbSize и wc.hIconSm определены в структуре
  // WNDCLASSEX, которой можно пользоваться для
  // регистрации класса окна в Windows 95
  wc.cbSize = sizeof(WNDCLASSEX);

  // Поле wc.hIconSm задает идентификатор маленькой
  // пиктограммы, которая будет отображаться в левой
  // части заголовка окна (в области системного меню).
  // Загружаем пиктограмму из ресурсов приложения при
  // помощи функции LoadImage, так как функция
  // LoadIcon может загрузить только обычную пиктограмму
  wc.hIconSm = LoadImage(hInst,
    MAKEINTRESOURCE(IDI_APPICON_SM), IMAGE_ICON, 16, 16, 0);
  
  // Завершаем заполнение структуры WNDCLASSEX
  wc.style = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc = (WNDPROC)WndProc;
  wc.cbClsExtra  = 0;
  wc.cbWndExtra  = 0;
  wc.hInstance = hInst;
  
  // Для загрузки обычной пиктограммы вы можете
  // использовать функцию LoadImage
  wc.hIcon = LoadImage(hInst,
    MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 32, 32, 0);
  
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  wc.lpszMenuName = NULL;
  wc.lpszClassName = szAppName;

  // Вызываем функцию RegisterClassEx, которая выполняет
  // регистрацию окна
  if(!RegisterClassEx(&wc))

    // В случае ошибки пытаемся зарегистрировать окно
    // функцией RegisterClass
    if(!RegisterClass((LPWNDCLASS)&wc.style))
      return FALSE;
    
  // Создаем главное окно приложения
  hWnd = CreateWindow(szAppName, szAppTitle,
    WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 
    0, NULL, NULL, hInst, NULL);
  if(!hWnd) return(FALSE);

  // Отображаем окно
  ShowWindow(hWnd, nCmdShow);
  UpdateWindow(hWnd);

  // Запускаем цикл обработки сообщений
  while(GetMessage (&msg, NULL, 0, 0))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return msg.wParam;
}

// -----------------------------------------------------
// Функция WndProc
// -----------------------------------------------------
LRESULT WINAPI
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch(msg)
  {
    // Для сообщения WM_CREATE назначаем обработчик,
    // расположенный в функции WndProc_OnCreate
    HANDLE_MSG(hWnd, WM_CREATE, WndProc_OnCreate);

    // Для сообщения WM_LBUTTONDOWN назначаем обработчик,
    // расположенный в функции WndProc_OnLButtonDown
    HANDLE_MSG(hWnd, WM_LBUTTONDOWN, WndProc_OnLButtonDown);

    // Для сообщения WM_DESTROY назначаем обработчик,
    // расположенный в функции WndProc_OnDestroy
    HANDLE_MSG(hWnd, WM_DESTROY, WndProc_OnDestroy);

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

// -----------------------------------------------------
// Функция WndProc_OnCreate
// -----------------------------------------------------
BOOL WndProc_OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct)
{
  return TRUE;
}

// -----------------------------------------------------
// Функция WndProc_OnDestroy
// -----------------------------------------------------
// Отключаем предупреждающее сообщение о том, что
// функция типа void возвращает управление при помощи
// оператора return. Этот оператор нужен для
// использования макрокоманды FORWARD_WM_LBUTTONDOWN
#pragma warning(disable: 4098)
void WndProc_OnDestroy(HWND hWnd)
{
  PostQuitMessage(0);
  return FORWARD_WM_DESTROY(hWnd, DefWindowProc);
}

// -----------------------------------------------------
// Функция WndProc_OnLButtonDown
// -----------------------------------------------------

#pragma warning(disable: 4098)
void 
WndProc_OnLButtonDown(HWND hWnd, BOOL fDoubleClick, 
  int x, int y, UINT keyFlags)
{
  MessageBox(NULL, "Hello, 32-bit world!", "Window", MB_OK);

  return FORWARD_WM_LBUTTONDOWN(hWnd, fDoubleClick, 
           x, y, keyFlags, DefWindowProc);
}

Файл resource.h (листинг 1.2) был создан автоматически системой Microsoft Visual C++ и содержит символические определения идентификаторов ресурсов приложения.

Листинг 1.2. Файл window\resource.h


//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by window.rc
//
#define IDI_APPICON                     101
#define IDI_APPICON_SM                  102

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC                     1
#define _APS_NEXT_RESOURCE_VALUE        105
#define _APS_NEXT_COMMAND_VALUE         40001
#define _APS_NEXT_CONTROL_VALUE         1000
#define _APS_NEXT_SYMED_VALUE           101
#endif
#endif

В файле ресурсов определены две пиктограммы - стандартная (с идентификатором IDI_APPICON) и маленькая (с идентификатором IDI_APPICON_SM).

Файл resource.h автоматически включается в файл определения ресурсов window.rc (листинг 1.3). Последний был создан также автоматически системой Microsoft Visual C++.

Листинг 1.3. Файл window\window.rc


//Microsoft Visual C++ generated resource script.
//
#include "resource.h"

#define APSTUDIO_READONLY_SYMBOLS
//////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "afxres.h"

//////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

#ifdef APSTUDIO_INVOKED
//////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//

1 TEXTINCLUDE DISCARDABLE 
BEGIN
    "resource.h\0"
END

2 TEXTINCLUDE DISCARDABLE 
BEGIN
    "#include ""afxres.h""\r\n"
    "\0"
END

3 TEXTINCLUDE DISCARDABLE 
BEGIN
    "\r\n"
    "\0"
END

//////////////////////////////////////////////////////////////
#endif    // APSTUDIO_INVOKED

//////////////////////////////////////////////////////////////
//
// Icon
//
IDI_APPICON             ICON    DISCARDABLE     "window.ico"
IDI_APPICON_SM          ICON    DISCARDABLE     "windowsm.ico"

#ifndef APSTUDIO_INVOKED
//////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
//////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED

Функция WinMain

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

Напомним, что для выполнения проверки мы не можем воспользоваться параметром hPrevInstance, так как для приложений Win32 этот параметр всегда равен NULL.

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

HWND FindWindow(
  LPCTSTR lpClassName,  // указатель на имя класса
  LPCTSTR lpWindowName  // указатель на имя окна
);

Через параметр lpClassName передается указатель на текстовую строку, закрытую двоичным нулем, в которую необходимо записать имя класса искомого окна. Вместо имени можно также передать через этот параметр атом, созданный функцией GlobalAddAtom , соответствующей строке имени класса. С атомами вы уже встречались в 11 томе "Библиотеки системного программиста".

Напомним, что атом является 16-разряной величиной, поэтому вы должны записать его значение в младшую половину 32-разрядного параметра lpClassName. Старшая половина при этом должна содержать нулевое значение.

На базе одного и того же класса можно создать несколько окон. Если вам нужно найти окно с заданным заголовком, то имя заголовка следует передать через параметр lpWindowName. Если же подойдет любое окно, параметр lpWindowName может иметь значение NULL.

Если окно будет найдено, функция FindWindow вернет его идентификатор. В противном случае она возвратит значение NULL.

В нашем случае мы можем ограничится указанием только первого параметра:

hWnd = FindWindow(szAppName, NULL);
if(hWnd)
{
  if(IsIconic(hWnd))
    ShowWindow(hWnd, SW_RESTORE);
  SetForegroundWindow(hWnd);
  return FALSE;
}

Пользователь может не помнить, какие приложения уже запущены, а какие нет. Когда он запускает приложение, делая двойной щелчок по соответствующей пиктограмме, то ожидает что на экране появится его главное окно. И в этом он абсолютно прав. Если приложение Window Application было запущено ранее, целесообразно активизировать и выдвинуть на передний план его главное окно. Это именно то, к чему приготовился пользователь.

Прежде всего мы проверяем, не было ли окно приложения минимизировано. Для этого мы вызываем известную вам из предыдущих томов "Библиотеки системного программиста" функцию IsIconic . Если окно минимизировано, восстанавливаем его нормальный размер с помощью функции ShowWindow , передавая ей в качестве первого параметра идентификатор найденного окна, а в качестве второго - константу SW_RESTORE .

Затем вне зависимости от того, было окно минимизировано или нет, выдвигаем его на передний план и активизируем с помощью функции SetForegroundWindow :

BOOL SetForegroundWindow(
  HWND hwnd // идентификатор активизируемого окна
);

В случае успеха эта функция возвращает значение TRUE, при ошибке - FALSE.

Если была найдена работающая копия приложения Window Application, мы завершаем работу текущей копии приложения. Если же копия работающего приложения не найдена, функция WinMain приступает к инициализации приложения.

Прежде всего выполняется регистрация класса окна. Приложения Win32 должны выполнять такую регистрацию немного не так, как это делают приложения Win16.

Напомним, что для регистрации класса окна приложения Win16 должны заполнить структуру типа WNDCLASS и затем передать ее адрес функции RegisterClass . В операционной системе Microsoft Windows 95 эта структура была расширена и теперь имеет тип WNDCLASSEX :

typedef struct _WNDCLASSEX 
{
  UINT    cbSize; 
  UINT    style;           // --------------------------------
  WNDPROC lpfnWndProc;     // Эта часть структуры WNDCLASSEX
  int     cbClsExtra;      // идентична структуре WNDCLASS
  int     cbWndExtra;      //
  HANDLE  hInstance;       //
  HICON   hIcon;           //
  HCURSOR hCursor;         //
  HBRUSH  hbrBackground;   //
  LPCTSTR lpszMenuName;    //
  LPCTSTR lpszClassName;   // --------------------------------
  HICON   hIconSm; 
} WNDCLASSEX;

В начало структуры было добавлено поле cbSize (размер структуры WNDCLASSEX), в конец - поле hIconSm (идентификатор маленькой пиктограммы, которая отображается в левом верхнем углу заголовка главного окна приложения). В остальном структура WNDCLASSEX в точности соответствует структуре WNDCLASS.

Для того чтобы зарегистрировать класс окна в операционной системе Microsoft Windows 95, вы должны заполнить структуру WNDCLASSEX и передать ее адрес функции RegisterClassEx . Заполнение структуры выполняется следующим образом:

memset(&wc, 0, sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.hIconSm = LoadImage(hInst,
    MAKEINTRESOURCE(IDI_APPICON_SM), IMAGE_ICON, 16, 16, 0);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra  = 0;
wc.cbWndExtra  = 0;
wc.hInstance = hInst;
wc.hIcon = LoadImage(hInst,
  MAKEINTRESOURCE(IDI_APPICON), IMAGE_ICON, 32, 32, 0);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = szAppName;

Для получения идентификатора маленькой пиктограммы мы воспользовались новой функцией LoadImage , так как функция LoadIcon позволяет загрузить только стандартную пиктограмму.

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

HANDLE LoadImage(
  HINSTANCE hInst,     // идентификатор модуля, 
                       // содержащего изображение
  LPCTSTR   lpszName,  // имя или идентификатор изображения
  UINT      uType,     // тип изображения
  int       cxDesired, // желаемая ширина изображения
  int       cyDesired, // желаемая высота изображения
  UINT      fuLoad     // флаги загрузки
);

Прежде всего мы перечислим возможные значения параметра fuLoad, определяющие выполняемые этой функцией действия.

Параметр Описание
LR_LOADFROMFILE Функция загружает изображение из файла, заданного параметром lpszName
LR_DEFAULTSIZE Если значение параметров cxDesired и cyDesired равны нулю, при загрузке изображения используются размеры по умолчанию
LR_LOADREALSIZE Если значение параметров cxDesired и cyDesired равны нулю, при загрузке пиктограммы или курсора используются размеры по умолчанию, взятые из системных метрик
LR_DEFAULTCOLOR Для отображения используется текущий цветовой формат
LR_MONOCROME Изображение загружается как черно-белое (монохромное)
LR_LOADMAP3DCOLORS При загрузке функция ищет в изображении таблицу цветов и заменяет темно-серый, серый и светло-серый цвета на системные, которые используются для того чтобы придать изображению трехмерный вид. Конкретно, выполняется такая замена:Исходный цвет RGB На что меняется128, 128, 128 COLOR_3DSHADOW 192, 192, 192 COLOR_3DFACE 223, 223, 223 COLOR_3DLIGHT
LR_LOADTRANSPARENT Загрузка в "прозрачном" режиме. В процессе загрузки выбирается значение цвета первого пиксела изображения и заменяется соответствующим значением из таблицы цветов, содержащим цвет окна по умолчанию COLOR_WINDOW . Все пикселы изображения, которые используют это значение таблицы, приобретают цвет COLOR_WINDOW
LR_SHARED Если изображение загружается несколько раз, его идентификатор будет использован повторно. Этот флаг не рекомендуется использовать для изображений с нестандартными размерами, которые могут изменяться, а также для изображений, загружаемых из файла

Загружая пиктограмму из ресурсов приложения при заполнении структуры WNDCLASSEX мы установили значение параметра fuLoad равным 0, что соответствует LR_DEFAULTCOLOR.

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

С помощью функции LoadImage вы можете загрузить системные ресурсы (битовые изображения, пиктограммы и курсоры, которые используются операционной системой). Соответствующие изображения называются OEM-изображениями. Их идентификаторы определены в файле winuser.h. Идентификаторы пиктограмм имеют префикс OIC_, курсоров - OCR_, битовых изображений - OBM_.

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

Параметр uType определяет тип загружаемого изображения и может принимать следующие значения:

Значение Описание
IMAGE_BITMAP Битовое изображение
IMAGE_CURSOR Курсор
IMAGE_ICON Пиктограмма

Через параметры cxDesired и cyDesired, как нетрудно догадаться, передается желаемая ширина и высота изображения в пикселах. Если же указать нулевые значения, будут использованы величины, принятые по умолчанию.

При заполнении структуры WNDCLASSEX мы вызываем функцию LoadImage два раза. В первый раз мы загружаем маленькую пиктограмму с размерами 16 х 16 пикселов, во второй раз - стандартную пиктограмму с размерами 32 х 32 пиксела.

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

Заполнив поля структуры WNDCLASSEX, мы вызываем функцию RegisterClassEx :

if(!RegisterClassEx(&wc))
  if(!RegisterClass((LPWNDCLASS)&wc.style))
    return FALSE;

В среде Microsoft Windows 95 функция RegisterClassEx должна выполнить все необходимые для регистрации действия и вернуть значение атома, который идентифицирует зарегистрированный класс.

Однако если вы запустите наше приложение в среде Microsoft Windows NT версии 3.5, функция RegisterClassEx вернет значение NULL. В программном интерфейсе операционной системы этой версии регистрация класса окна должны выполняться функцией RegisterClass.

В следующих версиях Microsoft Windows NT, когда в эту операционную систему будет встроена объектно-ориентированная оболочка, аналогичная оболочке Microsoft Windows 95, вы сможете выполнить расширенную регистрацию с помощью функции RegisterClassEx. Поэтому, для того чтобы наша программа смогла работать и в среде Microsoft Windows 95, и в среде Microsoft Windows NT версии 3.5 (а также более новых версий), мы вначале пытаемся использовать для регистрации функцию RegisterClassEx, а в случае неудачи - функцию RegisterClass, передавая последней адрес обычной структуры WNDCLASS.

После регистрации приложение Window Application создает главное окно, отображает его и запускает цикл обработки сообщений. Все эти действия были подробно описаны в 11 томе "Библиотеки системного программиста".

Функция WndProc

Функция WndProc предназначена для обработки сообщений, поступающих в очередь нашего приложения:

LRESULT WINAPI
WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch(msg)
  {
    HANDLE_MSG(hWnd, WM_CREATE, WndProc_OnCreate);
    HANDLE_MSG(hWnd, WM_LBUTTONDOWN, WndProc_OnLButtonDown);
    HANDLE_MSG(hWnd, WM_DESTROY, WndProc_OnDestroy);
    default:
      return(DefWindowProc(hWnd, msg, wParam, lParam));
  }
}

Ее особенностью является использование макрокоманды HANDLE_MSG, сокращающей объем листинга функции.

Макрокоманда HANDLE_MSG определена в файле windowsx.h следующим образом:

#define HANDLE_MSG(hwnd, msg, fn) \
 case (msg): return HANDLE_##msg((hwnd), \
 (wParam), (lParam), (fn))

Согласно этому определению, для обработки сообщения WM_CREATE вызывается макрокоманда HANDLE_WM_CREATE. Аналогично, для обработки сообщения WM_LBUTTONDOWN вызывается макрокоманда HANDLE_WM_LBUTTONDOWN, а для обработки сообщения WM_DESTROY - макрокоманда HANDLE_.WM_DESTROY.

Эти макрокоманды, наряду с аналогичными для других сообщений, определены в файле windowsx.h:

#define HANDLE_WM_CREATE(hwnd, wParam, lParam, fn) \
  ((fn)((hwnd), (LPCREATESTRUCT)(lParam)) ? 0L : (LRESULT)-1L)
#define HANDLE_WM_DESTROY(hwnd, wParam, lParam, fn) \
    ((fn)(hwnd), 0L)
#define HANDLE_WM_LBUTTONDOWN(hwnd, wParam, lParam, fn) \
    ((fn)((hwnd), FALSE, (int)(short)LOWORD(lParam), \
    (int)(short)HIWORD(lParam), (UINT)(wParam)), 0L)

Макрокоманда HANDLE_WM_CREATE вызывает функцию обарботки сообщения WM_CREATE, адрес которой передается ей через последний параметр. Прототип этой функции вы сможете найти все в том же файле windowsx.h рядом с определением макрокоманды HANDLE_WM_CREATE:

BOOL Cls_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)

Аналогичные прототипы определены и для других функций обработки сообщений.

Функции обработки сообщений

Функции обработки сообщений обычно выполняют всю работу, для которой создается приложение. Приложение Window Application практически ничего не делает, поэтому и функции обработки сообщений несложны:

BOOL WndProc_OnCreate(HWND hWnd, LPCREATESTRUCT lpCreateStruct)
{
  return TRUE;
}

void WndProc_OnDestroy(HWND hWnd)
{
  PostQuitMessage(0);
  return FORWARD_WM_DESTROY(hWnd, DefWindowProc);
}

void WndProc_OnLButtonDown(HWND hWnd, BOOL fDoubleClick, 
  int x, int y, UINT keyFlags)
{
  MessageBox(NULL, "Hello, 32-bit world!", "Window", MB_OK);
  return FORWARD_WM_LBUTTONDOWN(hWnd, fDoubleClick, 
           x, y, keyFlags, DefWindowProc);
}

Функция WndProc_OnCreate вызывается при создании окна и предназначена для инициализации данных, связанных с этим окном. В нашем случае она просто возвращает значение TRUE, сообщая тем самым, что инициализация завершилась успешно.

Функция WndProc_OnLButtonDown в ответ на щелчок мышью внутри окна выводит диалоговую панель с сообщением. Она завершается вызовом макрокоманды FORWARD_WM_LBUTTONDOWN, определенной в файле windowsx.h следующим образом:

#define FORWARD_WM_LBUTTONDOWN \
  (hwnd, fDoubleClick, x, y, keyFlags, fn) \
  (void)(fn)((hwnd), (fDoubleClick) ? WM_LBUTTONDBLCLK : \
  WM_LBUTTONDOWN, (WPARAM)(UINT)(keyFlags), \
  MAKELPARAM((x), (y)))

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

Макрокоманда FORWARD_WM_LBUTTONDOWN вызывает функцию DefWindowProc , передавая ей все необходимые параметры.

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

Использование Microsoft Visual C++ версии 2.0 в среде Windows 95

Система разработки Microsoft Visual C++ версии 2.0 предназначена для Windows NT, поэтому, хотя вы и можете работать с ней в среде Windows 95, у вас могут возникнуть некоторые проблемы.

Если в процессе компиляции файла ресурсов приложения *.rc происходит зацикливание, отредактируйте файл system.ini. Найдите в нем раздел [keyboard] и удалите (либо закройте символом комментария) в строке oemansi.bin= имя файла xlat866.bin:

[keyboard]
subtype=
type=4
keyboard.dll=
oemansi.bin=xlat866.bin

Вот что у вас должно получиться в результате:

oemansi.bin=

Вторая проблема, которая может перед вами возникнуть, вызвана тем, что Microsoft Visual C++ версии 2.0 отмечает загрузочные модули создаваемых приложений как предназначенные для работы в среде Windows NT, в то время как приложения Microsoft Windows 95 должны быть отмечены по-другому. В результате окна приложения могут не получать некоторые извещения. Могут возникнуть проблемы и с диалоговыми панелями.

Выход заключается в ручном редактировании параметров редактора связи для каждого создаваемого вновь приложения. Для этого из меню Project выберите строку Settings. На экране появится блокнот Project Settings. Откройте в этом блокноте страницу Link (рис. 1.18).

Рис. 1.18. Страница Link в блокноте Project Settings системы разработки Microsoft Visual C++ версии 2.0

Выбирая по одному проекты Win32 Debug и Win32 Release в списке Settings For в списке Project Options укажите параметр:

/SUBSYSTEM:windows,4.0

Кроме того, в список объектных модулей и библиотек Object/Library Modules добавьте библиотеку comctl32.lib. Эта библиотека необходима, если вы собираетесь работать с новыми органами управления Microsoft Windows 95.

Для того чтобы в палитре органов управления редактора диалогов появились новые органы управления, необходимо внести изменения в регистрационную базу данных. Эти изменения описаны в разделе "Орган управления Trackbar" седьмой главы этой книги.

Если вы приобрели SDK для Microsoft Windows 95, необходимо настроить параметры системы разработки Microsoft Visual C++ версии 2.0 таким образом, чтобы вначале использовались h- и lib-файлы из SDK, а только потом из Microsoft Visual C++.

Для этого выберите строку Options из меню Tools и в появившемся блокноте откройте страницу Directories. В списке Show Directories for выберите строку Include files. Затем нажмите кнопку Add и добавьте путь к каталогу include системы SDK. С помощью кнопок Move Up и Move Down добейтесь, чтобы этот каталог был указан до каталогов msvc20\include и msvc20\mfc\include.

Аналогичную операцию следует выполнить и для файлов библиотек, выбрав из списка Show Directories for строку Library files.

Если в вашем компьютере установлено мало оперативной памяти, вы не сможете использовать интегрировнную среду разработки Microsoft Visual C++. Тем не менее, вам будет доступна пакетная программа nmake.exe, с помощью которой можно выполнить трансляцию исходных текстов приложений. Образцы файла makefile, который необходимо подготовить для этой программы, вы найдете в каталоге с исходными текстами приложений, которые поставляются в составе SDK.

И последнее. Вместо встроенного отладчика, который не всегда работает в среде Microsoft Windows 95, используйте отладчик WinDbg, который поставляется в составе SDK для Microsoft Windows 95.

[Назад] [Содеожание] [Дальше]