Добавлен Ev3nt,
опубликован
Определение
Многие из программистов, наверное, видели нужные им функции в сторонних библиотеках, однако у них не было идей, как их использовать. Данный код позволяет вызывать функции из сторонних библиотек.
Код был честно взят из исходников RenderEdge, за что спасибо ENAleksey, а после, немного изменён мною.
Свойства
Алгоритм состоит из простого преобразования адреса функции и её аргументов в саму функцию. Имеется 4 вариации данного алгоритма: stdcall, fastcall, thiscall, vectorcall. Что это и как устроено, вы можете прочитать в интернете, в свободном доступе.
Реализация
stdcall:
template<typename R, typename F, typename ... A>
R inline stdcall(F f, A ... args)
{
return reinterpret_cast<R(CALLBACK*)(A...)>(f)(args...);
}
template<typename R, typename ... A>
R inline stdcall(HMODULE hModule, LPCSTR lpProcName, A ... args)
{
return stdcall<R>(GetProcAddress(hModule, lpProcName), args...);
}
template<typename R, typename ... A>
R inline stdcall(LPCSTR lpModuleName, LPCSTR lpProcName, A ... args)
{
return stdcall<R>(GetProcAddress(GetModuleHandle(lpModuleName), lpProcName), args...);
}
fastcall:
template<typename R, typename F, typename ... A>
R inline fastcall(F f, A ... args)
{
return reinterpret_cast<R(__fastcall*)(A...)>(f)(args...);
}
template<typename R, typename ... A>
R inline fastcall(HMODULE hModule, LPCSTR lpProcName, A ... args)
{
return fastcall<R>(GetProcAddress(hModule, lpProcName), args...);
}
template<typename R, typename ... A>
R inline fastcall(LPCSTR lpModuleName, LPCSTR lpProcName, A ... args)
{
return fastcall<R>(GetProcAddress(GetModuleHandle(lpModuleName), lpProcName), args...);
}
thiscall:
template<typename R, typename F, typename ... A>
R inline thiscall(F f, A ... args)
{
return reinterpret_cast<R(__thiscall*)(A...)>(f)(args...);
}
template<typename R, typename ... A>
R inline thiscall(HMODULE hModule, LPCSTR lpProcName, A ... args)
{
return thiscall<R>(GetProcAddress(hModule, lpProcName), args...);
}
template<typename R, typename ... A>
R inline thiscall(LPCSTR lpModuleName, LPCSTR lpProcName, A ... args)
{
return thiscall<R>(GetProcAddress(GetModuleHandle(lpModuleName), lpProcName), args...);
}
vectorcall:
template<typename R, typename F, typename ... A>
R inline vectorcall(F f, A ... args)
{
return reinterpret_cast<R(__vectorcall*)(A...)>(f)(args...);
}
template<typename R, typename ... A>
R inline vectorcall(HMODULE hModule, LPCSTR lpProcName, A ... args)
{
return vectorcall<R>(GetProcAddress(hModule, lpProcName), args...);
}
template<typename R, typename ... A>
R inline vectorcall(LPCSTR lpModuleName, LPCSTR lpProcName, A ... args)
{
return vectorcall<R>(GetProcAddress(GetModuleHandle(lpModuleName), lpProcName), args...);
}
Весь код:
#include <Windows.h>
namespace calls
{
// stdcall
template<typename R, typename F, typename ... A>
R inline stdcall(F f, A ... args)
{
return reinterpret_cast<R(CALLBACK*)(A...)>(f)(args...);
}
template<typename R, typename ... A>
R inline stdcall(HMODULE hModule, LPCSTR lpProcName, A ... args)
{
return stdcall<R>(GetProcAddress(hModule, lpProcName), args...);
}
template<typename R, typename ... A>
R inline stdcall(LPCSTR lpModuleName, LPCSTR lpProcName, A ... args)
{
return stdcall<R>(GetProcAddress(GetModuleHandle(lpModuleName), lpProcName), args...);
}
// fastcall
template<typename R, typename F, typename ... A>
R inline fastcall(F f, A ... args)
{
return reinterpret_cast<R(__fastcall*)(A...)>(f)(args...);
}
template<typename R, typename ... A>
R inline fastcall(HMODULE hModule, LPCSTR lpProcName, A ... args)
{
return fastcall<R>(GetProcAddress(hModule, lpProcName), args...);
}
template<typename R, typename ... A>
R inline fastcall(LPCSTR lpModuleName, LPCSTR lpProcName, A ... args)
{
return fastcall<R>(GetProcAddress(GetModuleHandle(lpModuleName), lpProcName), args...);
}
// thiscall
template<typename R, typename F, typename ... A>
R inline thiscall(F f, A ... args)
{
return reinterpret_cast<R(__thiscall*)(A...)>(f)(args...);
}
template<typename R, typename ... A>
R inline thiscall(HMODULE hModule, LPCSTR lpProcName, A ... args)
{
return thiscall<R>(GetProcAddress(hModule, lpProcName), args...);
}
template<typename R, typename ... A>
R inline thiscall(LPCSTR lpModuleName, LPCSTR lpProcName, A ... args)
{
return thiscall<R>(GetProcAddress(GetModuleHandle(lpModuleName), lpProcName), args...);
}
// vectorcall
template<typename R, typename F, typename ... A>
R inline vectorcall(F f, A ... args)
{
return reinterpret_cast<R(__vectorcall*)(A...)>(f)(args...);
}
template<typename R, typename ... A>
R inline vectorcall(HMODULE hModule, LPCSTR lpProcName, A ... args)
{
return vectorcall<R>(GetProcAddress(hModule, lpProcName), args...);
}
template<typename R, typename ... A>
R inline vectorcall(LPCSTR lpModuleName, LPCSTR lpProcName, A ... args)
{
return vectorcall<R>(GetProcAddress(GetModuleHandle(lpModuleName), lpProcName), args...);
}
}
Пример использования
Для примера, возьмём то, что я хочу подгрузить к WC3 свой mpq, для этого я нахожу функцию, зная, что в одном из случаев она подгружает war3patch.mpq
Из скриншота видно, что функция принимает 4 аргумента.
Теперь определяем типы данных, я уже знаю от Ladislava Zezula, какими типами данных являются аргументы функции и поэтому использую их.
Конечный мой код выглядит так:
#include <Windows.h>
template<typename R, typename F, typename ... A>
R inline stdcall(F f, A ... args)
{
return reinterpret_cast<R(CALLBACK*)(A...)>(f)(args...);
}
template<typename R, typename ... A>
R inline stdcall(LPCSTR lpModuleName, LPCSTR lpProcName, A ... args)
{
return stdcall<R>(GetProcAddress(GetModuleHandle(lpModuleName), lpProcName), args...);
}
BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
HANDLE hMPQ;
if (!stdcall<bool>("Storm.dll", (LPCSTR)266, "My.mpq", 9, 0, &hMPQ))
MessageBox(NULL, "Не удалось загрузить My.mpq", "Ошибка", MB_ICONERROR);
}
return TRUE;
}
`
ОЖИДАНИЕ РЕКЛАМЫ...
Комментарии пока отсутcтвуют.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.