14.35M
Category: programmingprogramming

Глубокое системное программирование

1.

Санкт-Петербургский государственный университет
телекоммуникаций им. проф. М.А.Бонч-Бруевича
Кафедра автоматизации предприятий связи (АПС)
Тема № 2. Глубокое системное программирование

2.

Подготовка к системному программированию
Visual Studio Professional 2013 (или Ultimate-версия):
http://msdn.microsoft.com/en-US/windows/hardware/gg454513
Windows Software Development Kit – SDK 8.1:
http://msdn.microsoft.com/en-US/windows/desktop/bg162891
Windows Driver Kit – WDK 8.1:
http://msdn.microsoft.com/en-US/windows/hardware/gg454513
Символьная информация о системных модулях Windows:
http://msdn.microsoft.com/en-US/windows/hardware/gg454513
Утилита Dependency Walker для просмотра зависимостей
DLL-библиотек:
http://www.dependencywalker.com/
Набор утилит Sysinternals для глубокого просмотра
процессов, дисков, сети и прочего:
http://technet.microsoft.com/en-us/sysinternals/bb545027
4

3.

Основы программирования для ОС Windows
При разработке приложений в Visual C++ множество
основных способов разработки программ:
- использование интерфейса API Windows;
- использование классов Microsoft Foundation
Classes;
- использование Windows Forms APP;
- ……………….
6

4.

Основы программирования для ОС Windows
Способы разработки приложений в среде Visual C++
7

5.

Основы программирования для ОС Windows
Программирование, управляемое событиями
Традиционные программы организованы иерархическим образом.
Например, в языке С++ наверху пирамиды находится функция main(),
которая вызывает подпрограммы.
Однако программа Windows не организована иерархически в чистом
виде. Программа содержит функции, но они предназначены для
формирования отклика на внешние события.
Поэтому говорят, что программы Windows управляются событиями.
События в приложении Windows представляют собой различные
происшествия, в частности:
- щелчок кнопкой мыши;
- Нажатие клавиши;
- Истечение определенного интервала времени;
- События могут быть сгенерированы функциями внутри вашей
программы или других программ.
8

6.

Архитектура, управляемая событиями
В основе взаимодействия программы с внешним миром и с
операционной системой лежит концепция сообщений.
С точки зрения приложения, сообщение является уведомлением о
том, что произошло некоторое событие, которое может требовать,
а может и не требовать выполнения определенных действий. Это
событие может быть следствием действий пользователя, например
перемещения курсора или щелчка кнопкой мыши, изменения
размеров окна или выбора пункта меню. Кроме того, событие
может
генерироваться приложением, а также операционной
системой.

7.

Архитектура, управляемая событиями
Сообщение - это структура данных, содержащая следующие элементы:
• дескриптор окна, которому адресовано сообщение;
• код (номер) сообщения;
• дополнительную информацию, зависящую от кода сообщения.
Сообщения в Windows описываются с помощью структуры MSG:
typedef struct tagMSG {
HWND hwnd;
// Идентификатор окна-получателя
UINT message;
// Идентификатор сообщения
WPARAM wParam;
// Дополнительная информация, смысл
LPARAM lParam;
// которой зависит от типа сообщения
DWORD time;
// Время посылки сообщения
POINT pt;
// Местоположение указателя мыши
} MSG;

8.

Архитектура, управляемая событиями
Сообщения от внешних источников, например от клавиатуры, адресуются в каждый
конкретный момент времени только одному из работающих приложений, а именно активному окну. Windows играет роль диспетчера сообщений. Для этого с момента
старта операционная система создает в памяти глобальный объект, называемый
системной очередью сообщений.
Все сообщения, генерируемые как аппаратурой, так и приложениями, помещаются в эту
очередь. Windows периодически опрашивает эту очередь и, если она не пуста,
посылает очередное сообщение нужному адресату, определяемому при помощи
дескриптора окна.
Сообщения, получаемые приложением, могут поступать асинхронно из разных источников.
Например, приложение может работать с системным таймером, посылающим ему
сообщения с заданным интервалом, и одновременно оно должно быть готовым в любой
момент получить любое сообщение от операционной системы. Чтобы не допустить потери
сообщений, Windows одновременно с запуском приложения создает глобальный объект,
называемый очередью сообщений приложения.

9.

Основы программирования для ОС Windows
Структура Windows-приложения
12

10.

Основы программирования для ОС Windows
Генерация аппаратных событий
На аппаратном уровне каждое устройство ввода Windows управляется
прерываниями.
Когда пользователь нажимает клавишу клавиатуры, генерируется аппаратное
прерывание. Windows приостанавливает работу и передает управлению
фрагменту кода –Interrupt Service Routine –ISR (Программа обработки
прерываний).
ISR формирует специальные данные и записывает их в регистры. Затем вызывается
специальная внутренняя программа Windows, которая извлекает данные из
регистров и помещает запись о событии в аппаратную очередь Windows.
Далее аппаратные события передаются в очередь приложения.
Таким образом, даже при том, что аппаратный ввод является управляемым
прерываниями, сообщения события обрабатываются приложением в
порядке FIFO.
13

11.

Основы программирования для ОС Windows
Назначение сообщений
Сообщения – это стандартный механизм связи внутри
программ
Источники сообщений
События аппаратного ввода генерируются мышью, клавиатурой, таймером и т.д.
События диспетчера окон генерируются Windows в ответ на действия пользователя,
выполняющего операции типа перемещения или изменения размеров окна, выбора
пунктов меню. Пример сообщения данного типа –WM_PAINT.
Индивидуальные окна могут посылать сообщения другим окнам. Например, для
указания текстовому полю об удалении текста посылается сообщение
WM_SETTEXT. Текстовое поле также использует данный механизм для сообщения
14
об изменении текста путем посылки программисту сообщения EN_CHANGE.

12.

Основы программирования для ОС Windows
Назначение сообщений
Сообщения Windows идентифицируются мнемоническими идентификаторами,
которые соответствуют целочисленным константам.
Сообщения, сгенерированные непосредственно Windows, начинаются с символов
«WM_» (Windows Message).
Сообщения, сгенерированные специфическими видами средств управления
Windows, имеют различные префиксы. Например, сообщения, сгенерированные
средствами редактирования имеют префикс «EN_» (Edit Notification).
Все эти константы определены в файле WinUser.h.
#define WM_NULL
#define WM_CREATE
#define WM_DESTROY
#define WM_MOVE
#define WM_SIZE
0x0000
0x0001
0x0002
0x0003
0x0005
15

