МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ
НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ “ЛЬВІВСЬКА ПОЛІТЕХНІКА”
/
Кафедра ЕОМ
Звіт
до лабораторної роботи № 6
з дисципліни
" Системне програмування "
«СТВОРЕННЯ DLL ТА ЇХ ВИКОРИСТАННЯ ПРИ НЕЯВНОМУ ЗВ’ЯЗУВАННІ НА МОВІ С»
Мета: Ознайомитись з технологією та оволодіти навиками створення та використання бібліотек динамічного компонування з використанням неявного зв’язування.
ТЕОРЕТИЧНІ ВІДОМОСТІ
Завершальним етапом створення програмного продукту є процес збирання (компонування) завантажувального модуля (.exe – файлу). Компонуванням (linking) називають процес створення фізичного або логічного виконуваного файла (модуля) із набору об’єктних файлів бібліотек для подальшого виконання або під час виконання і вирішення проблеми неоднозначності імен, що виникає при цьому.
У разі створення фізичного виконуваного файла для подальшого виконання компонування називають статичним, коли у такому файлі міститься все потрібне для виконання програми. У випадку створення логічного виконуваного файла під час виконання програми компонування називають динамічним, у цьому випадку образ виконуваного модуля збирають “на ходу”.
Статичне компонування виконуваних файлів має низку недоліків:
якщо кілька застосувань використовують спільний код (наприклад, код бібліотеки мови С), кожний виконуваний файл міститиме окрему копію цього коду в результаті такі файли займатимуть значне місце на диску і у пам’яті;
під час кожного оновлення застосування, його потрібно наново перекомпонувати і перевстановити;
неможливо реалізувати динамічне завантаження програмного коду під час виконання.
Для вирішення цих і подібних проблем було запропоновано концепцію динамічного компонування із використанням динамічних або розділюваних бібліотек.
Динамічна бібліотека (англ. Dynamic-Load Library — динамічно завантажувана бібліотека) - набір функцій, скомпонованих разом у вигляді бінарного файлу, який може бути динамічно завантажений в адресний простір
процесу, що використовує ці функції. Динамічне завантаження- завантаження під час виконання процесу. Динамічне компонування - компонування образу виконуваного файла під час виконання процесу із використанням динамічних бібліотек.
До переваги використання динамічних бібліотек, слід віднести:
оскільки бібліотечні функції містяться в окремому файлі, розмір виконуваного файла стає меншим;
якщо динамічну бібліотеку використовують кілька процесів, у пам’ять завантажують лише одну її копію, після чого сторінки коду бібліотеки відображаються в адресний простір кожного з цих процесів;
оновлення застосування може бути зведене до встановлення нової версії динамічної бібліотеки без необхідності перекомпонування тих його частин, які не змінилися;
динамічні бібліотеки дають змогу застосуванню реалізовувати динамічне завантаження модулів на вимогу;
динамічні бібліотеки дають можливість спільно використовувати ресурси застосування;
оскільки динамічні бібліотеки є двійковими файлами, можна організувати спільну роботу бібліотек, розроблених із використанням різних мов програмування.
Використання динамічних бібліотек не позбавлене недоліків:
динамічне зв’язування сповільнює завантаження застосування. Що більше таких бібліотек потрібно процесу, то більше файлів треба йому відобразити у свій адресний простір під час завантаження, а відображення кожного файла забирає час;
при відсутності спільного використання динамічної бібліотеки іншими застосування зовнішня пам’ять може використовуватися не ефективно. На відміну від статичного зв’язування, коли зі загальної бібліотеки вибираються тільки ті функції, що використовуються застосування, при використанні динамічного зв’язування до застосування необхідно додавати повну версію бібліотеки, навіть, якщо використовуються тільки декілька функцій. При значних обсягах бібліотеки втрати пам’яті відчутні;
найбільшою проблемою у використанні динамічного компонування є проблема зворотної сумісності динамічних бібліотек. Ця проблема виникає в ситуації, коли застосування встановлює нову версію DLL поверх попередньої. Якщо нова версія не має зворотної сумісності із попередніми, застосування, розраховані на використання попередніх версій бібліотеки, можуть припинити роботу;
ускладнюється процес інсталювання програмного продукту, в процесі якого необхідно досліджувати які з DLL вже інстальовано в ОС і які їх версії. Інстальована нова версія DLL з некоректною зворотною сумісністю, може негативно вплинути на виконання інших програм, що її використовують і навіть не підозрюють про підміну бібліотеки.
Використання DLL у Windows
Загальні бібліотеки функцій в ОС Windows реалізовані компанією Microsoft за DLL технологією. Як правило, ці бібліотеки мають розширення файлу *.dll, *.ocx (для бібліотек, що містять елементи керування ActiveX) або *.drv (драйвери старих версій ОС). Структура DLL така сама, як і в PE-файлів
(Portable Executable) для 32-, 64-розрядних Windows, та New-Executable (NE) для 16-бітових Windows.
DLL може містити 2 типи функцій: експортні та внутрішні. Експортні функції можуть бути викликані зі зовнішніх прикладних та визначаються за допомогою ключового слова __ declspec(dllexport). Внутрішні – це функції, які використовуються в середині DLL і не можуть бути викликані ззовні.
DLL є модулем (module). Тобто, вона складається з: сегментів коду, сегментів ресурсів та одного сегменту даних. Крім цього DLL може містити точку входу. Точка входу – це функція DllMain, яка викликається при завантаженні або вивантажені бібліотеки потоком або процесом. Ця функція має наступний прототип:
BOOL APIENTRY DllMain(
// Хендл DLL модуля
HANDLE hModule,
DWORD ul_reason_for_call,
// Причина виклику
LPVOID lpReserved );
// Зарезервовано
Якщо DllMain повертає FALSE, то бібліотека вважається такою, що не завантажилася. При неявному зв’язуванні це призведе до відмови запуску програми, а при явному – помилки завантаження лише цієї бібліотеки.
У процесі виконання вміст бібліотеки залишається незмінним (сегменти коду та сегменти ресурсів), що дозволяє завантажувати її в пам’ять в єдиному примірнику і використовувати багатьма завданнями одночасно. Використання dll дозволяє економити пам’ять, забезпечити модульність програм, полегшити процес встановлення програм.
Можливі 2 способи використання динамічних бібліотек. Вони називаються “явним” та “неявним” зв’язуванням. “Явне” та “неявне” зв’язування бібліотеки з програмою мають суттєві відмінності в процесі написання та компіляції програми.
Неявне зв’язування бібліотеки з програмою (Load-time dynamic linking) полягає в тому, що бібліотека (яка міститься у файлі з розширенням .dll) завантажується в пам’ять в момент завантаження програми. При відсутності бодай однієї з бібліотек при запуску програми відбудеться збій та припинення виконання програми.
Щоб реалізувати неявне зв’язування необхідно до проекту програми включити прототипи функцій, що містяться в бібліотеці та бібліотеку імпорту (має розширення .lib). На даному етапі наявність файлу з розширенням .dll не є необхідною. При компоновці створюється виконавчий файл, який містить код, що забезпечує систему інформацією, яка необхідна для автоматичного завантаження бібліотеки з .dll файлу та інформацією, яка необхідна для зв’язування імен функцій у програмі з їх адресами у бібліотеці.
Неявне зв’язування дозволяє здійснювати виклик функцій з бібліотеки написанням коду програми в стилі притаманному мовам С\С++.
Завдання
Створити DLL файл та здійснити неявне зв`язування на мові С.
ВАРІАНТИ ЗАВДАНЬ
Варіант №3
3. Знайти кількість слів у тексті, що починаються з заданої літери.
Лістинг програми:
First project: Ann_3
Sourse.cpp
#include "My_DLL.h"
#include<sstream>
#include<conio.h>
#pragma comment(lib,"My_lib.lib")
int main(){
char mass[256];
char ID = NULL;
cout << "Input start letter:" << endl;
cin >> ID;
cout << "Input words:" << endl;
cout << "Input | to finish string input" << endl;
cin.get(mass, 256, '|');
cout << "Quantity of appearance: " << CharStartCounter(mass, ID) << endl;
getch();
My_dll.h
#include <iostream>
#include <string.h>
using namespace std;
extern "C" __declspec(dllexport) int CharStartCounter(char* str, char c);
Second project: My_lib
My_dll.cpp
#include "my_dll_3.h"
extern "C" __declspec(dllexport) int CharStartCounter(char *mass, char ID)
{
int count = 0;
bool beginWord = true;
for (int i = 0; i < strlen(mass); i++){
if (isalnum(mass[i])){
if (beginWord == false)
continue;
else if (beginWord == true && tolower(mass[i])==tolower(ID)){
count++;
beginWord = false;
}
}
else if(isalnum(mass[i])){
beginWord = true;
continue;
}
}
return count;
}
My_dll_3.h
#ifndef _DLLTEST_H_
#define _DLLTEST_H_
#include <iostream>
using namespace std;
extern "C" __declspec(dllexport) int CharStartCounter(char* str, char c);
#endif
Фото роботи програми:
/
Алгоритм виконання:
First project: Ann_3
На початку програми ми підключаємо хедер-файл, який містить дані про функцію, яка знаходиться в файлі lib. Цей файл попередньо був створений виконанням програми My_Lib. Наступний крок був безпосереднє підключення файлу lib #pragma comment(lib,"My_lib.lib", подальше виконання програми не несе ніякої нової інформації, відбувається створення інтерфейсу на пам`ять де буде зберігатись зміна підтипу, створюється інтерфейс на пам’ять char-типу, потім вносяться дані у ті змінні і передаються як аргументи у функцію: PosCharCounter(mass, ID).
My_dll.h
extern "C" __declspec(dllexport) int CharStartCounter(char* str, char c); – дана стрічка коду дозволяє здійснити доступ до функції яка знаходиться в іншому проекті, та імпортувати DLL файл.
Second project: My_lib
My_dll.cpp
У даному файлі описується безпосереднє виконання функції, яка буде шукати кількість повторень заданого символу у заданій користувачем стрічці. На початку виконання створюється інтерфейс на пам*ять з іменем counter, а потім по циклу ми перевіряєм, що якщо символ співпаде із поточним символом стічки то ми інрементуємо зміну counter, а якщо не співпадає, то переходимо на інший символ у заданій стрічці, в кінці виконання функції ми повертаємо значення counter.
My_dll_3.h
У даному хедер-файлі ми оголошуємо прототип функції у якої буде глобальне поле видимості, виконання програми призведе до утворення файлів які ми зможемо підключити до попереднього проекту, та використати дану функцію
Висновок: Після виконання даної лабораторної роботи я ознайомилася з технологією та оволоділа навиками створення та використання бібліотек динамічного компонування з використанням неявного зв’язування.