//
//  APITHK.C
//
//  This file has API thunks that allow shlwapi to load and run on
//  multiple versions of NT or Win95.  Since this component needs
//  to load on the base-level NT 4.0 and Win95, any calls to system
//  APIs introduced in later OS versions must be done via GetProcAddress.
// 
//  Also, any code that may need to access data structures that are
//  post-4.0 specific can be added here.
//
//  NOTE:  this file does *not* use the standard precompiled header,
//         so it can set _WIN32_WINNT to a later version.
//


#include "priv.h"       // Don't use precompiled header here
#define _USERENV_       // Disable the declspec(dllimport)
#include <userenv.h>    // for ExpandEnvironmentStringsForUser

// the IsOS code is now centralized in shell\inc since shlwapi and those who cannot
// link to shlwapi.dll both need to include it.
#include <isos.c>


typedef BOOL (* PFNGFAXW) (LPCWSTR, GET_FILEEX_INFO_LEVELS, LPVOID );

STDAPI_(BOOL) MyGetLastWriteTime (LPCWSTR pszPath, FILETIME *pft)
{
    if (g_bRunningOnNT5OrHigher)
    {
        static PFNGFAXW s_pfn = NULL;
        WIN32_FILE_ATTRIBUTE_DATA fad;

        if (!s_pfn)
        {
            s_pfn = (PFNGFAXW) GetProcAddress(GetModuleHandle(TEXT("kernel32")), "GetFileAttributesExW");
        }

        ASSERT(s_pfn);
        
        if (s_pfn && s_pfn(pszPath, GetFileExInfoStandard, &fad))
        {
            *pft = fad.ftLastWriteTime;
            return TRUE;
        }
    }
    else
    {
        HANDLE hFile = CreateFileW(pszPath, GENERIC_READ, FILE_SHARE_READ,
                NULL, OPEN_EXISTING,
                FILE_ATTRIBUTE_NORMAL, 0);
        if (hFile != INVALID_HANDLE_VALUE)
        {
            GetFileTime(hFile, NULL, NULL, pft);

            CloseHandle(hFile);
            return TRUE;
        }
    }
    return FALSE;
}

STDAPI_(BOOL) NT5_ExpandEnvironmentStringsForUserW (HANDLE hToken, LPCWSTR lpSrc, LPWSTR lpDest, DWORD dwSize)
{
    RIPMSG(g_bRunningOnNT5OrHigher, "Cannot invoke NT5_ExpandEnvironmentStringsForUserW when not on NT5 or higher");
    return(ExpandEnvironmentStringsForUserW(hToken, lpSrc, lpDest, dwSize));
}

typedef BOOL (* PFNSETFILEPOINTEREX) (HANDLE, LARGE_INTEGER, PLARGE_INTEGER, DWORD);

STDAPI_(BOOL) NT5_SetFilePointerEx(HANDLE hFile, LARGE_INTEGER liDistance, PLARGE_INTEGER pliNewPos, DWORD dwMoveMethod)
{
    static PFNSETFILEPOINTEREX s_pfn = (PFNSETFILEPOINTEREX)-1;

    if (s_pfn == (PFNSETFILEPOINTEREX)-1)
    {
        s_pfn = (PFNSETFILEPOINTEREX) GetProcAddress(GetModuleHandle(TEXT("kernel32")), "SetFilePointerEx");
    }

    if (s_pfn)
    {
        return s_pfn(hFile, liDistance, pliNewPos, dwMoveMethod);
    }
    else
    {
        DWORD dwCurrent = SetFilePointer(hFile, liDistance.LowPart, NULL, dwMoveMethod);

        if (pliNewPos)
        {
            pliNewPos->LowPart = dwCurrent;
            pliNewPos->HighPart = 0;
        }

        // Because the high value is null, this return indicates failure.
        if (dwCurrent == INVALID_SET_FILE_POINTER)
        {
            return FALSE;
        }
    }

    return TRUE;
}

typedef LONG (* PFNREGOPENCURRENTUSER) (REGSAM, HKEY *);

