写东西碰到个小问题,就搜索了一下,找到了些答案,感觉还不错,有些价值,在这里做一下笔记,也许有人有用吧。

以下内容摘自:http://topic.csdn.net/t/20011214/16/421698.html ,原帖发帖日期:2001-12-14 16:12:00,内容有重新排版及修改,去掉了一些不重要的回帖。

还有部分内容摘自互联网,就不一一点名了。。。


//dll name "dll2.dll "
BOOL APIENTRY DllMain( HANDLE hModule,
    DWORD ul_reason_for_call,
    LPVOID lpReserved
)
{
HANDLE hThread;
DWORD ThreadId;
switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
//DisableThreadLibraryCalls((HINSTANCE)hModule);
hThread = CreateThread(NULL,0,ThreadProcFun,NULL,0,&ThreadId);
WaitForSingleObject(hThread,INFINITE);
CloseHandle(hThread);
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;
}
return TRUE;
}

在另一main cpp中

#include <windows.h>
#include <stdio.h>
typedef int(*PFUN_fnDll1)(void);
void main()
{
HINSTANCE hInstDll;
PFUN_fnDll1 pFun;
LPCSTR dllfile = "dll2.dll ";

hInstDll = LoadLibrary(dllfile); //执行到这里时出现死锁
}

烦请各位给个死锁的理由


很简单:

系统要再用 DLL_THREAD_ATTACH 来调用Dll,之后线程才真正启动,但是系统在 DLL_PROCESS_ATTACH 时就 WaitForSingleObject(),所以永远都没机会用 DLL_THREAD_ATTACH,而线程也不会得到执行并退出,所以也没机会通过 WaitForSingleObject,因此死锁了。


那我如果

DisableThreadLibraryCalls((HINSTANCE)hModule);

强制线程创建时不用 DLL_THREAD_ATTACH 来调用 dllmain 呢?我试了,还是会死锁。


DllMain()中不能创建线程!

PRB: Cannot Create an MFC Thread During DLL Startup

SYMPTOMS

An MFC DLL that creates a new MFC thread during startup hangs when loaded by an application. This includes whenever a thread is created by calling AfxBeginThread or CWinThread::CreateThread inside:

the InitInstance of a CWinApp-derived object in a Regular DLL.
a supplied DllMain or RawDllMain function in a Regular DLL.
a supplied DllMain or RawDllMain function in an Extension DLL.

CAUSE

For Regular DLLs, which have a CWinApp-derived object, the CWinApp::InitInstance override is called from MFC's supplied DllMain when a process is attaching to the DLL. That is, DllMain is entered with a Reason For Call of DLL_PROCESS_ATTACH, and in handling this, MFC calls in to InitInstance before cleaning up and leaving DllMain.

For Extension DLLs, the startup of the DLL is the same, except Extension DLLs do not have a CWinApp-derived object and therefore have no InitInstance.

Whenever new threads are created that use code in the DLL, DllMain is called with a Reason For Call of DLL_THREAD_ATTACH to announce to the DLL that a new thread is attaching to it. If a new thread is created in the InitInstance of an MFC Regular DLL or in the DllMain of any MFC DLL during DLL_PROCESS_ATTACH, this second thread will attempt to re-enter the DllMain, which has not yet been exited from in an effort to announce DLL_THREAD_ATTACH.

DllMain, however, is not re-entrant. That means that the second thread will not start executing until the initial creating thread has finished its work in InitInstance, returned to and left DllMain.

In versions of MFC included with 32-bit Visual C++ versions 2.2 and earlier, MFC allowed threads to be created during startup, and usually DLLs that did this would work acceptably. The second thread would get created without problem but would not start executing until the first thread left DllMain. However, it has never been a good idea to create threads in DllMain during DLL_PROCESS_ATTACH.

As of MFC 4.0, the CWinThread::CreateThread function, which is called by AfxBeginThread, now waits on the created thread to start up and initialize MFC specific data before it returns control to the calling thread. Because the second thread is waiting on the first thread to leave DllMain, both threads crash headlong into deadlock and the application hangs.

Note that this information is equally valid for the RawDllMain function. Moreover, MFC DLLs should not use a RawDllMain function at all.

RESOLUTION

Regular DLLs that create threads should only do so in functions exported from the DLL and called by client applications. Furthermore, no MFC DLL -- neither Extension nor Regular -- should create an MFC thread in the DllMain or RawDllMain function. This ensures that the thread will not be created in the middle of any critical startup code.

The recommended solution for MFC DLLs that need to create a thread when the DLL starts is to add a specific exported initialization function and create the thread in it. Applications that use the DLL would need to call this function sometime during startup, most likely during the application 's InitInstance if it uses MFC. Or, if the application is loading the DLL explicitly, the application should call the initialization function immediately after the call to load the library.

The practice of exporting an initialization function for a DLL is not uncommon. Nevertheless, there may be situations where DLLs created with earlier versions of MFC are being ported but the client application cannot be changed to include a call to an initialization function. The alternative to an initialization function is to create the thread in one of the pre- existing exported functions. Any of the DLL 's exported functions that require a running thread should be responsible for first checking to see if that thread exists and then creating it if it does not.

STATUS

This behavior is by design.


就算如此,系统必须在执行从 DllMain 的 DLL_PROCESS_ATTACH 完成后才会继续 Dll 的操作,刚刚说的 DLL_THREAD_ATTACH 只是代表 DLL_PROCESS_ATTACH 的后续动作而已,也就是系统根本到不 WaitForSingleObject 的后一句指令,所以也不会对Dll继续执行。


小弟不明白,为什么不会再次有调用dllmain的企图了而还是会“系统根本到不WaitForSingleObject的后一句指”?,我的理解是ThreadProcFun,很快就会执行完毕,而WaitForSingleObject也会执行成功并且反回。

请 "caigzhi "继续指点


《Windows高级编程指南》P433-434里有一样的例子和说明,如果没有,建议一定买一本(最好是它的第四版(Windows核心编程)),这是windows用户态编程最好的书。

你理解错了,只有DLL_PROCESS_ATTACH完成以后系统才能使用导入DLL的地址空间,这是常规方法不可逾越的步骤。


可我认为在 DisableThreadLibraryCalls() 之后,DLL_PROCESS_ATTACH 能走完啊(线程 ThreadProcFun 可以走完,WaitForSingleObject 也可以走完,然后 CloseHandle(),然后 break; 难道有错吗?

--请恕小弟愚笨


新线程在 DLL_PROCESS_ATTACH 结束前不会跑的起来,那时还没有新线程的入口地址和执行代码。

谢谢 caigzhi,一语中的,能交个朋友吗?给分了。



DLL中创建线程的问题

2011-08-24 15:39,http://hi.baidu.com/anowsober/blog/item/3ddebbf4227d65c2f3d385fa.html

关键字:DLL DllMain 创建 线程 无法启动

在 DllMain 中创建线程,必须等 DllMain 返回之后线程才能运行,在 exe 中没有这个问题。

如果在 DllMain 中调用的函数有无限循环或者有 Infinite 等待,也就是说这个函数在你等待的事件发生之前不会结束(DllMain 也就不会结束),并且这个函数中创建了新线程,那这些新线程永远(或者在等待的事件发生之前)不会运行。如果这个事件刚好是程序等待的退出事件,那就真永远了。悲剧就这么发生了~

MSDN 中关于 CreateThread 有这样的说明:

During process startup and DLL initialization routines, new threads can be created, but they do not begin execution until DLL initialization is done for the process.

译文:在进程启动和DLL初始化过程中,可以创建新的线程,但是在这个进程DLL初始化操作未完成之前,它们不开始执行。