// asptxn.cpp : Implementation of DLL Exports.


// Note: Proxy/Stub Information
//      To merge the proxy/stub code into the object DLL, add the file
//      dlldatax.c to the project.  Make sure precompiled headers
//      are turned off for this file, and add _MERGE_PROXYSTUB to the
//      defines for the project.
//
//      If you are not running WinNT4.0 or Win95 with DCOM, then you
//      need to remove the following define from dlldatax.c
//      #define _WIN32_WINNT 0x0400
//
//      Further, if you are running MIDL without /Oicf switch, you also
//      need to remove the following define from dlldatax.c.
//      #define USE_STUBLESS_PROXY
//
//      Modify the custom build rule for asptxn.idl by adding the following
//      files to the Outputs.
//          asptxn_p.c
//          dlldata.c
//      To build a separate proxy/stub DLL,
//      run nmake -f asptxnps.mk in the project directory.

#include "stdafx.h"
#include "resource.h"
#include <initguid.h>
#include "txnscrpt.h"
#include "dlldatax.h"

#include "txnscrpt_i.c"
#include "txnobj.h"

#include <dbgutil.h>
#include <comadmin.h>

#ifdef _MERGE_PROXYSTUB
extern "C" HINSTANCE hProxyDll;
#endif

CComModule _Module;

BEGIN_OBJECT_MAP(ObjectMap)
    OBJECT_ENTRY(CLSID_ASPObjectContextTxRequired,      CASPObjectContext)
    OBJECT_ENTRY(CLSID_ASPObjectContextTxRequiresNew,   CASPObjectContext)
    OBJECT_ENTRY(CLSID_ASPObjectContextTxSupported,     CASPObjectContext)
    OBJECT_ENTRY(CLSID_ASPObjectContextTxNotSupported,  CASPObjectContext)
END_OBJECT_MAP()

LPCSTR  g_szModuleName = "ASPTXN";

DECLARE_DEBUG_VARIABLE();

DECLARE_DEBUG_PRINTS_OBJECT();

/////////////////////////////////////////////////////////////////////////////
// DLL Entry Point

extern "C"
BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
{
    lpReserved;
#ifdef _MERGE_PROXYSTUB
    if (!PrxDllMain(hInstance, dwReason, lpReserved))
        return FALSE;
#endif
    if (dwReason == DLL_PROCESS_ATTACH)
    {
        CREATE_DEBUG_PRINT_OBJECT( g_szModuleName );
        if( !VALID_DEBUG_PRINT_OBJECT() )
        {
            return FALSE;
        }

        LOAD_DEBUG_FLAGS_FROM_REG_STR("System\\CurrentControlSet\\Services\\W3Svc\\ASP", 0);

        _Module.Init(ObjectMap, hInstance /*, ATL21 &LIBID_ASPTXNLib */);
        DisableThreadLibraryCalls(hInstance);
    }
    else if (dwReason == DLL_PROCESS_DETACH)
    {
        _Module.Term();
        DELETE_DEBUG_PRINT_OBJECT();
    }

    return TRUE;    // ok
}

/////////////////////////////////////////////////////////////////////////////
// Used to determine whether the DLL can be unloaded by OLE

STDAPI DllCanUnloadNow(void)
{
#ifdef _MERGE_PROXYSTUB
    if (PrxDllCanUnloadNow() != S_OK)
        return S_FALSE;
#endif
    return (_Module.GetLockCount()==0) ? S_OK : S_FALSE;
}

/////////////////////////////////////////////////////////////////////////////
// Returns a class factory to create an object of the requested type

STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
{
#ifdef _MERGE_PROXYSTUB
    if (PrxDllGetClassObject(rclsid, riid, ppv) == S_OK)
        return S_OK;
#endif
    return _Module.GetClassObject(rclsid, riid, ppv);
}

/////////////////////////////////////////////////////////////////////////////
// DllRegisterServer - Adds entries to the system registry

