DLL入口点问题/需要建议

3
我有一个动态的C++代码库,跨平台,大部分是本地C++。然后我从我的主要exe使用这个动态库。在使用gcc的OSX上一切都很好。现在我在Windows上,我不知道应该使用什么方法来进入dll。目前我没有DllMain函数,因为在gcc中不需要(据我所知)。我的初步测试工作正常,但经检查发现奇怪的是我的某个类构造函数在dll加载时被调用,所以我想在Windows上需要做更多的事情。那么我应该:
  • 添加DllMain函数?
  • 我可以安全地使用noentry编译器选项吗?
当我执行以上任何一个操作时,我开始收到编译器的投诉,比如“存在.CRT节,可能存在未处理的静态初始化程序或终止程序”。
我已阅读了这篇文章article,但关于最佳方法的建议和清晰度将不胜感激。我对我需要做什么有些模糊不清。

你的库中有static变量吗?如果是这样,那么你希望在库加载时调用这些变量的构造函数。 - Andy
3个回答

4
基于 .CRT 错误,您肯定需要一个 DllMain 函数。对于大多数 Windows 编译器来说,它们会自动为您提供 DllMain,这样您就不需要自己编写了。根据您问题的其他部分,最有可能的是您使用的是 Visual C++,其 CRT 会为您提供 DllMain。因此,虽然您确实需要 DllMain,但无需编写代码。
默认的 VC CRT DllMain 用于初始化所涉及 DLL 的 CRT,并初始化该 DLL 提供的所有静态/全局变量。
Unix 和 Windows 上的 DLL 模型存在显着差异,您应该将每个 DLL 视为具有更“私有”的状态集。尽管如果所有 DLL 都选择同一版本的 CRT DLL,则其中的一些状态将被共享。
由于 CRT 为您提供了 DllMain,因此您不应在链接器上抛出 /noentry。
.CRT 部分存在错误(您必须通过抛出 /noentry 看到),这告诉您需要一个 DllMain,因为您的 DLL 中有一个或多个对象需要静态初始化。
Martyn

0

您可以稍微修改代码,避免除 main 以外的所有入口点。实际上,如果您在函数之外定义了任何变量(全局但未静态链接),请将它们包裹在一个函数调用中。使用经常被忽视的静态函数变量。 例如,更改全局声明

SomeType var_name;

转换为:

SomeType & var_name(){static SomeType var; return var;}

同样地,您可以通过更改以下代码来更改静态类实例变量:

struct Container{
    Container();
    static Container instance;
};

Container Container::instance;

转换为:

struct Container{
    Container();
    static Container & instance();
};

Container & Container::instance(){
    static Container var;
    return var;
}

这本质上是一个单例,但如果您第一次访问实例来自多线程环境,则可能会出现一些并发问题。事实上,需要记住的是,与全局定义变量不同,静态局部定义变量将在第一次调用函数时初始化。


0
如果只是一个库,那么NOENTRY就足够了。DllMain用于控制DLL发生的事件(例如附加、分离等)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接