// You are expected to #include this file from your private dllload.c.

// WARNING!   Failure to observe these rules will result in really subtle
// (and horrible) runtime/build problems.
//
// WARNING!  If you choose to delay-load a DLL, you **must** disable
// import thunks for that DLL when you include its header file.  For example,
// you must #define _OLE32_ before you #include <ole32.h>.  Otherwise,
// what happens is that the linker ends up exporting your delayload thunk
// (because it thinks it's an exported function because the header file
// said so) and then everybody who links to your DLL will accidentally
// use the delayload thunk instead of the original function.  This is
// particularly gruesome because this problem hoses every DLL in the system
// **except for you**.
//
// WARNING!  But if you are delay-loading an optional function and
// you are statically linking to the target DLL for required functions
// (e.g., you are delayloading an NT5-only function), then you should not
// disable import thunks since you really do want import thunks for the
// regular functions.  The way do handle this is to delayload the function
// with an alternate name (e.g., prepend an underscore) and use the MAP
// version of the delay-load macros.  Then in your global header file,
// #define the function to its mapped name.
//
// End of warnings.

// Delay loading mechanism.  This allows you to write code as if you are
// calling implicitly linked APIs, and yet have these APIs really be
// explicitly linked.  You can reduce the initial number of DLLs that 
// are loaded (load on demand) using this technique.
//
// Use the following macros to indicate which APIs/DLLs are delay-linked
// and -loaded.
//
//      DELAY_LOAD
//      DELAY_LOAD_HRESULT
//      DELAY_LOAD_SAFEARRAY
//      DELAY_LOAD_UINT
//      DELAY_LOAD_INT
//      DELAY_LOAD_VOID
//
// Use these macros for APIs that are exported by ordinal only.
//
//      DELAY_LOAD_ORD
//      DELAY_LOAD_VOID_ORD
//
// Use these macros for APIs that only exist on the integrated-shell
// installations (i.e., a new shell32 is on the system).
//
//      DELAY_LOAD_SHELL
//      DELAY_LOAD_SHELL_HRESULT
//      DELAY_LOAD_SHELL_VOID
//
//
// Use DELAY_LOAD_IE_* for APIs that come from BrowseUI.  This used
// to be important when BrowseUI was in the IEXPLORE directory, but
// now it's in the System directory so the difference is pretty
// meaningless.
//
// Use DELAY_LOAD_OCX_* for APIs that come from OCXs and not DLLs.
//

/**********************************************************************/

#ifdef DEBUG

void _DumpLoading(LPTSTR pszDLL, LPTSTR pszFunc)
{
#ifdef DF_DELAYLOADDLL
    if (g_dwDumpFlags & DF_DELAYLOADDLL)
    {
        TraceMsg(TF_ALWAYS, "DLLLOAD: Loading %s for the first time for %s",
                 pszDLL, pszFunc);
    }
#endif
}

