//+---------------------------------------------------------------------------
//
//  Microsoft Windows
//  Copyright (C) Microsoft Corporation, 1997.
//
//  File:       D L O A D . C
//
//  Contents:   Delay Load Failure Hook
//
//  Notes:      This lib implements all of the stub functions for modules
//              that are delayloaded by the OS. It merges together all of the
//              dloadXXX.lib files from each depot.
//
//  To Use:     In your sources file, right after you specify the modules you
//              are delayloading do:
//
//                  DLOAD_ERROR_HANDLER=kernel32
//
//              If you want to use kernel32 as your dload error handler. If you
//              do this, your dll will be checked that everything it delayloads
//              has a proper error handler function by the delayload.cmd postbuild
//              script.
//
//              To check that all functions you delayload have error handlers you
//              can do the following:
//
//                  1. do a "link -dump -imports foo.dll", and find all functions 
//                     that you delay-import.
//
//                  2. do a "link -dump -symbols \nt\public\internal\base\lib\*\dload.lib"
//                     and make sure every function that shows up as delayloaded in step #1
//                     has a error handler fn. in dload.lib.
//
//                  3. if a function is missing in step #2 (dlcheck will also fails as 
//                     part of postbuild), you need to add an error handler. Go to the depot
//                     where that dll is build, and go to the dload subdir (usually under
//                     the root or under the published\dload subdir) and add an error handler.
//
//
//  Author:     shaunco   19 May 1998
//  Modified:   reinerf   12 Jan 2001   Changed above comment
//
//----------------------------------------------------------------------------

#include "pch.h"
#pragma hdrstop


// External global variables
//
extern HANDLE   BaseDllHandle;

#if DBG
extern int DloadBreakOnFail;
extern int DloadDbgPrint;
#endif

#if DBG

#define DBG_ERROR   0
#define DBG_INFO    1

//+---------------------------------------------------------------------------
// Trace a message to the debug console.  Prefix with who we are so
// people know who to contact.
//
INT
__cdecl
DbgTrace (
    INT     nLevel,
    PCSTR   Format,
    ...
    )
{
    INT cch = 0;
    if (DloadDbgPrint) {
    
        if (nLevel <= DBG_INFO)
        {
            CHAR    szBuf [1024];
            va_list argptr;
    
            va_start (argptr, Format);
            cch = vsprintf (szBuf, Format, argptr);
            va_end (argptr);
    
            OutputDebugStringA ("dload: ");
            OutputDebugStringA (szBuf);
        }
    }

    return cch;
}

//+---------------------------------------------------------------------------
// Cannot use RtlAssert since doing so will cause setupapi.dll to fail
// for upgrade over win95(gold)
//
VOID
WINAPI
DelayLoadAssertFailed(
    IN PCSTR FailedAssertion,
    IN PVOID FileName,
    IN ULONG LineNumber,
    IN PCSTR Message OPTIONAL
    )
{
    DbgTrace (
        DBG_ERROR,
        "Assertion failure at line %u in file %s: %s%s%s\r\n",
        LineNumber,
        FileName,
        FailedAssertion,
        (Message && Message[0] && FailedAssertion[0]) ? " " : "",
        Message ? Message : ""
        );

    if (DloadBreakOnFail) {
        DebugBreak();
    }
}

#endif // DBG


//+---------------------------------------------------------------------------
//
//
FARPROC
WINAPI
DelayLoadFailureHook (
    LPCSTR pszDllName,
    LPCSTR pszProcName
    )
{
    FARPROC ReturnValue = NULL;

    MYASSERT (pszDllName);
    MYASSERT (pszProcName);  

    // Trace some potentially useful information about why we were called.
    //
#if DBG
    if (!IS_INTRESOURCE(pszProcName))
    {
        DbgTrace (DBG_INFO,
            "DelayloadFailureHook: Dll=%s, ProcName=%s\n",
            pszDllName,
            pszProcName);
    }
    else
    {
        DbgTrace (DBG_INFO,
            "DelayloadFailureHook: Dll=%s, Ordinal=%u\n",
            pszDllName,
            (DWORD)((DWORD_PTR)pszProcName));
    }
#endif

    ReturnValue = LookupHandler(pszDllName, pszProcName);

    if (ReturnValue)
    {
#if DBG
        DbgTrace (DBG_INFO,
            "Returning handler function at address 0x%08x\n",
            (LONG_PTR)ReturnValue);
#endif
    }
#if DBG
    else
    {
        CHAR pszMsg [MAX_PATH];

        if (!IS_INTRESOURCE(pszProcName))
        {
            sprintf (pszMsg,
                "No delayload handler found for Dll=%s, ProcName=%s\n"
                "Please add one in private\\dload.",
                pszDllName,
                pszProcName);
        }
        else
        {
            sprintf (pszMsg,
                "No delayload handler found for Dll=%s, Ordinal=%u\n"
                "Please add one in private\\dload.",
                pszDllName,
                (DWORD)((DWORD_PTR)pszProcName));
        }

        DelayLoadAssertFailed ( "" , __FILE__, __LINE__, pszMsg);
    }
#endif

    return ReturnValue;
}