Операционная система Microsoft Windows 3.1 для программиста -том 1

Функция WinMain


Любая программа MS-DOS, составленная на языке программирования C или C++, должна содержать функцию с именем main. Эта функция первой получает управление сразу после того, как специальный стартовый модуль устанавливает расположение стека и кучи программы, а также выполняет все необходимые инициализирующие действия.

Если вы создаете приложение Windows с использованием языка программирования C или C++, прежде всего вы должны создать функцию с именем WinMain, которая является аналогом функции main в программах для MS-DOS.

Функция WinMain должна быть определена следующим образом:

int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdLine, int nCmdShow) { // Тело функции }

В определении функции WinMain использованы, вероятно, незнакомые вам типы - PASCAL, HINSTANCE, LPSTR. Эти типы описаны в include-файле с именем windows.h, который поставляется вместе с компилятором и должен быть включен в исходный текст программы при помощи оператора #include.

Тип PASCAL определен в файле windows.h следующим образом:

#define PASCAL _pascal

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

Это связано с тем, что такая функция должна сама освобождать стек перед возвратом. Если перед вызовом функции, описанной с ключевым словом _pascal или PASCAL, записать в стек неправильное количество параметров, перед возвратом из функции обязательно произойдет неправильное освобождение стека.

В частности, функция WinMain должна использовать ровно четыре параметра, как показано в предыдущем примере. Привычная вам функция main программы MS-DOS могла либо совсем не иметь параметров, либо использовать параметры argc и argv.

Функция WinMain возвращает значение типа int, что позволяет передать операционной системе Windows или отладчику код завершения приложения.


Первые два параметра имеют тип HINSTANCE, который в Windows версии 3.1 является 16-разрядным идентификатором. Не следует однако думать, что тип HINSTANCE эквивалентен типу int. Изучив include-файл windows.h, вы сможете убедиться в том, что это не так.



Параметр с именем hInstance является идентификатором приложения. Любое приложение перед запуском получает свой уникальный идентификатор, который передается ему через параметр hInstance.

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

Так как Windows - мультизадачная среда, вы можете запустить одновременно несколько приложений, и каждое приложение будет иметь свой, уникальный идентификатор.

У вас существует и другая возможность - вы можете запустить одно приложение несколько раз. Каждая копия приложения в этом случае также будет иметь свой собственный идентификатор.

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

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

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

if(hPrevInstance) return 0;

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

Третий параметр функции WinMain имеет имя lpszCmdLine. Он имеет тип LPSTR, который определяется в include-файле windows.h следующим образом:



# define FAR _far typedef char FAR* LPSTR;

Из этого определения видно, что параметр lpszCmdLine является дальним указателем на символьную строку. Что это за строка?

Программе MS-DOS при запуске из командной строки вы можете передать параметры. Эти параметры программа получает через параметры argc и argv функции main.

Аналогично, при запуске приложения Windows вы также можете указать параметры. Эти параметры должны быть записаны в текстовом виде после имени exe-файла приложения. Параметры можно задать для любой пиктограммы любой группы Program Manager. Для этого выберите из меню "File" строку "Properties" и в поле "Command Line" после пути к exe-файлу приложения допишите необходимые параметры.

Еще один способ указания параметров заключается в использовании для запуска приложения командной строки, появляющейся в отдельной диалоговой панели при выборе строки "Run..." из меню "File" приложения Program Manager.

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

Последний параметр функции WinMain имеет имя nCmdShow и тип int.

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

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


При запуске приложения с помощью строки "Run..." меню "File" приложения Program Manager кроме командной строки вы можете указать режим запуска "Run Minimized". В этом режиме правильно спроектированное приложение (способное анализировать параметр nCmdShow) при запуске сразу сворачивает свое главное окно в пиктограмму.

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

У вас может возникнуть вопрос - зачем переопределять тип _pascal как PASCAL, а тип _far как FAR?

Дело в том, что операционная система Windows задумана (во всяком случае Windows NT) как переносимая на различные платформы. Windows NT успешно работает не только на процессорах фирмы Intel, но и, например, на процессоре Alpha, созданном фирмой DEC и имеющем свою собственную архитектуру. Если вы планируете в будущем перетранслировать исходные тексты своих приложений для Windows NT, вам нельзя закладывать в них особенности архитектуры процессоров Intel. Например, тип FAR для Windows версии 3.1 определен как _far, а для Windows NT этот же тип может быть определен по-другому. Например, так:

#define FAR

Как дополнительная помощь в создании переносимых (мобильных) приложений, в операционной системе Windows программный интерфейс (API) отделен от самой операционной системы. Поэтому программный интерфейс Windows в принципе может быть реализован в среде другой операционной системы, такой, как UNIX или OS/2.


Содержание раздела