【windows核心编程】DLL相关(1)

 

DLL相关的东西

 

1、DLL的加载方式

隐式:

#pragma comment(lib, "XX.lib");

编译器去查找名为XX.dll的DLL,除了名字相同,该DLL和该LIB的GUID也相同。

 

显式:

HINSTANCE   hInst = LoadLibrary(TEXT("XX.dll"));

if(NULL == hInst)  retrun;

 

HINSTANCE hInst = LoadLibrary(TEXT("XX.dll"), NULL,   FLAGS);

第三个参数为一些标志,详见核心编程。

 

2、DLL的入口函数

原型

BOOL APIENTRY DllMain( HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
);

其中hModule为该DLL在当前进程地址空间中的位置,ul_reason_for_call为调用此函数的原因,lpReserved如果为显式加载则为0,如果为隐式加载则为非0。

详细说一下ul_reason_for_call

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
#ifdef _DEBUG

    switch (ul_reason_for_call)
    {
        //只在该DLL第一次加载进地址空间的时候被调用一次
        //此后当该DLL被加载进不同进程的地址空间时让然不调用
        //当主调线程通过该reason调用DllMain函数时,主调线程不会收到DLL_THREAD_ATTACH通知
    case DLL_PROCESS_ATTACH:
        OutputDebugString(TEXT("\r\n***********B Dll DLL_PROCESS_ATTACH ***********\r\n"));
        break;

        //当该DLL已经被加载到进程地址空间后,当有新【线程创建】的时候,新创建的线程先执行此段代码
        //然后再去执行线程本身的代码
        //不管有几个DLL,每个DLL的此处代码都会被新线程执行
    case DLL_THREAD_ATTACH:
        OutputDebugString(TEXT("\r\n***********B Dll DLL_THREAD_ATTACH ***********\r\n"));
        break;

        //当该DLL已经被加载到进程地址空间后,当有【线程结束】的时候,该线程结束之前会调用此处代码
        //然后才返回
        //不管有几个DLL,每个DLL的此处代码都会被执行
    case DLL_THREAD_DETACH:
        OutputDebugString(TEXT("\r\n***********B Dll DLL_THREAD_DETACH *********** \r\n"));
        break;

        //只有在该DLL从内存中卸载的时候才会被调用一次 
    case  DLL_PROCESS_DETACH:
        OutputDebugString(TEXT("\r\n***********B Dll DLL_PROCESS_DETACH ***********\r\n"));
        break;
    }

#endif

    return TRUE;
}

 

 

demo

有两个DLL, ADll.dll 和 BDll.dll

在程序中加载这个两个DLL, 然后创建一个新线程,看输出

//加载DLL
void CUseABDllDlg::OnBnClickedBtnLoadlib()
{
    HINSTANCE hInstA = LoadLibrary(_T("ADll.dll"));
    HINSTANCE HIntB = LoadLibrary(_T("BDll.dll"));
    if (NULL == hInstA || NULL == HIntB)
    {
        AfxMessageBox(_T("加载DLL失败"));
        return;
    }  
}

//线程函数
UINT WINAPI WorkThread(LPVOID lpParam)
{
#ifdef _DEBUG
    OutputDebugString(TEXT("\r\n&&&&&&&&&&&&&&&&&&线程被创建&&&&&&&&&&&&&&&&&\r\n"));
#endif

    return 0U;
}

//创建线程
void CUseABDllDlg::OnBnClickedButton2()
{
    HANDLE hThread = (HANDLE)_beginthreadex(NULL, 0, WorkThread, NULL, 0, NULL);
    if (NULL == hThread || INVALID_HANDLE_VALUE == hThread)
    {
        AfxMessageBox(_T("创建线程失败"));
    }
}

 

 

输出

 

结论:

每创建一个新线程,当前进程地址空间中的DLL的DllMain函数都会通过DLL_THREAD_ATTACH通知被调用一次

每结束一个线程,进程地址空间空的DLL的DllMain函数都会通过DLL_THREAD_DETACH通知被调用一次。

 

 

posted on 2014-05-27 20:17  崔好好  阅读(268)  评论(0编辑  收藏  举报

导航