- 4,809
- 6,487
Написали с FYP'ом враппер для работы с библиотеками недавно, но мне все стыдно было его выкладывать, и вот сейчас я вроде как готов им поделиться, так что хватайте, пока не удалил.
Основная фичатость враппера - более удобное взаимодействие с библиотеками.
Бонусная плюшка - кроссплатформенность и кросскомпиляторность.
Теперь подробнее и интереснее.
Создавая экземпляр враппера можно не дописывать у названия библиотеки расширение - враппер сам его допишет в соответствии с платформой.
У враппера перегружены операторы [] и (), для подтягивания символов библиотек (аля GetProcAddress). Работают они примерно одинаково, только () указывает, что импортируемая функция имеет тип __stdcall.
Есть пара методов.
name() - возвращает чистое имя библиотеки (без пути и с расширением).
path() - возвращает путь к библиотеке, если он был указан в конструкторе.
handle() - возвращает указатель на адресное пространство библиотеки (аля GetModuleHandle).
hasSuccess() - возвращает инфу о наличии ошибок в загрузке библиотеки.
error() - возвращает ошибку в виде сообщения (т.е. она сразу прямым текстом вам напишет, что ей не нравится).
Где-то тут вы должны меня упрекнуть в оформлении документации, сославшись на то, что всё написанное выше - невнятная хуйня. По этому ниже рассмотрим примеры юзания.
Основная фичатость враппера - более удобное взаимодействие с библиотеками.
Бонусная плюшка - кроссплатформенность и кросскомпиляторность.
Теперь подробнее и интереснее.
Создавая экземпляр враппера можно не дописывать у названия библиотеки расширение - враппер сам его допишет в соответствии с платформой.
У враппера перегружены операторы [] и (), для подтягивания символов библиотек (аля GetProcAddress). Работают они примерно одинаково, только () указывает, что импортируемая функция имеет тип __stdcall.
Есть пара методов.
name() - возвращает чистое имя библиотеки (без пути и с расширением).
path() - возвращает путь к библиотеке, если он был указан в конструкторе.
handle() - возвращает указатель на адресное пространство библиотеки (аля GetModuleHandle).
hasSuccess() - возвращает инфу о наличии ошибок в загрузке библиотеки.
error() - возвращает ошибку в виде сообщения (т.е. она сразу прямым текстом вам напишет, что ей не нравится).
Где-то тут вы должны меня упрекнуть в оформлении документации, сославшись на то, что всё написанное выше - невнятная хуйня. По этому ниже рассмотрим примеры юзания.
Пример 1. Из своей либы тащим свою функцию:
Вывод:
Пример 2. Оставим код из примера 1, но удалим нашу библиотеку.
Вывод:
Пример 3. Изменим код - подсосем системную библиотеку и вызове из нее __stdcall функцию
Вывод:
Пример 4. Сравним наш враппер с HMODULE, а так же вызовем метод handle()
Вывод:
Пример 5. Срань (потому что без комментов) на линуксе.
Вывод:
Пример 6. Срань с линукса на винде (в код добавлен _getch() что бы консолька не закрывалась, а в остольном точно такой же)
Вывод:
Пример 7. Возвращаемся к срани на линуксе, но теперь удаляем нашу либу (что бы показать какие ошибки там). Код из 5 примера.
Вывод:
C++:
#include <iostream>
#include <conio.h>
#include "Library.h"
// Инициализируем враппер как глобальную переменную.
Library lib = "libtest.dll";
int main()
{
std::cout << "Hello world" << std::endl;
// Проверяем, все ли хорошо загрузилось
if (!lib.hasSuccess()) {
std::cout << lib.error() << std::endl; // Если были ошибки, то выводим их
_getch();
return 1;
}
// Находим __cdecl функцию getTest
std::function<int(int)> f = lib["getTest"];
// Запускаем найденную функцию с аргументом 10 и сразу же выводим результат
std::cout << f(10) << std::endl;
_getch();
return 0;
}
Код:
Hello world
100
Вывод:
Код:
Hello world
The specified module could not be found.
Id: 126
C++:
#include <iostream>
#include <conio.h>
#include "Library.h"
Library lib = "kernel32.dll";
int main()
{
std::cout << "Hello world" << std::endl;
if (!lib.hasSuccess()) {
std::cout << lib.error() << std::endl;
_getch();
return 1;
}
// Обрати внимание невнимательный читатель! Скобки теперь круглые, это значит что функция будет иметь тип __stdcall.
std::function<int()> f = lib("GetTickCount");
std::cout << "Minutes after start the system: " << f() / 60000 << std::endl;
_getch();
return 0;
}
Код:
Hello world
Minutes after start the system: 17
C++:
#include <iostream>
#include <conio.h>
#include <assert.h>
#include "Library.h"
Library lib = "kernel32.dll";
int main()
{
std::cout << "Hello world" << std::endl;
if (!lib.hasSuccess()) {
std::cout << lib.error() << std::endl;
_getch();
return 1;
}
// Получаем HMODULE
HMODULE kernel32 = GetModuleHandleA("kernel32.dll");
// Сравниваем враппер с HMODULE
assert(lib == kernel32);
// Сравниваем Library::handle с HMODULE
assert(lib.handle() == (void*)kernel32);
// Если одно из сравнений в assert вернуло false, то вывода времени работы системы не будет
std::function<int()> f = lib("GetTickCount");
std::cout << "Minutes after start the system: " << f() / 60000 << std::endl;
_getch();
return 0;
}
Код:
Hello world
Minutes after start the system: 26
C++:
#include <iostream>
#include "Library.h"
Library lib = "./libtest";
int main(int argc, char **argv) {
std::cout << "Hello, world!" << std::endl;
if (!lib.hasSuccess()){
std::cout << lib.error() << std::endl;
return 1;
}
std::function<int(int)> f = lib["getTest"];
std::cout << f(17) << std::endl;
std::cout << lib.name() << std::endl;
std::cout << lib.path() << std::endl;
return 0;
}
Код:
Hello, world!
289
libtest.so
./
C++:
#include <iostream>
#include <conio.h>
#include "Library.h"
Library lib = "./libtest";
int main(int argc, char **argv) {
std::cout << "Hello, world!" << std::endl;
if (!lib.hasSuccess()) {
std::cout << lib.error() << std::endl;
_getch();
return 1;
}
std::function<int(int)> f = lib["getTest"];
std::cout << f(17) << std::endl;
std::cout << lib.name() << std::endl;
std::cout << lib.path() << std::endl;
_getch();
return 0;
}
Код:
Hello, world!
289
libtest.dll
./
Вывод:
Код:
Hello, world!
./libtest.so: cannot open shared object file: No such file or directory