Get the current HMODULE for the target DLL. This is 0 the first time an API in
that DLL is invoked.
Calculate the function index. This is an index into an Import Address Table.
Use the function index to point at the corresponding slot in the Image Name
Table.
Get either the function name or function ordinal from the Image Name Table
if ( hModule is 0 )
{
LoadLibrary( dllname )
copy hModule to hModule global variable pointed at by ImgDelayDescr
}
FARPROC pfnRet = GetProcAddress( hModule, function name or ordinal )
ppfnIATEntry = pfnRet; // ppfnIATEntry was passed in via the linker generated
// stub. Future calls to the API call directly through
// this pointer to the API code,rather than to the stub
return pfnIATEntry // The stub JMPs to this address
Figure 4 DelayLoadDemo.cpp
//==================================================
// DelayLoadDemo - Matt Pietrek 1998
// Microsoft Systems Journal, December 1998
// FILE: DelayLoadDemo.CPP
//==================================================
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include "delayimp.h"
int main()
{
GetTopWindow( 0 ); // Call a USER32 function
GetTopWindow( 0 ); // Call it a few more times to see that subsequent
GetTopWindow( 0 ); // calls bypass the /DELAYLOAD generated stubs
GetDesktopWindow();
InitCommonControls();
return 0;
}
FARPROC WINAPI MSJCheezyDelayLoadHook(unsigned dliNotify, PDelayLoadInfo pdli )
{
// Display which type of notification it is
switch( dliNotify )
{
case dliStartProcessing:
printf( "dliStartProcessing " );
break;
case dliNotePreLoadLibrary:
printf( "dliNotePreLoadLibrary " );
break;
case dliNotePreGetProcAddress:
printf( "dliNotePreGetProcAddress" );
break;
case dliNoteEndProcessing:
printf( "dliNoteEndProcessing " );
break;
}
// Display the DLL name and the HMODULE
printf( " %s(%08X) -> ", pdli->szDll, pdli->hmodCur );
// Display the API ordinal or API name, as appropriate
if ( pdli->dlp.fImportByName )
printf( " %s", pdli->dlp.szProcName );
else
printf( " ordinal:%u", pdli->dlp.dwOrdinal );
printf( "\n" );
return 0; // Make sure __delayLoadHelper doesn't think we did something!
}
//
// Override the standard definition of __pfnDliNotifyHook that's part of
// DELAYHLP.LIB
//
PfnDliHook __pfnDliNotifyHook = MSJCheezyDelayLoadHook;
Figure 5 DelayLoadDemo.mak
PROJ = DelayLoadDemo
OBJS = $(PROJ).OBJ
CFLAGS = $(CFLAGS) /W3 /GF /DWIN32_LEAN_AND_MEAN
LFLAGS = /SUBSYSTEM:console /DELAYLOAD:USER32.DLL /DELAYLOAD:COMCTL32.DLL
!if "$(DEBUG)" == "1"
CFLAGS = $(CFLAGS) /YX /Zi /D_DEBUG /Fd"$(PROJ).PDB" /Fp"$(PROJ).PCH"
LFLAGS = $(LFLAGS) /DEBUG /DEBUGTYPE:CV /PDB:none
!else
CFLAGS = $(CFLAGS) /O1 /DNDEBUG
!endif
LIBS = USER32.LIB COMCTL32.LIB DELAYIMP.LIB
$(PROJ).EXE: $(OBJS)
echo >NUL @<<$(PROJ).CRF
$(LFLAGS) $(OBJS) -OUT:$(PROJ).EXE $(LIBS)
<<
link @$(PROJ).CRF
.cpp.obj::
CL $(CFLAGS) /c $<
Figure 6 DelayLoadDemo Output
dliStartProcessing USER32.dll(00000000) -> GetTopWindow
dliNotePreLoadLibrary USER32.dll(00000000) -> GetTopWindow
dliNotePreGetProcAddress USER32.dll(77E70000) -> GetTopWindow
dliNoteEndProcessing USER32.dll(77E70000) -> GetTopWindow
dliStartProcessing USER32.dll(00000000) -> GetDesktopWindow
dliNotePreGetProcAddress USER32.dll(77E70000) -> GetDesktopWindow
dliNoteEndProcessing USER32.dll(77E70000) -> GetDesktopWindow
dliStartProcessing COMCTL32.dll(00000000) -> ordinal:17
dliNotePreLoadLibrary COMCTL32.dll(00000000) -> ordinal:17
dliNotePreGetProcAddress COMCTL32.dll(71030000) -> ordinal:17
dliNoteEndProcessing COMCTL32.dll(71030000) -> ordinal:17