// Forward references
HRESULT ViperizeContextObject();
HRESULT AddViperUtilPackage();
HRESULT RemoveViperUtilPackage(ICatalogCollection* pPkgCollectionT);
HRESULT AddContextObjectToViperPackage();


STDAPI DllRegisterServer(void)
{
#ifdef _MERGE_PROXYSTUB
    HRESULT hRes = PrxDllRegisterServer();
    if (FAILED(hRes))
        return hRes;
#endif

    HRESULT hr = NOERROR;

    // registers object, typelib and all interfaces in typelib
    hr = _Module.RegisterServer(TRUE);

    // create the iis utilities package
    if( SUCCEEDED(hr) )
    {
        HRESULT hrCoInit = CoInitialize( NULL );

        // This is kinda dopey, but remove the package if it exists
        // so we don't get bogus errors when we add. Ignore the return.
        RemoveViperUtilPackage(NULL);

        hr = ViperizeContextObject();

        if( SUCCEEDED(hrCoInit) )
        {
            CoUninitialize();
        }
    }
    return hr;
}

/////////////////////////////////////////////////////////////////////////////
// DllUnregisterServer - Removes entries from the system registry

STDAPI DllUnregisterServer(void)
{
#ifdef _MERGE_PROXYSTUB
    PrxDllUnregisterServer();
#endif

    HRESULT hr = NOERROR;

    HRESULT hrCoInit = CoInitialize( NULL );

    // Remove the iis utilities package before unregistering the objects
    hr = RemoveViperUtilPackage(NULL);

    if( SUCCEEDED(hrCoInit) )
    {
        CoUninitialize();
    }

    // We don't really care about failures...
    hr = _Module.UnregisterServer(/* ATL21 TRUE */);

    // NOTE: ATL doesn't unregister the typelibrary. Since
    // the interfaces we are exposing are internal to asp we should
    // consider removing the typelibrary registry entries.

    return hr;
}


// Registration code to be pulled from asp.dll

#define RELEASE(p) if ( p ) { p->Release(); p = NULL; }
#define FREEBSTR(p) SysFreeString( p ); p = NULL;

const WCHAR wszCLSID_ASPObjectContextTxRequired[]     = L"{14D0916D-9CDC-11D1-8C4A-00C04FC324A4}";
const WCHAR wszCLSID_ASPObjectContextTxRequiresNew[]  = L"{14D0916E-9CDC-11D1-8C4A-00C04FC324A4}";
const WCHAR wszCLSID_ASPObjectContextTxSupported[]    = L"{14D0916F-9CDC-11D1-8C4A-00C04FC324A4}";
const WCHAR wszCLSID_ASPObjectContextTxNotSupported[] = L"{14D09170-9CDC-11D1-8C4A-00C04FC324A4}";

const WCHAR wszASPUtilitiesPackageID[] = L"{ADA44581-02C1-11D1-804A-0000F8036614}";

