考虑代码
可执行程序:
int main ()
{
printf("Executable Main, loading library\n");
#ifdef HAVE_WINDOWS
HMODULE lib = LoadLibraryA ("testdll.dll");
#elif defined(HAVE_LINUX)
void * lib = dlopen("testdll.so", RTLD_LAZY);
#endif
if (lib) {
printf("Executable Main, Freeing library\n");
#ifdef HAVE_WINDOWS
FreeLibrary (lib);
#elif defined(HAVE_LINUX)
dlclose(lib);
#endif
}
printf("Executable Main, exiting\n");
return 0;
}
Run Code Online (Sandbox Code Playgroud)
DLL
struct Moo
{
Moo() { printf("DLL Moo, constructor\n"); }
~Moo() { printf("DLL Moo, destructor\n"); }
};
Moo m;
#ifdef HAVE_WINDOWS
BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved)
{
switch …
Run Code Online (Sandbox Code Playgroud) 序言:这个问题特别关注动态 CRT 的行为,并且仅与之相关/MD
.它并不质疑任何其他建议的有效性.DllMain
.
当我们被告知:(参考:动态链接库的最佳实践,MSDN,2006年5月17日)
您永远不应该在DllMain中执行以下任务:
- ...
- 使用动态 C运行时(CRT)中的内存管理功能.如果未初始化CRT DLL,则对这些函数的调用可能导致进程崩溃.
- ...
其他人已经对此提出质疑(如:质疑论证的有效性),既然我们在那里得到了答案,我们可以清楚地看到一个相当简单的案例,这可能会引起麻烦:
您正在假设DLL的入口点始终是_DllMainCRTStartup.情况并非如此,它只是链接器的默认值.它可以是程序员想要的任何东西,使用链接器的/ ENTRYPOINT选项可以快速轻松地更改.微软没有办法阻止这一点.
所以这些是这个问题的要素:
链接和不提供自定义时是否还有其他情况,动态 CRT应该不能完全初始化?/MD
/ENTRYPOINT
LoadLibrary
调用,只需链接时间DLL依赖项.额外:MS文档专门调用"内存管理功能",但据我所知,如果CRT未初始化,可能任何 CRT功能都应该是不安全的.为什么以这种方式调用内存管理功能?
三:
WRT.对于习惯ENTRYPOINT
:我不太明白这是一个如此重要的场景,它需要被包含在不做DllMain列表中而无需进一步限定.IFF我提供了一个自定义入口点,我负责正确初始化CRT,或者CRT在我的程序中的任何地方都不能正常工作,而不仅仅是DllMain.为什么要专门调用DllMain部分?
这导致我回到Q.1,即如果这是动态 CRT 存在问题的唯一情况.澄清或大开眼界为什么这对于DllMain来说更重要的是,对于DLL的其他部分,或者我可能会错过这里,我们将不胜感激.
额外链接:
理由:我觉得我应该为上下文添加这个:我问这个是因为我们有大量的代码通过全局C++对象构造函数来做事.实际上破坏的事情多年来一直经过审查(如并发LoadLibrary
,线程同步等),但所有代码都充满了std
C++和CRT功能,这些功能已经在Windows XP,7和Windows 10上运行多年了任何已知的打嗝.虽然我不是一个哭泣"但它只是有效",我必须在这里做一个工程判断,试图"修复"这个是否有任何短期到中等价值.因此,如果肥皂盒的答案可以留在他们的盒子里,我将不胜感激.
在 DllMain() 之前调用哪些函数?如果在 C 运行时初始化期间不止一个,那么顺序很重要。
在Windows上,标准DLL入口点称为DllMain.第二个参数是DWORD ul_reason_for_call
.
我在MSDN上查找了第二个参数的可能值.以下是显而易见的:
DLL_PROCESS_ATTACH:
DLL_THREAD_ATTACH:
DLL_THREAD_DETACH:
DLL_PROCESS_DETACH:
Run Code Online (Sandbox Code Playgroud)
但是关于:
DLL_PROCESS_VERIFIER
Run Code Online (Sandbox Code Playgroud)
何时使用此标志调用入口点?在DLL的"正常"操作期间我应该担心它吗?
请注意,我只DLL_PROCESS_VERIFIER
在Visual Studio 2005的头文件中看到,而不是2008.
我已经用 C++ 编写了一个 dll 和注入器。dll代码如下:
#include <cstdio>
#include <stdio.h>
#include <windows.h>
#include <string>
#include <fstream>
#include <winsock.h>
using namespace std;
#pragma comment(lib, "wsock32.lib")
extern "C" __declspec(dllexport) void UploadFile()
{
.....
}
INT APIENTRY DLLMain(HMODULE hinstDLL, DWORD fdwReason, LPVOID lpReserved)
{
switch(fdwReason)
{
case DLL_PROCESS_ATTACH:
MessageBox(0,"Process Attach","Info",MB_OK);
UploadFile();
break;
case DLL_THREAD_ATTACH:
MessageBox(0,"Thread Attach","Info",MB_OK);
UploadFile();
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_DETACH:
break;
default:
break;
}
return TRUE;
}
Run Code Online (Sandbox Code Playgroud)
dll 将特定文件上传到服务器。我能够使用 LoadLibrary() 和 CreateRemoteThread() 成功地将 dll 注入“notepad.exe”,但它没有被执行。甚至不是 dllmain() 函数。不知道出了什么问题。
我已经阅读了一些CreateProcess
不能从DllMain
函数中调用的来源。
创建过程:
不要从 DllMain 函数调用 CreateProcess。这会导致应用程序停止响应。
永远不要从 DllMain 中执行以下任务: 调用 CreateProcess。创建一个进程可以加载另一个 DLL。
这是为什么?它指出它会导致应用程序停止响应,但这只是一种症状。真正的原因是什么?
我问的原因是我尝试从一个DllMain
函数创建一个进程,它看起来工作得很好。
我正在学习COM.我在DLL中编写了一个简单的COM组件,并在注册表中注册了它.然后我创建了一个简单的客户端并尝试使用我的COM组件.但我不明白这种DllMain
行为(我也读过这个).
extern "C" BOOL WINAPI DllMain(
_In_ HINSTANCE hinstDLL,
_In_ DWORD fdwReason,
_In_ LPVOID lpvReserved){
pDll = hinstDLL;
if (DLL_PROCESS_ATTACH == fdwReason){
trace("DllMain(): DLL_PROCESS_ATTACH");
}
else if (DLL_THREAD_ATTACH == fdwReason){
trace("DllMain(): DLL_THREAD_ATTACH");
}
else if (DLL_PROCESS_DETACH == fdwReason){
trace("DllMain(): DLL_PROCESS_DETACH");
}
else if (DLL_THREAD_DETACH == fdwReason){
trace("DllMain(): DLL_THREAD_DETACH");
}
else{
trace("DllMain(): unknown variant...");
}
return TRUE;
}
Run Code Online (Sandbox Code Playgroud)
我期望每个DLL_PROCESS_ATTACH
人DLL_PROCESS_DETACH
都被调用并且每个DLL_THREAD_ATTACH
人DLL_THREAD_DETACH
都被调用(如果没有发生异常).
但我看到一个DLL_PROCESS_ATTACH
有两个DLL_THREAD_DETACH
:
为什么会这样?