13.

Основы программирования для ОС Windows
Назначение сообщений
typedef struct tagMSG { // msg
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG;
hwnd - Определяет окно которого процедура окна получает сообщение.
Message - Указывает номер сообщения.
wParam - Определяет дополнительную информацию о сообщении. Точный смысл зависит от
значения элемента сообщение.
lParam - Определяет дополнительную информацию о сообщении. Точный смысл зависит от
значения элемента сообщение.
time - Указывает время, когда сообщение было создано.
pt -Задает положение курсора в координатах экрана, когда сообщение было создано.
16

14.

Основные понятия. Элементы окна
Пиктограмма панели
заголовка
Текст панели заголовка
Панель
меню
Панель
инструменто
в
Клиентская
область
Панель
состояния
Стандартные окна программы Windows
17

15.

Интерфейс Windows API
Разработчиками ОС Windows была создана библиотека
функций, при помощи которых происходит
взаимодействие приложения с операционной
системой, так называемые функции Программного
интерфейса приложений (Application Program Interface).
Для разработки минимальной программы с
использованием Win API необходимо написать две
функции:
- WinMain(), с которой начинается выполнение
программы и происходит её инициализация;
- WndProc(), вызываемая Windows для обработки
сообщений приложения.
18

16.

Интерфейс Windows API
Структура Windows-программы
19

17.

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

18.

Каркас Windows-приложения
1. Определить класс окна.
2.
3.
4.
5.
Зарегистрировать окно.
Создать окно данного класса.
Отобразить окно.
Запустить цикл обработки сообщений.
Структура окна
Заголовок окна
Главное меню окна
Рабочая область окна

19.

Каркас Win32 приложения
Основу программы в Win32 составляет функция WinMain, которая
«заменяет» собой стандартную функцию main языков C и C++.
Описание этой функции имеет следующий вид:
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{

return Код_вовзрата;
}
В некоторых средах разработки вместо WINAPI пишут APIENTRY

20.

Каркас Win32 приложения
Параметры функции WinMain:
• HINSTANCE hInstance – идентификатор текущего приложения;
• HINSTANCE hPrevInstance – идентификатор приложения,
являющегося родительским для данного приложения;
• LPTSTR lpCmdLine – С-строка, содержащая параметры
командной строки;
• int nCmdShow – код вида начального отображения окна.
Возвращаемое значение функции WinMain: целое число,
интерпретируемое как код возврата. Обычно в качестве его
значения указывается параметр сообщения закрытия
приложения в виде:
(int) msg.wParam

21.

Каркас Win32 приложения
НАЧАЛО
Описание класса окна
Регистрация класса окна
Создание окна
Отображение окна
Ожидание, прием и
обработка сообщения
Это сообщение
завершения
Да
КОНЕЦ

22.

Каркас Win32 приложения
Для описания класса окна необходимо заполнить структуру типа WNDCLASSEX или
WNDCLASS (старый вариант).
typedef struct tagWNDCLASSEXW {
UINT
cbSize;
UINT
style;
WNDPROC lpfnWndProc;
int
cbClsExtra;
int
cbWndExtra;
HINSTANCE hInstance;
HICON hIcon;
HCURSOR hCursor;
HBRUSH hbrBackground;
LPCWSTR lpszMenuName;
LPCWSTR lpszClassName;
HICON hIconSm;
} WNDCLASSEXW;
//Размер структуры
//Стиль окна
//Адрес функции обработки сообщений
//Размер дополнительной памяти в байтах под
//структуру класса-окна (инициализируется 0)
//Размер дополнительной памяти в байтах под
//структуру окна (инициализируется 0)
//Код приложения
//Код идентификатора иконки приложения
//Код идентификатора курсора
//Код идентификатора кисти фона окна
//Имя ресурса, описывающего меню программы
//Имя класса окна
//Код идентификатора иконки класса окна

23.

Каркас Win32 приложения
После заполнения всех полей данной структуры класса окна необходимо
зарегистрировать с помощью функции RegisterClassEx() или
RegisterClass() (старый вариант).
Прототип функции:
ATOM RegisterClassEx(CONST WNDCLASSEX *lpwcx );
В параметре в функцию передается адрес заполненной структуры типа
WNDCLASSEX.
Функция возвращает идентификатор зарегистрированного класса окна в
случае успешного выполнения. В случае ошибки функция возвращает 0.

24.

Каркас Win32 приложения
После успешной регистрации класса окна необходимо создать само окно. Это осуществляется с
помощью функции CreateWindow.
Прототип функции:
HWND CreateWindow(
LPCTSTR lpClassName, //С-строка содержащая имя класса
LPCTSTR lpWindowName,
//C-строка содержащая имя окна
DWORD dwStyle,
//Стиль окна
int x,
//Позиция x на экране
int y,
//Позиция y на экране
int nWidth,
//Ширина окна (по оси X)
int nHeight,
//Высота окна (по оси Y)
HWND hWndParent,
//Дескриптор родительского окна
HMENU hMenu,
//Дескриптор главного меню
HINSTANCE hInstance, //Идентификатор приложения
LPVOID lpParam
//Параметры сообщения WM_CREATE
);

25.

Каркас Win32 приложения
В случае успешного выполнения функция CreateWindow
возвращает дескриптор созданного окна. В случае ошибки
функция возвращает NULL.
Некоторые стили окна:
WS_BORDER
Создает окно с «неподвижной» границей
WS_CAPTION
Создает окно у которого есть заголовок
WS_CHILD
Создает дочернее окно (вложено в другое окно)
WS_DISABLED
Создает «запрещенное» окно, в него не передаются сообщения
WS_DLGFRAME
Создает диалоговое окно
WS_HSCROLL
Создает окно с горизонтальной полосой прокрутки
WS_OVERLAPPE
D
Создает окно с заголовком и «подвижной» границей
WS_MAXIMIZE
Создает окно изначально развернутое на весь экран
WS_MINIMIZE
Создает окно изначально свернутое
WS_POPUP
Создает «всплывающее» окно (в противоположность WS_CHILD)
WS_VISIBLE
Создает окно изначально видимое на экране
WS_VSCROLL
Создает окно с вертикальной полосой прокрутки

26.

Каркас Win32 приложения
После того, как окно успешно создано, его необходимо отобразить используя функции
ShowWindow и UpdateWindow.
Функция отображения окна:
BOOL ShowWindow(HWND hWnd, int nCmdShow);
Некоторые типы команд отображения окна:
• SW_HIDE – скрыть окно и активизировать другое окно,
• SW_MAXIMIZE – развернуть на весь экран,
• SW_MINIMIZE – свернуть окно и активизировать предыдущее окно,
• SW_RESTORE – восстановить изначальные размеры окна,
• SW_SHOW – активизировать окно и отобразить его.
Функция возвращает истину, если окно было изначально видимо, и ложь – если нет.
Функция обновления окна:
void UpdateWindow(HWND hWnd);
Вызывает обновление (перерисовку) окна.

27.

Каркас Win32 приложения
После создания и отображения окна необходимо
организовать цикл получения и обработки сообщений.
Для этих целей в Win32 API используются следующие
функции:
• GetMessage – получение сообщения,
• TranslateMessage – преобразует сообщения виртуальных
клавиш в символьные сообщения,
• DispatchMessage – вызывает обработчик сообщения.

28.

Каркас Win32 приложения
Функция получения сообщения
BOOL GetMessage(
LPMSG lpMsg,
//Указатель на структуру MSG
HWND hWnd,
//Дескриптор окна
UINT wMsgFilterMin,
//Минимальный номер отслеживаемых сообщений
UINT wMsgFilterMax
//Максимальный номер отслеживаемых сообщений
);
Если функция получает сообщение отлично от WM_QUIT, то возвращается не
нулевое значение (истина).

29.

Каркас Win32 приложения
Функция преобразования сообщения виртуальных
символьные сообщения
BOOL TranslateMessage(const MSG *lpMsg );
клавиш
в
Возвращает значение «истина», если сообщение было успешно
преобразовано. Если сообщение не преобразовано, то
возвращает значение «ложь»
Данная функция предназначена для создания сообщений WM_CHAR
на основе сообщений WM_KEYDOWN и WM_KEYUP.

30.

Каркас Win32 приложения
Функция обработки сообщения
LRESULT DispatchMessage(const MSG *lpmsg );
Функция вызывает функцию-обработчик сообщений для данного окна и
возвращает результат обработки.
Значение результата зависит от самой функции-обработчика, и как
правило игнорируется.

31.

Типовая функция WinMain
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
MSG msg; HWND hwnd;
WNDCLASSEX wcx;
//Заполнение полей структуры wcx
if(!RegisterClassEx(&wcx)) return FALSE;
hwnd = CreateWindow(/*параметры*/);
if(!hwnd) return FALSE;
ShowWindow(hWnd,nCmdShow);
UpdateWindow(hWnd);
while(GetMessage(&msg,NULL,0,0)){
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}

32.

Функция-обработчик сообщений
Прототип функции:
LRESULT CALLBACK WndProc(
HWND hwnd,
//Дескриптор окна
UINT message,
//Код сообщения
WPARAM wParam,
//Первый параметр сообщения
LPARAM lParam
//Второй параметр
сообщения
);
Тип WPARAM – unsigned int
Тип LPARAM – long

33.

Типовой алгоритм функции WndProc
LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
switch(message){
case WM_DESTROY:
PostQuitMessage(0);
break;
case СОБЫТИЕ_1:
//Обработка события 1
break;
case СОБЫТИЕ_2:
//Обработка события 1
break;

default: return DefWindowProc(hwnd, message, wParam, lParam);
}
return 0;
}