/*===================================================================
GetSafeArrayOfCLSIDs

Get a SafeArray contains one ComponentCLSID

Parameter:
szComponentCLSID    the CLSID need to be put in the safe array
paCLSIDs            pointer to a pointer of safe array(safe array provided by
caller).

Return:        HRESULT
Side Affect:

Note:
===================================================================*/
HRESULT GetSafeArrayOfCLSIDs
(
IN LPCWSTR      szComponentCLSID,
OUT SAFEARRAY** paCLSIDs
)
{
    SAFEARRAY*          aCLSIDs = NULL;
    SAFEARRAYBOUND      rgsaBound[1];
    LONG                Indices[1];
    VARIANT             varT;
    HRESULT             hr = NOERROR;

    DBG_ASSERT(szComponentCLSID && paCLSIDs);
    DBG_ASSERT(*paCLSIDs == NULL);

    // PopulateByKey is expecting a SAFEARRAY parameter input,
    // Create a one element SAFEARRAY, the one element of the SAFEARRAY contains
    // the packageID.
    rgsaBound[0].cElements = 1;
    rgsaBound[0].lLbound = 0;
    aCLSIDs = SafeArrayCreate(VT_VARIANT, 1, rgsaBound);

    if (aCLSIDs)
        {
        Indices[0] = 0;

        VariantInit(&varT);
        varT.vt = VT_BSTR;
        varT.bstrVal = SysAllocString(szComponentCLSID);
        hr = SafeArrayPutElement(aCLSIDs, Indices, &varT);
        VariantClear(&varT);

        if (FAILED(hr))
            {
            DBGPRINTF((DBG_CONTEXT, "Failed to call SafeArrayPutElement, CLSID is %S, hr %08x\n",
                szComponentCLSID,
                hr));

            if (aCLSIDs != NULL)
                {
                HRESULT hrT = SafeArrayDestroy(aCLSIDs);
                if (FAILED(hrT))
                    {
                    DBGPRINTF((DBG_CONTEXT, "Failed to call SafeArrayDestroy(aCLSIDs), hr = %08x\n",
                        hr));
                    }
                aCLSIDs = NULL;
                }
            }
        }
    else
        {
        hr = HRESULT_FROM_WIN32(GetLastError());
        DBGPRINTF((DBG_CONTEXT, "Failed to call SafeArrayCreate, hr %08x\n",
                hr));
        }

    *paCLSIDs = aCLSIDs;
    return hr;
}

/*===================================================================
ViperizeContextObject

Creates a Viper package, and adds the Context object to that
package, and marks the object as "InProc".

Returns:
        HRESULT - NOERROR on success

Side effects:
        Creates Viper package, Viperizes Context object
===================================================================*/
HRESULT ViperizeContextObject(void)
        {
        HRESULT         hr;

        // Add the IIS utility package
        hr = AddViperUtilPackage();

        // Add the context object to the package
        if (SUCCEEDED(hr))
                hr = AddContextObjectToViperPackage();

        return hr;
        }

/*===================================================================
AddViperUtilPackage

Creates a Viper package named "IIS Utility"

Returns:
        HRESULT - NOERROR on success

Side effects:
        Creates Viper package
===================================================================*/
HRESULT AddViperUtilPackage(void)
        {
        HRESULT         hr;
        BSTR bstr       = NULL;
        VARIANT         varT;
        ICatalogCollection* pPkgCollection = NULL;
        ICatalogObject*         pPackage = NULL;
        ICOMAdminCatalog*   pCatalog = NULL;

        long lPkgCount, lChanges, i;

        VariantInit(&varT);

        // Create instance of the catalog object
        hr = CoCreateInstance(CLSID_COMAdminCatalog
                                        , NULL
                                        , CLSCTX_INPROC_SERVER
                                        , IID_ICOMAdminCatalog
                                        , (void**)&pCatalog);
        if (FAILED(hr))
                goto LErr;

        // Get the Packages collection
        bstr = SysAllocString(L"Applications");
        hr = pCatalog->GetCollection(bstr, (IDispatch**)&pPkgCollection);
        FREEBSTR(bstr);
        if (FAILED(hr))
                goto LErr;

        // Add new IIS Utilities package
        hr = pPkgCollection->Add((IDispatch**)&pPackage);
        if (FAILED(hr))
                goto LErr;

        // Set package ID to L"{ADA44581-02C1-11D1-804A-0000F8036614}",
        // MTS replication code looks for This fixed packageID
        bstr = SysAllocString(L"ID");
        varT.vt = VT_BSTR;
        varT.bstrVal = SysAllocString(wszASPUtilitiesPackageID);
        hr = pPackage->put_Value(bstr, varT);
        FREEBSTR(bstr);
        VariantClear(&varT);
        if (FAILED(hr))
                goto LErr;

        // Set package "Name" property to "IIS Utilities"
        bstr = SysAllocString(L"Name");
        varT.vt = VT_BSTR;
        varT.bstrVal = SysAllocString(L"IIS Utilities");
        hr = pPackage->put_Value(bstr, varT);
        FREEBSTR(bstr);
        VariantClear(&varT);
        if (FAILED(hr))
                goto LErr;

        // Set activation to InProc
        bstr = SysAllocString(L"Activation");
        varT.vt = VT_BSTR;
        varT.bstrVal = SysAllocString(L"InProc");
        hr = pPackage->put_Value(bstr, varT);
        FREEBSTR(bstr);
        VariantClear(&varT);
        if (FAILED(hr))
                goto LErr;

        // Set CreatedBy to MS IIS
        bstr = SysAllocString(L"CreatedBy");
        varT.vt = VT_BSTR;
        varT.bstrVal = SysAllocString(L"Microsoft Internet Information Services (tm)");
        hr = pPackage->put_Value(bstr, varT);
        FREEBSTR(bstr);
        VariantClear(&varT);
        if (FAILED(hr))
                goto LErr;

        // Set Deleteable = N property on package
        bstr = SysAllocString(L"Deleteable");
        varT.vt = VT_BSTR;
        varT.bstrVal = SysAllocString(L"N");
        hr = pPackage->put_Value(bstr, varT);
        FREEBSTR(bstr);
        VariantClear(&varT);
        if (FAILED(hr))
                goto LErr;

    	bstr = SysAllocString(L"AccessChecksLevel");
        varT.vt = VT_BSTR;
        varT.bstrVal = SysAllocString(L"0");
        hr = pPackage->put_Value(bstr, varT);
        FREEBSTR(bstr);
        VariantClear(&varT);
        if (FAILED(hr))
                goto LErr;

        // Save changes
        hr = pPkgCollection->SaveChanges(&lChanges);
        if (FAILED(hr))
                goto LErr;

LErr:
        RELEASE(pPkgCollection);
        RELEASE(pPackage);
        RELEASE(pCatalog);

        return hr;
        }

