- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
序言:这个问题仅与通过/MD
使用的动态CRT的行为有关。它不质疑任何其他建议的有效性。 DllMain
。
作为we've been told :(参见:Dynamic-Link库最佳实践,MSDN,2006年5月17日)
您永远不要在DllMain中执行以下任务:
...
使用动态C运行时(CRT)中的内存管理功能。如果未初始化CRT DLL,则对这些函数的调用会导致进程崩溃。
...
其他人已经have questioned this(如:对参数的有效性提出质疑),并且由于我们在那里有帮助地得到了答案,因此我们可以清楚地看到一个相当简单的情况,其中可以potentially cause troubles:
您是基于DLL的入口点始终为_DllMainCRTStartup的假设进行工作的。事实并非如此,这只是链接器的默认设置。它可以是程序员希望通过链接器的/ ENTRYPOINT选项快速,轻松地进行更改的任何内容。 Microsoft无法采取任何措施来防止这种情况。
因此,这些是此问题的要素:
链接/MD
而不提供自定义/ENTRYPOINT
时,是否还有其他情况需要动态初始化CRT?
具体来说,如果所有DLL加载仅通过“静态依赖项”完成,即根本没有任何显式的LoadLibrary
调用,则只需链接时DLL依赖项即可。
奖励:MS文档专门称呼“内存管理功能”,但据我所知,如果未初始化CRT,则任何CRT功能都可能不安全。为什么要用这种方式调出内存管理功能?
第三名:
Wrt。到自定义ENTRYPOINT
的方式:我不太清楚这怎么可能是一个如此重要的情况,以至于需要将其包含在not-do-in-DllMain列表中而无需进一步的限定。 IFF我提供了一个自定义的入口点,我负责正确初始化CRT,否则CRT不能在程序的任何地方正常工作,而不仅仅是DllMain。为什么要专门调出DllMain部分?
这使我回到Q.1,即如果这是唯一对动态CRT有问题的情况。对于这对于DllMain比DLL其他部分更重要的原因,或者我在这里可能会错过的内容,我们将不胜感激或大开眼界。
奖金链接:
When are global objects constructed and destructed by Visual C++?
DllMain : a horror story
Calling LoadLibrary from DllMain
原理:我觉得我应该在上下文中添加:我之所以这么问,是因为我们有大量的代码通过全局C ++对象构造函数来处理事务。多年来已经审查了实际发生的问题(例如并发的LoadLibrary
,线程同步等),但是所有代码都充满了std
C ++和CRT函数,在Windows XP上愉快地工作了很多年,7和Windows 10没有任何已知的问题。虽然我不是要哭“但它可以工作”,但我必须在这里进行工程判断,以尝试“解决”这一问题是否存在任何中短价值。因此,如果肥皂盒的答案可以留在他们的盒子里,我将不胜感激。
最佳答案
链接/MD
时,是否还有其他情况?
自定义/ENTRYPOINT
,动态CRT应该不完整
初始化了吗?
首先一些符号:
X具有静态导入(取决于)Y和Z:X[ Y, Z]
X入口点:X_DllMain
X_DllMain
呼叫LoadLibrary(Y)
:X<Y>
当使用/MD
时-在单独的DLL中使用crt。在这种情况下初始化意味着已调用crt DLL的入口点。因此问题可以更笼统,更清楚:
来自X[Y]
=> Y_DllMain
在X_DllMain
之前调用?
一般情况下因为Y[X]
或Y[Z[X]]
可以是循环依赖项。
最著名的示例user32[gdi32]
和gdi32[user32]
或win10中的示例取决于gdi32[gdi32full[user32]]
。因此必须先调用user32_DllMain
或gdi32_DllMain
吗?但是很明显,任何crt DLL都不依赖于我们的自定义DLL。因此,让我们排除循环依赖的情况。
当加载程序加载模块X时-加载所有它的依赖模块(并且依赖关系-这是递归过程),如果它尚未在内存中,则加载程序构建调用图,并开始调用模块入口点。很明显,如果A[B]
,则加载程序总是尝试在B_DllMain
之前调用A_DllMain
(当循环顺序未定义时,循环依赖除外)。但是调用图中将包含哪些模块?所有X依赖模块?当然不。当我们开始加载X时,其中一些模块可能已经在内存中(加载)。因此,它的入口点已经使用DLL_PROCESS_ATTACH
调用,并且现在不能再次调用。在XP,Vista,Win7中使用的这种策略:
当我们加载X时:
加载或定位所有依赖模块在内存中
仅调用新加载的模块(在X之后)的入口点。
如果A[B]
-在B_DllMain
之前调用A_DllMain
示例:已加载X[Y[W[Z]], Z]
//++begin load X
Z_DllMain
W_DllMain
Y_DllMain
X_DllMain
// --end load X
LoadLibrary
,则会发生这种情况。
X[Y<W[ Z]>, Z]
//++begin load X
Y_DllMain
//++begin load W
W_DllMain
//--end load W
Z_DllMain
X_DllMain
// --end load X
W_DllMain
,
Z_DllMain
将在
W[Z]
之前被调用。正是因为这不建议从DLL入口点调用
LoadLibrary
。
ExitThread
。在DLL分离期间退出线程可能会导致
ExitProcess
调用-挂起。因此确实会出现死锁,但不会在呼叫
ExitThread
-后者期间发生。
LoadLibrary
调用
DllMain
-user32.dll始终从其入口点为imm32.dll调用
LoadLibrary
(仍然为true,并且在win10上)
X[Y<W[Z]>, Z]
//++begin load X
Y_DllMain
//++begin load W
Z_DllMain
W_DllMain
//--end load W
X_DllMain
// -- end load X
test.exe[ kernel32, D1< D2[kernel32, msvcrt] >, msvcrt ]
SomeFunc
LoadLibraryW(L"D2")
,然后调用
D2.SomeFunc
/NODEFAULTLIB kernel32.lib msvcrt.lib
)
#include <Windows.h>
extern "C"
{
__declspec(dllimport) int __cdecl sprintf(PSTR buf, PCSTR format, ...);
}
BOOLEAN WINAPI MyEp( HMODULE , DWORD ul_reason_for_call, PVOID )
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
OutputDebugStringA("D2.DllMain\n");
}
return TRUE;
}
INT_PTR WINAPI SomeFunc()
{
__pragma(message(__FUNCDNAME__))
char buf[32];
// this is only for link to msvcrt.dll
sprintf(buf, "D2.SomeFunc\n");
OutputDebugStringA(buf);
return 0;
}
#ifdef _WIN64
#define FuncName "?SomeFunc@@YA_JXZ"
#else
#define FuncName "?SomeFunc@@YGHXZ"
#endif
__pragma(comment(linker, "/export:" FuncName ",@1,NONAME,PRIVATE"))
/NODEFAULTLIB kernel32.lib
)
#include <Windows.h>
#pragma warning(disable : 4706)
BOOLEAN WINAPI MyEp( HMODULE hmod, DWORD ul_reason_for_call, PVOID )
{
if (ul_reason_for_call == DLL_PROCESS_ATTACH)
{
OutputDebugStringA("D1.DllMain\n");
if (hmod = LoadLibraryW(L"D2"))
{
if (FARPROC fp = GetProcAddress(hmod, (PCSTR)1))
{
fp();
}
}
}
return TRUE;
}
INT_PTR WINAPI SomeFunc()
{
__pragma(message(__FUNCDNAME__))
OutputDebugStringA("D1.SomeFunc\n");
return 0;
}
#ifdef _WIN64
#define FuncName "?SomeFunc@@YA_JXZ"
#else
#define FuncName "?SomeFunc@@YGHXZ"
#endif
__pragma(comment(linker, "/export:" FuncName ",@1,NONAME"))
/NODEFAULTLIB kernel32.lib D1.lib msvcrt.lib
)
#include <Windows.h>
extern "C"
{
__declspec(dllimport) int __cdecl sprintf(PSTR buf, PCSTR format, ...);
}
__declspec(dllimport) INT_PTR WINAPI SomeFunc();
void ep()
{
char buf[32];
// this is only for link to msvcrt.dll
sprintf(buf, "exe entry\n");
OutputDebugStringA(buf);
ExitProcess((UINT)SomeFunc());
}
LDR: D1.dll loaded - Calling init routine
D1.DllMain
Load: D2.dll
LDR: D2.dll loaded - Calling init routine
D2.DllMain
D2.SomeFunc
LDR: msvcrt.dll loaded - Calling init routine
exe entry
D1.SomeFunc
LdrpRunInitializeRoutines - INFO: Calling init routine for DLL "D1.dll"
D1.DllMain
Load: D2.dll
LdrpRunInitializeRoutines - INFO: Calling init routine for DLL "D2.DLL"
D2.DllMain
D2.SomeFunc
LdrpRunInitializeRoutines - "msvcrt.dll"
exe entry
D1.SomeFunc
D2.DllMain
,在msvcrt入口点之前调用了
D2[msvcrt]
LdrpInitializeNode - INFO: Calling init routine for DLL "D1.dll"
D1.DllMain
LdrpInitializeNode - INFO: Calling init routine for DLL "msvcrt.dll"
LdrpInitializeNode - INFO: Calling init routine for DLL "D2.DLL"
D2.DllMain
D2.SomeFunc
exe entry
D1.SomeFunc
X[Y]
时没有在内存中进行任何未初始化的Y-
Y_DllMain
将在
X_DllMain
之前调用。或者换句话说-如果没有人从DLL入口点调用
LoadLibrary(X)
(或
LoadLibrary(Z[X])
)。因此,如果您的DLL将以“正常”方式加载(而不是通过
LoadLibrary
调用
DllMain
或在某些dll加载事件中从驱动程序注入),则可以确保已调用crt入口点(已初始化crt)
X[Y]
-
Y_DllMain
将始终在
X_DllMain
之前调用。
/ENTRYPOINT
。
DllMainCRTStartup
-该模块会按名称调用函数
DllMain
(这不是入口点)。因此,在动态crt的情况下-我们实际上有2个crt部分-主要部分在单独的DLL中,它将在调用您的DLL入口点之前进行初始化(如果不是特殊情况,我将介绍更高的版本和win7,vista,xp)。和小的静态部分(模块内部的代码)。该静态部分何时被称为已满取决于您。此部分
DllMainCRTStartup
进行一些内部初始化,在代码(
initterm
)中初始化全局对象,然后调用
DllMain
,然后返回(通过DLL分离)为全局变量调用析构函数。
DllMainCRTStartup
关于winapi - 在哪种情况下,动态CRT在调用用户提供的DllMain时尚未初始化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48302191/
在 JavaScript 中,我们可以动态创建 元素并附加到 部分,以便为大量元素应用 CSS 规则。 这种方法的优点或缺点是什么? 如果它确实提供了与元素上的 javascript 迭代相比的性
我有这个代码 import "./HTTPMethod.dart"; import '../../DataModel/DataModel.dart'; mixin RouterMixin { HT
哪些 OLAP 工具支持动态、动态地创建维度或层次结构? 例如,层次结构将成员定义为:“前 5 名”、“前 6-10 名”、“其他”... 计算成员是通常的答案,我正在寻找不同的东西。计算器的问题。成
我正在 CakePHP 中创建一个“表单编辑器”。 该界面允许用户选择要应用于字段的验证,例如数字、电子邮件等 因此,我需要根据用户输入为模型动态创建验证。为此,我可以使用验证对象:https://b
这是一个场景: 我有一个Web服务,我们将其称为部署在tomcat(轴)上的StockQuoteService。通过此 Web 服务公开了 getStockQuote() 方法。 现在,我想构建一个
我正在尝试从服务器获取 JSON 响应并将其输出到控制台。 Future login() async { var response = await http.get( Uri.
我从另一个问题中得到了这段代码(感谢 chunhunghan)。我需要创建一个登录屏幕,并尝试根据服务器发回给我的响应来验证用户凭据,但是每次我尝试运行代码时,它都会给我“未处理的异常:Interna
当我在“Dart”主程序中运行它时,一切正常,并且我得到了一个与会者列表。但是,当我在我的 Flutter 应用程序中调用它时,出现错误: flutter:“List”类型不是“List>”类型的子类
本文实例为大家分享了js实现验证码动态干扰的具体代码,供大家参考,具体内容如下 效果一 效果二 代码一 ?
目前我正在为我的网站使用 No-Ip,我想使用 cloudflare 来抵御 ddos 和机器人程序。我注意到您需要一个用于 cloudflare 的域。我还搜索了网络,发现了一个叫做 cloud
有没有办法在 Excel VBA 中构建动态 if 语句?基本上我正在尝试创建一个参数化计算,用户将能够输入不同的变量,即 变量 1 “变量 2” “变量 3” 在这种情况下 变量 1 是单元格引用
大家好, 请查看上面的图片,我有两张 table 。在下面代码的第一个表中,我得到了这种格式。 但我想像 Table2 那样格式化,每个合并单元格中的行数是动态的,而且不一样。 有没有办法像table
如何根据我添加的 View 修改标题部分的高度?heightForHeaderInSection在 viewForHeaderInSection 之前被调用我不知道 View 大小,直到我创建它。 最
是否存在在运行时生成 AST/解析树的解析器?有点像一个库,它会接受一串 EBNF 语法或类似的东西并吐出数据结构? 我知道 antlr、jlex 和他们的同类。他们生成可以做到这一点的源代码。 (喜
我在持有汽车制造商的表格上有一个 MultipleChoiceField。我想将我的汽车数据库过滤到已检查的品牌,但这会导致问题。如何动态获取所有 Q(make=...) 语句? 我如何开始:['va
$end = preg_replace($pattern, $replacement, $str); 如何使替换字符串 $replacement 随 $str 中的每次匹配而变化?例如,我想用关联的图
我正在编写一个 VBA 程序,用于过滤表中的值。我试图使其成为一个适用于您提供的所有表格的通用程序。在我的程序中,我必须设置它正在过滤的表的范围:Set rng = dataSheet.Range("
我正在循环一个元素数组,并且我想使用给定的模板递归地显示该元素 然后在该模板内使用带有切换功能的按钮来显示/隐藏给定元素的Child的更深级别模板(Child也是一个元素) 这是我的模板
从客户端(html)发送表单,服务器端通过选择选项之一决定运行哪个函数。 const decideWho = (form) => { const choice = form.choice; c
我有一个具有以下属性的按钮: circle_normal.xml(在 res/drawable 中) circle.xml(在 res/drawable 中)
我是一名优秀的程序员,十分优秀!