The VC ++ compiler knows its name-switching scheme, so why not use this? Inside template<typename T> T GetProcAddress(HMODULE h, const char* name) __FUNCDNAME__ macro contains the garbled name GetProcAddress . This includes part T So, inside GetProcAddress<void(*)(int) we have a substring with the distorted name void(*)(int) . From this we can trivially infer the distorted name void foo(int);
This code is based on the VC ++ __FUNCDNAME__ . For MinGW, you will need to base this on __PRETTY_FUNCTION__ instead .
FARPROC GetProcAddress_CppImpl(HMODULE h, const char* name, std::string const& Signature) { // The signature of T appears twice in the signature of T GetProcAddress<T>(HMODULE, const char*) size_t len = Signature.find("@@YA"); std::string templateParam = Signature.substr(0, len); std::string returnType = Signature.substr(len+4); returnType.resize(templateParam.size()); // Strip off our own arguments (HMODULE and const char*) assert(templateParam == returnType); // templateParam and returnType are _pointers_ to functions (P6), so adjust to function type (Y) std::string funName = "?" + std::string(name) + "@@Y" + templateParam.substr(2); return ::GetProcAddress(h, funName.c_str()); } template <typename T> T GetProcAddress(HMODULE h, const char* name) { // Get our own signature. We use `const char* name` to keep it simple. std::string Signature = __FUNCDNAME__ + 18; // Ignore prefix " ??$GetProcAddress@ " return reinterpret_cast<T>(GetProcAddress_CppImpl(h, name, Signature)); } // Showing the result struct Dummy { }; __declspec(dllexport) void foo( const char* s) { std::cout << s; } __declspec(dllexport) void foo( int i, Dummy ) { std::cout << "Overloaded foo(), got " << i << std::endl; } __declspec(dllexport) void foo( std::string const& s ) { std::cout << "Overloaded foo(), got " << s << std::endl; } __declspec(dllexport) int foo( std::map<std::string, double> volatile& ) { std::cout << "Overloaded foo(), complex type\n"; return 42; } int main() { HMODULE h = GetModuleHandleW(0); foo("Hello, "); auto pFoo1 = GetProcAddress<void (*)( const char*)>(h, "foo"); // This templated version of GetProcAddress is typesafe: You can't pass // a float to pFoo1. That is a compile-time error. pFoo1(" world\n"); auto pFoo2 = GetProcAddress<void (*)( int, Dummy )>(h, "foo"); pFoo2(42, Dummy()); // Again, typesafe. auto pFoo3 = GetProcAddress<void (*)( std::string const& )>(h, "foo"); pFoo3("std::string overload\n"); auto pFoo4 = GetProcAddress<int (*)( std::map<std::string, double> volatile& )>(h, "foo"); // pFoo4 != NULL, this overload exists. auto pFoo5 = GetProcAddress<void (*)( float )>(h, "foo"); // pFoo5==NULL - no such overload. }
source share