/*===================================================================
RemoveViperUtilPackage

Removes the Viper package named "IIS Utility"

Parameters:
        ICatalogCollection* pPkgCollection
                If non-null, will use this collection.  Otherwise, will
                open its own collection

Returns:
        HRESULT - NOERROR on success

Side effects:
        Removes Viper package
===================================================================*/
HRESULT RemoveViperUtilPackage(ICatalogCollection* pPkgCollectionT)
        {
        HRESULT                 hr;
    ICatalogCollection* pPkgCollection = NULL;
        ICatalogObject*         pPackage = NULL;
        ICOMAdminCatalog*       pCatalog = NULL;
        LONG                lPkgCount, lChanges, i;
        SAFEARRAY*          aCLSIDs = NULL;

        // if package collection was passed, use it
        if (pPkgCollectionT != NULL)
                {
                pPkgCollection = pPkgCollectionT;
                }
        else
                {
                BSTR                bstr = NULL;

                // Create instance of the catalog object
                hr = CoCreateInstance(CLSID_COMAdminCatalog
                                                , NULL
                                                , CLSCTX_INPROC_SERVER
                                                , IID_ICOMAdminCatalog
                                                , (void**)&pCatalog);
                if (FAILED(hr))
                        goto LErr;

                // Get the Packages collection
                bstr = SysAllocString(L"Applications");
                hr = pCatalog->GetCollection(bstr, (IDispatch**)&pPkgCollection);
                FREEBSTR(bstr);
                if (FAILED(hr))
                        goto LErr;
                }

    hr = GetSafeArrayOfCLSIDs(wszASPUtilitiesPackageID, &aCLSIDs);
    if (FAILED(hr))
        {
        DBGPRINTF((DBG_CONTEXT, "Failed to get SafeArrayofCLSIDs, szPackageID is %S, hr %08x",
            wszASPUtilitiesPackageID,
            hr));
        goto LErr;
        }

    //
    // Populate it
    //
    hr = pPkgCollection->PopulateByKey(aCLSIDs);
    if (FAILED(hr))
        {
        DBGPRINTF((DBG_CONTEXT, "Failed to call PopulateByKey(), hr = %08x\n",
            hr));
        goto LErr;
        }

        // Delete any existing "IIS Utilities" package
    hr = pPkgCollection->get_Count(&lPkgCount);
    if (FAILED(hr))
        {
        DBGPRINTF((DBG_CONTEXT, "pPkgCollection->Populate() failed, hr = %08x\n",
            hr));
        goto LErr;
        }

    if (SUCCEEDED(hr) && lPkgCount == 1)
        {
        hr = pPkgCollection->get_Item(0, (IDispatch**)&pPackage);
        if (FAILED(hr))
            {
            goto LErr;
            }

        BSTR    bstr = NULL;
        VARIANT varT;

        // Found it - remove it and call Save Changes
        // First, Set Deleteable = Y property on package
        bstr = SysAllocString(L"Deleteable");
        VariantInit(&varT);
        varT.vt = VT_BSTR;
        varT.bstrVal = SysAllocString(L"Y");
        hr = pPackage->put_Value(bstr, varT);
        FREEBSTR(bstr);
        VariantClear(&varT);
        if (FAILED(hr))
            {
            goto LErr;
            }

        RELEASE(pPackage);

        // Let save the Deletable settings
        hr = pPkgCollection->SaveChanges(&lChanges);
        if (FAILED(hr))
            {
            DBGPRINTF((DBG_CONTEXT, "Save the Deletable settings failed, hr = %08x\n",
                hr));
            goto LErr;
            }

        // Now we can delete
        hr = pPkgCollection->Remove(0);
        if (FAILED(hr))
            {
            DBGPRINTF((DBG_CONTEXT, "Remove the Component from package failed, hr = %08x\n",
                hr));
            goto LErr;
            }

        // Aha, we should be able to delete now.
        hr = pPkgCollection->SaveChanges(&lChanges);
        if (FAILED(hr))
            {
            DBGPRINTF((DBG_CONTEXT, "Save changes failed, hr = %08x\n",
                hr));
            goto LErr;
            }
        }
LErr:

    if (aCLSIDs != NULL)
        {
        HRESULT hrT = SafeArrayDestroy(aCLSIDs);
        aCLSIDs = NULL;
        }

    if (pPkgCollectionT == NULL)
                RELEASE(pPkgCollection);
        RELEASE(pCatalog);
        RELEASE(pPackage);

        return hr;
        }

