
- •1.1 Основы программирования в операционной системе Windows
- •1.1.1 Вызов функций api
- •1.1.2 Структура программы
- •1.2 Вопросы системного программирования в Windows
- •1.2.1 Страничная и сегментная адресация.
- •1.2.2 Адресное пространство процесса.
- •2.1 Управление процессами
- •2.2 Процессы и потоки в Windows
- •2.3 Создание процессов
- •2.4 Определение исполняемого образа и командной строки
- •2.5 Идентификация процессов
- •3.1 Создание потока. Функция CreateThread
- •3.2. Завершение потока
- •3.3 Другие функции работы с потоками
- •3.4 Структура context
- •3.5 Приоритеты потоков
- •4.1 Объект critical_section
- •4.2 Мьютексы
- •4.3 Семафоры
- •5.1 События
- •7.1 Кучи
- •7.2 Управление памятью кучи
- •Другие функции для работы с кучей
- •Резюме по управлению кучей
- •Отображение адресного пространства процесса в объекты отображения
- •Что такое импорт
- •Явная загрузка dll
- •Явное подключение экспортируемого идентификатора
- •10.1 Управление файлами и каталогами Создание и открытие файлов
- •10.2 Управление каталогами
- •10.3 Другие методы получения атрибутов файлов и каталогов
- •11.1 Блокировка файлов
- •11.2 Реестр
- •12.1 Стандартные устройства и консольный ввод-вывод
- •12.2 Асинхронный ввод-вывод и порты завершения
- •Параметры
- •Цели системы безопасности
- •Параметры
- •Аварийное завершение
- •Использование именованных каналов
- •Параметры
- •Наблюдение за сообщениями в именованном канале
- •Параметры
Отображение адресного пространства процесса в объекты отображения
Следующий этап — выделение виртуального адресного пространства и отображение его в файл через объект отображения. С точки зрения программиста, такое выделение памяти аналогично действию функции HeapAlloc, но намного грубее, более крупными частями. Возвращается указатель на выделенный блок (или образ файла); отличие состоит в том, что выделенный блок отображается в указанный пользователем файл, а не в файл подкачки обмена. Объект отображения файла играет ту же роль, что и куча при использовании функции HeapAlloc.
lpvoidMapViewOfFile ( HANDLE hMapObject, DWORD fdwAccess,
DWORD dwOffsetHigh, DWORD dwOffsetLow, SIZE_T cbMap);
Возвращаемое значение: начальный адрес блока (образ файла) или NULL. при неудаче.
Параметры
hMapObject указывает объект отображения файла, полученный от функций CreateFileMapping или OpenFileMapping. Значение параметра fdwAccess должно соответствовать правам доступа объекта отображения. возможны три значения флагов: FILE_MAP_WRITE, FILE_MAP_READ и FILE_MAP_ALL_ACCESS (поразрядное "или" двух предыдущих флагов).
Параметры dwOffsetHigh и dwOffsetLow определяют начальное положение области отображения. Начальный адрес должен быть кратным 64К. Для отображения от начала файла используйте нулевое значение смещения.
cbMap указывает размер отображаемой области в байтах. Его нулевое значение при вызове функции MapViewOfFile указывает на то, что весь файл должен быть отображен.
Функция MapViewOfFileEx аналогична, за исключением того, что необходимо указывать начальный адрес в памяти. Этот адрес, например, может быть адресом начала массива в области данных программы. При успешном вызове этой функции Windows обеспечивает возможность использования данного базового адреса всеми процессами. Это значит, что виртуальное адресное пространство заимствуется у всех процессов. В Windows 2000/NT возникает ошибка в случае, если процесс уже отобразил затребованное пространство.
Освобождение образа файла выполняется так же, как и освобождение памяти, выделенной в куче, т.е. функцией HeapFree..
BOOL UnmapViewOfFile ( LPVOID lpBaseAddress )
Функция FlushViewOfFile заставляет систему записывать "грязные" (измененные) страницы на диск. Обычно процесс, который получает доступ к файлу с помощью отображения, и процесс, использующий для этого стандартные функции ввода-вывода, не будут иметь согласованных образов файла. Выполнение файлового ввода-вывода без буферизации не поможет, так как отображенная память не будет немедленно записываться в файл.
Лекция 9. Тема: Динамические библиотеки
В DLL содержатся все функции Windows API. Три самые важные DLL: Kernel32.dll (управление памятью, процессами и потоками), User32.dll (поддержка пользовательского интерфейса, в том числе, функции, связанные с созданием окон и передачей сообщений) и GDI32.dll (графика и вывод текста).
В Windows есть другие DLL:
AdvAPI32.dll – содержит функции для защиты объектов, работы с реестром и регистрации событий
ComDlg32.dll – стандартные диалоговые окна (вроде FileOpen и FileSave)
ComCtl32.dll – поддерживает стандартные элементы управления
DLL нужно применять для реализации следующих возможностей:
Расширение функциональности приложения.
Возможность использования разных языков программирования.
Более простое управление проектом.
Экономия памяти..
Разделение ресурсов..
Упрощение локализации.
Решение проблем, связанных с особенностями различных платформ..
Реализация специфических возможностей.
DLL и адресное пространство процесса.
DLL представляет собой набор модулей исходного кода, в каждом их которых содержится определенное число функций, вызываемых приложением или другим DLL. Причем в DLL обычно нет кода, предназначенного для обработки циклов выборки сообщений и создания окон.
Файлы с исходным кодом компилируются и компонуются также, как и при создании EXE-файла, но при компоновке нужно указать ключ /DLL.
Чтобы приложение (или другая DLL) могла вызывать функции, содержащиеся в DLL, образ ее файла нужно сначала спроецировать на адресное пространство вызывающего процесса. Это выполняется за счет неявного связывания при загрузке, либо за счет явного – в период выполнения. Теперь все функции DLL доступны всем потокам этого процесса. Когда поток вызывает из DLL какую-то функцию, та считывает свои параметры из списка потока и размещает в этом стеке собственные локальные переменные. Кроме того, любые созданные кодом объекты принадлежат вызывающему потоку или процессу – DLL ничем не владеет.
При проецировании образа DLL-файла на адресное пространство процесса система создает также экземпляры глобальных и статических переменных.
Неявное связывание EXE – и DLL – модулей
Неявное связывание (implicit linking) - самый распространенный метод.
Исполняемый модуль (EXE) импортирует функции и переменные из DLL, а DLL– модули экспортирует их в исполняемый модуль. DLL – также может импортировать функции и переменные их других DLL.
Создание DLL-модуля
DLL может экспортировать переменные, функции или С++ классы в другие модули.
При разработке DLL сначала создается заголовочный файл, который включается во все модули исходного кода нашей DLL. Кроме того, его нужно поставлять вместе со своей DLL, чтобы другие разработчики могли включать его в свои модули исходного кода, которые импортируют наши функции или переменные. Единый заголовочный файл, используемый при сборке DLL и любых исполняемых модулей, существенно облегчает поддержку приложения.
При компиляции исходного файла DLL MYLIBAPI определяется как __declspec (dllexport) до включения заголовочного файла MyLib.h. Такой модификатор означает, что данная переменная, функция или C++ класс экспортируется из DLL.
Также следует обратить внимание, что в файле MyLibFile1.cpp перед экспортируемой переменной или функцией не ставится идентификатор MYLIBAPI. Он здесь не нужен: проанализировав заголовочный файл, компилятор запоминает, какие переменные и функции являются экспортируемыми.
Идентификатор MYLIBAPI включает extern. Модификатор extern не даёт компилятору искажать имена переменных или функции, и они становятся доступными исполняемым модулям, написанным на С, С++ или любом другом языке программирования. Этим модификатором можно пользоваться только в коде С++, но ни в коем случае ни в коде на стандартном С.
Мы рассмотрели, как используется заголовочный файл в исходных файлах DLL.
А в исходных файлах ЕХЕ-модуля MYLIBAPI определять не надо: включая заголовочный файл, вы определяете этот идентификатор как – DLLSPEC(DLLIMPORT), и при помещении исходного кода ЕХЕ-модуля компилятор поймёт, что переменные и функции импортируются из DLL.
Что такое экспорт
Если перед переменной, прототипом функции или С++ классом указан модификатор – _deсlspec(dllexport), компилятор Microsoft C/C++ встраивает в конечный obj-файл дополнительную информацию. Она понадобится при сборке DLL из OBJ-файлов.
Обнаружив такую информацию, компоновщик создает LIB-файл со списком идентификаторов, экспортируемых из DLL. Этот LIB-файл нужен при сборке любого EXE-модуля, ссылающегося на такие идентификаторы. Компоновщик также вставляет в конечный DLL-файл таблицу экспортируемых идентификаторов – раздел экспорта, в котором содержится список (в алфавитном порядке) идентификаторов экспортируемых функций, переменных и классов. Туда же помещается относительный виртуальный адрес (relative virtual address, RVA) каждого идентификатора внутри DLL-модуля.
Создание EXE-модуля
Вот пример исходного кода EXE-модуля, который импортирует идентификаторы, экспортируемые DLL, и ссылается на них внутри в процессе выполнения.
//Модуль: MyExeFilel.cpp
//Сюда включаются стандартные заголовочные файлы Windows и библиотеки С
#include <windows.h>
//включаем экспортируемые структуры данных, идентификаторы, функции и переменные
#include “MyLib\MyLib.h”
….
int WINAPI WinMain(HINSTANCE hinstExe, HINSTANCE, LPTSTR
pszCmdLine, int){
int nLeft=10, nRight=25;
TCHAR sz[100];
wsprintf(sz, TEXT(“%d + %d = %d”), nLeft, nRight, Add(nLeft,
nRight));
MessageBox(NULL, sz, TEXT(“Calculation”), MB_OK);
wsprintf(sz, TEXT(“The result from the last Add is: %d”), g_nResult);
MessageBox(NULL, sz, TEXT(“Last Result”), MB_OK);
return (0);
}
Создавая фалы исходного кода для EXE-модуля, нужно включить в них заголовочный файл DLL, иначе импортируемые идентификаторы окажутся неопределенными, и компилятор выдаст массу предупреждений об ошибках.
MYLIBAPI в исходных файлах EXE-модуля до заголовочного файла DLL не определяется. Поэтому при компиляции приведенного выше кода MYLIBAPI за счет заголовочного файла MyLib.h будет определен как __declspec(dllimport). Встречая такой модификатор перед именем переменной, функции или С++ класса, компилятор понимает, что данный идентификатор импортируется из какого-то DLL –модуля.
Далее компоновщик собирает все OBJ-модули в конечный EXE-модуль. Для этого он должен знать, в каких DLL содержаться импортируемые идентификаторы, на которые есть ссылки в коде. Информацию об этом он получает из передаваемого ему LIB-файла (в котором указан список идентификаторов, экспортируемых DLL)