34.

Некоторые сообщения
WM_CREATE
Событие создания окна
WM_DESTROY
Событие уничтожения окна
WM_MOVE
Событие перемещения окна
WM_SIZE
Событие изменения размеров окна
WM_PAINT
Событие перерисовки содержимого окна
WM_COMMAND
Событие поступления сообщения для (от) элемента
управления
WM_MOUSEMOVE
Событие перемещения курсора мыши
WM_LBUTTONDOWN
Событие нажатия левой кнопки мыши
WM_LBUTTONUP
Событие отпускания левой кнопки мыши
WM_LBUTTONDBLCLK
Событие двойного нажатия левой кнопки мыши
WM_RBUTTONDOWN
Событие нажатия правой кнопки мыши
WM_RBUTTONUP
Событие отпускания правой кнопки мыши
WM_RBUTTONDBLCLK
Событие двойного нажатия правой кнопки мыши
WM_KEYDOWN
Событие нажатия клавиши на клавиатуре
WM_KEYUP
Событие отпускания клавиши на клавиатуре
WM_CHAR
Событие ввода символа
WM_TIMER
Событие срабатывания таймера

35.

Дополнительные функции
Функция определения существования окна
BOOL IsWindow(HWND hwnd);
Функция проверки наличия фокуса ввода у окна
BOOL IsWindowEnabled(HWND hwnd);
Функция разрешения или запрета фокуса ввода у окна
BOOL EnableWindow(HWND hwnd, BOOL flag);
Функция передачи фокуса управления окну
HWND SetFocus(HWND hwnd);
Функция поиска окна с заданными классом и названием
HWND FindWindow(LPCTSTR lpClassName, LPCTSTR lpWindowName);

36.

Дополнительные функции
Функция перемещения окна
BOOL MoveWindow(HWND hwnd, int x, int y, int nWidth, int nHeight,
BOOL bRepaint);
Функция относительного перемещения окна:
BOOL SetWindowPos(HWND hwnd, HWND hwndInsertAfter, int x, int y,
int nWidth, int nHeight, UINT uFlags);
hwndInsertAfter может быть дескриптором существующего окна или одним из
следующих значений:
• HWND_BOTTOM – помещает окно ниже других окон,
• HWND_NOTOPMOST – помещает временное или дочернее окно выше временных
или дочерних окон, но ниже перекрывающихся окон,
• HWND_TOP – помещает окно выше всех окон,
• HWND_TOPMOST – то же, что HWND_NOTOPMOST, но окно сохраняет позицию
после потери активности.

