S.l.e!ep.¢%

像打了激速一样,以四倍的速度运转,开心的工作
简单、开放、平等的公司文化;尊重个性、自由与个人价值;
posts - 1098, comments - 335, trackbacks - 0, articles - 1
  C++博客 :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

第二十章 DLL高级技巧

Posted on 2009-05-10 22:51 S.l.e!ep.¢% 阅读(1096) 评论(0)  编辑 收藏 引用 所属分类: DLL

第二十章 DLL高级技巧

1.概览

 1.1动态加载DLL文件 LoadLibraryEx

                HMODULE LoadLibraryEx(

PCTSTR pszDLLPathName,

HANDLE hFile,

DWORD dwFlags);

              返回DLL加载到进程空间原首地址。

              dwFlags 可以有以下几个值

              (1) DONT_RESOLVE_DLL_REFERENCES

                              建议永远不要使有这个值,它的存在仅仅是为了向后兼容、

                              更多内容请访问:http://blogs.msdn.com/oldnewthing/archive/2005/02/14/372266.aspx

              (2) LOAD_LIBRARY_AS_DATAFILE

                              把要加载的DLL文件以数据文件的形式加载到进程中。

                              GetModuleHandleGetProcAddress返回NULL

              (3) LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE

                              与前者相同,不同的时独占打开,禁止其它进程访问和修改该DLL中的内容。

              (4) LOAD_LIBRARY_AS_IMAGE_RESOURCE

                              不修改DLL中的RVA,以image的形式加载到进程中。常与LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE一起使用。

              (5) LOAD_WITH_ALTERED_SEARCH_PATH

                              修改DLL的加载路径

  1.2 DLL 的加载与卸载

              (1)加载

                              不要在同一进程中,同时使用LoadLIbraryLoadLibraryEx加载同一DLL文件。

                              DLL的引用计数是以进程为单位的。LoadLibrary会把DLL文件加载到内存,然后映射到进程空间中。

                              多次加载同一DLL只会增加引用计数而不会多次映射。当所有进程对DLL的引用计数都为0时,系统会在内存中释放该DLL

              (2)卸载

                              FreeLibrary,FreeLibraryAndExitThread对当前进程的DLL的引用计数减1

              (3) GetProcAddress

                              取得函数地址。它只接受ANSI字符串。

2.DLL的入口函数

                2.1 DllMain

              BOOL WINAPI DllMain(

              HINSTANCE hInstDll, ""加载后在进程中的虚拟地址

              DWORD fdwReason, ""系统因何而调用该函数

              PVOID fImpLoad ""查看是隐工还是动态加载该DLL

 

              DLLsDllMain方法来初始化他们自已。DllMain中的代码应尽量简单,只做一些简单的初始化工作。

              不要在DllMain中调用LoadLibrary,FreeLibraryShell, ODBC, COM, RPC, socket 函数,从而避免不可预期的错误。

 

                2.2 fdwReason的值

               (1)DLL_PROCESS_ATTACH

               系统在为每个进程第一次加载该DLL时会,执行DLL_PROCESS_ATTACH后面的语句来初始化DLL,DllMain的返回值仅由它决定。

 系统会忽略DLL_THREAD_ATTACH等执行后DllMain的返回值。

               如果DllMain返回FALSE,系统会自动调用DLL_PROCESS_DETACH的代码并解除DLL文件中进程中的内存映射。

               

               (2)DLL_PROCESS_DETACH

                              如果DLL是因进程终止而卸载其在进程中的映射,那么负责调用ExitProcess的线程会调用DllMainDLL_PROCESS_DETACH所对应的代码。

                              如果DLL是因FreeLibraryFreeLibraryAndExitThread,而卸载其在进程中的映射,

那么FreeLibraryFreeLibraryAndExitThread会负责调用DllMainDLL_PROCESS_DETACH所对应的代码。

                              如果DLL是因TerminateProcess而卸载其在进程中的映射,系统不会调用DllMainDLL_PROCESS_DETACH所对应的代码。

              (3) DLL_THREAD_ATTACH

                              若进程是先加载的DLL,后创建的线程

                                              那么在进程中创建新线程时(主线程除外),系统会执行该进程已载的所有DLLDllMainDLL_THREAD_ATTACH对应的代码。

                              若进程是先创建的线程,后加载的DLL

                                              那么系统不会调用DLLDllMain中的代码。

              (4) DLL_THREAD_DETACH

                              进程中的线程退出时,会先执行所有已加载DLLDllMainDLL_THREAD_DETACH所对应的代码。若该代码中有死循环,线程不会退出。

             

 2.3 同步化DllMain的调用

              同一时间只能有一个线程调用DllMain中的代码,所以下面的代码会导致死循环

BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, PVOID fImpLoad) {

 

   HANDLE hThread;

   DWORD dwThreadId;

 

   switch (fdwReason) {

   case DLL_PROCESS_ATTACH:

      // The DLL is being mapped into the process' address space.

 

      // Create a thread to do some stuff.

      hThread = CreateThread(NULL, 0, SomeFunction, NULL,

         0, &dwThreadId);// CreateThreadDLL_THREAD_ATTACH中的代码,但是由于当前线程并未执行完毕,

//所以DLL_THREAD_ATTACH中的代码不会被执行,且CreateThread永无不会返回。

 

      // Suspend our thread until the new thread terminates.

      WaitForSingleObject(hThread, INFINITE);

 

      // We no longer need access to the new thread.

      CloseHandle(hThread);

      break;

 

   case DLL_THREAD_ATTACH:

      // A thread is being created.

      break;

 

   case DLL_THREAD_DETACH:

      // A thread is exiting cleanly.

      break;

 

   case DLL_PROCESS_DETACH:

      // The DLL is being unmapped from the process' address space.

      break;

   }

   return(TRUE);

}

 

3.延时加载DLL

(1)延时加载DLL的限制

              延时加载是指当程序在运行时用到DLL中的函数时自动会自动加载DLL函数,它与动态加载不同。

              http://msdn2.microsoft.com/en-us/library/yx1x886y(VS.80).aspx

 

4.已知的DLL (Known DLLs)

              位置:HKEY_LOCAL_MACHINE"SYSTEM"CurrentControlSet"Control"Session Manager"KnownDLLs

              LoadLibrary在查找DLL会先去该位置查找有无相应的键值与DLL要对应,若有则根据链值去%SystemRoot%"System32加载键值对应的DLL

              若无则根据默认规去寻找DLL

 

5.Bind and Rebase Module

              它可以程序启动的速度。ReBaseImage


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理