/*
 * inetcpl.c - Indirect calls to inetcpl.cpl.
 */


/* Headers
 **********/

#include "project.h"
#pragma hdrstop

#include "inetcpl.h"


/* Types
 ********/

/* Internet CPL vtable */

typedef struct internetcplvtbl
{
   HRESULT (WINAPI *AddInternetPropertySheets)(LPFNADDPROPSHEETPAGE pfnAddPage, LPARAM lparam, PUINT pucRefCount, LPFNPSPCALLBACK pfnCallback);
}
INTERNETCPLVTBL;
DECLARE_STANDARD_TYPES(INTERNETCPLVTBL);


/* Module Constants
 *******************/

#pragma data_seg(DATA_SEG_READ_ONLY)

PRIVATE_DATA CCHAR s_cszInternetCPL[]               = "inetcpl.cpl";
PRIVATE_DATA CCHAR s_cszAddInternetPropertySheets[] = "AddInternetPropertySheets";

#pragma data_seg()


/* Module Variables
 *******************/

/* Internet CPL reference count */
PRIVATE_DATA UINT s_ucRef = 0;

PRIVATE_DATA HINSTANCE s_hinstInternetCPL    = NULL;

/* Internet CPL vtable */

PRIVATE_DATA PINTERNETCPLVTBL s_pinetcplvtbl = NULL;


/***************************** Private Functions *****************************/


#ifdef DEBUG

PRIVATE_CODE BOOL IsValidPCINTERNETCPLVTBL(PCINTERNETCPLVTBL pcinetcplctbl)
{
   return(IS_VALID_READ_PTR(pcinetcplctbl, CINTERNETCPLVTBL) &&
          IS_VALID_CODE_PTR(pcinetcplctbl->AddInternetPropertySheets, AddInternetPropertySheets));
}


PRIVATE_CODE BOOL InternetCPLNotLoadedStateOK(void)
{
   return(! s_hinstInternetCPL &&
          ! s_pinetcplvtbl);
}


PRIVATE_CODE BOOL InternetCPLLoadedStateOK(void)
{
   return(IS_VALID_HANDLE(s_hinstInternetCPL, INSTANCE) &&
          IS_VALID_STRUCT_PTR(s_pinetcplvtbl, CINTERNETCPLVTBL));
}


PRIVATE_CODE BOOL InternetCPLStateOK(void)
{
   return(InternetCPLNotLoadedStateOK() ||
          InternetCPLLoadedStateOK());
}

#endif   /* DEBUG */


PRIVATE_CODE BOOL IsInternetCPLLoaded(void)
{
   ASSERT(InternetCPLStateOK());

   return(s_hinstInternetCPL != NULL);
}


PRIVATE_CODE BOOL GetInternetCPLProc(PCSTR pcszProc, FARPROC *pfp)
{
   ASSERT(IS_VALID_STRING_PTR(pcszProc, CSTR));
   ASSERT(IS_VALID_WRITE_PTR(pfp, FARPROC));

   ASSERT(IS_VALID_HANDLE(s_hinstInternetCPL, INSTANCE));

   *pfp = GetProcAddress(s_hinstInternetCPL, pcszProc);

   if (*pfp)
      TRACE_OUT(("GetInternetCPLProc(): Got address of %s!%s.",
                 s_cszInternetCPL,
                 pcszProc));
   else
      WARNING_OUT(("GetOLEProc(): Failed to get address of %s!%s.",
                   s_cszInternetCPL,
                   pcszProc));

   ASSERT(! *pfp ||
          IS_VALID_CODE_PTR(*pfp, FARPROC));

   return(*pfp != NULL);
}


PRIVATE_CODE BOOL FillInternetCPLVTable(void)
{
   BOOL bResult;

   ASSERT(IS_VALID_HANDLE(s_hinstInternetCPL, INSTANCE));

   if (AllocateMemory(sizeof(*s_pinetcplvtbl), &s_pinetcplvtbl))
   {
      bResult = GetInternetCPLProc(s_cszAddInternetPropertySheets,
                                   &(FARPROC)(s_pinetcplvtbl->AddInternetPropertySheets));

      if (bResult)
         TRACE_OUT(("FillInternetCPLVTable(): Internet CPL vtable filled successfully."));
      else
      {
         FreeMemory(s_pinetcplvtbl);
         s_pinetcplvtbl = NULL;
      }
   }
   else
      bResult = FALSE;

   ASSERT(! bResult ||
          InternetCPLLoadedStateOK());

   return(bResult);
}


PRIVATE_CODE BOOL LoadInternetCPL(void)
{
   BOOL bResult;

   bResult = IsInternetCPLLoaded();

   if (! bResult)
   {
      s_hinstInternetCPL = LoadLibrary(s_cszInternetCPL);

      if (s_hinstInternetCPL)
      {
         bResult = FillInternetCPLVTable();

         if (bResult)
            TRACE_OUT(("LoadInternetCPL(): %s loaded.",
                       s_cszInternetCPL));
      }
      else
         WARNING_OUT(("LoadInternetCPL(): LoadLibrary(%s) failed.",
                      s_cszInternetCPL));

      if (! bResult)
         UnloadInternetCPL();
   }

   ASSERT(InternetCPLStateOK());

   return(bResult);
}


/****************************** Public Functions *****************************/



PUBLIC_CODE void UnloadInternetCPL(void)
{
    if (s_pinetcplvtbl)
    {
        FreeMemory(s_pinetcplvtbl);
        s_pinetcplvtbl = NULL;

        TRACE_OUT(("UnloadInternetCPL(): Freed %s vtable.",
                   s_cszInternetCPL));
    }

    if (s_hinstInternetCPL)
    {
        FreeLibrary(s_hinstInternetCPL);
        s_hinstInternetCPL = NULL;

        TRACE_OUT(("UnloadInternetCPL(): Freed %s.",
                   s_cszInternetCPL));
    }


    return;
}


HRESULT InternetCPLCanUnloadNow(void)
{
    return ((s_ucRef > 0) ? S_FALSE : S_OK);
}


#pragma warning(disable:4100) /* "unreferenced formal parameter" warning */
PUBLIC_CODE HRESULT WINAPI AddInternetPropertySheets(
                                             LPFNADDPROPSHEETPAGE pfnAddPage,
                                             LPARAM lparam, PUINT pucRefCount,
                                             LPFNPSPCALLBACK pfnCallback)
{
    HRESULT hr;

    /*
     * Increment the Internet CPL's reference count around this call it so that
     * it is not unloaded during the call.
     */

    if (LoadInternetCPL())
        hr = s_pinetcplvtbl->AddInternetPropertySheets(pfnAddPage, lparam,
                                                       &s_ucRef,
                                                       pfnCallback);
    else
        hr = E_FAIL;

    return(hr);
}

#pragma warning(default:4100) /* "unreferenced formal parameter" warning */