37.

Дополнительные функции
Вывод окна на передний план и передача ему управления:
BOOL SetForegroundWindow(HWND hwnd);
Функция получения системных метрик:
int GetSystemMetric(int nIndex);
nIndex может принимать следующие значения:
• SM_CXMIN – минимальная ширина окна,
• SM_CYMIN – минимальная высота окна,
• SM_CXSCREEN – ширина окна,
• SM_CYSCREEN – высота окна,
• SM_CYCAPTOIN – высота заголовка окна,
• SM_CYMENU – высота меню окна.

38.

Дополнительные функции
Функция получения параметров окна:
BOOL GetWindowRect(HWND hwnd, LPRECT rect);
Функция получения параметров рабочей области окна:
BOOL GetClientRect(HWND hwnd, LPRECT rect);
typedef struct{
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT;
//Левый край
//Верхний край
//Правый край
//Нижний край

39.

Окно сообщения
Вызов окна сообщения осуществляется с помощью функции:
int WINAPI MessageBox(
HWND hwnd,
//Дескриптор окна
LPCTSTR lpText,
//С-строка текста сообщения
LPCTSTR lpCaption,
//С-строка заголовка
сообщения
UINT uType
//Флаги окна сообщения
);
MB_ABORTRETRYIGNORE
Стоп, Отмена, Пропустить
MB_OK
ОК
MO_OKCANCEL
ОК, Отмена
MB_RETRYCANCEL
Повтор, Отмена
MB_YESNO
Да, Нет
MB_YESNOCANCEL
Да, Нет, Отмена

40.

Окно сообщения
Флаг
№ кнопки
Флаг
№ кнопки
MB_DEFBUTTON1
Первая
MB_DEFBUTTON3 Третья
MB_DEFBUTTON1
Вторая
MB_DEFBUTTON4 Четвертая
Флаг
Вид иконки
MB_ICONEXCLAMATION,
MB_ICONWARNING
Восклицательный знак
MB_ICONINFORMATION,
MB_ICONASTERIX
Символ i
MB_ICONQUESTION
Знак вопроса
MB_ICONSTOP,
MB_ICONERROR,
MB_ICONHAND
Знак остановки

41.

Окно сообщения
MB_APPLMODAL
Окно hwnd переводится в неактивное
состояние на время работы окна сообщения
MB_SYSTEMMODAL
На время работы окна сообщения все другие
приложения в неактивном состоянии
MB_TASKMODAL
На время работы окна сообщения текущее
приложение в неактивном состоянии. Если
hwnd=NULL, то все перекрывающие окна
MB_HELP
Добавляет кнопку «Справка»
MB_RIGHT
Текст выравнивается по правому краю
MB_RTLREADING
Отображает символы сообщения и текст
заголовка в направлении справа налево
MB_SETFOREGROUND Окно сообщения выдвигается на передний
план

42.

Интерфейс Windows API
Функция WinMain() выполняет четыре основные функции:
- сообщает ОС, какого вида окно требуется программе;
- создает окно программы;
- инициализировать окно программы;
- извлекает сообщения Windows, предназначенные программе.
На псевдокоде функцию WinMain() можно представить следующим образом:
WinMain(список аргументов)
{
Подготовить и зарегистрировать класс окна с нужными характеристиками;
Создать экземпляр зарегистрированного класса;
Пока не произошло необходимое для выхода события
{
Извлечь очередное сообщение из очереди сообщений;
Передать его через Windows оконной функции;
}
Возврат из программы
}
45

43.

Интерфейс Windows API
Функция WinMain()
После того как Windows загружает программу, то она вызывает функцию WinMain.
int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int
nCmdShow)
{
MyRegisterClass(hInstance);
// Выполнить инициализацию приложения:
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32_API));
// Цикл основного сообщения:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int) msg.wParam;
}
46

44.

Интерфейс Windows API
Функция WindowProc()
Функция WndProc() является «функцией обратного
вызова». Такие функции вызываются операционной
системой, а не самой программой.
WindowProc() обрабатывает все сообщения, которые
поступают окну программы.
LRESULT CALLBACK WINDOWPROC(HWND hWnd, UINT
message,WPARAM wParam, LPARAM lParam);
Аргументы функции:
hWnd – дескриптор окна, в котором произошло событие;
message – тип сообщения;
47

45.

Интерфейс Windows API
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Разобрать выбор в меню:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: добавьте любой код отрисовки...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
48

46.

Интерфейс Windows API
Передача сообщений
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
49

47.

Интерфейс Windows API
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: добавьте любой код отрисовки...
GetClientRect(hWnd,&rect);
DrawText(hdc,L"Здравствуй, МИР!",-1,&rect,
DT_SINGLELINE|DT_CENTER|DT_VCENTER);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam,
lParam);
}
return 0;
50

48.

Библиотеки динамической компоновки DLL
Одной из особенностей Windows-приложений является их способность подключать
во время работы необходимые функции и ресурсы, которые размещены в так
называемых библиотеках динамической компоновки (Dynamic-Link Libraries, DLL).
Все функции Windows содержатся в dll-файлах, например, графические функции
размещены в файле gdi32.dll. Преимущество использования библиотек
динамической компоновки перед статическими библиотеками проявляется в том, что
приложение, состоящее даже из нескольких модулей, использует лишь один
экземпляр функции, тогда как из статической библиотеки каждый программный
модуль при-соединяет свою копию функции на этапе компоновки. Рассмотрим
подробно способы создания динамических библиотек и их использование.

49.

Создание DLL
Создание проекта библиотеки DLL в Visual Studio
1. В строке меню выберите Файл > Создать > Проект, чтобы открыть диалоговое окно Создание проекта.
2. В верхней части диалогового окна для параметра Язык установите значение C++ , для параметра
Платформа — значение Windows, а для параметра Тип проекта — значение Библиотека.
3. В отфильтрованном списке типов проектов щелкните Библиотека динамической компоновки (DLL) , а затем
нажмите кнопку Далее.
4. На странице Настроить новый проект введите MathLibrary в поле Имя проекта. Примите заданные по
умолчанию Расположение и Имя решения. Для параметра Решение задайте Создать новое решение. Снимите
флажок Разместить решение и проект в одном каталоге, если он установлен.
5. Нажмите кнопку Создать, чтобы создать проект.

