/*************************************************************
Module name: app.cpp
Notices: Written 1998 by Jeffrey Richter
Description: Demonstration of delay-load DLL error handling.
*************************************************************/
#include <Windows.h>
#include <Delayimp.h> // For error handling & advanced features
#include "lib\lib.h" // My DLL's function prototypes
// Statically link __delayLoadHelper/__FUnloadDelayLoadedDLL
#pragma comment(lib, "Delayimp.lib")
// Tell the linker that my DLL should be delay loaded
#pragma comment(linker, "/DelayLoad:lib.dll")
// Tell the linker that I want to be able to unload by DLL
#pragma comment(linker, "/Delay:unload")
// Tell the linker to make the delay-load DLL unbindable
// You usually want this, so I commented out this line
//#pragma comment(linker, "/Delay:nobind")
// Forward function prototype
LONG WINAPI DelayLoadDllExceptionFilter(PEXCEPTION_POINTERS pep);
int WINAPI WinMain(HINSTANCE hinstExe, HINSTANCE,
LPSTR pszCmdLine, int nCmdShow) {
// Wrap all calls to delay-load DLL functions inside SEH
__try {
int x = 0;
// If you're in the debugger, try the new Debug.Modules menu item to see
// that the DLL is not loaded prior to executing the line below
x = fnLib(); // Attempt to call delay-load function
// Use Debug.Modules to see that the DLL is now loaded
x = fnLib2(); // Attempt to call delay-load function
// Unload the delay-loaded DLL
// NOTE: Name must exactly match /DelayLoad:(DllName)
__FUnloadDelayLoadedDLL("lib.dll");
// Use Debug.Modules to see that the DLL is now unloaded
x = fnLib(); // Attempt to call delay-load function
// Use Debug.Modules to see that the DLL is loaded again
}
__except (DelayLoadDllExceptionFilter(GetExceptionInformation())) {
// Nothing to do in here, thread continues to run normally
}
// More code goes here...
return(0);
}
LONG WINAPI DelayLoadDllExceptionFilter(PEXCEPTION_POINTERS pep) {
// Assume we recognize this exception
LONG lDisposition = EXCEPTION_EXECUTE_HANDLER;
// If this is a Delay-load problem, ExceptionInformation[0] points
// to a DelayLoadInfo structure that has detailed error info
PDelayLoadInfo pdli = PDelayLoadInfo(pep->ExceptionRecord
->ExceptionInformation[0]);
// Create a buffer where we construct error messages
char sz[500] = { 0 };
switch (pep->ExceptionRecord->ExceptionCode) {
case VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND):
// The DLL module was not found at runtime
wsprintf(sz, "Dll not found: %s", pdli->szDll);
break;
case VcppException(ERROR_SEVERITY_ERROR, ERROR_PROC_NOT_FOUND):
// The DLL module was found but it doesn't contain the function
if (pdli->dlp.fImportByName) {
wsprintf(sz, "Function %s was not found in %s",
pdli->dlp.szProcName, pdli->szDll);
} else {
wsprintf(sz, "Function ordinal %d was not found in %s",
pdli->dlp.dwOrdinal, pdli->szDll);
}
break;
default:
lDisposition = EXCEPTION_CONTINUE_SEARCH; // We don't recognize this // exception
break;
}
if (lDisposition == EXCEPTION_EXECUTE_HANDLER) {
// We recognized this error and constructed a message, show it
MessageBox(NULL, sz, NULL, MB_OK);
}
return(lDisposition);
}
// Skeleton DliHook function that does nothing interesting
FARPROC WINAPI DliHook(unsigned dliNotify, PDelayLoadInfo pdli) {
FARPROC fp = NULL; // Default return value
// NOTE: The members of the DelayLoadInfo structure pointed
// to by pdli shows the results of progress made so far.
switch (dliNotify) {
case dliStartProcessing:
// Called when __delayLoadHelper attempts to find a DLL/function
// Return 0 to have normal behavior, or non-0 to override
// everything (you will still get dliNoteEndProcessing)
break;
case dliNotePreLoadLibrary:
// Called just before LoadLibrary
// Return NULL to have __delayLoadHelper call LoadLibary
// or you can call LoadLibrary yourself and return the HMODULE
fp = (FARPROC)(HMODULE) NULL;
break;
case dliFailLoadLib:
// Called if LoadLibrary fails
// Again, you can call LoadLibary yourself here and return an HMODULE
// If you return NULL, __delayLoadHelper raises the
// ERROR_MOD_NOT_FOUND exception
fp = (FARPROC)(HMODULE) NULL;
break;
case dliNotePreGetProcAddress:
// Called just before GetProcAddress
// Return NULL to have __delayLoadHelper call GetProcAddress
// or you can call GetProcAddress yourself and return the address
fp = (FARPROC) NULL;
break;
case dliFailGetProc:
// Called if GetProcAddress fails
// Again, you can call GetProcAddress yourself here and return an address
// If you return NULL, __delayLoadHelper raises the
// ERROR_PROC_NOT_FOUND exception
fp = (FARPROC) NULL;
break;
case dliNoteEndProcessing:
// A simple notification that __delayLoadHelper is done
// You can examine the members of the DelayLoadInfo structure
// pointed to by pdli and raise an exception if you desire
break;
}
return(fp);
}
// Tell __delayLoadHelper to call my hook function
PfnDliHook __pfnDliNotifyHook = DliHook;
PfnDliHook __pfnDliFailureHook = DliHook;