STDAPI_(LONG) NT5_RegOpenCurrentUser(REGSAM sam, HKEY *phk)
{
    static PFNREGOPENCURRENTUSER s_pfn = (PFNREGOPENCURRENTUSER)-1;

    if (s_pfn == (PFNREGOPENCURRENTUSER)-1)
    {
        if (g_bRunningOnNT5OrHigher)
            s_pfn = (PFNREGOPENCURRENTUSER) GetProcAddress(GetModuleHandle(TEXT("advapi32")), "RegOpenCurrentUser");
        else
            s_pfn = NULL;
    }

    if (s_pfn)
    {
        return s_pfn(sam, phk);
    }
    else
    {
        *phk = NULL;
        return ERROR_CAN_NOT_COMPLETE;
    }
}


typedef BOOL (__stdcall *PFNACTCTX)(HANDLE, ULONG_PTR *);
typedef BOOL (__stdcall *PFNDEACTCTX)(DWORD, ULONG_PTR );
typedef HANDLE (__stdcall *PFNCREATECTX)(ACTCTX*);
typedef void (__stdcall *PFNRELCTX)(HANDLE);

static PFNACTCTX s_pfnAct = (PFNACTCTX)-1;
static PFNDEACTCTX s_pfnDeact = (PFNDEACTCTX)-1;
static PFNCREATECTX s_pfnCreateact = (PFNCREATECTX)-1;
static PFNRELCTX s_pfnReleaseact = (PFNRELCTX)-1;

HANDLE XP_CreateActCtx(ACTCTX* p)
{
    if (s_pfnCreateact == (PFNCREATECTX)-1)
    {
#ifdef UNICODE
        s_pfnCreateact = (PFNCREATECTX)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "CreateActCtxW");
#else
        s_pfnCreateact = (PFNCREATECTX)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "CreateActCtxA");
#endif

    }

    if (s_pfnCreateact)
        return s_pfnCreateact(p);

    return NULL;
}

void XP_ReleaseActCtx(HANDLE h)
{
    if (s_pfnReleaseact == (PFNRELCTX)-1)
    {
        s_pfnReleaseact = (PFNRELCTX)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "ReleaseActCtx");
    }

    if (s_pfnReleaseact)
        s_pfnReleaseact(h);
}

BOOL XP_ActivateActCtx(HANDLE h, ULONG_PTR* p)
{
    if (s_pfnAct == (PFNACTCTX)-1)
    {
        s_pfnAct = (PFNACTCTX)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "ActivateActCtx");
    }

    *p = 0;

    if (s_pfnAct)
    {
        return s_pfnAct(h, p);
    }

    return TRUE;
}

BOOL XP_DeactivateActCtx(ULONG_PTR p)
{
    if (s_pfnDeact == (PFNDEACTCTX)-1)
    {
        s_pfnDeact = (PFNDEACTCTX)GetProcAddress(GetModuleHandle(TEXT("Kernel32")), "DeactivateActCtx");
    }

    if (s_pfnDeact && p)
        return s_pfnDeact(0, p);

    return TRUE;
}



STDAPI_(HANDLE) XP_CreateAndActivateContext(ULONG_PTR* pul)
{
    HANDLE hActCtx;
    ACTCTX act = {0};
    TCHAR szPath[MAX_PATH];

    GetModuleFileName(g_hinst, szPath, ARRAYSIZE(szPath));

    act.cbSize = sizeof(act);
    act.dwFlags = ACTCTX_FLAG_RESOURCE_NAME_VALID;
    act.lpResourceName = MAKEINTRESOURCE(123);
    act.lpSource = szPath;

    hActCtx = XP_CreateActCtx(&act);

    if (hActCtx)
    {
        XP_ActivateActCtx(hActCtx, pul);
    }

    return hActCtx;

}

STDAPI_(void) XP_DeactivateAndDestroyContext(HANDLE hActCtx, ULONG_PTR ul)
{
    if (hActCtx != INVALID_HANDLE_VALUE)
    {
        if (ul != 0)
            XP_DeactivateActCtx(ul);

        XP_ReleaseActCtx(hActCtx);
    }
}