7. Вывод информации в окно. Механизм перерисовки окна. Понятие области обновления окна. Операции с областью обновления окна



страница7/21
Дата28.11.2016
Размер2.21 Mb.
Просмотров5902
Скачиваний1
1   2   3   4   5   6   7   8   9   10   ...   21

12. Системы координат. Трансформации. Матрица трансформаций. Виды трансформаций и их представление в матрице трансформаций. Преобразования в страничной системе координат. Режимы масштабирования.
Системы координат

Cуществует несколько видов систем координат:

Мировая – world coordinate space (2^32). Обеспечивает параллельный перенос, масштабирование, отражение, поворот, наклон.
Устройства – device coordinate space (2^27). Обеспечивает параллельный перенос (к началу координат на устройстве).
Физическая – physical device coordinate space. Например, клиентская область окна на экране. Для дисплея физическая система координат характеризуется двумя осями Х и У. Х – горизонтально направлена вправо. У – вертикально вниз. Координаты – целые числа.
Логическая (страничная) – page coordinate space (2^32). Устаревшая система координат, основанная на режимах масштабирования (mapping modes). Обеспечивает параллельный перенос, масштабирование, отражение.

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

При выводе, Windows осуществляет перерасчет. В логической системе координат направления осей Х и У можно задать, и единицами измерения могут быть не только пиксели устройства, но и десятые, сотые доли миллиметра и дюйма.

При пересчете Windows осуществляет пересчет логической точки (LP) из логического пространства координат, в физическую точку из физической системы координат (DP). Это делается за 3 шага:

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

2. Масштабирование полученного изображения путем масштабирования заданной точки (умножением на заданный коэффициент). Изображение переносится на физическую плоскость.

3. Параллельный перенос изображения на физической плоскости за счет добавления заданных константных значений.

DX=(LX-XWO)*XVE/XWE+XVO

DY=(LY-YWO)*YVE/YWE+YVO

Где:


LX – координата Х в логической системе

XWO – смещение по оси Х в логической системе

XVO – смещение по оси Х в физической системе координат

XVE/XWE – масштабный интерфейс по оси Х

В ОС существуют функции, которые выполняют заданные преобразования для массива точек: LPtoDP() и DPtoLP().

Матрицы трансформаций

Сама матрица трансформации имеет размер 3х3 и в общем виде записывается так:

матрица преобразований

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

формула преобразования

Коэффициент

Описание

a

Изменение масштаба по горизонтали. Значение больше 1 расширяет элемент, меньше 1, наоборот, сжимает.

b

Наклон по горизонтали. Положительное значение наклоняет влево, отрицательное вправо.

c

Наклон по вертикали. Положительное значение наклоняет вверх, отрицательное вниз.

d

Изменение масштаба по вертикали. Значение больше 1 расширяет элемент, меньше 1 — сжимает.

tx

Смещение по горизонтали в пикселах. Положительное значение сдвигает элемент вправо на заданное число пикселов, отрицательное значение сдвигает влево.

ty

Смещение по вертикали в пикселах. При положительном значении элемент опускается на заданное число пикселов вниз или вверх при отрицательном значении.

Для работы с трансформацией необходимо включить расширенный графический режим:

int SetGraphicsMode(HDC hdc, int iMode); GM_ADVANCED

Матрица трансформаций представлена структурой:

struct XFORM {

FLOAT eM11;

FLOAT eM12;

FLOAT eM21;

FLOAT eM22;

FLOAT eDx;

FLOAT eDy;

};

Переменные соответствуют следующим элементам матрицы:





Виды трансформаций

Параллельный перенос:



Масштабирование:



Отражение:



Поворот:


Наклон:




Режимы масштабирования

В процессе вывода изображения функции графического интерфейса GDI преобразуют логические координаты в физические. Для определения способа такого преобразования используется атрибут с названием режим масштабирования (mapping mode), который хранится в контексте устройства вывода.

Для установки типа масштабирования используется метод контекста устройства int SetMapMode(HDC hdc, int fnMapMode), а для получения типа масштабирования - метод GetMapMode().

Для указания режима масштабирования в файле windows.h определены символьные константы с префиксом MM_ (от Mapping Mode - режим масштабирования).

