用dumpbin来查看dll导出了哪些函数(接口)。尤其是观察导出的那个类继承自模板(实例化了模板后再导出)

文章讲述了在VisualStudio中使用`dumpbin`查看dll导出时遇到的问题,特别是关于`GenericFactoryPro`类的静态成员导出导致的单例冲突。作者解释了为何需要在类名前添加参数以保持导出函数唯一性,并通过示例展示了不同类如何意外共享同一单例实例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

启动vs的“开发人员命令提示”

直接执行dumpbin,它会给出所有支持的选项:

给出dll的完整路径,可以将信息导出到文本文件:

D:\DevTools\VS2015>dumpbin /exports D:\123\test.dll >123123.txt

下面的代码

template <
    typename DerivedName, //signature,在类中不做使用。
    typename AbstractProduct, //接口
    typename ProductTypeKey, //key
    typename ...ArgTypes //其他参数
>
class GenericFactoryPro
{
protected:

    GenericFactoryPro() {}
    GenericFactoryPro(const GenericFactoryPro&) = delete; 
    GenericFactoryPro(GenericFactoryPro&&) = delete;
    GenericFactoryPro operator=(const GenericFactoryPro& other) = delete;

public:
    ~GenericFactoryPro() {}

    //具体产品注册类Register。使用内嵌类可明显简化设计
    template <typename ConcreteProduct>
    class Register
    {
    public:
        Register(const ProductTypeKey& key)
        {
            ...
        }
    private:
        inline static AbstractProduct* ConcreteProductCreator(ArgTypes... args)
        {
            ...
        }
    };

    bool Unregister(const ProductTypeKey& conp)
    {
        ...
    }

    std::shared_ptr<AbstractProduct> NewInstance(const ProductTypeKey& conp, ArgTypes... args)
    {
        ...
    }

    std::vector<ProductTypeKey> GetOrderedKeyVec()
    {
        ...
    }


    int GetSize()
    {
        ..
    }

    ProductTypeKey GetKey(unsigned n) 
    {
       ...
    }

    inline static GenericFactoryPro<DerivedName, AbstractProduct, ProductTypeKey, ArgTypes...>& GetSingletonInstance()
    {
        static GenericFactoryPro<DerivedName, AbstractProduct, ProductTypeKey, ArgTypes...> unique_generic_factory;
        return unique_generic_factory;
    }
};


struct EXPORT_attribute ECClassDefMgr123 : public GenericFactoryPro<ECClassDefMgr123, ECClassDef, ObjectType>
{
    //ECClassDefMgr() = delete;
    //~ECClassDefMgr() = delete;
};