#define ENSURE_LOADED(_hmod, _dll, _ext, pszfn)         \
    (_hmod ? (_hmod) : (_DumpLoading(TEXT(#_dll) TEXT(".") TEXT(#_ext), pszfn), \
                        _hmod = LoadLibraryA(#_dll "." #_ext)))

#else

#define ENSURE_LOADED(_hmod, _dll, _ext, pszfn)         \
    (_hmod ? (_hmod) : (_hmod = LoadLibraryA(#_dll "." #_ext)))

#endif  // DEBUG


/**********************************************************************/

void _GetProcFromDLL(HMODULE* phmod, LPCSTR pszDLL, FARPROC* ppfn, LPCSTR pszProc)
{
#ifdef DEBUG
    CHAR szProcD[MAX_PATH];
    if (!IS_INTRESOURCE(pszProc)) {
        lstrcpynA(szProcD, pszProc, ARRAYSIZE(szProcD));
    } else {
        wsprintfA(szProcD, "(ordinal %d)", LOWORD((DWORD_PTR)pszProc));
    }
#endif
    // If it's already loaded, return.
    if (*ppfn) {
        return;
    }

    if (*phmod == NULL) {
#ifdef DEBUG
#ifdef DF_DELAYLOADDLL
        if (g_dwDumpFlags & DF_DELAYLOADDLL)
        {
            TraceMsg(TF_ALWAYS, "DLLLOAD: Loading %s for the first time for %s",
                 pszDLL, szProcD);
        }
#endif
        if (g_dwBreakFlags & 0x00000080)
        {
            DebugBreak();
        }
#endif
        *phmod = LoadLibraryA(pszDLL);
#ifdef UNIX
        if (*phmod == NULL) {
           if (lstrcmpiA(pszDLL, "inetcpl.dll") == 0) {
               *phmod = LoadLibraryA("inetcpl.cpl");
           }
        }
#endif
        if (*phmod == NULL) {
            return;
        }
    }

#if defined(DEBUG) && defined(DF_DELAYLOADDLL)
    if (g_dwDumpFlags & DF_DELAYLOADDLL) {
        TraceMsg(TF_ALWAYS, "DLLLOAD: GetProc'ing %s from %s for the first time",
             pszDLL, szProcD);
    }
#endif
    *ppfn = GetProcAddress(*phmod, pszProc);
}

#if defined(DEBUG) && defined(BROWSEUI_IN_IEXPLORE_DIRECTORY)
void _GetProcFromSystemDLL(HMODULE* phmod, LPCSTR pszDLL, FARPROC* ppfn, LPCSTR pszProc)
{

#ifdef UNIX
    if (lstrcmpiA(pszDLL, "inetcpl.dll") == 0) {
        _GetProcFromDLL(phmod, "inetcpl.cpl", ppfn, pszProc);
        return;
    }
#endif

    // You must use DELAY_LOAD_IE for BROWSEUI since BROWSEUI lives in the
    // IE directory, not the System directory.
    if (lstrcmpiA(pszDLL, "BROWSEUI.DLL") == 0) {
        ASSERT(!"Somebody used DELAY_LOAD instead of DELAY_LOAD_IE on BROWSEUI");
    }
    _GetProcFromDLL(phmod, pszDLL, ppfn, pszProc);
}
#else
#define _GetProcFromSystemDLL           _GetProcFromDLL
#endif

// NOTE: this takes two parameters that are the function name. the First (_fn) is the name that
// NOTE: the function will be called in this DLL and the other (_fni) is the
// NOTE: name of the function we will GetProcAddress. This helps get around functions that
// NOTE: are defined in the header files with _declspec...

//
//  HMODULE _hmod - where we cache the HMODULE (aka HINSTANCE)
//           _dll - Basename of the target DLL, not quoted
//           _ext - Extension of the target DLL, not quoted (usually DLL)
//           _ret - Data type of return value
//        _fnpriv - Local name for the function
//            _fn - Exported name for the function
//          _args - Argument list in the form (TYPE1 arg1, TYPE2 arg2, ...)
//         _nargs - Argument list in the form (arg1, arg2, ...)
//           _err - Return value if we can't call the actual function
//
#define DELAY_LOAD_NAME_EXT_ERR(_hmod, _dll, _ext, _ret, _fnpriv, _fn, _args, _nargs, _err) \
_ret __stdcall _fnpriv _args                \
{                                       \
    static _ret (__stdcall *_pfn##_fn) _args = NULL;   \
    _GetProcFromSystemDLL(&_hmod, #_dll "." #_ext, (FARPROC*)&_pfn##_fn, #_fn); \
    if (_pfn##_fn)               \
        return _pfn##_fn _nargs; \
    return (_ret)_err;           \
}

#define     DELAY_LOAD_NAME_ERR(_hmod, _dll,       _ret, _fnpriv, _fn, _args, _nargs, _err) \
        DELAY_LOAD_NAME_EXT_ERR(_hmod, _dll,  DLL, _ret, _fnpriv, _fn, _args, _nargs, _err)

#define DELAY_LOAD_ERR(_hmod, _dll, _ret, _fn,      _args, _nargs, _err) \
   DELAY_LOAD_NAME_ERR(_hmod, _dll, _ret, _fn, _fn, _args, _nargs, _err)

#define DELAY_LOAD(_hmod, _dll, _ret, _fn, _args, _nargs) DELAY_LOAD_ERR(_hmod, _dll, _ret, _fn, _args, _nargs, 0)
#define DELAY_LOAD_HRESULT(_hmod, _dll, _fn, _args, _nargs) DELAY_LOAD_ERR(_hmod, _dll, HRESULT, _fn, _args, _nargs, E_FAIL)
#define DELAY_LOAD_SAFEARRAY(_hmod, _dll, _fn, _args, _nargs) DELAY_LOAD_ERR(_hmod, _dll, SAFEARRAY *, _fn, _args, _nargs, NULL)
#define DELAY_LOAD_UINT(_hmod, _dll, _fn, _args, _nargs) DELAY_LOAD_ERR(_hmod, _dll, UINT, _fn, _args, _nargs, 0)
#define DELAY_LOAD_INT(_hmod, _dll, _fn, _args, _nargs) DELAY_LOAD_ERR(_hmod, _dll, INT, _fn, _args, _nargs, 0)
#define DELAY_LOAD_BOOL(_hmod, _dll, _fn, _args, _nargs) DELAY_LOAD_ERR(_hmod, _dll, BOOL, _fn, _args, _nargs, FALSE)
#define DELAY_LOAD_BOOLEAN(_hmod, _dll, _fn, _args, _nargs) DELAY_LOAD_ERR(_hmod, _dll, BOOLEAN, _fn, _args, _nargs, FALSE)
#define DELAY_LOAD_DWORD(_hmod, _dll, _fn, _args, _nargs) DELAY_LOAD_ERR(_hmod, _dll, DWORD, _fn, _args, _nargs, FALSE)
#define DELAY_LOAD_LRESULT(_hmod, _dll, _fn, _args, _nargs) DELAY_LOAD_ERR(_hmod, _dll, LRESULT, _fn, _args, _nargs, FALSE)
#define DELAY_LOAD_WNET(_hmod, _dll, _fn, _args, _nargs) DELAY_LOAD_ERR(_hmod, _dll, DWORD, _fn, _args, _nargs, WN_NOT_SUPPORTED)
#define DELAY_LOAD_LPVOID(_hmod, _dll, _fn, _args, _nargs) DELAY_LOAD_ERR(_hmod, _dll, LPVOID, _fn, _args, _nargs, 0)

// the NAME variants allow the local function to be called something different from the imported
// function to avoid dll linkage problems.
#define DELAY_LOAD_NAME(_hmod, _dll, _ret, _fn, _fni, _args, _nargs) DELAY_LOAD_NAME_ERR(_hmod, _dll, _ret, _fn, _fni, _args, _nargs, 0)
#define DELAY_LOAD_NAME_HRESULT(_hmod, _dll, _fn, _fni, _args, _nargs) DELAY_LOAD_NAME_ERR(_hmod, _dll, HRESULT, _fn, _fni, _args, _nargs, E_FAIL)
#define DELAY_LOAD_NAME_SAFEARRAY(_hmod, _dll, _fn, _fni, _args, _nargs) DELAY_LOAD_NAME_ERR(_hmod, _dll, SAFEARRAY *, _fn, _fni, _args, _nargs, NULL)
#define DELAY_LOAD_NAME_UINT(_hmod, _dll, _fn, _fni, _args, _nargs) DELAY_LOAD_NAME_ERR(_hmod, _dll, UINT, _fn, _fni, _args, _nargs, 0)
#define DELAY_LOAD_NAME_BOOL(_hmod, _dll, _fn, _fni, _args, _nargs) DELAY_LOAD_NAME_ERR(_hmod, _dll, BOOL, _fn, _fni, _args, _nargs, FALSE)
#define DELAY_LOAD_NAME_DWORD(_hmod, _dll, _fn, _fni, _args, _nargs) DELAY_LOAD_NAME_ERR(_hmod, _dll, DWORD, _fn, _fni, _args, _nargs, 0)

#define DELAY_LOAD_NAME_VOID(_hmod, _dll, _fn, _fni, _args, _nargs)                               \
void __stdcall _fn _args                                                                \
{                                                                                       \
    static void (__stdcall *_pfn##_fni) _args = NULL;                                   \
    if (!ENSURE_LOADED(_hmod, _dll, DLL, TEXT(#_fni)))                                       \
    {                                                                                   \
        AssertMsg(BOOLFROMPTR(_hmod), TEXT("LoadLibrary failed on ") ## TEXT(#_dll));         \
        return;                                                                         \
    }                                                                                   \
    if (_pfn##_fni == NULL)                                                              \
    {                                                                                   \
        *(FARPROC*)&(_pfn##_fni) = GetProcAddress(_hmod, #_fni);                         \
        AssertMsg(BOOLFROMPTR(_pfn##_fni), TEXT("GetProcAddress failed on ") ## TEXT(#_fni));    \
        if (_pfn##_fni == NULL)                                                          \
            return;                                                                     \
    }                                                                                   \
    _pfn##_fni _nargs;                                                                   \
}

#define DELAY_LOAD_VOID(_hmod, _dll, _fn, _args, _nargs)   DELAY_LOAD_NAME_VOID(_hmod, _dll, _fn, _fn, _args, _nargs)



// For private entrypoints exported by ordinal.
#define DELAY_LOAD_ORD_ERR(_hmod, _dll, _ret, _fn, _ord, _args, _nargs, _err) \
_ret __stdcall _fn _args                \
{                                       \
    static _ret (__stdcall *_pfn##_fn) _args = NULL;   \
    _GetProcFromSystemDLL(&_hmod, #_dll, (FARPROC*)&_pfn##_fn, (LPCSTR)_ord);   \
    if (_pfn##_fn)               \
        return _pfn##_fn _nargs; \
    return (_ret)_err;           \
}

#define DELAY_LOAD_ORD(_hmod, _dll, _ret, _fn, _ord, _args, _nargs) DELAY_LOAD_ORD_ERR(_hmod, _dll, _ret, _fn, _ord, _args, _nargs, 0)
#define DELAY_LOAD_EXT_ORD(_hmod, _dll, _ext, _ret, _fn, _ord, _args, _nargs) DELAY_LOAD_ORD_ERR(_hmod, #_dll "." #_ext, _ret, _fn, _ord, _args, _nargs, 0)


#define DELAY_LOAD_ORD_VOID(_hmod, _dll, _fn, _ord, _args, _nargs)                     \
void __stdcall _fn _args                \
{                                       \
    static void (__stdcall *_pfn##_fn) _args = NULL;   \
    _GetProcFromSystemDLL(&_hmod, #_dll, (FARPROC*)&_pfn##_fn, (LPCSTR)_ord);   \
    if (_pfn##_fn)              \
        _pfn##_fn _nargs;       \
    return;                     \
}
#define DELAY_LOAD_VOID_ORD DELAY_LOAD_ORD_VOID // cuz people mess this up all the time

#define DELAY_LOAD_ORD_BOOL(_hmod, _dll, _fn, _ord, _args, _nargs) \
    DELAY_LOAD_ORD_ERR(_hmod, _dll, BOOL, _fn, _ord, _args, _nargs, 0)

#define DELAY_LOAD_EXT(_hmod, _dll, _ext, _ret, _fn, _args, _nargs) \
        DELAY_LOAD_NAME_EXT_ERR(_hmod, _dll, _ext, _ret, _fn, _fn, _args, _nargs, 0)

#define DELAY_LOAD_EXT_WRAP(_hmod, _dll, _ext, _ret, _fnWrap, _fnOrig, _args, _nargs) \
        DELAY_LOAD_NAME_EXT_ERR(_hmod, _dll, _ext, _ret, _fnWrap, _fnOrig, _args, _nargs, 0)

#if defined(BROWSEUI_IN_IEXPLORE_DIRECTORY) || defined(UNIX)
/*----------------------------------------------------------
Purpose: Loads the DLL via a CLSID it is known to be registered for
*/
void _GetProcFromCLSID(HMODULE* phmod, const CLSID *pclsid, FARPROC* ppfn, LPCSTR pszProc)
{
    if (*phmod == NULL) {
        //
        //  SHPinDLLOfCLSID does all the annoying work of opening the
        //  appropriate registry key, doing REG_EXPAND_SZ, etc.
        //  It also loads the DLL with exactly the same name that OLE does,
        //  which is important because NT4 SP3 didn't like it when you loaded
        //  a DLL sometimes via SFN and sometimes via LFN.  (It would
        //  think they were different DLLs, and two copies of it got loaded
        //  into memory.  Aigh!)
        //
        *phmod = (HMODULE)SHPinDllOfCLSID(pclsid);
        if (!*phmod) 
            return;
    }

    // We don't know the name of the DLL, but fortunately _GetProcFromDLL
    // doesn't need it if *phmod is already filled in.
    ASSERT(*phmod);
    _GetProcFromDLL(phmod, "", ppfn, pszProc);
}

//
//  Private exports by ordinal for browseui.  loads from the browseui in apppath dir
//

#ifndef UNIX

#define DELAY_LOAD_IE_ORD_ERR(_hmod, _dll, _ret, _fn, _ord, _args, _nargs, _err) \
_ret __stdcall _fn _args                \
{                                       \
    static _ret (__stdcall *_pfn##_fn) _args = NULL;   \
    _GetProcFromCLSID(&_hmod, &CLSID_##_dll, (FARPROC*)&_pfn##_fn, (LPCSTR)_ord);   \
    if (_pfn##_fn)               \
        return _pfn##_fn _nargs; \
    return (_ret)_err;           \
}

#else

#define DELAY_LOAD_IE_ORD_ERR(_hmod, _dll, _ret, _fn, _ord, _args, _nargs, _err) \
_ret __stdcall _fn _args                \
{                                       \
    static _ret (__stdcall *_pfn##_fn) _args = NULL;   \
    _GetProcFromCLSID(&_hmod, &CLSID_##_dll, (FARPROC*)&_pfn##_fn, (LPCSTR)#_fn);   \
    if (_pfn##_fn)               \
        return _pfn##_fn _nargs; \
    return (_ret)_err;           \
}

#endif
    
#ifndef UNIX

#define DELAY_LOAD_IE_ORD_VOID(_hmod, _dll, _fn, _ord, _args, _nargs) \
void __stdcall _fn _args                \
{                                       \
    static void (__stdcall *_pfn##_fn) _args = NULL;   \
    _GetProcFromCLSID(&_hmod, &CLSID_##_dll, (FARPROC*)&_pfn##_fn, (LPCSTR)_ord); \
    if (_pfn##_fn)              \
        _pfn##_fn _nargs;       \
    return;                     \
}

#else

#define DELAY_LOAD_IE_ORD_VOID(_hmod, _dll, _fn, _ord, _args, _nargs) \
void __stdcall _fn _args                \
{                                       \
    static void (__stdcall *_pfn##_fn) _args = NULL;   \
    _GetProcFromCLSID(&_hmod, &CLSID_##_dll, (FARPROC*)&_pfn##_fn, (LPCSTR)#_fn); \
    if (_pfn##_fn)              \
        _pfn##_fn _nargs;       \
    return;                     \
}

#endif

#else // BrowseUI is in the System directory

#define DELAY_LOAD_IE_ORD_ERR       DELAY_LOAD_ORD_ERR
#define DELAY_LOAD_IE_ORD_VOID      DELAY_LOAD_ORD_VOID

#endif

#define DELAY_LOAD_IE(_hmod, _dll, _ret, _fn, _ord, _args, _nargs) DELAY_LOAD_IE_ORD_ERR(_hmod, _dll, _ret, _fn, _ord, _args, _nargs, 0)
#define DELAY_LOAD_IE_HRESULT(_hmod, _dll, _fn, _ord, _args, _nargs) DELAY_LOAD_IE_ORD_ERR(_hmod, _dll, HRESULT, _fn, _ord, _args, _nargs, E_FAIL)
#define DELAY_LOAD_IE_BOOL(_hmod, _dll, _fn, _ord, _args, _nargs) DELAY_LOAD_IE_ORD_ERR(_hmod, _dll, BOOL, _fn, _ord, _args, _nargs, FALSE)

#define DELAY_LOAD_IE_ORD(_hmod, _dll, _ret, _fn, _ord, _args, _nargs) DELAY_LOAD_IE_ORD_ERR(_hmod, _dll, _ret, _fn, _ord, _args, _nargs, 0)

#ifndef NO_LOADING_OF_SHDOCVW_ONLY_FOR_WHICHPLATFORM

/*----------------------------------------------------------
Purpose: Performs a loadlibrary on the DLL only if the machine
     has the integrated shell installation.

*/
void _SHGetProcFromDLL(HINSTANCE* phinst, LPCSTR pszDLL, FARPROC* ppfn, LPCSTR pszProc)
{
    if (PLATFORM_INTEGRATED == WhichPlatform())
        _GetProcFromSystemDLL(phinst, pszDLL, ppfn, pszProc);
    else
        TraceMsg(TF_ERROR, "Could not load integrated shell version of %s for %d", pszDLL, pszProc);
}

#endif // NO_LOADING_OF_SHDOCVW_ONLY_FOR_WHICHPLATFORM

//
//  Private exports by ordinal for integrated-shell installs
//


#define DELAY_LOAD_SHELL_ERR(_hinst, _dll, _ret, _fn, _ord, _args, _nargs, _err) \
_ret __stdcall _fn _args                \
{                                       \
    static _ret (__stdcall *_pfn##_fn) _args = NULL;   \
    _SHGetProcFromDLL(&_hinst, #_dll ".DLL", (FARPROC*)&_pfn##_fn, (LPCSTR)_ord);   \
    if (_pfn##_fn)               \
        return _pfn##_fn _nargs; \
    return (_ret)_err;           \
}

#define DELAY_LOAD_SHELL(_hinst, _dll, _ret, _fn, _ord, _args, _nargs) DELAY_LOAD_SHELL_ERR(_hinst, _dll, _ret, _fn, _ord, _args, _nargs, 0)
#define DELAY_LOAD_SHELL_HRESULT(_hinst, _dll, _fn, _ord, _args, _nargs ) DELAY_LOAD_SHELL_ERR(_hinst, _dll, HRESULT, _fn, _ord, _args, _nargs, E_FAIL )


#define DELAY_LOAD_SHELL_VOID(_hinst, _dll, _fn, _ord, _args, _nargs) \
void __stdcall _fn _args                \
{                                       \
    static void (__stdcall *_pfn##_fn) _args = NULL;   \
    _SHGetProcFromDLL(&_hinst, #_dll ".DLL", (FARPROC*)&_pfn##_fn, (LPCSTR)_ord); \
    if (_pfn##_fn)              \
        _pfn##_fn _nargs;       \
    return;                     \
}

// Following Macros are functionally  same as above only that they are
// using function name on UNIX rather than ordinals. The above macros 
// are left untouched because other dlls like shdocvw/shdoc401 still use
// them.

#ifndef UNIX

#define DELAY_LOAD_SHELL_ERR_FN(_hinst, _dll, _ret, _fn, _ord, _args, _nargs, _err, _realfn) \
_ret __stdcall _fn _args                \
{                                       \
    static _ret (__stdcall *_pfn##_fn) _args = NULL;   \
    _SHGetProcFromDLL(&_hinst, #_dll ".DLL", (FARPROC*)&_pfn##_fn, (LPCSTR)_ord);   \
    if (_pfn##_fn)               \
        return _pfn##_fn _nargs; \
    return (_ret)_err;           \
}

#else

#define DELAY_LOAD_SHELL_ERR_FN(_hinst, _dll, _ret, _fn, _ord, _args, _nargs, _err, _realfn) \
_ret __stdcall _fn _args                \
{                                       \
    static _ret (__stdcall *_pfn##_fn) _args = NULL;   \
    _SHGetProcFromDLL(&_hinst, #_dll ".DLL", (FARPROC*)&_pfn##_fn, (LPCSTR)#_realfn);   \
    if (_pfn##_fn)               \
        return _pfn##_fn _nargs; \
    return (_ret)_err;           \
}

#endif

#define DELAY_LOAD_SHELL_FN(_hinst, _dll, _ret, _fn, _ord, _args, _nargs, _realfn) DELAY_LOAD_SHELL_ERR_FN(_hinst, _dll, _ret, _fn, _ord, _args, _nargs, 0, _realfn)
#define DELAY_LOAD_SHELL_HRESULT_FN(_hinst, _dll, _fn, _ord, _args, _nargs, realfn) DELAY_LOAD_SHELL_ERR_FN(_hinst, _dll, HRESULT, _fn, _ord, _args, _nargs, E_FAIL, _realfn)


#ifndef UNIX

#define DELAY_LOAD_SHELL_VOID_FN(_hinst, _dll, _fn, _ord, _args, _nargs, _realfn) \
void __stdcall _fn _args                \
{                                       \
    static void (__stdcall *_pfn##_fn) _args = NULL;   \
    _SHGetProcFromDLL(&_hinst, #_dll ".DLL", (FARPROC*)&_pfn##_fn, (LPCSTR)_ord); \
    if (_pfn##_fn)              \
        _pfn##_fn _nargs;       \
    return;                     \
}

#else

#define DELAY_LOAD_SHELL_VOID_FN(_hinst, _dll, _fn, _ord, _args, _nargs, _realfn) \
void __stdcall _fn _args                \
{                                       \
    static void (__stdcall *_pfn##_fn) _args = NULL;   \
    _SHGetProcFromDLL(&_hinst, #_dll ".DLL", (FARPROC*)&_pfn##_fn, (LPCSTR)#_realfn); \
    if (_pfn##_fn)              \
        _pfn##_fn _nargs;       \
    return;                     \
}

#endif