50.

После создания решения созданный проект вместе с исходными файлами отобразится в окне обозревателя
решений в Visual Studio.
Пока эта библиотека DLL ничего не
делает. Затем вы создадите файл
заголовка для объявления функций,
экспортируемых вашей библиотекой
DLL, и добавите определения функций в
библиотеку DLL, чтобы сделать ее более
полезной.

51.

Добавление файла заголовка в библиотеку DLL
1. Чтобы создать файл заголовка для функций, последовательно щелкните Проект > Добавить новый элемент.
2. В диалоговом окне Добавление нового элемента в левой области щелкните Visual C++ . В центральной
области выберите Заголовочный файл (.h) . Укажите MathLibrary.h в качестве имени для файла заголовка.

52.

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

53.

4. Замените все содержимое этого файла заголовка следующим кодом:
// MathLibrary.cpp : Defines the exported functions for the DLL.
#include "pch.h" // use stdafx.h in Visual Studio 2017 and earlier
#include <utility>
#include <limits.h>
#include "MathLibrary.h"
// Special case when index == 0, just return b value
if (index_ > 0)
{
// otherwise, calculate next sequence value
previous_ += current_;
}
std::swap(current_, previous_);
++index_;
return true;
// DLL internal state variables:
static unsigned long long previous_; // Previous value, if any
static unsigned long long current_; // Current sequence value
static unsigned index_;
// Current seq. position
// Initialize a Fibonacci relation sequence
// such that F(0) = a, F(1) = b.
// This function must be called before any other function.
void fibonacci_init(
const unsigned long long a,
const unsigned long long b)
{
index_ = 0;
current_ = a;
previous_ = b; // see special case when initialized
}
// Produce the next value in the sequence.
// Returns true on success, false on overflow.
bool fibonacci_next()
{
// check to see if we'd overflow result or position
if ((ULLONG_MAX - previous_ < current_) ||
(UINT_MAX == index_))
{
return false;
}
}
// Get the current value in the sequence.
unsigned long long fibonacci_current()
{
return current_;
}
// Get the current index position in the sequence.
unsigned fibonacci_index()
{
return index_;
}
Этот файл заголовка объявляет некоторые функции для создания
обобщенной последовательности Фибоначчи, исходя из двух начальных
значений. Вызов fibonacci_init(1, 1) создает знакомую последовательность
чисел Фибоначчи.

54.

Добавление реализации в библиотеку DLL
1. В обозревателе решений щелкните узел Файлы решения правой кнопкой мыши и выберите пункты
Добавить > Новый элемент. Создайте новый CPP-файл с именем MathLibrary.cpp, аналогично добавлению
нового файла заголовка на предыдущем шаге.
2. В окне редактора выберите вкладку MathLibrary.cpp, если она уже открыта. Если нет, то в обозревателе
решений дважды щелкните файл MathLibrary.cpp в папке Исходные файлы проекта MathLibrary.
3. В редакторе замените содержимое файла MathLibrary.cpp следующим кодом:
// MathLibrary.cpp : Defines the exported functions for the DLL.
#include "pch.h" // use stdafx.h in Visual Studio 2017 and
earlier
#include <utility>
#include <limits.h>
#include "MathLibrary.h"
// DLL internal state variables:
static unsigned long long previous_; // Previous value, if any
static unsigned long long current_; // Current sequence value
static unsigned index_;
// Current seq. position
// Initialize a Fibonacci relation sequence
// such that F(0) = a, F(1) = b.
// This function must be called before any other function.
void fibonacci_init(
const unsigned long long a,
const unsigned long long b)
{
index_ = 0;
current_ = a;
previous_ = b; // see special case when initialized
}
// Produce the next value in the sequence.
// Returns true on success, false on overflow.
bool fibonacci_next()
{
// check to see if we'd overflow result or position
if ((ULLONG_MAX - previous_ < current_) ||
(UINT_MAX == index_))
{
return false;
}
// Special case when index == 0, just return b value
if (index_ > 0)
{
// otherwise, calculate next sequence value
previous_ += current_;
}
std::swap(current_, previous_);
++index_;
return true;
}
// Get the current value in the sequence.
unsigned long long fibonacci_current()
{
return current_;
}

55.

1>------ Build started: Project: MathLibrary, Configuration: Debug Win32 -----1>pch.cpp
1>dllmain.cpp
1>MathLibrary.cpp
1>Generating Code...
1> Creating library C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.lib and object
C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.exp
1>MathLibrary.vcxproj -> C:\Users\username\Source\Repos\MathLibrary\Debug\MathLibrary.dll
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

56.

Создание клиентского приложения, которое использует библиотеку DLL
Библиотека DLL предоставляет эти сведения в библиотеке импорта — файле, который содержит сведения о
поиске функций и данных вместо фактического кода. Во время выполнения библиотека DLL должна быть
доступна клиенту в месте, которое может найти операционная система.
Одним из решений является копирование всех этих файлов в ваш клиентский проект. Для сторонних библиотек
DLL, которые вряд ли изменятся во время разработки вашего клиента, этот метод может быть лучшим
способом их использования. Однако, когда вы также создаете библиотеку DLL, лучше избегать дублирования.
Если вы делаете локальную копию файлов библиотеки DLL, которые находятся в стадии разработки, вы
можете случайно изменить файл заголовка только в одной копии или использовать устаревшую библиотеку.
Чтобы избежать рассинхронизации, мы рекомендуем вам установить путь включения в своем клиентском
проекте, чтобы добавить файлы заголовков библиотеки DLL напрямую из проекта DLL. Кроме того, укажите
путь к библиотеке в своем клиентском проекте, чтобы добавить библиотеки импорта DLL из проекта DLL.
Наконец, скопируйте встроенную библиотеку DLL из проекта DLL в выходной каталог своей сборки клиента.
Этот шаг позволяет вашему клиентскому приложению использовать тот же код библиотеки DLL, который вы
создали.

