В данной статье я предполагаю что вы уже достаточно ознакомились с С++, что бы уметь создавать классы и перегружать для них различные операторы и что вы уже «прятали» какие-то свои механизмы в класс.
If (AllocConsole())
{
std::ios::sync_with_stdio();
}
Для удобства советую обернуть его в функцию. Например:
void CreateConsole()
{
if (AllocConsole())
{
int hCrt = _open_osfhandle((long)GetStdHandle(STD_OUTPUT_HANDLE), 4);
*stdout = *(::_fdopen(hCrt, "w"));
::setvbuf(stdout, NULL, _IONBF, 0);
*stderr = *(::_fdopen(hCrt, "w"));
::setvbuf(stderr, NULL, _IONBF, 0);
std::ios::sync_with_stdio();
}
Вызванная консоль работает только в режиме вывода и работает он также как и в консольных приложениях. Выводите информацию как и обычно - cout/wcout.
Для работоспособности данного кода необходимо включить в прект следующие файлы:
#include
#include #include
и включить пространство имен std в глобальное пространство имён:
using namespace std;
Конечно же, если вы не хотите этого делать, то просто допишите std:: ко всем сущностям которые в ней находятся.
Cout< Но делать так каждый раз (особенно если вам часто приходиться делать что-то подобное) очень неудобно. Class newrect:public RECT Теперь просто выводите обьект с помощью cout/wcout: Cout< И вам в удобном виде будет выводиться всё так, как вам требуется. Один раз хорошенько продумав и написав такой класс вы облегчите себе жизнь и будете больше времени уделять обучению и оттачиванию навыков чем написанию одного и того же каждый раз. Тем более, я считаю это очень полезно - самому сделать такой класс и дополнять его по необходимости. Наконец-то! Наконец-то! Сегодня мы начнём создавать полноценное окно Windows. Прощай убогая консоль!!! К этому моменту вы уже должны неплохо знать синтаксис C++, уметь работать с ветвлениями и циклами, хорошо понимать работу функций. Если вы справились с морским боем, можете считать, что всё это вы усвоили. Венгерская форма записи
Весь код, который мы встретим в WinAPI написан в венгерской форме. Это такое соглашение по написанию кода. При этом перед именем переменной ставится начальная буква типа. Все слова в именах переменных и функций начинаются с заглавной буквы. Вот несколько префиксов: b - переменная типа bool. Например, указатель будет называться вот так: void* pData;
Данная форма записи используется Microsoft. Многие критикуют этот способ именования переменных. Но подобные вещи (соглашения о кодировании) в больших компаниях жизненно необходимы. Напомню, что идентификаторы констант обычно состоят только из заглавных букв: WM_DESTROY. WM_DESTOY - это 2, константа определена через define. Кроме того, в winAPI используется очень много переопределённых типов. Вот на этой страничке - http://msdn.microsoft.com/en-us/library/aa383751(VS.85).aspx , можете найти описания всех типов Windows (на английском). И ещё одна вещь, которую мы не разбирали. Указателям часто присваивается значение NULL. Считайте, что это просто 0 и указатели которым присвоено значение NULL (ноль), не указывают ни на какой участок памяти. Windows API (WinAPI)
Все программы под Windows используют специальный интерфейс программирования WinAPI. Это набор функций и структур на языке C, благодаря которым ваша программа становится совместимой с Windows. Windows API обладает огромными возможностями по работе с операционной системой. Можно даже сказать - безграничными. Мы не рассмотрим даже один процент всех возможностей WinAPI. Первоначально я хотел взять больше материала, но это заняло бы слишком много времени, и увязнув в болоте WinAPI, до DirectX"а мы добрались бы через пару лет. Описание WinAPI займёт два урока (включая этот). В них мы рассмотрим только каркас приложения под Windows. Программа под Windows точно так же как и программа под DOS, имеет главную функцию. Здесь эта функция называется WinMain. Функция WinMain
Программа под Windows состоит из следующих частей (всё это происходит внутри WinMain): Создание и регистрация класса окна. Не путайте с классами C++. WinAPI написана на C, здесь нет классов в привычном для нас понимании этого слова. Теперь разберём всё это подробно: WinAPI: Структура WNDCLASS
Прежде всего нужно создать и заполнить структурную переменную WNDCLASS, а затем на её основе зарегистрировать оконный класс. Вот как выглядит эта структура: код на языке c++
typedef struct {
UINT style; // стиль окна
WNDPROC lpfnWndProc; // указатель на оконную процедуру
int cbClsExtra; // дополнительные байты после класса. Всегда ставьте 0
int cbWndExtra; // дополнительные байты после экземпляра окна. Всегда ставьте 0
HINSTANCE hInstance; // экземпляр приложения. Передаётся в виде параметра в WinMain
HICON hIcon; // иконка приложения
HCURSOR hCursor; // курсор приложения
HBRUSH hbrBackground; // цвет фона
LPCTSTR lpszMenuName; // имя меню
LPCTSTR lpszClassName; // имя класса
} WNDCLASS, *PWNDCLASS; Структура WNDCLASS в составе WinAPI определяет базовые свойства создаваемого окна: иконки, вид курсора мыши, есть ли меню у окна, какому приложению будет принадлежать окно... После того как вы заполните эту структуру, на её основе можно зарегистрировать оконный класс. Речь идёт не о таких классах как в C++. Скорее можно считать, что оконный класс это такой шаблон, вы его зарегистрировали в системе, и теперь на основе этого шаблона можно создать несколько окон. И все эти окна будут обладать свойствами, которые вы определили в структурной переменной WNDCLASS. WinAPI: Функция CreateWindow код на языке c++
HWND CreateWindow(LPCTSTR lpClassName, // имя класса
LPCTSTR lpWindowName, // имя окна (отображается в заголовке)
DWORD dwStyle, // стиль окна
int x, // координата по горизонтали от левого края экрана
int y, // координата по вертикали от верхнего края экрана
int nWidth, // ширина окна
int nHeight, // высота окна
HWND hWndParent, // родительское окно
HMENU hMenu, // описатель меню
HINSTANCE hInstance, // экземпляр приложения
LPVOID lpParam // параметр; всегда ставьте NULL); Если в оконном классе (структуре WNDCLASS) задаются базовые свойства окна, то здесь - более специфические для каждого окна: размер окна, координаты... Данная функция возвращает описатель окна. С помощью описателя можно обращаться к окну, это примерно как идентификатор. Обратите внимание, что здесь очень много новых типов. На самом деле они все старые, просто переопределены. Например: HWND - это переопределение типа HANDLE, который в свою очередь является переопределением PVOID, который в свою очередь является переопределением void*. Как глубоко закопана правда! Но всё же тип HWND - это указатель на void. Окно состоит из нескольких частей. Практически в каждой программе вы увидите: заголовок окна, системное меню (если нажать на иконку приложения в левой верхней части окна), три системные кнопки для работы с окном: свернуть, развернуть на весь экран и закрыть. Также, практически всегда в приложении присутствует меню. Вот как раз последнего у нас точно не будет. И, конечно же, большую часть окна занимает т.н. клиентская область, в которой обычно и работает пользователь. Это что касается оконного режима. Довольно долго мы будем практиковаться с DiectX именно в окне - не будем пользоваться полноэкранным режимом. Обработка сообщений (Message handling)
Основным отличием всех наших предыдущих программ от программ под Windows является обработка сообщений. Например, когда пользователь нажимает какую-нибудь клавишу на клавиатуре, генерируется сообщение, что была нажата клавиша. Затем это сообщение поступает в приложение, которое было активным, когда пользователь нажал клавишу. Здесь у нас произошло событие (event) - была нажата клавиша. Событием может быть: перемещение курсора мыши, смена фокуса приложения, нажатие клавиши клавиатуры, закрытие окна. Событий очень много. Очень! За секунду в операционной системе может происходить десятки событий. Так вот, когда происходит какое-либо событие, операционная система создаёт сообщение: была нажата такая-то клавиша, координаты курсора мыши изменились, открылось новое окно. Сообщения может создавать как операционная система, так и различные приложения. Сообщение представляет собой структуру, и выглядят следующим образом: код на языке c++
typedef struct tagMSG {
HWND hwnd; // окно, которое получит это сообщение
UINT message; // код сообщения
WPARAM wParam; // параметр
LPARAM lParam; // параметр
DWORD time; // время, когда произошло сообщение
POINT pt; // координаты курсора мыши
} MSG; Обратите внимание, как с помощью typedef переопределяются структуры. Чтобы создать данную структуру можно воспользоваться следующим кодом: код на языке c++
msg.messgae == 2; // эти две строки эквивалентны так как
msg.message == WM_DESTROY; // константа WM_DESTROY равна двум Здесь, поле, в котором содержится код сообщения (имя сообщения, сравнивается с константой WM_DESTROY. WM - от Windows Message (сообщение Windows). WM_DESTROY - это сообщение, которое генерируется при закрытии окна (destroy - уничтожить). Коды сообщений определены с помощью констант и имеют префикс WM_: WM_CLOSE, WM_CREATE и др. В структуре MSG встречается тип HWND - от Window Handle (дескриптор окна или описатель окна). Это такая штука, которая "описывает" окно. Это что-то вроде идентификатора (имени окна). Запомните это слово - handle (описатель, дескриптор). В Windows это понятие используется очень часто. Почти все типы Windows, которые начинаются с H - описатели: описатель иконки, описатель шрифта, описатель экземпляра приложения. Их штук тридцать насколько я помню. Все взаимодействия между приложениями в Windows осуществляются с помощью этих самых описателей окон (HWND). Существует ещё один важный описатель - описатель приложения (HINSTANCE - первый параметр WinMain) - это уникальный идентификатор приложения, благодаря которому операционная система не сможет перепутать две разных программы. Это примерно как штрих-код. Мы рассмотрим его позже. Каждый раз, когда пользователь совершает какое-то действие, создаётся и заполняется сообщение: задаётся описатель окна, которое должно получить данное сообщение, задаётся идентификатор сообщения, заполняются параметры, заполняется время (текущее) и указываются координаты курсора мыши (смотрите структуру). После этого данное сообщение помещается в очередь сообщений операционной системы. Когда доходит очередь до нашего сообщения, оно отправляется нужному окну (windows знает какому окну отправлять каждое сообщение благодаря описателям). Когда сообщение приходит в приложение, оно помещается в очередь сообщений приложения. Как только до него доходит очередь, оно обрабатывается. Смотрите, между тем моментом, когда пользователь совершил какое-либо действие (произошло событие и сгенерировалось сообщение) и тем моментом, когда программа среагировала на это действие (сообщение было обработано программой) происходит много событий. Ведь как в очереди сообщений Windows так и в очереди сообщений приложения может быть много сообщений. В первом случае речь может идти о сотнях, во втором случае как минимум о нескольких. Оконная процедура (Window procedure - WndProc)
Продолжаем с того момента, как сообщение попало в очередь сообщений приложения. Как только до него дошла очередь, оно обрабатывается. Для обработки сообщений в каждой программе должна существовать специальная функция - оконная процедура. Обычно она называется WndProc (от Window Procedure). Вызов оконной процедуры расположен в основном цикле программы и выполняется при каждой итерации цикла. Сообщения (в виде структурных переменных MSG) попадают в данную функцию в виде параметров: описатель окна, идентификатор сообщения и два параметра. Обратите внимание, что в оконную процедуру не передаются поля time и pt. То есть сообщение уже "разобрано". Внутри оконной процедуры расположено ветвление switch, в котором идёт проверка идентификатора сообщения. Вот пример простой оконной процедуры (она полностью рабочая): код на языке c++
// не обращайте пока внимания на HRESULT и __stdcall. Мы рассмотрим их позже
HRESULT __stdcall WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_PAINT:
// код обработки сообщения WM_PAINT
return 0;
case WM_DESTROY:
// код обработки сообщения WM_DESTROY
return 0;
}
// обработчик всех остальных сообщений
} И последнее - основной цикл. Он очень прост. Каждую итерацию цикла проверяется очередь сообщений приложения. Если в очереди сообщений есть сообщение, оно вытаскивается из очереди. Затем в теле цикла происходит вызов оконной процедуры, чтобы обработать взятое из очереди сообщение. Вот, в общем-то, и всё на сегодня. Уже видно, что программа под WinAPI намного сложнее программы под DOS. Как я уже писал выше, в следующем уроке мы разберём код работающей программы. В качестве упражнения создайте новый проект. В окне New Project (Новый проект) выберите шаблон (template) - Win32Project (до сих пор мы выбирали Win32 Console Application). В одном из следующих окон не ставьте флажок Empty Project (пустой проект) и IDE сгенерирует заготовку программы. Если вы внимательно посмотрите на код файла имя_проекта.cpp, то вы обнаружите все вещи, которые мы обсуждали: структурную переменную MSG, заполнение структуры WNDCLASS, создание окна функцией CreateWindow, основной цикл программы. Кроме того, в файле определена функция WndProc. В ней происходит обработка нескольких сообщений в ветвях switch: WM_COMMAND, WM_PAINT, WM_DESTROY. Найдите всё это в файле. Кроме того что мы рассмотрели, в программе содержится много дополнительного кода. В следующем выпуске мы рассмотрим код программы, в котором будет вырезано всё лишнее. Он будет намного проще и понятнее того, что генерирует IDE. API (Application Programming Interface) - это
интерфейс программирования приложений,
термин, часто упоминаемый разработчиками
программного обеспечения. Если
разрабатываемое вами приложение имеет
функцию, позволяющую обращаться к нему из
других приложений, то это - API вашего
приложения. Параметры, которые принимает
ваша функция, образуют её API, так как они
являются средством, при помощи которого
другие приложения взаимодействуют с данной
функцией. Операционная система Windows
предоставляет большой набор функций,
позволяющих различным приложениям, в том
числе и приложениям Visual FoxPro, обмениваться
информацией с Windows на достаточно низком
уровне. Эти функции принято называть Windows API.
Использование Windows API в приложениях Visual FoxPro
позволяет реализовать возможности,
недостижимые стандартными средствами
языка. Функции Windows API скомпонованы в
динамически связанные библиотеки (Dynamic Link
Library, DLL
). Как правило, файлы таких
библиотек имеют расширение dll
. Перед тем,
как использовать Windows API функцию в вашем
приложении, вы должны её объявить
. Для
объявления функции применяется команда
DECLARE..DLL: DECLARE [cFunctionType
] FunctionName
IN LibraryName
;
[cParamType1
[@] ParamName1
, cParamType2
[@] ParamName2
, ...]
Параметры команды: cFunctionType FunctionName
LibraryName
AliasName
cParamType
Параметр может передаваться как
по значению, так и по ссылке. Для указания
того, что параметр передаётся по ссылке,
используется символ "@". С точки зрения Visual FoxPro не
существует никакой разницы между типами
данных Long и Integer. Обычно тип Integer применяется
для обозначения целых чисел со знаком, а тип Long
- целых чисел без знака. ParamName
Все функции Windows API, как, впрочем, и
сама Windows, написаны на языке
программирования Си. Поэтому для того,
чтобы понять, как правильно использовать API
функции в Visual FoxPro (который, кстати, так же
написан на Си, по крайней мере, его ядро),
познакомимся, какие типы данных
применяются в Си и Windows, и, что не менее важно,
разберёмся с такими типами данных, как
перечисления, структуры и указатели. Кроме
того, вы узнаете, что такое прототипы
функций в Си, и как, основываясь на описании
прототипа функции в MSDN, правильно объявить
её в команде DECLARE..DLL. Если вы знакомы с языком
программирования Си, то знаете, как легко в
нём можно создавать различные типы данных.
Достаточно написать следующий код: Typedef int INT32;
и вот у вас новый тип INT32, который
полностью соответствует типу int. Но, с точки
зрения Си, это совершенно разные типы, и
попытка присвоить переменной типа INT32
значение переменной типа int приведёт к
ошибке! Изобилие типов данных заставляет многих
разработчиков думать, что программирование
с использованием API является трудным. Но это
не так! В Си в основном используются
следующие типы данных: тип char
- символ в
формате ANSI. Имеет длину 8 разрядов (один
байт). тип wchar
- символ в
формате Unicode. Имеет длину 16 разрядов (два
байта). тип int
- целые числа. Они
делятся в Си на три типа: int
, short int
и
long int
. Последние обычно сокращаются до
short
и long
. Тип short
- это 16-ти
разрядное, а типы int
и long
- 32-х
разрядные целые числа. тип float
- вещественные числа,
имеющие дробную часть. Имеют длину 32
разряда (4 байта). тип double
- вещественные
числа двойной точности. Имеют длину 64 разряда (8 байт). тип enum
- перечисляемый
тип данных. тип void
используется для
обозначения величин, имеющих нулевую
длину и не имеющих значения. тип pointer
- указатель; он не содержит
информацию в общепринятом смысле - как
другие типы Си; вместо этого, в каждом
указателе находится адрес ячейки памяти,
где хранятся реальные данные. Имеет длину
32 разряда (4 байта). Как ни странно, строковый тип в Си отсутствует. На самом деле все строки
представлены в Си как массивы символов. Некоторые типы могут объявляться
как беззнаковые. Модификатор unsigned
(без
знака) используется со следующими
типами данных: char
, short
, int
и long
. Например, следующее объявление
переменной в Си: Usigned int имя_переменной
;
означает, что эта переменная -
целое 32-х разрядное целое без знака. Модификатор const
указывает,
что переменная указанного типа является
константой, то есть её значение не может
быть изменено. Перечисляемый тип enum
связывает с переменной набор именованных
констант, называемых перечисляемыми
константами. Объявление перечисляемого
типа выглядит так: Enum поле_тега
{ const1
, const2
, ... } переменная
;
Если поле_тега
опускается, то после закрывающей фигурной
скобки необходимо указать переменную
.
Если поле_тега
указано, то
не указывается переменная
. Исторически сложилось так, что
тип enum равнозначен типу int - то есть
переменная перечисляемого типа занимает в
памяти 4 байта. Каждая перечисляемая
константа
имеет значение, определяемое её порядковым номером
в списке; нумерация
начинается с нуля. Рассмотрим перечисление
CombineMode: Enum CombineMode{
CombineModeReplace,
CombineModeIntersect,
CombineModeUnion,
CombineModeXor,
CombineModeExclude,
CombineModeComplement
};
В этом перечислении константа CombineModeReplace имеет значение 0,
константа CombineModeIntersect
имеет значение 1, и так далее; константа CombineModeComplement имеет значение 5. Значения перечисляемых констант
могут быть указаны явно, как, например, в следующем примере: Enum DashCap{
DashCapFlat = 0,
DashCapRound = 2,
DashCapTriangle = 3
};
Перечисленные типы данных покрывают 99%
всех типов данных, используемых в
программировании Windows API. Это звучит слишком
просто, не так ли? Почему же описания API функций
содержат все эти типы - HWND, HINSTANCE, POINT и им
подобные? Причиной тому является то, что Cи имеет
особенность, называемую strict-typing
.
Однажды появившись, переменная одного типа
может принимать только те значения, которые
соответствуют ее типу. Вы не можете сначала
сохранить в переменной строку, а затем
присвоить ей число. В Visual FoxPro
мы обычно стараемся симулировать подобное
путем соглашения о наименованиях. Например,
cName представляет собой переменную символьного
типа,
тогда как nCount - числовую. Strict-typing
позволяет создать новый тип данных, присвоив
существующему типу данных новое имя. Каждый
новый тип представляется отличным от
других типов, несмотря на то, что внутренне
они хранят одно и то же. Windows усложняет использование этой
концепции. К примеру, тип LONG в
действительности представляет собой long int,
а тип UINT - unsigned int. Оба типа являются 32-разрядными
целыми числами. Производные типы данных
определяются в различных include-файлах (файлы
с расширением.h). Если вы приобрели Visual
Studio.NET, то можете найти эти файлы в папке ..\VC7\PlatformSDK\Include\
. Определение того, какой из базовых типов
Си действительно представляет тип
данных, используемый в API функции, является
одной из тяжелейших задач в
программировании API. Используйте следующее правило: если
вы не можете найти слово float, double, char
или str
где-либо
в имени функции или параметра, тогда это обычно 32-разрядное целое.
Потребуется некоторое время для понимания и выработки
навыков, но потом вы будете
запросто преобразовывать типы данных. В
следующей таблице приведены основные типы
данных Windows и соответствующие им типы,
используемые при объявлении функции в Visual
FoxPro: Другой концепцией, широко используемой в
Си, являются указатели (pointers). Указатель
представляет собой переменную, которая
содержит адрес области памяти, по которому
хранятся данные. Тип указателя всегда
определяется типом данных, на которые он
указывает; его размер всегда равен четырём
байтам. Например, указатель на переменную
типа SHORT
представляет собой 32-разрядное целое число, как и
указатель на любой другой тип данных.
Описание указателя, принятое в
программировании Windows API, начинается с
символов "LP", что означет Long Pointer, или "длинный
указатель", работающий с 32-х разрядной
моделью памяти. Затем может следовать
символ "C" (const), указывающий, что данные не
должны изменяться. Далее следует описание типа
данных переменной, адрес которой хранится в
указателе. Например, LPDWORD - указатель на
переменную типа DWORD. Указатели на числовые данные при
объявлении Windows API функции передаются по
ссылке. Как пример рассмотрим функцию
GetFileSize. Вот её прототип (подробнее о
прототипах функций буде рассказано ниже): DWORD GetFileSize(HANDLE hFile, // дескриптор файла
LPDWORD lpFileSizeHigh // указатель);
Второй параметр, передаваемый
функции - указатель на переменную типа DWORD, в
которую функция поместит значение размера
файла в байтах. Объявление этой функции в Visual FoxPro: DECLARE GetFileSize IN WIN32API Long hFile, Long @ FileSizeHight
Как видите, параметр FileSizeHight
передаётся функции по ссылке
, потому
что передача по ссылке - это и есть передача
указателя. Сложнее обстоит дело со строками.
Как уже говорилось, символьные строки в Cи -
это массивы, поэтому в программировании API
функций применяется тип str
,
определяющий массив символов типа CHAR (соответственно,
тип wstr
определяет массив символов типа
WCHAR). В следующей таблице показаны
типы указателей на символьные строки: Указатели на символьные данные
могут передаваться как по ссылке, так и по
значению - тип String в объявлении
функции в Visual FoxPro всегда передаёт
указатель
на переменную, содержащую
символьные данные. Используйте передачу
символьных данных по ссылке только тогда, когда API
функция должна изменить значение параметра. Структуру можно рассматривать
как набор переменных различных типов,
образующих единое целое. В Си структура
создаётся при помощи ключевого слова struct
,
за которым следует необязательное поле
тега
(tag) и список элементов
структуры: Struct поле_тега
{
тип_элемента элемент1
;
тип_элемента элемент2
;
.....
тип_элемента элементN
;
};
Возможно и такое объявление
структуры: Struct {
тип_элемента элемент1
;
тип_элемента элемент2
;
.....
тип_элемента элементN
;
} переменная
;
В этом объявлении
отсутствует поле тега
и создаётся так
называемый анонимный структурный тип;
такой синтаксис позволяет связать с этим
структурным типом одну или несколько
переменных, как, например, в следующем
примере: Struct {
WORD wYear
;
WORD wMonth
;
WORD wDayOfWeek
;
WORD wDay
;
WORD wHour
;
WORD wMinute
;
WORD wSecond
;
WORD wMilliseconds
;
} SYSTEMTIME, *PSYSTEMTIME;
Структуры очень похожи на записи
таблиц Visual FoxPro. Так, если запись таблицы
personal
содержит поля fio
, address
, tlfnumber и
email
, то
для обращения к полю tlfnumber используется
следующий синтаксис: Personal.tlfnumber
Так же выглядит и обращение к
полю структуры: SYSTEMTIME.wMinute
Для формирования структур в Visual
FoxPro используются переменные, содержащие
строки символов.
Например, для рассмотренной выше структуры
SYSTEMTIME вам понадобится переменная длиной 16 байт. В
первые два байта этой переменной заносится
значение поля wYear
, в следующие два байта - значение поля
wMonth
, в
следующие два байта - значение поля wDayOfWeek
,
и так далее, пока структура не будет
полностью сформирована. А при объявлении API
функции в Visual FoxPro тип параметра, в котором
передаётся переменная, содержащая структуру, должен быть типа String.
Как записать в строковую переменную
числовые данные, вы узнаете чуть позже. При программировании Windows API на Си
описание указателя на структуру начинается
с символов LP (Long Pointer), за которыми следует
наименование структуры. Так, указатель нас
структуру SYSTEMTIME будет иметь тип LPSYSTEMTIME,
указатель на структуру POINT будет иметь тип
LPPOINT, и так далее. Как видите, ничего
сложного, но, благодаря этой концепции,
существует чрезвычайно большое
количество типов указателей на структуры. Если данные в передаваемой
структуре не должны изменяться, то
указатель на такую структуру объявляется
так: CONST имя_стуктуры
*
Здесь модификатор CONST означает, что данные
в структуре не должны меняться, а символ (*)
после имени структуры означает, что вся эта
строка есть описание указателя на
структуру. В следующем примере показан
прототип функции CopyRect, которая копирует
одну структуру в другую: BOOL CopyRect(LPRECT lprcDst
,
CONST RECT * lprcSrc
);
Теперь, когда с типами данных всё
стало более-менее понятно, познакомимся
подробнее с
таким понятием Си, как прототипы функций. Согласно стандарта ANSI, все
функции в Си должны иметь прототипы. Прототип
функции достаточно прост: Если в прототипе указан тип VOID
как возвращаемый_тип
, то это означает,
что функция не возвращает никаких значений.
Если тип VOID указан как тип_параметра
, то
это означает, что функция не имеет
параметров. Информацию о прототипах Windows API функций,
включенных в библиотеки Kernel32.dll,
Gdi32.dll, User32.dll, Mpr.dll и Advapi32.dll, в MSDN для Visual Studio.NET вы можете найти,
последовательно открывая следующие
разделы оглавления (Contents) справки: MSDN Library Windows Development
Win32 API
SDK Documentacion
Reference
В разделе
Reference вы можете посмотреть описания функций,
открыв один из следующих подразделов: Вот ещё один адрес в MSDN, по
которому так же имеется информация об API
функциях: MSDN Library User
Interface Design and Development
SDK Documentacion
Windows Shell
Shell Reference
Shell Functions
На следующем рисунке показан
фрагмент окна справочной системы MSDN: Вот как, например, описана в MSDN
функция CopyRect: CopyRect
The CopyRect
function copies the coordinates of one rectangle to another. BOOL CopyRect(
Parameters
lprcDst
Return Values
If the function succeeds, the return value is nonzero.
Remarks
Because applications can use rectangles for different purposes, the rectangle functions do not use an explicit unit of measure. Instead, all rectangle coordinates and dimensions are given in signed, logical values. The mapping mode and the function in which the rectangle is used determine the units of
measure.
Example Code
For an example, see Using
Rectangles
.
Requirements
Windows NT/2000/XP: Included in Windows NT 3.1 and later. Как видите, информация
достаточно исчерпывающая. Функция
возвращает значение типа BOOL, ей передаются
два параметра: типа LPRECT и CONST RECT* - указатели на
структуры типа RECT. При
объявлении этой функции в Visual FoxPro вы должны
указать, что первый параметр передаётся по
ссылке, а второй - по значению: DECLARE Long CopyRect IN User32.dll String @ Dst
, String Src
А как я определил, что эта функция
находится в библиотеке User32.dll? Очень просто.
В разделе рекомендаций (Requirements
)
пункт Library гласит: Use User32.lib. Подставьте
вместо расширения lib
расширение dll
-
и всё! Кстати, там же, в пункте Header,
сообщается, в каком include-файле содержится
описание прототипа функции. Но это ещё не всё! Так как функция
работает со структурами, то в её описании
присутствует гиперссылка на структуру RECT.
Щёлкните мышью по этой гиперссылке, и на
экране появится подробное описание структуры. В девятой версии Visual FoxPro
существенно расширены возможности
встроенных функций BINTOC и CTOBIN. Теперь эти
функции можно применять для преобразования
числовых данных в формат, пригодный для
использования в структурах. Напомню, что
функция BINTOC выполняет преобразование числа
в строку, а функция CTOBIN - строки в число. Синтаксис функции BINTOC: BINTOC(nExpression
, eFlag
)
Из всех возможных значений,
которые может принимать параметр eFlag
,
нас интересуют следующие: Синтаксис функции CTOBIN: CTOBIN(cExpression
, eFlag
)
Возможные значения параметра eFlag
: Ниже показаны примеры
использования этих функций: CTOBIN(BINTOC(1000.55,"4RS"), "4RS") && Результат: 1000
? CTOBIN(BINTOC(-1000.55,"4RS"), "4RS") && Результат: -1000
? CTOBIN(BINTOC(1000.55,"F"), "4N") && Результат: 1000.549987929
? CTOBIN(BINTOC(-1000.55,"F"), "4N") && Результат: -1000.549987929
? CTOBIN(BINTOC(1000.55,"B"), "8N") && Результат: 1000.55
? CTOBIN(BINTOC(-1000.55,"B"), "8N") && Результат: -1000.55
В качестве примера запишем в
переменную Visual FoxPro структуру RECT. Эта
структура используется в рассмотренной
ранее функции CopyRect для описания координат
прямоугольной области. Вот как эта
структура описывается в MSDN: Typedef struct _RECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT, *PRECT;
Как видите, структура RECT содержит
четыре поля, в каждом из которых хранится
значение типа LONG. Для её формирования в Visual
FoxPro понадобится строка длиной 16 байт. Ниже показан код, в котором
объявляется функция CopyRect, формируются
структуры Dst и Src для передачи их как
параметров функции, и затем выполняется
копирование одной структуры в другую. В
примере используется функция BINTOC для
преобразования числа в строку: DECLARE Long CopyRect IN WIN32API String @ Dst, String Src
* Формируем структуру Src
cSrc = BINTOC(nLeft,"4RS") + BINTOC(nTop,"4RS") + ;
BINTOC(nRight,"4RS") + BINTOC(nBottom,"4RS")
* Подготавливаем место для структуры Dst
cDst = REPLICATE(CHR(0),16)
nResult = CopyRect(@cDst, cSrc) && Копирование
В следующем примере показано, как,
используя функцию CTOBIN, можно "разобрать"
структуру, получив числовые значения
её полей: NLeft = CTOBIN(SUBSTR(cDst,1,4), "4RS") && RECT.left
nTtop = CTOBIN(SUBSTR(cDst,5,4), "4RS") && RECT.top
nRight = CTOBIN(SUBSTR(cDst,9,4), "4RS") && RECT.right
nBottom = CTOBIN(SUBSTR(cDst,13,4), "4RS") && RECT.bottom
Достаточно часто встречается
ситуация, когда передаваемая Windows API функции
структура содержит указатели. В качестве примера рассмотрим
функцию StartDoc, создающую документ для печати
на принтере. Вот её прототип: Int StartDoc(HDC hdc
, // handle to DC
CONST DOCINFO* lpdi
// contains file names);
Как видите, второй передаваемый
функции параметр - это указатель на
структуру DOCINFO. Вот эта структура: Typedef struct {
int cbSize
;
LPCTSTR lpszDocName
;
LPCTSTR lpszOutput
;
LPCTSTR lpszDatatype
;
DWORD fwType
;
} DOCINFO, *LPDOCINFO;
Первое поле структуры, cbSize
,
содержит значение длины структуры в байтах.
А вот следующие три поля - это указатели на
переменные, содержащие символьные данные. В
частности, поле lpszDocName
содержит указатель
на строку с наименованием печатаемого
документа (это то самое имя документа,
которое вы видите, просматривая очередь
печатаемых документов). В Visual FoxPro достаточно сложно сформировать
структуру, содержащую указатели. Во-первых,
нужно выделить блок памяти и получить
указатель на него. Во-вторых, необходимо
переписать в эту память значение
переменной Visual FoxPro - таким образом, у нас
будет полностью реализован механизм
указателей. Последнее, что остаётся сделать
- это поместить значение указателя в
структуру. При этом нужно выполнить одно
существенное требование: выделенная память
не должна быть перемещаемой - иначе может
оказаться, что наш указатель в какой-то
момент будет показывать на область, к
которой наши данные не имеют никакого
отношения! Есть несколько возможностей
получить блок памяти. Можно взять "кусочек"
как из общей памяти Windows, так и из
памяти, выделенной процессу (то есть вашему
приложению). Второй способ имеет более
высокое быстродействие, тем не менее здесь
мы рассмотрим способ работы с памятью Windows
как более простой. Функция GlobalAlloc получает у Windows
блок памяти указанного размера и
возвращает указатель на него. Вот прототип
этой функции: HGLOBAL GlobalAlloc(UINT uFlags
, // атрибуты распределения памяти
SIZE_T dwBytes
// размер в байтах);
Параметр uFlags
определяет, как
будет распределяться память. В MSDN написано,
что он может принимать одно из следующих
значений: Из таблицы следует, что для
параметра uFlags
следует использовать
значение GPTR. Но как узнать, какое
это
значение? Найдите в MSDN описание функции
GlobalAlloc и в разделе
Requirements
посмотрите, в каком include-файле
находится её прототип. Это файл Winbase.h.
Именно в нём и следует искать описание
значений констант. Вот
фрагмент этого файла, в котором
определяются перечисленные в таблице
константы:
/* Global Memory Flags */
#define GMEM_FIXED 0x0000
#define GMEM_MOVEABLE 0x0002
#define GMEM_NOCOMPACT 0x0010
#define GMEM_NODISCARD 0x0020
#define GMEM_ZEROINIT 0x0040
#define GMEM_MODIFY 0x0080
#define GMEM_DISCARDABLE 0x0100
#define GMEM_NOT_BANKED 0x1000
#define GMEM_SHARE 0x2000
#define GMEM_DDESHARE 0x2000
#define GMEM_NOTIFY 0x4000
#define GMEM_LOWER GMEM_NOT_BANKED
#define GMEM_VALID_FLAGS 0x7F72
#define GMEM_INVALID_HANDLE 0x8000
#define GHND (GMEM_MOVEABLE | GMEM_ZEROINIT)
#define GPTR (GMEM_FIXED | GMEM_ZEROINIT)
Следовательно, GPTR = GMEM_FIXED + GMEM_ZEROINIT
= 0x0000 + 0x0040 = 0x0040. Какой размер должен иметь
выделяемый блок памяти? Конечно, равный
длине строки, в которой хранится
наименование документа. В следующем
примере показаны действия, начиная с
объявления API функции и заканчивая
выделением блока памяти: uFlags
, Long dwBytes
cDocumentName = "Имя печатаемого документа" && Имя документа
nLenDocumentName = LEN(cDocumentName) && Длина строки
hGlobal = GlobalAlloc(GPTR, nLenDocumentName)
Следующая задача - переписать
содержимое переменной cDocumentName в полученный
блок памяти. Воспользуемся для этого встроенной
функцией Visual FoxPro SYS(2600). Вот её синтаксис: SYS(2600, dwAddress
, nLenght
[, cNewString
])
Функция ведёт себя по разному в
зависимости от того, указан параметр cNewString
или нет. Если параметр cNewString
указан
,
то функция копирует nLenght
байт из
переменной cNewString
в память по адресу,
указанному в dwAddress
. Если параметр cNewString
не
указан
, то функция возвращает nLenght
байт из памяти по адресу, указанному в dwAddress
. Как видите, параметр dwAddress
-
это указатель
. Запишем содержимое строки
cDocumentName в выделенную функцией GlobalAlloc память: SYS(2600, hGlobal, nLenDocumentName, cDocumentName)
Вот полный код формирования
структуры DOCINFO:
#DEFINE GPTR 0x0040
DECLARE Long GlobalAlloc IN WIN32API Long uFlags
, Long dwBytes
cDocumentName = "Имя печатаемого документа"
nLenDocumentName = LEN(cDocumentName)
hGlobal = GlobalAlloc(GPTR, nLenDocumentName)
SYS(2600, dwAddress
, nLenght
[, cNewString
])
* Начинаем формировать структуру DOCINFO
* cDocInfo - переменная, в которой формируется структура
cDocInfo = BINTOC(20,"4RS") && DOCINFO.cbSize
cDocInfo = cDocInfo + BINTOC(hGlobal,"4RS") && DOCINFO.lpszDocName
cDocInfo = cDocInfo + REPLICATE(CHR(0),12) && Остальные поля структуры
* Конец формирования структуры
Структура формируется в
переменной cDocInfo
. В первые четыре байта
записываем число 20 - это размер структуры (поле
cbSize
). Следующие четыре байта,
добавляемые в переменную, - это указатель на
область памяти, в которую переписано
содержимое переменной cDocumentName -
наименование документа. Затем к переменной
добавляются ещё двенадцать нулевых байтов -
это поля структуры lpszOutput
, lpszDatatype
и fwType
,
которые, согласно документации, могут
игнорироваться; это означает, что поля
должны иметь нулевые значения.
Таким образом, получилась строка длиной 20
байтов - что и требовалось. Применяя в ваших приложениях
функции Windows API, вы должны помнить о том, Visual
FoxPro не может управлять памятью,
резервируемой этими функциями. Поэтому,
если вы распределяете память, например, при
помощи функции GlobalAlloc, то вы обязательно
должны после использования вернуть эту
память Windows, вызвав функцию GlobalFree. Для
каждой API функции, резервирующей память,
имеется функция - антипод, освобождающая
зарезервированную память. Вот прототип функции GlobalFree: HGLOBAL GlobalFree(HGLOBAL hMem // указатель на блок памяти);
Функция получает только один
параметр - указатель на блок памяти. Вот её
объявление и использование в Visual FoxPro: DECLARE Long GlobalFree IN WIN32API Long hGlobal
GlobalFree(hGlobal)
здесь hGlobal - указатель на блок
памяти, возвращаемый функцией GlobalAlloc. Если вы будете забывать
возвращать распределённую память, то тогда
вы рискуете столкнуться с проблемой,
называемой утечкой памяти. Последствия
такой утечки могут быть весьма печальны - от
резкого замедления работы вашего
приложения, вызванного фрагментацией
памяти, до краха операционной системы. Массив с точки зрения Си - это
переменная, содержащая несколько элементов
одного типа. Доступ к каждому отдельному
элементу массива осуществляется при помощи
индекса. Все элементы массива имеют
одинаковый размер, нельзя описывать
массивы со смешанными типами данных. Все
элементы массива хранятся в памяти
последовательно, один за другим, при этом
минимальное значение индекса
соответствует первому элементу, а
максимальное - последнему. Массив Visual FoxPro имеет совершенно
другую организацию, которая позволяет
хранить в его элементах совершенно разные
типы данных. Поэтому невозможно передать
массив из Visual FoxPro в Windows API функцию, просто
указав его имя как параметр. Более того, в
команде DECLARE..DLL нет такого типа данных, как
массивы. Тем не менее выход из этого
положения есть. Как и для структур, для
передачи массивов используются символьные
переменные. Числовые данные из массива
должны быть преобразованы в строку, которую
вы и передаёте как параметр в Windows API функцию. В следующем
примере показан код функции ArrayToString,
формирующей строку из массива.
Функция получает получает массив taArray
(по
ссылке) и флаг tlTypeOfValue
, указывающий, как
нужно преобразовать значения элементов
массива - как целые (tlTypeOfValue=
.F.)
или вещественные (tlTypeOfValue=
.T.) числа: FUNCTION ArrayToString
PARAMETERS taArray, tlTypeOfValue
EXTERNAL ARRAY taArray
LOCAL lnLenArray, lnIndex, lcStruct, lcType
lcType = IIF(tlTypeOfValue = .t., "F", "4RS")
lnLenArray = ALEN(taArray) && Количество элементов в массиве
lcStruct = ""
FOR lnIndex = 1 TO lnLenArray
lcStruct = lcStruct + BINTOC(taArray, lcType)
ENDFOR
RETURN lcStruct
ENDFUNC
Функция работает как с
одномерными, так и с двумерными массивами. В кодировке ANSI (применяемой в Visual
FoxPro) каждый
символ определяется одним байтом, то есть
максимальное количество символов равно 256,
что, конечно, очень мало. Например, при
русификации часть стандартных символов ANSI
заменяется на символы кириллицы. А в
некоторых алфавитах, например, японской
кане, столько символов, что одного байта для
их кодировки просто недостаточно. Для
поддержки таких языков, и, что более важно,
для облегчения "перевода" программ на
другие языки, была разработана кодировка
Unicode. Каждый символ в Unicode состоит из
двух байтов, что позволило расширить набор
допустимых символов до 65536. Достаточно
большое количество функций Windows API
используют при работе с символьными
строками формат Unicode. Для работы с
такими функциями необходимо выполнять
конвертирование символьных данных из одного формата в другой. Встроенная функция Visual FoxPro STRCONV
выполняет конвертирование строк как из
формата ANSI в UNICODE, так и обратно. Вот её
синтаксис: STRCONV(cExpression
, nConversionSetting
[, nRegionalIdentifier
[, nRegionalIDType
]])
Параметр cExpression
- это строка,
которую необходимо конвертировать.
Параметр nConversionSetting
указывает характер
конвертирования. Из всех его возможных
значений нас интересуют только два: Необязательные параметры nRegionalIdentifier
и nRegionalIDType
определяют дополнительные
региональные настройки и могут быть
безболезненно проигнорированы. Ниже показаны примеры
использования функции STRCONV: CUnicodeString = STRCONV(cANSIString, 5) && Конвертирование в Unicode
cANSIString = STRCONV(cUnicodeString, 6) && Конвертирование в ANSI
Возможно, при прочтении этого
раздела у вас сложилось впечатление, что
работать с Windows API функциями в Visual FoxPro
достаточно просто. И да, и нет. Например,
некоторые API функции используют типы данных,
не поддерживаемые в команде DECLARE..DLL,
например, 64-х разрядные целые числа. Так же
есть ряд функций, называемых функциями
обратного вызова. В прототипе такой функции
перед описанием возвращаемого типа
присутствует модификатор CALLBACK. К сожалению,
вы не можете использовать такие функции, по
крайней мере, напрямую. Так же бывает, что
структура содержит указатель на функцию -
такие API в Visual FoxPro так же нельзя
использовать. Интерфейс прикладного программирования WindowsAPI (applicationprogramminginterface) является интерфейсом системного программирования в пользовательском режиме для семейства операционных систем Windows. До выхода 64-разрядных версий Windows программный интерфейс для 32-разрядных версий операционных систем Windows назывался Win32 API, чтобы его можно было отличить от исходной 16-разрядной версии Windows API (которая служила интерфейсом программирования для начальных 16-разрядных версий Windows). Windows API состоит из нескольких тысяч вызываемых функций, которые разбиты на следующие основные категории: Описание WindowsAPI можно найти в документации по набору инструментальных средств разработки программного обеспечения - WindowsSoftwareDevelopmentKit (SDK). Эта документация доступна на веб-сайте www.msdn.microsoft.com. Она также включена со всеми уровнями подписки в сеть MicrosoftDeveloperNetwork (MSDN), предназначенную для разработчиков. Microsoft .NET Framework состоит из библиотеки классов под названием Framework Class Library (FCL) и управляемой среды выполнения кода -Common Language Runtime (CLR). CLR обладает функциями своевременной компиляции, проверки типов, сборки мусора и обеспечения безопасности доступа к коду. Предлагая эти функции, CLR предоставляет среду разработки, повышающую производительность работы программистов и сокращающую количество наиболее распространенных ошибок программирования. Среда CLR реализована, как классический COM-сервер, код которого находится в стандартной Windows DLL-библиотеке, предназначенной для работы в пользовательском режиме. Фактически все компоненты.NET Framework реализованы как стандартные Windows DLL-библиотеки пользовательского режима, наложенные поверх неуправляемых функций Windows API. (Ни один из компонентов.NET Framework не работает в режиме ядра.) Взаимоотношения между этими компонентами показаны на рисунке. Некоторые термины в пользовательской и программной документации Windows в разных контекстах имеют разные значения. Например, слово служба может относиться к вызываемой в операционной системе стандартной подпрограмме, драйверу устройства или к обслуживающему процессу. Что именно означают те или иные термины, показано в следующем списке: Интересно, что Win32 не планировался в качестве исходного интерфейса программирования для той системы, которая в ту пору называлась Windows NT. Поскольку проект Windows NT запускался в качестве замены для OS/2 версии 2, первоначальным интерфейсом программирования был 32-разрядный OS/2 PresentationManagerAPI. Но через год после запуска проекта произошел взлет поступившей в продажу Microsoft Windows 3.0. В результате этого Microsoft сменила направление и сделала Windows NT будущей заменой семейства продуктов Windows, а не заменой OS/2. В связи с этим и возникла необходимость выработать спецификацию Windows API - до этого, в Windows 3.0, API существовал только в виде 16-разрядного интерфейса. Хотя в Windows API намечалось введение множества новых функций, недоступных в Windows 3.1, Microsoft решила сделать новый API, по возможности, максимально совместимым по именам, семантике и используемым типам данных с 16-разрядным Windows API, чтобы облегчить бремя переноса существующих 16-разрядных Windows-приложений в Windows NT. Этим, собственно, и объясняется тот факт, что многие имена функций и интерфейсов могут показаться непоследовательными: так нужно было для обеспечения совместимости нового Windows API со старым 16-разрядным Windows API. Аббревиатура API,
Application Programming Interface (API) - это просто
некоторый готовый набор функций, который
могут использовать разработчики
приложений. В общем случае данное
понятие эквивалентно тому, что раньше
чаще называли библиотекой подпрограмм.
Однако чаще всего под API подразумевается
некоторая особая категория таких
библиотек. В ходе разработки
практически любого достаточно сложного
приложения (MyAppication) для конечного
пользователя формируется набор
специфических внутренних функций,
используемых для реализации данной
конкретной программы, который называется
MyApplication API. Часто оказывается, что эти
функции могут эффективно использоваться
также для создания других приложений,
в том числе другими программистами.
В этом случае авторы исходя из стратегии
продвижения своего продукта должны
решить вопрос - открывают ли они
доступ к этому набору для внешних
пользователей или нет? При положительном
ответе на него в описании программного
пакета, как его достоинство, появляется
фраза о том, что «комплект включает
открытый набор API-функций». Таким образом,
чаще всего под API подразумевается набор
функций, являющийся частью одного
приложения, но при этом доступных
для использования в других программах.
Например, Excel кроме интерфейса для
конечного пользователя имеет набор
функций Excel API, который может использоваться,
в частности, при создании приложений
с помощью VB. Соответственно,
Windows API - это набор функций, являющийся
частью самой операционной системы
и в то же время - доступной
для любого другого приложения. И в этом
плане вполне оправдана аналогия с набором
системных прерываний BIOS/DOS, который
фактически представляет собой DOS API. Отличие заключается
в том, что состав функций Windows API,
с одной стороны значительно шире,
по сравнению с DOS, с другой -
не включает многие средства прямого
управления ресурсами компьютера, которые
были доступны программистам в предыдущей
ОС. Кроме того, обращение к Windows API
выполняется с помощью обыкновенных
процедурных обращений, а вызов функций
DOS - через специальную машинную
команду процессора, которая называется
Interrupt («прерывание»). Win16 API и Win32 API Как известно смена
Windows 3.x на Windows 95 ознаменовала собой
переход от 16-разрядной архитектуры
операционной системы к 32-разрядной.
Одновременно произошла замена
16-разрядного Windows API (Win16 API) на новый
32-разрядный вариант (Win32 API) . В данном
случае нужно просто иметь в виду, что
за небольшим исключением набор
Win32 API является единым для семейств
Windows 9x и Windows NT. При знакомстве
с Win API обнаруживается, что многие
встроенные функции - не что иное,
как обращение к соответствующим
системным процедурам, но только
реализованные в виде синтаксиса
данного языка. Учитывая это, необходимость
использования API определяется следующим
вариантами: API-функции, которые
полностью реализованы в виде встроенных
функций. Тем не менее, иногда и в этом
случае бывает полезным перейти
к применению API, так как это позволяет
порой существенно повысить производительность
(в частности, за счет отсутствия
ненужных преобразований передаваемых
параметров). Встроенные функции
реализуют лишь частный случай
соответствующей API-функции. Это довольно
обычный вариант. Огромное число
API-функций вообще не имеют аналогов
в существующем сегодня варианте
компиляторов. Например, удалить каталог
нельзя средствами VB - для этого нужно
использовать функцию DeleteDirectory. Следует также
подчеркнуть, что некоторые API-функции
(их доля в Win API весьма незначительна)
не могут вызываться из программ
из-за ряда ограничений языка, например
отсутствие возможности работы с адресами
памяти. Но в ряде случаев могут
помочь нетривиальные приемы программирования
(в частности, в случае с теми же
адресами). Win API
и
Dynamic Link Library
(DLL)
Набор Win API реализован
в виде динамических DLL-библиотек. В данном случае
под DLL мы подразумеваем традиционный
вариант двоичных динамических библиотек,
которые обеспечивают прямое обращение
приложений к нужным процедурам -
подпрограммам или функциям (примерно
также как это происходит при вызове
процедур внутри проекта). Такие библиотеки
могут создаваться с помощью разных
инструментов - VC++, Delphi, Fortran, Assembler. Обычно файлы
динамических библиотек имеют расширение.DLL, но это совсем не обязательно.
Для Win16 часто применялось расширение.EXE, драйверы внешних устройств обозначаются
с помощью.DRV. Определить точное
число API-функций Windows и файлов,
их содержащих, достаточно сложно
(но все они находятся в системном
каталоге). В этом плане лучше выделить
состав библиотек, составляющих ядро
операционной системы, и основных
библиотек с ключевыми дополнительными
функциями. Библиотеки Win32 API
ядра операционной системы Windows 95/98: KERNEL32.DLL: низкоуровневые
функции управления памятью, задачами
и другими ресурсами системы; USER32.DLL: здесь
в основном находятся функции управления
пользовательским интерфейсом; GDI32.DLL: библиотека
Graphics Device Interface - разнообразные функции
вывода на внешние устройства; COMDLG32.DLL: функции,
связанные с использованием диалоговых
окон общего назначения. Основные библиотеки
с функциями расширения: COMCTL32.DLL: набор
дополнительных элементов управления
Windows, в том числе Tree List и Rich Text; MAPI32.DLL: функции
работы с электронной почтой; NETAPI32.DLL: элементы
управления и функции работы с сетью; ODBC32.DLL: функции
этой библиотеки нужны для работы
с различными базами данных через
протокол ODBC; WINMM.DLL: операции
доступа к системным средствам
мультимедиа.
Здесь нам на помощь приходит наследование.
Создайте класс который открыто наследуется от структуры RECT и перегрузите оператор вывода << так, как вам угодно.
Например:
{
public:
friend ostream& operator<<(ostream &strm,newrect &rect)
{
strm<<"Prtint RECT object:\n";
strm<
}
};
Так же вы можете сделать с любыми нужными вам операторами.
Например, если надо сравнивать или присваивать структуры (допустим тот же RECT или POINT) - перегрузите operator==() и operator=() соответственно.
Если хотите реализовать оператор меньше < что бы быстро сравнивать размеры окна и т.д. перегрузите operator<().
Так вы можете делать, я предполагаю, почти с любыми структурами и самое главное, что все функции которые работают с обычным объектом структуры RECT так же хорошо будут работать и с его наследником.
И еще рекомендую всю эту красоту вынести в отдельный подключаемый файл и использовать при необходимости.Свой класс
Не знаю как у остальных, но так как я совсем зелёный, я решил для каждой изученной функции или для каждой главы/под главы книги создавать новый проект, что бы всё было по полочкам и можно было в любой момент вернуться и освежить в памяти необходимые моменты.
Так как в WinAPI даже для создания простейшего окна нужно заполнить структуру класса, зарегистрировать её и написать тривиальную оконную процедуру, я после третьего или четвертого проекта вспомнил что я всё таки на С++ пишу.
В итоге я всё спрятал в простенький класс. Хендл окна, его имя, имя класса, адрес оконной процедуры, класс окна (WNDCLASS) всё спрятано в private секцию класса.
Для их получения достаточно описать простенькие методы-Get"еры, к примеру:
HWND GetHWND()
LPCTSTR GetClsName() и т.д.
Заполнение и регистрация оконного класса, создание самого окна и его показ производиться в конструкторе.
Для удобства можно перегрузить конструктор, а заполнение и регистрацию оконного класса спрятать в отдельную private функцию класса и вызывать в каждом из конструкторов. Удобство перегрузки состоит в том, что мне иногда необходимо создать совсем простенькое окно и я вызываю конструктор с двумя параметрами - имя окна и hinstance приложения.
В другой раз мне нужно создать окно с особыми размерами, не с дефолтной процедурой окна и с каким-то другим определённым стилем - я вызываю конструктор с сопутствующими параметрами.
Этот класс у меня определён в отдельно подключаемом файле, который лежит в include папке IDE.
Шаблон такого класса:
class BaseWindow
{
WNDCLASSEX _wcex;
TCHAR _className;
TCHAR _windowName;
HWND _hwnd;
bool _WindowCreation();
public:
BaseWindow(LPCTSTR windowName,HINSTANCE hInstance,DWORD style,UINT x,UINT y,UINT height,UINT width);
BaseWIndow(LPCTSTR windowName,HINSTANCE hInstance);
const HWND GetHWND()const{return HWND;}
LPCTSTR GetWndName()const{return _windowName;}
}; P.S.
Всё описанное справедливо для:
Платформа - Windows 7 32 bit
IDE - Visual Studio 2010
Может у кого-то эти советы будут вызывать смех и иронию, но всё-таки мы все когда-то в чём-то были новичками/стажерами/junior"ами.
Прошу к посту отнестись с понимаем. Конструктивная критика, конечно же приветствуется.
l - переменная типа long integer.
w - от word (слово) - 16 бит. Переменная типа unsigned short.
dw - от double word (двойное слово) - 32 бита. Переменная типа unsigned long.
sz - строка заканчивающаяся нулём (string terminated zero). Просто обычная строка, которую мы постоянно использовали.
p или lp - указатель (от pointer). lp (от long pointer) - данные указатели перешли из прошлого. Сейчас lp и p означают одно и то же.
h - описатель (от handle).
Создание окна программы.
Основной цикл, в котором обрабатываются сообщения.
Обработка сообщений программы в оконной процедуре. Оконная процедура представляет собой обычную функцию.
Вот эти четыре пункта - основа программы Windows. В течение этого и следующего урока мы разберём всё это подробно. Если вы запутаетесь в описании программы, то вернитесь к этим пунктам.
После регистрации оконного класса, на его основе создаётся главное окно приложения (мы сейчас приступили ко второму пункту). Делается это с помощью функции CreateWindow. Она имеет следующий прототип:
Объявление Windows API функций в Visual
FoxPro
необязательный параметр, указывает тип данных, возвращаемых
функцией:cFunctionType
Размер,
байт
Описание
Short
16-ти разрядное целое
число
Integer, Long
4
32-х разрядное целое
число
Single
4
32-х разрядное
вещественное число
Double
8
64-х разрядное
вещественное число
String
-
Строка символов
имя функции в DLL-библиотеке. Имя функции
чувствительно к регистру символов, то
есть GetDC и GETDC - это имена совершенно
разных функций.
наименование DLL-библиотеки, в которой
находится функция. Для библиотек Kernel32.dll,
Gdi32.dll, User32.dll, Mpr.dll и Advapi32.dll можно
использовать синоним WIN32API.
необязательный параметр, позволяет вместо имени функции
использовать придуманный вами псевдоним.
Написание псевдонима, в отличие от имени
функции, не чувствительно к регистру
символов. Как правило, псевдоним
используется, когда имя API функции
совпадает с именем встроенной (или вашей)
функции Visual FoxPro.
указывает тип данных передаваемого функции
значения:
необязательный параметр, носит чисто описательный характер и, как
правило, игнорируется.Базовые типы данных Си
Типы данных Windows
Тип данных
Windows
Тип в
объявлении
функции
Описание
BOOL
Long
32-х разрядное целое число. 0 означает false,
все остальное означает true.
BOOLEAN
Long
тоже самое, что и BOOL.
BYTE
String
8-ми разрядное целое число
CHAR
String
8-ми разрядное целое число
CLSID
String
COLORREF
Long
32-х разрядное целое число
DWORD
Long
32-х разрядное целое число
DOUBLE
Double
64-х разрядное вещественное число
FLOAT
Single
32-х разрядное вещественное число
GUID
String
128-разрядное число (16 байт)
HANDLE
Long
HBITMAP
Long
32-х разрядное целое число без знака
HDC
Long
32-х разрядное целое число без знака
HICON
Long
32-х разрядное целое число без знака
HGLOBAL
Long
32-х разрядное целое число без знака
HKL
Long
32-х разрядное целое число без знака
HLOCAL
Long
32-х разрядное целое число без знака
HINSTANCE
Long
32-х разрядное целое число без знака
HRESULT
Long
32-х разрядное целое число без знака
HWND
Long
32-х разрядное целое число без знака
LONG
Long
32-х разрядное целое число
LPARAM
Long
32-х разрядное целое число без знака
SHORT
Integer
16-ти разрядное целое число
SIZE_T
Long
32-х разрядное целое число без знака
TCHAR
String
Соответствует типу CHAR для строк
формата ANSI и WCHAR для строк формата Unicode
UCHAR
String
Символ в ANSI кодировке
UINT
Long
32-х разрядное целое число без знака
ULONG
Long
32-х разрядное целое число без знака
USHORT
Integer
UUID
String
128-разрядное число (16 байт)
VOID
нет
Не имеет значения
WCHAR
String
UNICODE character
WNDPROC
Long
32-х разрядное целое число без знака
WORD
Integer
16-ти разрядное целое число без знака
WPARAM
Long
32-х разрядное целое число без знака
Указатели
Тип
указателя
на строку
Описание
LPSTR
Указатель на модифицируемую
нуль-терминированную строку ANSI-формата.
Передаётся по ссылке
LPCSTR
Указатель на немодифицируемую
нуль-терминированную строку ANSI-формата.
Передаётся по значению
LPTSTR
Соответствует типу LPSTR для
строк формата ANSI и типу LPWSTR для строк
формата UNICODE. Передаётся по ссылке.
LPCTSTR
Соответствует типу LPSTR для
строк формата ANSI и типу LPWSTR для строк
формата UNICODE. Передаётся по значению.
LPWSTR
Указатель на модифицируемую
нуль-терминированную строку UNICODE.
Передаётся по ссылке
LPCWSTR
Указатель на немодифицируемую
нуль-терминированную строку UNICODE.
Передаётся по значению
Структуры
Описание прототипов функций в MSDN
LPRECT lprcDst
, // destination rectangle
CONST RECT* lprcSrc
// source rectangle
);
Pointer to the RECT
structure that receives the logical coordinates of the source rectangle.
lprcSrc
Pointer to the RECT structure whose coordinates are to be copied in logical units.
If the function fails, the return value is zero.
Windows NT/2000/XP:
To get extended error information, call GetLastError.
Windows 95/98/Me: Included in Windows 95 and later.
Header: Declared in Winuser.h; include Windows.h.
Library: Use User32.lib.Формирование структур в Visual FoxPro
Структуры, содержащие указатели
Особенности использования
памяти
Передача в функцию массивов
Кодировка символьных данных:
форматы ANSI и UNICODE
Службы, функции и стандартные программы.
История Win32 API.