动态连接库入口点函数

  DLL可以制定一个入口点函数,如果指定了入口点函数,系统在进程或线程载入或卸载DLL时就会调用入口点函数。这可以用来实现简单的初始化及清除任务。例如,新的线程创建时,可以设立线程局部存储器,然后线程终止时清除局部存储。

  如果用C运行时库连接DLL,就会自动提供一个入口点函数,并允许提供一个单独的初始化函数。还是看看运行时库的文档获取更多信息吧。

  如果你提供自己的入口点,请参见DllMain函数。DllMain是一个用户定义的函数名称占位符。实际生成DLL时,必须指定其实际的名字。更多信息,参见您所使用的开发工具的相关文档。

调用入口点函数

系统将在以下事件发生时调用入口点函数:

  • 进程载入DLL时。对于使用了载入时动态连接的程序,DLL通过进程初始化来载入。对于使用了运行时连接的程序,DLL在调用LoadLibrary或LoadLibraryEx返回前载入。
  • 进程卸载DLL时。进程终止或者调用了FreeLibrary函数,同时引用计数为0,则DLL被卸载。但如果进程作为TerminateProcess或TerminateThread函数的结果终止,系统不会调用入口点函数。
  • 新线程创建,但所在线程已载入DLL时。你可以在线程创建时利用DisableThreadLibraryCalls 函数禁止通知。
  • 已载入DLL的进程中的线程正常终止,而不是用TerminateThread或TerminateProcess终止时。进程卸载DLL时,整个进程仅会调用入口点函数一次,而不是进程所拥有的线程一个一次。线程终止时可以通过DisableThreadLibraryCalls禁用通知。

  每次只会有一个线程调用入口点函数。

  系统将会在进程或线程的上下文调用函数时调用入口点函数,并允许DLL的入口点函数在调用进程的虚地址空间中分配内存或打开访问程序的句柄。入口点函数通过线程局部存储器(TLS)也可以为新线程分配内存空间。关于线程局部存储器的更多信息,参照“局部存储器”。

定义入口点函数

  DLL入口点函数必须按照标准调用约定进行声明,如果声明不正确,DLL不会被载入,并且系统会指出DLL入口点函数必须用WINAPI声明。

Windows Me/98/95:  如果DLL入口点声明不正确,DLL不会载入,系统显示以“Error starting program,”开始的消息,并指示用户需要检查文件以纠正错误。

  在函数的主体部分,你可以处理以下入口点调用后的情况:

  • 一个进程载入DLL (DLL_PROCESS_ATTACH).
  • 当前进程创建一个新的线程(DLL_THREAD_ATTACH).
  • 线程正常退出 (DLL_THREAD_DETACH).
  • 进程卸载DLL (DLL_PROCESS_DETACH).

  入口点应该仅实现一些简单的初始化任务,而且不能调用LoadLibrary或LoadLibraryEx函数(或者其他简介调用这些函数的函数),这是因为这样可能会在DLL载入时在次序上造成依赖性循环。这会导致系统执行初始化代码前一个DLL就被使用了。同样入口点函数不能调用FreeLibrary函数(或者间接调用FreeLibrary的函数),这是由于系统执行终止代码后DLL仍被使用。

  调用Kernel32.dll中的其他函数是安全的,因为调用入口点函数时,该DLL可被担保已被载入到进程的地址空间中。通常我们在入口点函数中创建同步对象如临界区及互斥体,并使用TLS。不要使用注册函数,因为他们在Advapi32.dll中。如果要动态链接C运行库,就不要调用malloc,而应该用HeapAlloc。

  调用导入的函数与Kernel32.dll中的不同,可能会产生某些问题,而且很难诊断。例如,调用User、Shell及COM函数时会导致访问违规错误,这是因为这些DLL中某些函数使用LoadLibrary调用了其他系统组件。

  下例示范了如何构建DLL入口函数:

BOOL WINAPI DllMain(
    HINSTANCE hinstDLL,  // handle to DLL module
    DWORD fdwReason,     // reason for calling function
    LPVOID lpReserved )  // reserved
{
    // Perform actions based on the reason for calling.
    switch( fdwReason ) 
    { 
        case DLL_PROCESS_ATTACH:
         // Initialize once for each new process.
         // Return FALSE to fail DLL load.
            break;

        case DLL_THREAD_ATTACH:
         // Do thread-specific initialization.
            break;

        case DLL_THREAD_DETACH:
         // Do thread-specific cleanup.
            break;

        case DLL_PROCESS_DETACH:
         // Perform any necessary cleanup.
            break;
    }
    return TRUE;  // Successful DLL_PROCESS_ATTACH.
}

 

入口点函数返回值

  当一个DLL入口点函数由于程序载入被调用时,函数返回TRUE以表明调用成功。对于使用载入时链接的程序而言,FALSE返回值将导致程序初始化失败并终止。对于使用运行时链接的程序而言,返回值为FALSE将导致LoadLibrary或LoadLibraryEx函数返回NULL,指示失效。(系统会立即用DLL_PROCESS_DETACH调用入口点函数并卸载该DLL)如果出于其他原因调用入口点函数的话,该函数的返回值将会被忽略。

你可能感兴趣的:(MSDN)