在 1998年12月的MSJ出版刊物中, Jeffrey和我寫了關於 在 vc6中使用DelayLoad 功能的專欄.最終結果,是證明了它是多麼cool.但是,不幸的是,還有很多人不了解DelayLoad,他們以為這個新特點是 最新版本的WINNT才有的.
在開始的時候,讓我重申一遍:DelayLoad不是最新的操作系統帶的特有功能,它可以在任何win32系統中起作用.我將寫一個簡單例子來說明. DelayLoadProfile, 實現了一個很小功能,很多程序都可以得益於它.
預覽:
通常的,當調用一個dll中的函數時,連接器會將dll和函數加入你的可執行文件.最後,所有引用的函數會放在imports段中. 當加載該程序的時候,win32程序加載器會掃描所有imports段的每個dll.加載,和重新定位imports段的所有函數,將信息寫入 引入地址表(ImportAddress Table, IAT).簡單說來,IAT就是一個函數指針的表.調用該 引入函數的時候,就到IAT中去找. 那麼,DelayLoad的機理是什麼呢?當你為一個Dll進行"DelayLoad"的時候,連接器不將原來的值放入imports段,相反,它為每個DelayLoad的引入函數的名稱和地址,生成一個小的根區, 備份下來。第一次引用的時候,它調用LoadLibrary加載Dll,然後,它調用GetProcAddress取得該函數的地址。最後,改寫自己在IAT的值,以便以後的程序可以直接調用.
上面的是簡化的步驟.實際上,根區是一小段代碼,它以靜態的方式連接到可執行文件中.代碼在delayimp.lib中,必須被 連接程序引用.並且,該代碼要足夠智能,當一個函數第一次被引用的時候,要調用LoadLibrary,以後調用就不用引用了. 和引用Dll相比,DelayLoad不會加太多的時間和空間,這種方式 調用LoadLibrary只會引起稍微一點點的性能損失.每次程序啟動,在針對引入表的函數地址定位的時候,依次對DelayLoad引入的調用GetProcAddress,相對於Win32加載器來說,所損失的性能也可以忽略不記.