57.

Создание клиентского приложения в Visual Studio
1. В строке меню выберите Файл > Создать > Проект, чтобы открыть диалоговое окно Создание проекта.
2. В верхней части диалогового окна для параметра Язык выберите значение C++ , для параметра Платформа
— значение Windows, а для параметра Тип проекта — значение Консоль.
3. В отфильтрованном списке типов проектов щелкните Консольное приложение, а затем нажмите кнопку
Далее.
4. На странице Настроить новый проект введите MathClient в поле Имя проекта. Примите заданные по
умолчанию Расположение и Имя решения. Для параметра Решение задайте Создать новое решение. Снимите
флажок Разместить решение и проект в одном каталоге, если он установлен.
5. Нажмите кнопку Создать, чтобы создать клиентский проект.

58.

Добавление заголовка библиотеки DLL в путь включения
1. Щелкните правой кнопкой мыши узел MathClient в обозревателе решений, чтобы открыть диалоговое окно
Страницы свойств.
2. В раскрывающемся списке Конфигурация выберите пункт Все конфигурации, если он еще не выбран.
3. В области слева выберите пункт Свойства конфигурации > C/C++ > Общие.
4. На панели свойств щелкните раскрывающийся элемент управления рядом с полем ввода параметра
Дополнительные каталоги включаемых файлов, а затем щелкните Правка.
![Редактирование свойства "Дополнительные каталоги включаемых файлов"](media/mathclient-additional-includedirectories-property.png "Редактирование свойства "Дополнительные каталоги включаемых файлов"")
5. Дважды щелкните в верхней панели диалогового окна Дополнительные каталоги включаемых файлов, чтобы
включить элемент управления "Поле ввода". Или щелкните значок папки, чтобы создать новую запись.
6. В элементе управления "Поле ввода" укажите путь к расположению файла заголовка MathLibrary.h. Чтобы
перейти к нужной папке, можно выбрать элемент управления с многоточием ( ... ).
..\..\MathLibrary\MathLibrary
Если библиотеки DLL и клиентские проекты находятся в одном решении, относительный путь может выглядеть
следующим образом:
..\MathLibrary
![Добавление расположения заголовка в свойство "Дополнительные каталоги включаемых
файлов"](media/mathclient-additional-include-directories.png "Добавление расположения заголовка в свойство
"Дополнительные каталоги включаемых файлов"")
7. После ввода пути к файлу заголовка в диалоговом окне Дополнительные каталоги включаемых файлов
нажмите кнопку ОК. В диалоговом окне Страницы свойств нажмите кнопку OK, чтобы сохранить изменения.

59.

Теперь можно добавить файл MathLibrary.h и использовать функции, которые он объявляет, в вашем
клиентском приложении. Замените содержимое файла MathClient.cpp, используя следующий код:
// MathClient.cpp : Client app for MathLibrary DLL.
// #include "pch.h" Uncomment for Visual Studio 2017 and earlier
#include <iostream>
#include "MathLibrary.h"
int main()
{
// Initialize a Fibonacci relation sequence.
fibonacci_init(1, 1);
// Write out the sequence values until overflow.
do {
std::cout << fibonacci_index() << ": "
<< fibonacci_current() << std::endl;
} while (fibonacci_next());
// Report count of values written before overflow.
std::cout << fibonacci_index() + 1 <<
" Fibonacci sequence values fit in an " <<
"unsigned 64-bit integer." << std::endl;
}

60.

Чтобы устранить эту проблему, можно скопировать файл библиотеки
непосредственно в проект клиентского приложения. Компоновщик
сможет найти и использовать его автоматически. Однако если и
библиотека, и клиентское приложение находятся в стадии разработки,
это может привести к изменениям в одной копии, которые не будут
отображаться в другой. Чтобы избежать этой проблемы, можно задать
свойство Дополнительные зависимости, чтобы сообщить системе сборки
о том, что проект зависит от MathLibrary.lib. Также можно задать путь
Дополнительные каталоги библиотек в проекте, включив в него путь к
исходной библиотеке при компоновке.

61.

Добавление библиотеки импорта DLL в проект
1. Щелкните правой кнопкой мыши узел MathClient в обозревателе решений и выберите Свойства, чтобы
открыть диалоговое окно Страницы свойств.
2. В раскрывающемся списке Конфигурация выберите пункт Все конфигурации, если он еще не выбран. Это
гарантирует, что любые изменения свойств применяются к сборкам отладки и выпуска.
3. В области слева выберите пункт Свойства конфигурации > Компоновщик > Ввод. На панели свойств
щелкните раскрывающийся элемент управления рядом с полем ввода параметра Дополнительные
зависимости, а затем щелкните Правка.
![Редактирование
свойства
"Дополнительные
зависимости"](media/mathclient-additional-dependenciesproperty.png "Редактирование свойства "Дополнительные зависимости"")
4. В диалоговом окне Дополнительные зависимости добавьте MathLibrary.lib в список в верхнем элементе
управления "Поле ввода".

62.

5. Нажмите кнопку OK, чтобы вернуться в диалоговое окно Страницы свойств.
6. В области слева выберите пункт Свойства конфигурации > Компоновщик > Общие. На панели свойств
щелкните раскрывающийся элемент управления рядом с полем ввода параметра Дополнительные каталоги
библиотек, а затем щелкните Правка.
![Редактирование свойства "Дополнительные каталоги библиотеки"](media/mathclient-additional-librarydirectories-property.png "Редактирование свойства "Дополнительные каталоги библиотеки"")
7. Дважды щелкните в верхней панели диалогового окна Дополнительные каталоги библиотек, чтобы включить
элемент управления "Поле ввода". В элементе управления "Поле ввода" укажите путь к расположению файла
MathLibrary.lib. По умолчанию он находится в папке с именем Debug непосредственно в папке решения DLL.
При создании сборки выпуска файл помещается в папку с именем Release. Можно использовать макрос
$(IntDir), чтобы компоновщик мог найти библиотеку DLL независимо от типа создаваемой сборки. Если вы
следовали инструкциям по размещению клиентского проекта в отдельном решении, отличном от проекта DLL,
относительный путь должен выглядеть следующим образом:
..\..\MathLibrary\$(IntDir)
8. Как только вы ввели путь к файлу библиотеки,
в диалоговом окне Дополнительные каталоги
библиотек нажмите кнопку ОК, чтобы вернуться
в диалоговое окно Страницы свойств. Нажмите
ОК, чтобы сохранить изменения свойств.

63.

![Ошибка "Библиотека DLL MathLibrary не найдена"](media/mathclient-system-error-mathlibrary-dll-not-found.png
"Ошибка "Библиотека DLL MathLibrary не найдена"")
Чтобы избежать этой проблемы, можно скопировать библиотеку DLL в каталог, в котором
находится исполняемый файл клиента, в процессе сборки. Можно добавить событие после
сборки в ваш проект, чтобы добавить команду, которая копирует библиотеку DLL в
выходной каталог вашей сборки. Указанная здесь команда копирует библиотеку DLL только
в том случае, если она отсутствует или была изменена. Он использует макросы для
копирования в расположения отладки или выпуска на основе конфигурации сборки.

64.

Копирование библиотеки DLL в событие после сборки
1. Щелкните правой кнопкой мыши узел MathClient в обозревателе решений и выберите Свойства, чтобы
открыть диалоговое окно Страницы свойств.
2. В раскрывающемся списке Конфигурация выберите пункт Все конфигурации, если он еще не выбран.
3. В области слева выберите Свойства конфигурации > События сборки > Событие после сборки.
4. В области свойств щелкните элемент управления "Поле ввода" в поле Командная строка. Если вы
следовали инструкциям по размещению клиентского проекта в отдельном решении, отличном от проекта DLL,
введите следующую команду:
xcopy /y /d "..\..\MathLibrary\$(IntDir)MathLibrary.dll" "$(OutDir)"
5. Нажмите кнопку OK, чтобы сохранить
изменения в свойствах проекта.

65.

Теперь в вашем клиентском приложении есть все, что нужно для сборки и запуска. Соберите приложение,
щелкнув команду Сборка > Собрать решение в меню. Окно Вывод в Visual Studio должно иметь примерно
следующий вид в зависимости от используемой версии Visual Studio:
1>------ Build started: Project: MathClient, Configuration: Debug Win32 -----1>MathClient.cpp
1>MathClient.vcxproj -> C:\Users\username\Source\Repos\MathClient\Debug\MathClient.exe
1>1 File(s) copied
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
Для закрытия
командного окна
нажмите любую
клавишу.

66.

Использование DLL
Практически невозможно создать приложение Windows, в котором не использовались бы библиотеки DLL. В
DLL содержатся все функции Win32 API и несчетное количество других функций операционных систем Win32.
Вообще говоря, DLL - это просто наборы функций, собранные в библиотеки. Однако, в отличие от своих
статических родственников (файлов . lib), библиотеки DLL не присоединены непосредственно к выполняемым
файлам с помощью редактора связей. В выполняемый файл занесена только информация об их
местонахождении. В момент выполнения программы загружается вся библиотека целиком. Благодаря этому
разные процессы могут пользоваться совместно одними и теми же библиотеками, находящимися в памяти.
Такой подход позволяет сократить объем памяти, необходимый для нескольких приложений, использующих
много общих библиотек, а также контролировать размеры ЕХЕ-файлов.
Однако, если библиотека используется только одним приложением, лучше сделать ее обычной, статической.
Конечно, если входящие в ее состав функции будут использоваться только в одной программе, можно просто
вставить в нее соответствующий файл с исходным текстом.
Чаще всего проект подключается к DLL статически, или неявно, на этапе компоновки. Загрузкой DLL при
выполнении программы управляет операционная система. Однако, DLL можно загрузить и явно, или
динамически, в ходе работы приложения.

67.

Существует два способа использования DLL-библиотек: неявное (implicit linking) и явное (explicit linking)
связывание.
Неявное связывание
Неявное связывание (Implicit linking) — самый распространенный в настоящее время способ загрузки
DLL-библиотек. Суть его заключается в том, что компоновщик при построении исполняемого exe- файла не
включает код функций в тело про-граммы, а создает раздел импорта, где перечисляются символические имена
функций и переменных для каждой из DLL-библиотек. Для этого к проекту необходимо подключить
соответствующий lib файл. При запуске программы загрузчик операционной системы анализирует раздел
импорта, загружает все необходимые DLL-библиотеки и, что важно, проецирует их на адресное пространство
загружаемого приложения. Причем, если в загружаемой DLL-библиотеке существует свой раздел импорта, то
загружаются и те dll-файлы, которые там указаны. Однако если библиотека один раз уже загружена, то второй
раз она не загружается, а строится ссылка на уже существующий экземпляр.
Поиск DLL-библиотек осуществляется по стандартной схеме:
1. В папке, откуда запущено приложение.
2. В текущей папке.
3. В системной папке Windows\system32. 4. В папке Windows.
5. В папках, которые перечислены в переменной окружения PATH.
Если библиотека не найдена, загрузка приложения прекращается и выводится сообщение об ошибке.

68.

Явная загрузка DLL
Неявное связывание, несмотря на свою очевидную простоту, имеет и определенные недостатки.
Основным из них является одновременная (с приложением) загрузка и последующее удаление из
памяти всех DLL-библиотек, независимо от того, что большая часть из них может и не
понадобиться. Однако имеется возможность во время работы приложения загружать только
необходимые DLL, освобождая занимаемую ими память, когда потребность в них отпала. Такой
способ называют явным связыванием (explicit linking).
Каждое приложение имеет свое адресное пространство, и чтобы получить доступ к функциям и ресурсам,
размещенным в DLL-библиотеке, нужно спроецировать библиотеку на адресное пространство приложения. Это
можно сделать функцией LoadLibrary():
HMODULE WINAPI LoadLibraryW(LPCWSTR lpLibFileName); аргументом которой является имя DLL-библиотеки.
Функция возвращает дескриптор спроецированного в память dll-файла.
HMODULE— тип возвращаемого значения, это просто другое обозначение дескриптора приложения
HINSTANCE.
Функция FreeLibrary() выгружает DLL-библиотеку из памяти:
BOOL WINAPI FreeLibrary(HMODULE hLibModule);
Эта функция принимает дескриптор, полученный при загрузке DLL, и возвращает TRUE при успешном
завершении.

69.

Загрузка ресурсов из DLL
Помимо функций из DLL-библиотеки можно загрузить и ресурсы. Для примера создадим простенькую DLL,
содержащую в ресурсе одну иконку, и рассмотрим два способа ее извлечения при явном и неявном
связывании.
Создадим проект DLL-библиотеки и импортируем туда иконку IDI_ICON1.
Библиотека динамической компоновки, содержащая ресурсы
#include "stdafx.h" #include "resource.h"
__declspec(dllexport) HICON hIcon;
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hIcon = LoadIcon(hModule, MAKEINTRESOURCE(IDI_ICON1));
break;
case DLL_PROCESS_DETACH: DestroyIcon(hIcon); break;
}
return TRUE;
}

