9

与 C++一起使用的常见“解决方案”GetProcAddress是“extern“C”,但这会破坏重载。名称修改允许多个函数共存,只要它们的签名不同。但是有没有办法找到这些修改后的名称GetProcAddress

4

4 回答 4

7

VC++ 编译器知道它自己的名称修饰方案,那么为什么不使用它呢?在内部template<typename T> T GetProcAddress(HMODULE h, const char* name),宏__FUNCDNAME__包含GetProcAddress. 这包括T部分。因此,在 内部GetProcAddress<void(*)(int),我们有一个名称为 的子字符串void(*)(int)。从中,我们可以简单地推导出void foo(int);

此代码依赖于 VC++ 宏__FUNCDNAME__对于MinGW ,您需要基于此__PRETTY_FUNCTION__

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.
}
于 2013-04-15T13:47:10.953 回答
4

用于dumpbin /exports 'file.dll'获取所有符号的装饰/未装饰名称。

于 2013-04-15T13:46:48.903 回答
2

仅仅通过使用是不可能做到的GetProcAddress。但是,一种方法是枚举该特定模块的所有导出函数,并进行模式匹配以查找所有损坏的名称。

更具体地说,请在此处参考此答案。您需要做的唯一更改是将TRUEfor参数和forMappedAsImage参数的返回值传递给函数调用。GetModuleHandleBaseImageDirectoryEntryToData

void EnumerateExportedFunctions(HMODULE hModule, vector<string>& slListOfDllFunctions)
{
    DWORD *dNameRVAs(0);
    _IMAGE_EXPORT_DIRECTORY *ImageExportDirectory;
    unsigned long cDirSize;
    _LOADED_IMAGE LoadedImage;
    string sName;
    slListOfDllFunctions.clear();

    ImageExportDirectory = (_IMAGE_EXPORT_DIRECTORY*)
        ImageDirectoryEntryToData(hModule,
        TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &cDirSize);
    if (ImageExportDirectory != NULL)
    {
        dNameRVAs = (DWORD *)ImageRvaToVa(LoadedImage.FileHeader, 
            LoadedImage.MappedAddress,
        ImageExportDirectory->AddressOfNames, NULL);
        for(size_t i = 0; i < ImageExportDirectory->NumberOfNames; i++)
        {
            sName = (char *)ImageRvaToVa(LoadedImage.FileHeader, 
                    LoadedImage.MappedAddress,
                   dNameRVAs[i], NULL);
         slListOfDllFunctions.push_back(sName);
        }
    }
}
于 2013-04-15T13:51:06.470 回答
0

我不明白为什么你会想要/需要MSalters 解决方案的 constexpr 版本,但它就是这样,完成了命名空间修改。用于

using F = int(double*);
constexpr auto f = mangled::name<F>([]{ return "foo::bar::frobnicate"; });
constexpr const char* cstr = f.data();

其中F是函数签名,foo::bar::frobnicate是函数的(可能是限定的)名称。

#include<string_view>
#include<array>

namespace mangled
{
    namespace detail
    {
        template<typename F>
        inline constexpr std::string_view suffix()
        {
            auto str = std::string_view(__FUNCDNAME__);
            return str.substr(14, str.size() - 87);
        }
        
        template<typename L>
        struct constexpr_string
        {
            constexpr constexpr_string(L) {}
            static constexpr std::string_view data = L{}();
        };

        template<typename Name>
        inline constexpr int qualifiers()
        {
            int i = -2, count = -1;
            while(i != std::string_view::npos)
            {
                i = Name::data.find("::", i + 2);
                count++;
            }
            return count;
        }

        template<typename Name>
        inline constexpr auto split()
        {
            std::array<std::string_view, qualifiers<Name>() + 1> arr = {};
            int prev = -2;
            for(int i = arr.size() - 1; i > 0; i--)
            {
                int cur = Name::data.find("::", prev + 2);
                arr[i] = Name::data.substr(prev + 2, cur - prev - 2);
                prev = cur;
            }
            arr[0] = Name::data.substr(prev + 2);
            return arr;
        }

        template<typename F, typename Name>
        struct name_builder
        {
            static constexpr auto suf = detail::suffix<F>();
            static constexpr auto toks = split<Name>();
            static constexpr auto len = Name::data.size() + suf.size() - toks.size() + 6;
            static constexpr auto str = [] {
                std::array<char, len> arr = {};
                arr[0] = '?';
                int i = 1;
                for(int t = 0; t < toks.size(); t++)
                {
                    if(t > 0)
                        arr[i++] = '@';
                    for(auto c : toks[t])
                        arr[i++] = c;
                }

                arr[i++] = '@';
                arr[i++] = '@';
                arr[i++] = 'Y';

                for(auto c : suf)
                    arr[i++] = c;
                
                return arr;
            }();
        };
    }

    template<typename F, typename LambdaString>
    inline constexpr std::string_view name(LambdaString)
    {
        using Cs = detail::constexpr_string<LambdaString>;
        using N = detail::name_builder<F, Cs>;
        return {N::str.data(), N::len};
    }
}
于 2020-09-26T11:26:06.373 回答