有没有办法找到要在GetProcAddress中使用的C ++受损名称?

时间:2013-04-15 13:42:05

标签: windows visual-c++

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

4 个答案:

答案 0 :(得分:6)

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.
}

答案 1 :(得分:2)

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

答案 2 :(得分:1)

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

更具体地说,请参阅this answer here。您需要进行的唯一更改是将TRUE传递给MappedAsImage参数,并将GetModuleHandle Base的返回值传递给ImageDirectoryEntryToData函数调用

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);
        }
    }
}

答案 3 :(得分:0)

我不太清楚为什么您会想要/需要MSalters' solution的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};
    }
}