Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
3 семестр, WinAPI, MFC.pdf
Скачиваний:
370
Добавлен:
15.06.2014
Размер:
6.17 Mб
Скачать

7.Какие диалоговые окна предоставляют собой интерфейс, посредством которого пользователь может ввести текстовую строку для поиска и, если необходимо, строку для замены?

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

Динамически подключаемые библиотеки

Динамически подключаемые библиотеки (dynamic-link libraries, DLLs) — краеугольный камень операционной системы Windows, начиная с самой первой ее версии. В DLL содержатся все функции интерфейса Win32 API. Три самых важных DLL-библиотеки: KERNEL32.DLL (управление памятью, процессами и потоками), USER32.DLL (поддержка пользовательского интерфейса, в том числе функции, связанные с созданием окон и передачей сообщений) и GDI32.DLL (графика и вывод текста).

В Windows есть и другие DLL, функции которых предназначены для более специализированных задач. Например, в ADVAPI32.DLL содержатся функции для

защиты объектов, работы с реестром и регистрации событий, в COMDLG32.DLL

— стандартные диалоговые окна, a LZ32.DLL поддерживает декомпрессию файлов.

Создание DLL

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

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

Чтобы приложение (или другая DLL) могло вызывать функции из DLL,

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

Это делается либо неявной компоновкой при загрузке, либо явной — в период выполнения.

Как только DLL спроецирована на адресное пространство вызывающего процесса,

еефункции доступны всем потокам этого процесса.

Когда поток вызывает из DLL какую-то функцию, та считывает свои параметры из стека потока и размещает в этом стеке собственные локальные переменные.

Кроме того, любые созданные кодом DLL объекты принадлежат вызывающему потоку или процессу — DLL в Win32 ничем не владеет.

Например, если функция из DLL вызывает VirtualAlloc, резервируется регион в адресном пространстве того процесса, которому принадлежит поток, обратившийся к функции

из DLL. Если DLL будет выгружена из адресного пространства процесса, зарезервированный регион не освободится, так как система не фиксирует того, что регион выделен библиотечной функцией. Считается, что он принадлежит процессу и поэтому освободится, только если поток этого процесса вызовет VirtualFree или завершится сам процесс.

Глобальные и статические переменные DLL-библиотеки обрабатываются точно так, как

переменные ЕХЕ – файла, т.е. не разделяются его параллельно выполняемыми экземплярами.

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

В 16-разрядной Windows DLL-библиотеки обрабатываются иначе, чем в Win32.

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

В Win32-cpeдe DLL нужно спроецировать на адресное пространство процесса, прежде чем тот сможет вызывать ее функции.

Глобальные и статические данные DLL-библиотек в 16-разрядной Windows и Win32 тоже обрабатываются по-разному.

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

 

Вот пример использования DLL для разделения данных между двумя приложениями:

HGLOBAL g_hData = NULL;

 

 

 

void SetData(LPVOID IpvData,

int nSize) { LPVOID Ipv;

 

g_hData

=

LocalAlloc(LMEM_MOVEABLE,

nSize);

Ipv

 

 

=

 

LocalLock(g_hData);

memcpy(lpv,

 

 

IpvData,

nSize);

LocalUnlock(g_hData);

 

 

 

 

}

 

 

 

 

 

void GetData(LPVOID IpvData, int nSize)

{

 

LPVOID Ipv = LocalLock(g_hData);

 

 

memcpy(IpvData, Ipv, nSize);

 

 

 

LocalUnlock(g_hData);

}

Вызов SetData приводит к выделению блока памяти из сегмента данных DLL, копированию в него данных, на которые указывает параметр IpvData, и сохранению описателя блока в глобальной переменной g_hData. Теперь другое при-

ложение может вызвать GetData. Та, используя глобальную переменную g_hData, блокирует выделенную область локальной памяти, копирует данные из нее в буфер, идентифицируемый параметром IpvData, и возвращает управление.

В Win32: во-первых, у DLL в Win32 нет собственных локальных куч. Во-вторых,

глобальные и статические переменные не разделяются между разными проек-

циями одной DLL; система создает отдельный экземпляр глобальной переменной g_hData для каждого процесса, и значения, хранящиеся в разных экземплярах переменной, не обязательно одинаковы.

Проецирование DLL на адресное пространство процесса

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