会看到类似这样的导出信息,

         10    9 005EDEA8 ?$TSS0@?1??GetSingletonInstance@?$GenericFactoryPro@UECClassDefMgr123@@UECClassDef@@UObjectType@@$$V@@SAAEAV2@XZ@4HA = ?$TSS0@?1??GetSingletonInstance@?$GenericFactoryPro@UECClassDefMgr123@@UECClassDef@@UObjectType@@$$V@@SAAEAV2@XZ@4HA (int `public: static class GenericFactoryPro<struct ECClassDefMgr123,struct ECClassDef,struct ObjectType> & __cdecl GenericFactoryPro<struct ECClassDefMgr123,struct ECClassDef,struct ObjectType>::GetSingletonInstance(void)'::`2'::$TSS0)

         18   11 00001E79 ??0?$GenericFactoryPro@UECClassDefMgr123@@UECClassDef@@UObjectType@@$$V@@IEAA@XZ = @ILT+3700(??0?$GenericFactoryPro@UECClassDefMgr123@@UECClassDef@@UObjectType@@$$V@@IEAA@XZ)

        304  12F 0001203A ??1?$GenericFactoryPro@UECClassDefMgr123@@UECClassDef@@UObjectType@@$$V@@QEAA@XZ = @ILT+69685(??1?$GenericFactoryPro@UECClassDefMgr123@@UECClassDef@@UObjectType@@$$V@@QEAA@XZ)

       1224  4C7 000089C7 ?GetKey@?$GenericFactoryPro@UECClassDefMgr123@@UECClassDef@@UObjectType@@$$V@@QEAA?AUObjectType@@I@Z = @ILT+31170(?GetKey@?$GenericFactoryPro@UECClassDefMgr123@@UECClassDef@@UObjectType@@$$V@@QEAA?AUObjectType@@I@Z)

       1262  4ED 0000CDBF ?GetOrderedKeyVec@?$GenericFactoryPro@UECClassDefMgr123@@UECClassDef@@UObjectType@@$$V@@QEAA?AV?$vector@UObjectType@@V?$allocator@UObjectType@@@std@@@std@@XZ = @ILT+48570(?GetOrderedKeyVec@?$GenericFactoryPro@UECClassDefMgr123@@UECClassDef@@UObjectType@@$$V@@QEAA?AV?$vector@UObjectType@@V?$allocator@UObjectType@@@std@@@std@@XZ)

       1308  51B 0000CCD9 ?GetSingletonInstance@?$GenericFactoryPro@UECClassDefMgr123@@UECClassDef@@UObjectType@@$$V@@SAAEAV1@XZ = @ILT+48340(?GetSingletonInstance@?$GenericFactoryPro@UECClassDefMgr123@@UECClassDef@@UObjectType@@$$V@@SAAEAV1@XZ)

       1316  523 000106E5 ?GetSize@?$GenericFactoryPro@UECClassDefMgr123@@UECClassDef@@UObjectType@@$$V@@QEAAHXZ = @ILT+63200(?GetSize@?$GenericFactoryPro@UECClassDefMgr123@@UECClassDef@@UObjectType@@$$V@@QEAAHXZ)

       1554  611 000059B6 ?NewInstance@?$GenericFactoryPro@UECClassDefMgr123@@UECClassDef@@UObjectType@@$$V@@QEAA?AV?$shared_ptr@UECClassDef@@@std@@AEBUObjectType@@@Z = @ILT+18865(?NewInstance@?$GenericFactoryPro@UECClassDefMgr123@@UECClassDef@@UObjectType@@$$V@@QEAA?AV?$shared_ptr@UECClassDef@@@std@@AEBUObjectType@@@Z)

       1788  6FB 00014623 ?Unregister@?$GenericFactoryPro@UECClassDefMgr123@@UECClassDef@@UObjectType@@$$V@@QEAA_NAEBUObjectType@@@Z = @ILT+79390(?Unregister@?$GenericFactoryPro@UECClassDefMgr123@@UECClassDef@@UObjectType@@$$V@@QEAA_NAEBUObjectType@@@Z)

       2348  92B 005EDE78 ?unique_generic_factory@?1??GetSingletonInstance@?$GenericFactoryPro@UECClassDefMgr123@@UECClassDef@@UObjectType@@$$V@@SAAEAV2@XZ@4V2@A = ?unique_generic_factory@?1??GetSingletonInstance@?$GenericFactoryPro@UECClassDefMgr123@@UECClassDef@@UObjectType@@$$V@@SAAEAV2@XZ@4V2@A (class GenericFactoryPro<struct ECClassDefMgr123,struct ECClassDef,struct ObjectType> `public: static class GenericFactoryPro<struct ECClassDefMgr123,struct ECClassDef,struct ObjectType> & __cdecl GenericFactoryPro<struct ECClassDefMgr123,struct ECClassDef,struct ObjectType>::GetSingletonInstance(void)'::`2'::unique_generic_factory)

为什么上面的GenericFactoryPro要加第一个参数呢?

首先,继承自GenericFactoryPro主要是为了生成一个单例,添加的第一个参数并没有用在实际代码中,主要是为了将导出的函数名保持唯一性。如果不唯一的话就会出现有意思的事,见:http://t.csdnimg.cn/BXdie

比如:

A.dll里这样定义:

template <
    typename AbstractProduct, //接口
    typename ProductTypeKey=std::wstring, //key
    typename ...ArgTypes //其他参数
>
class GenericFactory
{
protected:

    GenericFactory() {}
    GenericFactory(const GenericFactory&) = delete; 
    GenericFactory(GenericFactory&&) = delete;
    GenericFactory operator=(const GenericFactory& other) = delete;

public:
    ~GenericFactory() {}

    //具体产品注册类Register。使用内嵌类可明显简化设计
    template <typename ConcreteProduct>
    class Register
    {
    public:
        Register(const ProductTypeKey& key)
        {
            GenericFactory::GetSingletonInstance().m_OrderedKeyVec.push_back(key);
            GenericFactory::GetSingletonInstance().m_mapConFactory.emplace(key, ConcreteProductCreator);
        }
    private:
        inline static AbstractProduct* ConcreteProductCreator(ArgTypes... args)
        {
            ...
        }
    };

    bool Unregister(const ProductTypeKey& conp)
    {
        ...
    }

    std::shared_ptr<AbstractProduct> NewInstance(const ProductTypeKey& conp, ArgTypes... args)
    {
       ...
    }

    std::vector<ProductTypeKey> GetOrderedKeyVec()
    {
        ..
    }


    int GetSize()
    {
        ...
    }

    ProductTypeKey GetKey(unsigned n) 
    {
       ...
    }

    inline static GenericFactory<AbstractProduct, ProductTypeKey, ArgTypes...>& GetSingletonInstance()
    {
        static GenericFactory<AbstractProduct, ProductTypeKey, ArgTypes...> unique_generic_factory;
        return unique_generic_factory;
    }
};

struct EXPORT_attribute ECClassDefMgr123 : public GenericFactory<ECClassDef, ObjectType>
{
    //ECClassDefMgr() = delete;
    //~ECClassDefMgr() = delete;
};

struct EXPORT_attribute ECClassDefMgr456 : public GenericFactoryPro<ECClassDef, ObjectType>
{
    //ECClassDefMgr() = delete;
    //~ECClassDefMgr() = delete;
};

B.dll里这样使用

void fun()
{
    auto& fac1 = ECClassDefMgr123::GetSingletonInstance();
    auto& fac2 = ECClassDefMgr456::GetSingletonInstance();
    if(&fac1==&fac2)
    {
        std::cout<<"wc, 地址相同,它俩指向了同一个单例!";
    }
}

会发现,虽然类名不一样(一个是ECClassDefMgr123,一个是ECClassDefMgr456),但它们最后指向的单例是同一个。因为它们用的是同一个导出的static变量:unique_generic_factory

导出名称类似:

?unique_generic_factory@?1??GetSingletonInstance@?$GenericFactoryPro@@UECClassDef@@UObjectType@@$$V@@SAAEAV2@XZ@4V2@A = ?unique_generic_factory@?1??GetSingletonInstance@?$GenericFactoryPro@@UECClassDef@@UObjectType@@$$V@@SAAEAV2@XZ@4V2@A (class GenericFactoryPro<struct ECClassDef,struct ObjectType> `public: static class GenericFactoryPro<struct ECClassDef,struct ObjectType> & __cdecl GenericFactoryPro<struct ECClassDef,struct ObjectType>::GetSingletonInstance(void)'::`2'::unique_generic_factory)

### DUMPBIN 工具概述及其使用方法 DUMPBIN 是一种用于查看 COFF(Common Object File Format)二进制文件信息的强大工具[^1]。它能够帮助开发者分析目标文件、可执行文件以及动态链接库 (DLL) 的结构和内容。 #### 如何设置环境以便运行 DUMPBIN? 如果尝试运行 `dumpbin` 命令时收到错误提示:“‘dumpbin’ 不是内部或外部命令”,则需要配置开发环境变量以支持该工具的调用[^2]。具体操作如下: - 定位到 VCVARS32.bat 文件所在的路径,例如: ```plaintext C:\Program Files\Microsoft Visual Studio 8\VC\bin\vcvars32.bat ``` - 启动 CMD 提示符窗口并将此 `.bat` 文件拖放到其中并按 Enter 键。 - 成功加载后会显示消息:"Setting environment for using Microsoft Visual Studio 2005 x86 tools." 此时表示已成功设置了必要的环境变量。 #### DUMPBIN 的基本语法 以下是 DUMPBIN 的一般形式: ```bash dumpbin [options] filename [...] ``` | 参数 | 描述 | |------|-----| | `/HEADERS` | 显示指定文件头信息,包括时间戳、入口点等数据项。 | | `/SYMBOLS` | 列出符号表中的条目详情。 | | `/EXPORTS` | 展现导出函数列表。适用于 DLL 和 EXE 型的目标文件。 | | `/IMPORTS` | 查看导入模块及对应函数名称集合。 | #### 实际应用案例展示 ##### 示例一:获取 PE 头部基本信息 假设有一个名为 test.exe 的应用程序,可以利用下面这条指令提取它的头部概况: ```bash dumpbin /HEADERS test.exe ``` 这将返回关于这个特定程序映像的关键元数据属性[^1]。 ##### 示例二:列举所有公开接口 对于某个共享库 lib.dll ,我们可能关心哪些功能被暴露出来供其他组件调用,则应采用这样的方式查询: ```bash dumpbin /EXPORTS lib.dll ``` 结果里包含了每一个可供外界访问的方法签名[^2]。 ##### 示例三:探索依赖关系 当怀疑项目存在隐秘关联或者想要验证实际需求链路时,可以通过审查输入记录来达成目的。比如针对 app.exe 执行以下语句即可获得其所依赖的第三方资源清单: ```bash dumpbin /IMPORTS app.exe ``` ### 结论 以上介绍了如何正确启动 DUMPBIN 环境,并提供了几个常见场景下的实践例子。这些技巧可以帮助软件工程师更深入理解编译产物背后隐藏的知识点。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值