Восемь существующих режимов масштабирования координат задаются с помощью символьных констант, определенных в файле Wingdi.h:

Режим масштабирования

Логических единиц

Физических единиц

Направление осей

Х

У

MM_TEXT

1

1 pixel





MM_LOMETRIC

10

1 mm





MM_HIMETRIC

100

1 mm





MM_LOENGLISH

100

1 inch





MM_HIENGLISH

1000

1 inch





MM_TWIPS

1440

1 inch





MM_ISOTROPIC

Задается

Задается





MM_ANISOTROPIC

Задается

Задается





По умолчанию действует режим ММ_ТЕХТ, в котором ось Y имеет направление сверху вниз.

Отличие MM_ISOTROPIC от MM_ANISOTROPIC заключается в том, что, при масштабировании в первом из этих двух режимов, оси координат будут масштабироваться равномерно, то есть изображение будет масштабироваться без искажений. Для определения ориентации осей координат и единиц измерения необходимо использовать функции SetWindowExtEx и SetViewportExtEx.




13. Понятие ресурсов программ Windows. Виды ресурсов. Операции с ресурсами.

Ресурсы – двоичные данные, записываемые в исполняемый модуль приложения.

Стандартные виды ресурсов:

· Курсор – Cursor

· Картинка – Bitmap

· Значок – Icon

· Меню – Menu

· Окно диалога – Dialog Box

· Таблица строк – String Table

· Таблица сообщений (об ошибках) – Message Table

· Шрифт – Font

· Таблица горячих клавиш – Accelerator Table

· Информация о версии – Version Information

· Ресурс Plug and Play

· Ресурс VXD

· Ресурс HTML

· Манифест приложения – Side-by-Side Assembly Manifest

· Двоичные данные – RCData

Окна выполняемые в монопольном режиме – окна диалога. В ОС окна диалога загружаются из ресурса и выполняются с помощью одной функции.

Программист может создавать свои собственные типы ресурсов. Ресурсы – отдельны от кода и данных. Ресурсы обладают свойством разделяемости. Несколько программ могут использовать копию одного ресурса.

В .ехе файле ресурс может идентифицироваться числом (0..65536) или строкой. Ресурсы создаются на языке описания ресурсов и располагается в фалах *.rc. При сборке ехе файла rc файлы дописываются в ехе файл.

Добавление и удаление ресурсов исполняемого модуля:

· HANDLE BeginUpdateResource(LPCTSTR pFileName, bool bDeleteExistingResources);

· bool UpdateResource(HANDLE hUpdate, LPCTSTR lpType, LPCTSTR lpName, WORD wLanguage, void* lpData, DWORD cbData);

· bool EndUpdateResource(HANDLE hUpdate, bool fDiscard);
Функция BeginUpdateResource возвращает дескриптор, который может быть использован функцией UpdateResource для добавления, удаления или замены ресурсов в исполняемом файле.Процесс записи ресурсов в файл начинается с вызова BeginUpdateResource. При этом флаг bDeleteExistingResources задает режим записи: с удалением существующих ресурсов или без.Заканчивается процесс записи вызовом EndUpdateResource. Если флаг bDiscard установлен в TRUE, то запись ресурсов отменяется, в противном случае ресурсы записываются в файл.

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


Загрузка ресурсов из исполняемого модуля:

· HRSRC FindResourceEx(HMODULE hModule, LPCTSTR lpType, LPCTSTR lpName, WORD wLanguage); FindResource, EnumResourceXxx.

· HGLOBAL LoadResource(HMODULE hModule, HRSRC hResInfo); LoadImage, LoadMenu, LoadXxx.

· DWORD SizeofResource( HMODULE hModule, HRSRC hResInfo);

Функция FindResource выясняет место ресурса с заданным типом и именем в указанном модуле.

Функция LoadResource загружает указанный ресурс в глобальную память.



14. Понятие динамически-загружаемой библиотеки. Создание DLL-библиотеки. Использование DLL-библиотеки в программе методом статического импорта процедур. Соглашения о вызовах процедур DLL-библиотеки. Точка входа-выхода DLL-библиотеки.



  • Динамически-загружаемая библиотека (DLL) – двоичный модуль операционной системы. Это программа с множеством точек входа. Включает код, данные и ресурсы.

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

