Вызов функций по средству reinterpret_cast | C++

Published

Определение

Многие из программистов, наверное, видели нужные им функции в сторонних библиотеках, однако у них не было идей, как их использовать. Данный код позволяет вызывать функции из сторонних библиотек.
Код был честно взят из исходников 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;
}


Views: 257

Комментарии пока отсутcтвуют.