#ifdef __cplusplus

// ADVPACK.DLL delay load

class CRunSetupHook
{
    public:

#ifdef WX86
#define DELAYRSCAPI(_fn, _args, _nargs) \
    DWORD _fn _args { \
        HRESULT hres = Init(); \
        DWORD dwRet = (DWORD)hres; \
        if (SUCCEEDED(hres)) { \
            dwRet = _pfn##_fn _nargs; \
        } \
        return dwRet;    } \
    DWORD (STDAPICALLTYPE* _pfn##_fn) _args; \
    DWORD _fn##X86 _args { \
        HRESULT hres = InitX86(); \
        DWORD dwRet = (DWORD)hres; \
        if (SUCCEEDED(hres)) { \
            dwRet = _pfn##_fn##X86 _nargs; \
        } \
        return dwRet;    } \
    DWORD (STDAPICALLTYPE* _pfn##_fn##X86) _args;
#else
#define DELAYRSCAPI(_fn, _args, _nargs) \
    DWORD _fn _args { \
        HRESULT hres = Init(); \
        DWORD dwRet = (DWORD)hres; \
        if (SUCCEEDED(hres)) { \
            dwRet = _pfn##_fn _nargs; \
        } \
        return dwRet;    } \
    DWORD (STDAPICALLTYPE* _pfn##_fn) _args;
#endif

    HRESULT     Init(void);
#ifdef WX86
    HRESULT     InitX86(void);

    typedef BOOL (*pfnUnloadFn)(HMODULE hMod);
    pfnUnloadFn pfnUnload;
#endif
    CRunSetupHook();
    ~CRunSetupHook();

    BOOL    m_fInited;
    HMODULE m_hMod;
#ifdef WX86
    BOOL    m_fInitedX86;
    HMODULE m_hModX86;
    HMODULE m_hModWx86;
#endif

    DELAYRSCAPI( RunSetupCommand,
    (HWND    hWnd,
    LPSTR   szCmdName,
    LPSTR   szInfSection,
    LPSTR   szDir,
    LPSTR   szTitle,
    HANDLE *phEXE,
    DWORD   dwFlags,
    LPVOID  pvReserved),
    (hWnd, szCmdName, szInfSection, szDir, szTitle, phEXE, dwFlags,pvReserved));

    DELAYRSCAPI( NeedReboot,
    (DWORD dwRebootCheck),
    (dwRebootCheck));

    DELAYRSCAPI( NeedRebootInit, (), ());

    DELAYRSCAPI( TranslateInfString,
    (PCSTR  pszInfFilename,
    PCSTR  pszInstallSection,
    PCSTR  pszTranslateSection,
    PCSTR  pszTranslateKey,
    PSTR   pszBuffer,
    DWORD  dwBufferSize,
    PDWORD pdwRequiredSize,
    PVOID  pvReserved),
    (pszInfFilename, pszInstallSection, pszTranslateSection, pszTranslateKey,
    pszBuffer, dwBufferSize, pdwRequiredSize, pvReserved));


    DELAYRSCAPI( AdvInstallFile,
    (HWND hwnd,
    LPCSTR lpszSourceDir,
    LPCSTR lpszSourceFile,
    LPCSTR lpszDestDir,
    LPCSTR lpszDestFile,
    DWORD dwFlags,
    DWORD dwReserved),
    (hwnd, lpszSourceDir, lpszSourceFile, lpszDestDir, lpszDestFile, dwFlags,
    dwReserved));

};

inline
CRunSetupHook::CRunSetupHook()
{
    m_fInited = FALSE;
    m_hMod = NULL;
#ifdef WX86
    m_hModX86 = m_hModWx86 = NULL;
#endif
}

inline
CRunSetupHook::~CRunSetupHook()
{
    if (m_fInited) {
        if (m_hMod) {
            FreeLibrary(m_hMod);
        }
#ifdef WX86
        if (m_hModX86) {
            if (pfnUnload) {
                (*pfnUnload)(m_hModX86);    // free x86 advpack.dll
            }
        }
        
        if (m_hModWx86) {
            FreeLibrary(m_hModWx86);    // free wx86.dll
        }
#endif
    }
}

inline
HRESULT 
CRunSetupHook::Init(void)
{
    if (m_fInited) {
        return S_OK;
    }

    m_hMod = LoadLibrary( "ADVPACK.DLL" );

    if (!m_hMod) {
        return HRESULT_FROM_WIN32(GetLastError());
    }

#define CHECKAPI(_fn) \
    *(FARPROC*)&(_pfn##_fn) = GetProcAddress(m_hMod, #_fn); \
    if (!(_pfn##_fn)) return E_UNEXPECTED;

    CHECKAPI(RunSetupCommand);
    CHECKAPI(NeedReboot);
    CHECKAPI(NeedRebootInit);

    CHECKAPI(TranslateInfString);
    CHECKAPI(AdvInstallFile);

    m_fInited = TRUE;
    return S_OK;
}

#ifdef WX86
inline
HRESULT 
CRunSetupHook::InitX86(void)
{
    typedef HMODULE (*pfnLoadFn)(LPCWSTR name, DWORD dwFlags);
    typedef PVOID (*pfnThunkFn)(PVOID pvAddress, PVOID pvCbDispatch, BOOLEAN fNativeToX86);
    pfnLoadFn pfnLoad;
    pfnThunkFn pfnThunk;

    if (m_fInitedX86) {
        return S_OK;
    }

    // No need to check the reg key to see if Wx86 is installed and enabled.
    // By the time this routine runs, that has already been done.
    m_hModWx86 = LoadLibrary("wx86.dll");
    if (!m_hModWx86) {
        return HRESULT_FROM_WIN32(GetLastError());
    }
    pfnLoad = (pfnLoadFn)GetProcAddress(m_hModWx86, "Wx86LoadX86Dll");
    pfnUnload = (pfnUnloadFn)GetProcAddress(m_hModWx86, "Wx86FreeX86Dll");
    pfnThunk = (pfnThunkFn)GetProcAddress(m_hModWx86, "Wx86ThunkProc");
    if (!pfnLoad || !pfnThunk || !pfnUnload) {
        HRESULT hr = HRESULT_FROM_WIN32(GetLastError());
        FreeLibrary(m_hModWx86);
        return hr;
    }

    // Load x86 advpack.dll
    m_hModX86 = (*pfnLoad)( L"ADVPACK.DLL", 0 );

    if (!m_hModX86) {
        return HRESULT_FROM_WIN32(GetLastError());
    }

#undef CHECKAPI
#define CHECKAPI(_fn, n) \
    *(FARPROC*)&(_pfn##_fn##X86) = GetProcAddress(m_hModX86, #_fn); \
    if (!(_pfn##_fn##X86)) return E_UNEXPECTED;                  \
    *(FARPROC*)&(_pfn##_fn##X86) = (FARPROC)(*pfnThunk)(_pfn##_fn##X86, (PVOID)n, TRUE);

    CHECKAPI(RunSetupCommand, 8);
    CHECKAPI(NeedReboot, 1);
    CHECKAPI(NeedRebootInit, 0);

    CHECKAPI(TranslateInfString, 8);
    CHECKAPI(AdvInstallFile, 7);

    m_fInitedX86 = TRUE;
    return S_OK;
}
#endif


#endif