· Создавая DLL, Вы создаете набор функций, которые могут быть вызваны из EXE-модуля (или другой DLL). DLL может экспортировать переменные, функции или C++ классы в другие модули. На самом деле я бы не советовал экспортировать переменные, потому что это снижает уровень абстрагирования Вашего кода и усложняет его поддержку. Кроме того, C++ классы можно экспортировать, только если импортирующие их модули транслируются тем же компилятором. Так что избегайте экспорта C++ классов, если Вы не уверены, что разработчики EXE модулей будут пользоваться тем же компилятором.

· При разработке DLL Вы сначала создаете заголовочный файл, в котором содержатся экспортируемые из нее переменные (типы и имена) и функции (прототипы и имена). В этом же файле надо определить все идентификаторы и структуры данных, используемые экспортируемыми функциями и переменными. Заголовочный файл включается во все модули исходного кода Вашей DLL. Более того, Вы должны поставлять его вместе со своей DLL, чтобы другие разработчики могли включать его в свои модули исходного кода, которые импортируют Ваши функции или переменные. Единый заголовочный файл, используемый при сборке DLL и любых исполняемых модулей, существенно облегчает поддержку приложения.

Модуль: MyLib.h

************************************************************/

#ifdef MYLIBAPI

// MYLIBAPI должен быть определен во всех модулях исходного кода DLL

// до включения этого файла

// здесь размещаются все экспортируемые функции и переменные

#else

// этот заголовочный файл включается в исходный код EXE-файла; // указываем, что все функции и переменные импортируются #define MYLIBAPI extern "C" __declspec(dllimport)

#endif

////////////////////////////////////////////////////////////////////////////

// здесь определяются все структуры данных и идентификаторы (символы)

////////////////////////////////////////////////////////////////////////////

// Здесь определяются экспортируемые переменные. // Примечание: избегайте экспорта переменных. MYLIBAPI int g_nResult;

////////////////////////////////////////////////////////////////////////////

// здесь определяются прототипы экспортируемых функций MYLIBAPI int Add(int nLeft, int nRight);

Этот заголовочный файл надо включать в самое начало исходных файлов Вашей DLL следующим образом.

/***************************************************************************

Модуль: MyLibFile1.cpp

***************************************************************************/

// сюда включаются стандартные заголовочные файлы Windows и библиотеки C #include

// этот файл исходного кода DLL экспортирует функции и переменные

#define MYLIBAPI extern "C" __declspec(dllexport)

// включаем экспортируемые структуры данных, идентификаторы, функции и переменные

#include "MyLib.h" ////////////////////////////////////////////////////////////////////////////

// здесь размещается исходный код этой DLL int g_nResult;

int Add(int nLeft, int nRight) { g_nResult = nLeft + nRight; return(g_nResult);

}

При компиляции исходного файла DLL, показанного на предыдущем листинге, MYLIBAPI определяется как __declspec(dllexport) до включения заголовочного файла MyLib.h. Такой модификатор означает, что данная переменная, функция или C++ класс экспортируется из DLL. Заметьте, что идентификатор MYLIBAPI помещен в заголовочный файл до определения экспортируемой переменной или функции.

Также обратите внимание, что в файле MyLibFile1.cpp перед экспортируемой переменной или функцией не ставится идентификатор MYLIBAPI. Он здесь не нужен: проанализировав заголовочный файл, компилятор запоминает, какие переменные и функции являются экспортируемыми.

Идентификатор MYLIBAPI включает extern. Пользуйтесь этим модификатором только в коде на C++, но ни в коем случае не в коде на стандартном C. Обычно компиляторы C++ искажают (mangle) имена функций и переменных, что может приводить к серьезным ошибкам при компоновке. Представьте, что DLL написана на C++, а исполняемый код — на стандартном C. При сборке DLL имя функции будет искажено, но при сборке исполняемого модуля — нет. Пытаясь скомпоновать исполняемый модуль, компоновщик сообщит об ошибке: исполняемый модуль обращается к несуществующему идентификатору. Модификатор extern не дает компилятору искажать имена переменных или функций, и они становятся доступными исполняемым модулям, написанным на C, C++ или любом другом языке программирования.

