微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

为什么我可以使用运行时加载的 dll 未导出的函数

如何解决为什么我可以使用运行时加载的 dll 未导出的函数

我有一个相当简单的插件系统,可以在运行时加载和重新加载 dll。没有涉及任何静态链接。 .exe 仅包含加载 dll 所需的代码。它目前通过使用 LoadLibrary/GetProcAddress/FreeLibrary 函数在 Windows 下执行此操作。 (在 VisualStudio 中)没有设置额外的库目录、项目引用或库。

然而,我正在做的是包括我稍后动态加载的 dll 项目中的一些头文件(以防万一)。现在我知道我可能应该只使用 GetProcAddress 查询的接口函数调用 dll,但这是我第一次这样做,所以我只是想弄清楚。

现在假设我得到了 CreateWindow 函数函数指针,如下所示:

void Loadplugin(PlatformPlugin* plugin)
{
  plugin->Handle = LoadLibrary(plugin->PLUGIN_FILE_TEMP);
  plugin->CreateWindow = (PLUGIN_PLATFORM_CreateWindow)GetProcAddress(plugin->Handle,"CreateWindow");
}

CreateWindow 函数返回一个指向 Window 对象的指针,该对象主要包含虚拟函数,并由特定于平台的 Window 类(如 WindowsWindow)继承:

class Window
{
public:
  virtual unsigned int GetWidth() const = 0;
  virtual unsigned int GetHeight() const = 0;
};

class WindowsWindow : public Window
{
 public:
   virtual unsigned int GetWidth() const override;
   virtual unsigned int GetHeight() const override;
};

当然也有一个带有定义的 .cpp 文件。 这里出现了“问题”:当调用 CreateWindow 时,我得到了有效的指针,当在它上面调用 GetWidth 时,我也得到了正确的结果。但是您可能已经注意到,我从未导出任何 Window 类或函数。据我了解,我不应该调用 GetWidth 但我可以。 Dependencywalker 证实了这一点,并只向我展示了 CreateWindow 作为导出的函数。 我怎么能叫它呢?包含的头文件在理论上只为编译器提供调用函数所需的信息,但由于头文件实际上不包含函数实现,链接器如何知道我的函数的地址?

解决方法

虚函数的地址存储在对象的 vtable 中。因此,您不需要导出符号来调用这些函数,只需要一个有效的对象(或一个对象的地址)和 vtable 布局的知识(由您的头文件提供)。

然后编译器可以索引到 vtable 中以找到要调用的地址并调用它。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?