// Wrappers for APIs that have moved elsewhere

#include "priv.h"
#include "shlwapip.h"

//------------------------------------------------------------------------
//
// APIs from SHDOCVW that are now forwarded to SHLWAPI
//
//
//  Note that we cannot use DLL forwarders because there is a bug
//  in Win95 where the loader screws up forwarders for bound DLLs.

STDAPI_(DWORD) StopWatchModeFORWARD(VOID)
{
    return StopWatchMode();
}

STDAPI_(DWORD) StopWatchFlushFORWARD(VOID)
{
    return StopWatchFlush();
}

STDAPI SHRunIndirectRegClientCommandForward(HWND hwnd, LPCWSTR pszClient)
{
    return SHRunIndirectRegClientCommand(hwnd, pszClient);
}

#ifdef ux10
/*IEUNIX : In the hp-ux linker, there is no option of specifying an internal name and an external name.  */
#define StopWatch StopWatch
#define StopWatchFORWARD StopWatch
#endif 

STDAPI_(DWORD) StopWatchFORWARD(DWORD dwId, LPCSTR pszDesc, DWORD dwType, DWORD dwFlags, DWORD dwCount)
{
    return StopWatchA(dwId, (LPCSTR)pszDesc, dwType, dwFlags, dwCount);
}

//------------------------------------------------------------------------
//
// APIs from SHDOCVW that are now forwarded to SHELL32/SHDOC41

//
//  This variable name is a misnomer.  It's really
//
//  g_hinstShell32OrShdoc401DependingOnWhatWeDetected;
//
//  I can live with the misnomer; saves typing.  Think of it as
//  "the INSTANCE of SHDOC401 or whatever DLL is masquerading as
//  SHDOC401".
//
//

extern "C" { HINSTANCE g_hinstSHDOC401 = NULL; }

//
//  GetShdoc401
//
//  Detect whether we should be using Shell32 or Shdoc401 to handle
//  active desktop stuff.  The rule is
//
//  If PF_FORCESHDOC401 is set, then use shdoc401. (DEBUG only)
//  If shell32 version >= 5, then use shell32.
//  Else use shdoc401.
//
//  Warning:  THIS FUNCTION CANNOT BE CALLED DURING PROCESS_ATTACH
//  because it calls LoadLibrary.

HINSTANCE GetShdoc401()
{
    DWORD dwMajorVersion;
    HINSTANCE hinst;
    HINSTANCE hinstSh32 = GetModuleHandle(TEXT("SHELL32.DLL"));
    ASSERT(hinstSh32);

#ifdef DEBUG
    if (g_dwPrototype & PF_FORCESHDOC401) {
        hinstSh32 = NULL; // force SHDOC401 to be loaded
    }
#endif

    if (hinstSh32) {
        DLLVERSIONINFO dllinfo;
        DLLGETVERSIONPROC pfnGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hinstSh32, "DllGetVersion");

        dllinfo.cbSize = sizeof(DLLVERSIONINFO);
        if (pfnGetVersion && SUCCEEDED(pfnGetVersion(&dllinfo))) {
            dwMajorVersion = dllinfo.dwMajorVersion;
        } else {
            dwMajorVersion = 0;
        }
    } else {
        dwMajorVersion = 0;
    }

    if (dwMajorVersion >= 5) {
        hinst = hinstSh32;
    } else {
        hinst = LoadLibrary(TEXT("SHDOC401.DLL"));

        if (NULL == hinst)
        {
            // If this fails we're screwed
            TraceMsg(TF_ERROR, "Failed to load SHDOC401.DLL.");
        }
    }
    g_hinstSHDOC401 = hinst;

    return hinst;
}

//
//  GetShdoc401ProcAddress
//
//  Get a procedure from SHDOC401 or whoever is masquerading as same.
//
//  Warning:  THIS FUNCTION CANNOT BE CALLED DURING PROCESS_ATTACH
//  because it calls LoadLibrary.

FARPROC GetShdoc401ProcAddress(FARPROC *ppfn, UINT ord)
{
    if (*ppfn) {
        return *ppfn;
    } else {
        HINSTANCE hinst = g_hinstSHDOC401;

        //
        //  No race condition here.  If two threads both call GetShdoc401,
        //  all that happens is that we load SHDOC401 into memory and then
        //  bump his refcount up to 2 instead of leaving it at 1.  Big deal.
        //
        if (hinst == NULL) {
            hinst = GetShdoc401();
        }

        if (hinst) {
            return *ppfn = GetProcAddress(hinst, (LPCSTR)LongToHandle(ord));
        } else {
            return NULL;
        }
    }
}

//
//  Delay-load-like macros.
//

#define DELAY_LOAD_SHDOC401(_type, _err, _fn, _ord, _arg, _nargs)   \
    STDAPI_(_type) _fn _arg                                         \
    {                                                               \
        static FARPROC s_pfn##_fn = NULL;                           \
        FARPROC pfn = GetShdoc401ProcAddress(&s_pfn##_fn, _ord);    \
        if (pfn) {                                                  \
            typedef _type (__stdcall *PFN##_fn) _arg;               \
            return ((PFN##_fn)pfn) _nargs;                          \
        } else {                                                    \
            return _err;                                            \
        }                                                           \
    }                                                               \

#define DELAY_LOAD_SHDOC401_VOID(_fn, _ord, _arg, _nargs)           \
    STDAPI_(void) _fn _arg                                          \
    {                                                               \
        static FARPROC s_pfn##_fn = NULL;                           \
        FARPROC pfn = GetShdoc401ProcAddress(&s_pfn##_fn, _ord);    \
        if (pfn) {                                                  \
            typedef void (__stdcall *PFN##_fn) _arg;                \
            ((PFN##_fn)pfn) _nargs;                                 \
        }                                                           \
    }                                                               \

// IE4 Shell Integrated Explorer called ShellDDEInit in shdocvw to
// set up DDE. Forward this call to SHELL32/SHDOC401 appropriately.

DELAY_LOAD_SHDOC401_VOID(ShellDDEInit, 188,
                         (BOOL fInit),
                         (fInit));

DELAY_LOAD_SHDOC401(HANDLE, NULL,
                    SHCreateDesktop, 200,
                    (IDeskTray* pdtray),
                    (pdtray));

DELAY_LOAD_SHDOC401(BOOL, FALSE,
                    SHDesktopMessageLoop, 201,
                    (HANDLE hDesktop),
                    (hDesktop));

// This may not have been used in IE4
DELAY_LOAD_SHDOC401(BOOL, FALSE,
                    DDEHandleViewFolderNotify, 202,
                    (IShellBrowser* psb, HWND hwnd, LPNMVIEWFOLDER lpnm),
                    (psb, hwnd, lpnm));

DELAY_LOAD_SHDOC401(LPNMVIEWFOLDER, NULL,
                    DDECreatePostNotify, 82,
                   (LPNMVIEWFOLDER pnm), 
                   (pnm));
                    
                    
