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.
Figure 1   Pseudocode for __delayLoadHelper
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