/*===================================================================
AddContextObjectToViperPackage

Adds the Context object to the Viper package named "IIS Utility"

Returns:
        HRESULT - NOERROR on success

Side effects:
        Adds the object to the Viper package
===================================================================*/
HRESULT AddContextObjectToViperPackage()
{
        HRESULT         hr;
        BSTR bstr                   = NULL;
        BSTR bstrAppGUID    = NULL;
        BSTR bstrGUID       = NULL;
        VARIANT varName;
        VARIANT varKey;
        VARIANT varT;
        ICatalogCollection* pPkgCollection = NULL;
        ICatalogCollection* pCompCollection = NULL;
        ICatalogObject*         pComponent = NULL;
        ICatalogObject*         pPackage = NULL;
        ICOMAdminCatalog*       pCatalog = NULL;
        long                lPkgCount, lCompCount, lChanges, iT;
    BOOL                fFound;
        SAFEARRAY*          aCLSIDs = NULL;

        VariantInit(&varKey);
        VariantClear(&varKey);
        VariantInit(&varName);
        VariantClear(&varName);
        VariantInit(&varT);
        VariantClear(&varT);

        // Create instance of the catalog object
        hr = CoCreateInstance(CLSID_COMAdminCatalog
                                        , NULL
                                        , CLSCTX_INPROC_SERVER
                                        , IID_ICOMAdminCatalog
                                        , (void**)&pCatalog);
        if (FAILED(hr))
                goto LErr;

        // Get the Packages collection
        bstr = SysAllocString(L"Applications");
        hr = pCatalog->GetCollection(bstr, (IDispatch**)&pPkgCollection);
        SysFreeString(bstr);
        if (FAILED(hr))
                goto LErr;

    hr = GetSafeArrayOfCLSIDs(wszASPUtilitiesPackageID, &aCLSIDs);
    if (FAILED(hr))
        {
        DBGPRINTF((DBG_CONTEXT, "Failed to get SafeArrayofCLSIDs, szPackageID is %S, hr %08x",
            wszASPUtilitiesPackageID,
            hr));
        goto LErr;
        }

    bstrAppGUID = SysAllocString(wszASPUtilitiesPackageID);

        // Actually put the components in the package
        bstrGUID = SysAllocString(wszCLSID_ASPObjectContextTxRequired);
        hr = pCatalog->ImportComponent(bstrAppGUID ,bstrGUID);
        SysFreeString(bstrGUID);
        if (FAILED(hr))
                goto LErr;
        bstrGUID = SysAllocString(wszCLSID_ASPObjectContextTxRequiresNew);
        hr = pCatalog->ImportComponent(bstrAppGUID ,bstrGUID);
        SysFreeString(bstrGUID);
        if (FAILED(hr))
                goto LErr;
        bstrGUID = SysAllocString(wszCLSID_ASPObjectContextTxSupported);
        hr = pCatalog->ImportComponent(bstrAppGUID ,bstrGUID);
        SysFreeString(bstrGUID);
        if (FAILED(hr))
                goto LErr;
        bstrGUID = SysAllocString(wszCLSID_ASPObjectContextTxNotSupported);
        hr = pCatalog->ImportComponent(bstrAppGUID ,bstrGUID);
        SysFreeString(bstrGUID);
        if (FAILED(hr))
                goto LErr;

    varKey.vt = VT_BSTR;
    varKey.bstrVal = SysAllocString(wszASPUtilitiesPackageID);

    //
    // Populate packages
    //
    hr = pPkgCollection->PopulateByKey(aCLSIDs);
    if (FAILED(hr))
        {
        DBGPRINTF((DBG_CONTEXT, "Failed to call PopulateByKey(), hr = %08x\n",
            hr));
        goto LErr;
        }

        // Find "IIS Utilities" package
    hr = pPkgCollection->get_Count(&lPkgCount);
    if (FAILED(hr))
        {
        DBGPRINTF((DBG_CONTEXT, "pPkgCollection->Populate() failed, hr = %08x\n",
            hr));
        goto LErr;
        }

    if (SUCCEEDED(hr) && lPkgCount == 1)
        {
        hr = pPkgCollection->get_Item(0, (IDispatch**)&pPackage);
        if (FAILED(hr))
            {
            goto LErr;
            }
        }

        DBG_ASSERT(pPackage != NULL);

        // Get the "ComponentsInPackage" collection.
        bstr = SysAllocString(L"Components");
        hr = pPkgCollection->GetCollection(bstr, varKey, (IDispatch**)&pCompCollection);
        SysFreeString(bstr);
        if (FAILED(hr))
                goto LErr;

        // Repopulate the collection so we can find our object and set properties on it
        hr = pCompCollection->Populate();
        if (FAILED(hr))
                goto LErr;

        // Find our components in the list (should be four)

        hr = pCompCollection->get_Count(&lCompCount);
        if (FAILED(hr))
                goto LErr;
        DBG_ASSERT(lCompCount == 4);
        RELEASE(pComponent);
        VariantClear(&varKey);

        for (iT = (lCompCount-1); iT >= 0 ; iT--)
                {
                hr = pCompCollection->get_Item(iT, (IDispatch**)&pComponent);
                if (FAILED(hr))
                        goto LErr;

                hr = pComponent->get_Key(&varKey);
                if (FAILED(hr))
                        goto LErr;
                DBG_ASSERT(varKey.bstrVal);
                fFound = FALSE;

                if (_wcsicmp(varKey.bstrVal, wszCLSID_ASPObjectContextTxRequired) == 0)
                        {
            // Required
                bstr = SysAllocString(L"3");
                fFound = TRUE;
                        }
                else if (_wcsicmp(varKey.bstrVal, wszCLSID_ASPObjectContextTxRequiresNew) == 0)
                    {
                    // Requires New
                bstr = SysAllocString(L"4");
                fFound = TRUE;
                    }
                else if (_wcsicmp(varKey.bstrVal, wszCLSID_ASPObjectContextTxSupported) == 0)
                    {
                    // Supported
                bstr = SysAllocString(L"2");
                fFound = TRUE;
                    }
                else if (_wcsicmp(varKey.bstrVal, wszCLSID_ASPObjectContextTxNotSupported) == 0)
                    {
                    // Not Supported
                bstr = SysAllocString(L"1");
                fFound = TRUE;
                    }

        if (fFound)
            {
                varT.vt = VT_BSTR;
                varT.bstrVal = bstr;
                bstr = SysAllocString(L"Transaction");
                hr = pComponent->put_Value(bstr, varT);
                FREEBSTR(bstr);
                VariantClear(&varT);
                if (FAILED(hr))
                        goto LErr;

                bstr = SysAllocString(L"Description");
                varT.vt = VT_BSTR;
                varT.bstrVal = SysAllocString(L"ASP Tx Script Context");
                hr = pComponent->put_Value(bstr, varT);
                FREEBSTR(bstr);
                VariantClear(&varT);
                if (FAILED(hr))
                        goto LErr;

                bstr = SysAllocString(L"EventTrackingEnabled");
                varT.vt = VT_BSTR;
                varT.bstrVal = SysAllocString(L"N");
                hr = pComponent->put_Value(bstr, varT);
                FREEBSTR(bstr);
                VariantClear(&varT);
                if (FAILED(hr))
                        goto LErr;
            }

                VariantClear(&varKey);
                RELEASE(pComponent);
                }

        // Save changes
        hr = pCompCollection->SaveChanges(&lChanges);
        if (FAILED(hr))
                goto LErr;

        bstr = SysAllocString(L"Activation");
        varT.vt = VT_BSTR;
        varT.bstrVal = SysAllocString(L"InProc");
        hr = pPackage->put_Value(bstr, varT);
        FREEBSTR(bstr);
        VariantClear(&varT);
        if (FAILED(hr))
                goto LErr;

        // Save changes
        hr = pPkgCollection->SaveChanges(&lChanges);
        if (FAILED(hr))
                goto LErr;

        hr = pPkgCollection->Populate();
        if (FAILED(hr))
                goto LErr;

        // Now that our one object is added to the package, set the Changeable property
        // on the package to "No", so no one can mess with it
        bstr = SysAllocString(L"Changeable");
        varT.vt = VT_BSTR;
        varT.bstrVal = SysAllocString(L"N");
        hr = pPackage->put_Value(bstr, varT);
        FREEBSTR(bstr);
        VariantClear(&varT);
        if (FAILED(hr))
                goto LErr;

        // Save changes
        hr = pPkgCollection->SaveChanges(&lChanges);
        if (FAILED(hr))
                goto LErr;

LErr:
        DBG_ASSERT(SUCCEEDED(hr));
    if (aCLSIDs)
        {
        SafeArrayDestroy(aCLSIDs);
        aCLSIDs = NULL;
        }

        RELEASE(pCompCollection);
        RELEASE(pPkgCollection);
        RELEASE(pComponent);
        RELEASE(pPackage);
        RELEASE(pCatalog);
    FREEBSTR(bstrAppGUID);
        FREEBSTR(bstr);
        VariantClear(&varName);
        VariantClear(&varKey);
        VariantClear(&varT);

        return hr;

} // AddContextObjectToViperPackage