Copyright © Microsoft Corporation. This document is an archived reproduction of a version originally published by Microsoft. It may have slight formatting modifications for consistency and to improve readability. |
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