想象一下,我们有一个包含2个项目的解决方案:MakeDll(一个dll应用程序),它创建一个dll,以及UseDll(一个exe应用程序),它使用dll。现在我知道基本上有两种方式,一种是愉快的,另一种则不是。令人愉快的方式是UseDll静态链接到MakeDll.lib,并且只是dllimports函数和类并使用它们。令人不快的方式是使用LoadLibrary和GetProcAddress,我甚至无法想象如何使用重载函数或类成员,换句话说除了extern“C”函数之外的其他任何东西。
我的问题如下(所有关于第一个选项)
提前致谢。
P.S。我正在使用MS Visual Studio 2008
答案 0 :(得分:3)
它基本上包含DLL中的函数列表,包括名称和序数(尽管几乎没有人使用序数)。链接器使用它在UseDLL.exe中创建一个导入表 - 即一个表示(实质上)的引用:“此文件依赖于MakeDll.dll中的函数xxx”。当加载程序加载该可执行文件时,它会查看导入表,并(递归地)加载它列出的所有DLL,并且(至少在概念上)使用GetProcAddress
来查找函数,因此它可以将它们的地址放入可执行的地方。
它通常在加载可执行文件的过程中加载。您可以使用/ delayload开关来延迟加载,直到调用该DLL中的函数。
一般来说,是的。在添加虚函数的特定情况下,它将依赖于类'vtable布局保持不变,而不是添加新函数。除非你采取措施确保或验证自己,否则取决于它是一个非常糟糕的主意。
答案 1 :(得分:1)
MakeDll.lib
包含导出的函数及其RVAs到MakeDll.dll
MakeDll.dll
根据为相关dll定义的加载类型加载到应用程序中。 (例如DELAYLOAD)。 Raymond Chen对此有interesting article。
只要MakeDll.dll
中使用的所有RVA偏移都没有更改,您就可以使用UseDll.exe
的新更新版本。如果您为多态类更改vtable
布局,就像在先前定义的vtable
中间添加新函数一样,您将需要重新编译UseDll.exe
。除此之外,您可以将更新的dll与之前编译的UseDll.exe
。
答案 2 :(得分:1)
令人不快的方式是使用LoadLibrary和GetProcAddress,我甚至无法想象如何使用重载函数或类成员,换句话说除了extern“C”函数之外的其他任何东西。
是的,这是令人不快的,但并不像听起来那么糟糕。如果您选择使用此选项,则需要执行以下操作:
// Common.h: interface common to both sides.
// Note: 'extern "C"' disables name mangling on methods.
extern "C" class ISomething
{
// Public virtual methods...
// Object MUST delete itself to ensure memory allocator
// coherence. If linking to different libraries on either
// sides and don't do this, you'll get a hard crash or worse.
// Note: 'const' allows you to make constants and delete
// without a nasty 'const_cast'.
virtual void destroy () const = 0;
};
// MakeDLL.c: interface implementation.
class Something : public ISomething
{
// Overrides + oher stuff...
virtual void destroy () const { delete this; }
};
extern "C" ISomething * create () { return new Something(); }
我已经成功地在两端使用不同的C ++编译器部署了这样的设置(即G ++和MSVC在所有4种可能的组合中互换)。
您可以随意更改Something
的实施。但是,您可以不更改界面而无需重新编译双方!当你想到它时,这是非常直观的:双方都依赖于对方对ISomething
的定义。 >为增加这种额外的灵活性所做的是使用编号的接口(如DirectX所做)或使用一组接口并测试功能(如COM所做)。前者设置非常直观,但需要纪律,第二口井......将重新发明轮子!