Теперь Вы знаете, как используется заголовочный файл в исходных файлах DLL. А как насчет исходных файлов EXE-модуля? В них MYLIBAPI определять не надо: включая заголовочный файл, Вы определяете этот идентификатор как __declspec(dllimport), и при компиляции исходного кода EXE-модуля компилятор поймет, что переменные и функции импортируются из DLL.

Просмотрев стандартные заголовочные файлы Windows (например, WinBase.h), Вы обнаружите, что практически тот же подход исповедует и Microsoft.

Статический импорт DLL-библиотеки

  • Экспорт функции при создании DLL:

n __declspec(dllexport) int Min(int X, int Y);

- Добавить библиотеку DLL в проект Visual Studio.

- __declspec(dllimport) int Min(int X, int Y);

- При сборке проекта будет создана статическая библиотека импорта с расширением LIB. Эта статическая библиотека включается в EXE-файл и содержит код вызова функции Min из DLL-библиотеки.

  • Соглашения о вызовах подпрограмм:

- __declspec(dllimport) int __stdcall Min(int X, int Y);

- __cdecl – Параметры передаются на стек в обратном порядке. За освобождение стека после вызова подпрограммы отвечает вызывающая программа.

- __pascal – Передача параметров на стек в прямом порядке. Освобождение стека осуществляет сама вызванная подпрограмма.

- __stdcall – Соглашение для стандартных DLL ОС Windows. Передача параметров на стек происходит в обратном порядке. Освобождение стека выполняет вызванная подпрограмма.

__register – Передача параметров преимущественно через регистры процессора. Не используется при создании DLL, поскольку не стандартизировано.

  • Соглашения о вызовах подпрограмм:

n- Разные способы передачи параметров создают трудности. Главная трудность связана с применением соглашения __stdcall. В VisualStudio использование соглашение о вызовах __stdcall вводит определенные правила именования функций в DLL. Функция получает имя: _Имя@КоличествоБайтПараметров.



_Min@8

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

EXPORTS

Min,Max

При наличии DEF-файла компилятор выбирает из него имена для функций.

Функция входа/выхода

В DLL может быть лишь одна функция входа/выхода. Система вызывает ее в некоторых ситуациях (о чем речь еще впереди) сугубо в информационных целях, и обычно она используется DLL для инициализации и очистки ресурсов в конкретных процессах или потоках. Если Вашей DLL подобные уведомления не нужны, Вы не обязаны реализовывать эту функцию. Пример — DLL, содержащая только ресурсы. Но если же уведомления необходимы, функция должна выглядеть так:

BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, PVOID fImpLoad) {

switch (fdwReason) {

case DLL_PROCESS_ATTACH:

// DLL проецируется на адресное пространство процесса

break;

case DLL_THREAD_ATTACH: // создается поток break;

case DLL_THREAD_DETACH:

// поток корректно завершается

break;

case DLL_PROCESS_DETACH:
// DLL отключается от адресного пространства процесса break;

}

return(TRUE); // используется только для DLL_PROCESS_ATTACH }



Не забывайте, что DLL инициализируют себя, используя функции DllMain. К моменту выполнения Вашей DllMain другие DLL в том же адресном пространстве могут не успеть выполнить свои функции DllMain, т. е. они окажутся неинициализированными. Поэтому Вы должны избегать обращений из DllMain к функциям, импортируемым из других DLL. Кроме того, не вызывайте из DllMain функции LoadLibrary(Ex) и FreeLibrary, так как это может привести к взаимной блокировке.

В документации Platform SDK утверждается, что DllMain должна выполнять лишь простые виды инициализации — настройку локальной памяти потока, создание объектов ядра, открытие файлов и т. д. Избегайте обращений к функциям, связанным с User, Shell, ODBC, COM, RPC и сокетами (а также к функциям, которые их вызывают), потому что соответствующие DLL могут быть еще не инициализированы. Кроме того, подобные функции могут вызывать LoadLibrary(Ex) и тем самым приводить к взаимной блокировке.

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


Поделитесь с Вашими друзьями:
1   2   3   4   5   6   7   8   9   10   ...   21


База данных защищена авторским правом ©nethash.ru 2019
обратиться к администрации

войти | регистрация
    Главная страница


загрузить материал