延迟加载的D L L是个隐含链接的D L L,它实际上要等到你的代码试图引用
D L L中包含的一个符号时才进行加载。延迟加载的D L L在下列情况下是非常有用的:
• 如果你的应用程序使用若干个D L L,那么它的初始化时间就比较长,因为加载程序要将所有需要的D L L映射到进程的地址空间中。解决这个问题的方法之一是在进程运行的时候分开加载各个D L L。延迟加载的D L L能够更容易地完成这样的加载。
• 如果调用代码中的一个新函数,然后试图在老版本的系统上运行你的应用程序,而该系统中没有该函数,那么加载程序就会报告一个错误,并且不允许该应用程序运行。你需要一种方法让你的应用程序运行,然后,如果(在运行时)发现该应用程序在老的系统上运行,那么你将不调用遗漏的函数。例如,一个应用程序在Windows 2000上运行时想要使用P S A P I函数,而在Windows 98上运行想要使用To o l H e l p函数(比如P r o c e s s 3 2 N e x t)。当该应用程序初始化时,它调用G e t Ve r s i o n E x函数来确定主操作系统,并正确地调用相应的其他函数。如果试图在Windows 98上运行该应用程序,就会导致加载程序显示一条错误消息,因为Windows 98上并不存在P S A P I . d l l模块。同样,延迟加载的D L L能够使你非常容易地解决这个问题。
------摘自<<Windows核心编程>>
下面我以简单的代码来展示延迟加载DLL的实现.
#include <TlHelp32.h>
#include <shlwapi.h>
#pragma comment(lib, "shlwapi.lib")

#include <delayimp.h>
// 这个链接开关告诉链接程序将一个特殊的函数--delayLoadHelper嵌入到
// 你的可执行模块。
#pragma comment(lib, "delayimp.lib")

// 延迟加载
#pragma comment(linker, "/Delayload:"shlwapi.dll"")

// 允许卸载DLL
// __FUnloadDelayLoadedDLL(_T("shlwapi.dll"));可以用此函数将你加载
// 的DLL卸载掉
// D e l a y : u n l o a d链接程序开关告诉链接程序将另一个节放入文
// 件中。该节包含了你清除已经调用的函数时需要的信息,这样它们就可以
// 再次调用- - d e l a y L o a d H e l p e r函数。当调用
// - -F U n l o a d D e l a y L o a d e d D l l时,你将想要卸载的延
// 迟加载的D L L的名字传递给它。该函数进入文件中的未卸载节,并清除
// D L L的所有函数地址,然后
// - - F U n l o a d D e l a y L o a d e d D l l调用
// F r e e L i b r a r y,以便卸载该D L L。
#pragma comment(linker, "/Delay:unload")

void IsModuleLoaded(TCHAR * pszModuleName)


{
HMODULE hModule = GetModuleHandle(pszModuleName);


TCHAR szName[MAX_PATH] = {0};
_stprintf(szName,
_T("Module "%s" is %sloaded."),
pszModuleName,
(hModule == NULL) ? _T("not ") : _T(""));
::MessageBox(NULL,
szName,
_T("提示"),
MB_OK);
}

void GetProcessID(LPTSTR pszProcessName, DWORD& th32ProcessID)


{
HANDLE hSnapshot = NULL;
__try

{
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hSnapshot)

{
__leave;
}

PROCESSENTRY32 pe;
ZeroMemory(&pe, sizeof(PROCESSENTRY32));
pe.dwSize = sizeof(PROCESSENTRY32);

BOOL bProcess = Process32First(hSnapshot, &pe);
while (bProcess)

{
if (pe.szExeFile == StrStrI
(pe.szExeFile, pszProcessName))

{
th32ProcessID = pe.th32ProcessID;
break;
}

bProcess = Process32Next(hSnapshot, &pe);
}

if (!bProcess)

{
__leave;
}
}
__finally

{
if (INVALID_HANDLE_VALUE != hSnapshot)

{
CloseHandle(hSnapshot);
}
}
} 用如下代码测试即可
IsModuleLoaded(_T("shlwapi"));
DWORD dwProcessID;
GetProcessID(_T("csrss.exe"), dwProcessID);
std::cout << dwProcessID << std::endl;
IsModuleLoaded(_T("shlwapi"));
当程序初始化时并未将DLL映射到进程的地址空间,直到调用函数GetProcessID时,由于其中要导出shlwapi.dll的函数StrStrI,此时该DLL被加载,并且一直存在于进程的地址空间中。