70.

Программный код библиотеки не содержит ни одной функции, а только описание глобальной переменной
hIcon, объявленной как "экспортируемая":
__declspec(dllexport) HICON hIcon;
Функция DllMain(), которую называют функцией входа/выхода, вызывается операционной системой при
загрузке и выгрузке DLL-библиотеки и имеет три параметра:
HModule— дескриптор библиотеки, присваивается при загрузке; ul_reason_for_call— код уведомления;
lpReserved — зарезервировано для дальнейшего применения.
Код уведомления ul_reason_for_call может принимать одно из четырех значений: DLL_PROCESS_ATTACH—
при создании нового процесса; DLL_PROCESS_DETACH— при завершении процесса;
DLL_THREAD_ATTACH— при создании нового потока; DLL_THREAD_DETACH— при завершении потока.
Иконку можно загрузить из ресурса библиотеки функцией LoadIcon():
hIcon = LoadIcon(hModule, MAKEINTRESOURCE(IDI_ICON1));
Мы сохраняем в глобальной переменной дескриптор иконки, чтобы при выгрузке библиотеки из памяти по
уведомлению DLL_PROCESS_DETACHосвободить память:
DestroyIcon(hIcon);
Поскольку
потоков
создавать
не
планируется,
то
уведомления
DLL_THREAD_ATTACH
и
DLL_THREAD_DETACHобрабатывать не будем.

