# Delay Load DLLs API

This API allows a user to try to pre-load all delay load DLLs and get back information on any delay load DLLs that failed to load properly. You can also unload the delay load DLLs.

The API will first be described in a generic, language-agnostic manner. The C bindings will be given later.

The basic API operations (aka functions) are: LOAD, UNLOAD, GET_DLL_ERRORS, GET_FUNC_ERRORS, IS_DLL_LOADED, IS_DLL_FULLY_LOADED.

Each of the operations returns a status code along with any other return values. The status code is a Win32 error value. It is used to signal an error in calling the function (ERROR_INVALID_PARAMETER) or an out of memory condition (ERROR_NOT_ENOUGH_MEMORY). Otherwise, the status code will be zero (ERROR_SUCCESS).

LOAD
  Loads all delay load DLLs for the calling module. Also checks whether each of the function pointers from each delay load DLL could be loaded. Returns a handle representing the state of the load operation. The process error mode is set to not display system critical error message boxes while each DLL is loaded. It is up to the caller to make sure that this does not cause any problems for the calling application. Unless there is not enough memory, this function will always succeed, but the load state may contain errors in loading individual DLLs. If there is not enough memory, the status code will be ERROR_NOT_ENOUGH_MEMORY.
Status Codes
  `ERROR_SUCCESS, ERROR_NOT_ENOUGH_MEMORY`
Example
  `handle = LOAD()`

UNLOAD
  Given a handle, unload all loaded delay load DLLs.
Status Codes
  `ERROR_SUCCESS, ERROR_INVALID_PARAMETER`
Example
  `UNLOAD(handle)`

GET_DLL_ERRORS
  Given a handle, get a list of DLLs that failed to load along with the error codes resulting from the attempt to load each of these DLLs.
Status Codes
  `ERROR_SUCCESS, ERROR_INVALID_PARAMETER`
Example
  `dll_errors = GET_DLL_ERRORS(handle)`

GET_FUNC_ERRORS
  Given a handle, get a list of functions that failed to load along with the error codes resulting from the attempt to load each of these DLLs.
Status Codes
  `ERROR_SUCCESS, ERROR_INVALID_PARAMETER`
Example
  `func_errors = GET_FUNC_ERRORS(handle)`

IS_DLL_LOADED
  Given a handle and DLL name, checkes whether the given DLL name is loaded. Note that a DLL might have been loaded without being able to resolve all of its function pointers specified in the dealy load DLL import table. In this case, this function will still return TRUE. If a DLL name that was not a delay load DLL for the current module is specified, FALSE will be returned.
Status Codes
  `ERROR_SUCCESS, ERROR_INVALID_PARAMETER`
Example
  `boolean = IS_DLL_LOADED(handle, dll_name)`

IS_DLL_FULLY_LOADED
  Given a handle and DLL name, checkes whether the given DLL name is loaded and that all of the desired function pointers for the DLL were loaded. If a DLL name that was not a delay load DLL for the current module is specified, FALSE will be returned.
Status Codes
  `ERROR_SUCCESS, ERROR_INVALID_PARAMETER`
Example
  `boolean = IS_DLL_FULLY_LOADED(handle, dll_name)`

## C Function Names

API Function |  | C Function
LOAD |  | DelayLoadDllsLoad
UNLOAD |  | DelayLoadDllsFree
GET_DLL_ERRORS |  | DelayLoadDllsGetDllErrors
GET_FUNC_ERRORS |  | DelayLoadDllsGetFuncErrors
IS_DLL_LOADED |  | DelayLoadDllsLoadedDll
IS_DLL_FULLY_LOADED |  | DelayLoadDllsLoadedDllAll

## To Do

If a DLL fails to load, it would be nice to figure out whether it, in turn, failed to load a DLL. If so, report the failed DLL.

A potential way to do this might be to traverse a DLL's import table...TBD...

## Lessons Learned

Write API documentation first. Take care to have better function names. (Reading Code Complete and writing the API documentation in a language-agnostic way (as opposed to C-centric) helps a lot.)