Неявная компоновка

Неявная компоновка (implicit linking). При сборке приложения компоновщику нужно указать набор LIB-файлов. Каждый такой файл содержит список функций данной

DLL. Обнаружив, что приложение ссылается на функции, упомянутые в LIB-файле для DLL, компоновщик внедряет имя этой DLL в конечный исполняемый файл.

Поиск DLL осуществляется в :

каталоге, содержащем ЕХЕ - файл;

текущем каталоге процесса;

системном каталоге Windows;

основном каталоге Windows;

каталогах, указанных в переменной окружения PATH.

Явная компоновка

Образ DLL-файла можно спроецировать на адресное пространство процесса явным образом для чего один из потоков должен вызвать либо LoadLibrary, либо LoadLibraryEx: HINSTANCE LoadLibrary(LPCTSTR IpszLibFile);

HINSTANCE LoadLibraryEx(LPCTSTR IpszLibFile, HANDLE hFile, DWORD dwFlags);

Обе функции ищут образ DLL-файла и пытаются спроецировать его на адресное пространство вызывающего процесса. Значение типа HINSTANCE, возвращаемое обеими

функциями, сообщает адрес виртуальной памяти, по которому спроецирован образ файла. Если спроецировать DLL на адрес пространство процесса не удалось, функции возвращают NULL.

Обратим внимание на 2 дополнительных параметра функции LoаdLibraryEx: hFile и dwFlags. Первый зарезервирован и должен быть NULL. Во втором можно передать либо 0,

либо комбинацию флагов DONT_RESOLVE_DLL_REFERENCES, LOAD_LIВRARY_AS_DATAFILE и LOAD_WITH_ALTERED_SEARCH_PATH.

Рассмотрим эти параметры:

DONT_RESOLVE_DLL_REFERENCES. Данный флаг заставляет систему

проецировать DLL, не обращаясь к DllMain и с ее помощью инициализирует библиотеку. При загрузке библиотеки система проверяет, используются ли ею другие DLL; если да, то загружает и их. При установке флага

DONT_RESOLVE_DLL_REFERENCES дополнительные DLL автоматически не загружаются.

LOAD_LIBRARY_AS_DATAFILE. DLL проецирует на адресное пространство процесса так, будто это файл данных. При этом система не тратит дополнительного времени на подготовку к исполнению какого-либо кода из данного файл. Этот флаг

стоит указать, если DLL содержит только ресурсы и никаких функций. Также флаг может потребоваться, если Вам нужны ресурсы, содержащиеся в какомнибудь ЕХЕ – файле.

LOAD_WITH_ALTERED_SEARCH_PATH. Изменяет алгоритм, используемый

LoadLibraryEx при поиске DLL-файла. Однако, если данный флаг установлен, функция ищет файл, просматривая каталоги в таком порядке:

1.Каталог, заданный в параметре IpszLibFile.

2.Текущий каталог процесса.

3.Системный каталог Windows.

4.Основной каталог Windows.

5.Каталоги, перечисленные в переменной окружения PATH.

И еще один фактор может повлиять на то, где система ищет файлы DLL. В реестре есть раздел:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs

Здесь может содержаться набор параметров, имена которых совпадают с именами некоторых DLL-файлов. Значения параметров представляют собой строки, идентичные именам параметров, только дополненные расширением “.DLL.”.

Когда Вы вызываете LoadLibrary или LoadLibraryEx, каждая из них сначала

проверяет, указано ли имя DLL вместе с расширением “.DLL”. Если нет, поиск DLL ведется по уже знакомым Вам правилам.

Если же расширение “.DLL” указано, функция его отбрасывает и ищет в разделе реестра KnownDLLs параметр с идентичным именем. Если его нет, вновь применяются описанные ранее правила. Есть — система обращается к значению, связанному с параметром, и пытается загрузить определенную в нем DLL. При этом система ищет DLL в каталоге, на который указывает значение, связанное с параметром реестра DllDirectory.

Если DLL загружается явно, ее можно отключить от адресного пространства процесса функцией FreeLibrary.

BOOL FreeLibrary(HINSTANCE hinstDll);

При вызове FreeLibrary, Вы должны передать значение типа HINSTANCE, которое идентифицирует выгружаемую DLL. Это значение Вы получите, предварительно вызвав

LoadLibran или LoadLibraryEx.