71.

Два способа загрузки иконки:
1. Создадим проект демонстрационной задачи. В папку этого проекта скопируем созданные файлы библиотеки
DllIcon.dllи DllIcon.lib.
В свойствах проекта добавим имя библиотеки DllIcon.lib. На глобальном уровне опишем импортируемую
переменную:
__declspec(dllimport) HICON hIcon;
а в сообщении WM_CREATE переопределим малую иконку класса окна:
SetClassLong(hWnd, GCL_HICONSM, (LONG)hIcon);
Поскольку окно прорисовывается после обработки этого сообщения, мы увидим в заголовке окна новую
пиктограмму приложения.
2. Для явной загрузки библиотеки создадим новый проект, нам понадобится лишь dll-файл созданной
библиотеки, подключать lib-файл не нужно. В сообщении WM_CREATEнеобходимо получить дескриптор
библиотеки:
hDll = LoadLibrary(_T("DllIcon"));
передавая ей в качестве параметра имя DLL-файла. Далее, функцией GetProcAddress()находим дескриптор
иконки, уже загруженной в библиотеке, передавая ей дескриптор иконки как текстовую строку.
hIcon = *((HICON*)GetProcAddress(hDll, "hIcon")); Переменная hIconописана как HICON.
После этого мы можем, как и в предыдущем случае, изменить малую иконку класса окна:
SetClassLong(hWnd, GCL_HICONSM, (LONG)hIcon);
Результат работы этого варианта программы будет идентичен предыдущему. lib-файл в проекте нам не нужен,
но нужно иметь в виду, что DLL-библиотека должна быть создана с использованием def-файла:
EXPORTS hIcon

72.

DLL, содержащие только ресурсы
Можно использовать DLL-библиотеку, как контейнер для хранения ресурсов, на-пример: курсоров, иконок и пр.
В этом случае головная функция DllMain() ничего не делает и будет выглядеть так:
BOOL APIENTRY DllMain( HMODULE, DWORD, LPVOID)
{
return TRUE;
}
#define IDI_ICON1 101
Если создать такую библиотеку, то обработчик сообщения WM_CREATEмог бы выглядеть так:
HMODULE hDll;
HICON hIcon; . . .
case WM_CREATE:
hDll = LoadLibrary(_T("DllIcon"));
hIcon = LoadIcon(hDll, MAKEINTRESOURCE(IDI_ICON1)); SetClassLong(hWnd, GCL_HICONSM, (LONG)hIcon);
break;

73.

Спасибо за
внимание!
Подготовил
к.т.н. Павлович А.А.

74.

Задание для самостоятельной работы
1.
2.
3.
4.
5.
6.
7.
8.
В чем отличие библиотек динамической компоновки от статических библиотек?
Какие действия выполняет функция DllMain(), коды уведомлений?
Объявление экспортируемых переменных и функций. Проблема "искажения" имен, спецификатор
компоновки extern "C" и def-файл.
Явное и неявное связывание DLL-библиотек.
Пути поиска dll-файла.
Формат функций LoadLibrary(), GetProcAddress(), FreeLibrary().
Как найти адрес функции и переменной в DLL-библиотеке?
Как создать DLL-библиотеку для хранения ресурсов?
Подготовка к лабораторной №1
1. Создайте DLL-библиотеку UserString для работы с С-строкой, включив в нее аналоги стандартных функций:
strlen(), strcpy(), strcat(), strrev()…
2. Постройте демонстрационную задачу для использования созданной библиотеки при неявном и явном
связывании.
3. Создайте библиотеку, содержащую набор ресурсов: иконку, курсор, растровое изображение. Постройте
демонстрационную задачу, использующую ресурсы этой DLL-библиотеки.
4. Создайте DLL-библиотеку с галереей рисунков одинакового размера. В число экспортируемых переменных
включите название галереи и количество изображений. Окно создаваемого приложения заполните этими
рисунками.
5. При помощи утилиты dumpbin просмотрите разделы экспорта и импорта созданных библиотек.
English     Русский Rules