Figure 5   IDelegatorFactory

////////////////////////////////////////////////////////
// excerpt from delegate.idl
//

[
    uuid(9b8c32f3-249a-11d2-a7bb-006008d25ccf),
    object,
    local
]
interface IDelegatorFactory : IUnknown
{
    typedef enum _DelegatorOptions
    {
        DO_MBV_INPROC           = 0x00000001,
        DO_MBV_LOCAL            = 0x00000002,
        DO_MBV_DIFFERENTMACHINE = 0x00000004,
        DO_MBV_ALL              = 0x00000007,
        DO_MAINTAIN_IDENTITY    = 0x00000008
    } DelegatorOptions;

    HRESULT CreateDelegator( [in] IUnknown* pUnkOuter,
                             [in] IUnknown* pUnkInner,
                             [in] CLSID* pclsidHook,
                             [in] IUnknown* pHook,
                             [in] DWORD grfOptions,
                             [in] REFIID iid,
                             [out, iid_is(iid)] void** ppv );
}


Figure 6   IAlternateCredentialDelegatorHook

////////////////////////////////////////////////////////
// excerpt from delegate.idl
//

[
    uuid(9b8c32f8-249a-11d2-a7bb-006008d25ccf),
    object,
    local
]
interface IAlternateCredentialDelegatorHook : IUnknown
{
    typedef enum _ACDH_OPTIONS
    {
        ACDH_AUTHNSVC        = 0x00000001,
        ACDH_AUTHZSVC        = 0x00000002,
        ACDH_SERVERPRINCIPAL = 0x00000004,
        ACDH_AUTHNLEVEL      = 0x00000008,
        ACDH_IMPLEVEL        = 0x00000010,
        ACDH_CREDENTIALS     = 0x00000020,
        ACDH_CAPS            = 0x00000040
    } ACDH_OPTIONS;

    HRESULT Init( [in] DWORD grfOptions,
                  [in] DWORD nAuthnSvc,
                  [in] DWORD nAuthzSvc,
                  [in] const OLECHAR* pszServerPrincipal,
                  [in] DWORD nAuthnLevel,
                  [in] DWORD nImpLevel,
                  [in] const OLECHAR* pszAuthority,
                  [in] const OLECHAR* pszPrincipal,
                  [in] const OLECHAR* pszPassword,
                  [in] DWORD grfCaps );
}


Figure 7   Using the Alternate Credentials Hook

////////////////////////////////////////////////////////
// acdh.cpp
//
// This example demonstrates the use of the alternate
// credentials hook, with a fictitious penguin object
//

#define _WIN32_WINNT 0x403
#include <windows.h>
#include "delegate.h"
#include "delegate_i.c"

// imaginary header files with penguin interface & GUID definitions
#include "penguin.h"
#include "penguin_i.c"

// This is a useful helper function that applies the delegator
// coupled with an initialized alternate credentials hook
HRESULT WrapWithAlternateCredentials(
            IUnknown*&     rpUnk,
            const wchar_t* pszAuthority,
            const wchar_t* pszPrincipal,
            const wchar_t* pszPassword,
            REFIID iid, void** ppv )
{
    IAlternateCredentialDelegatorHook* phook = 0;
    HRESULT hr = CoCreateInstance( CLSID_CoAlternateCredentialDelegatorHook,
                                   0, CLSCTX_INPROC_SERVER,
                                   IID_IAlternateCredentialDelegatorHook,
                                   (void**)&phook );
    if ( SUCCEEDED( hr ) )
    {
        hr = phook->Init( ACDH_CREDENTIALS, 0, 0, 0, 0, 0,
                          pszAuthority, pszPrincipal, pszPassword, 0 );
        if ( SUCCEEDED( hr ) )
        {
            IDelegatorFactory* pfactory = 0;
            hr = CoGetClassObject( CLSID_CoDelegator, CLSCTX_INPROC_SERVER, 0,
                                   IID_IDelegatorFactory, (void**)&pfactory );
            if ( SUCCEEDED( hr ) )
            {
                hr = pfactory->CreateDelegator( 0, rpUnk,
                                                0, phook,
                                                DO_MBV_INPROC,
                                                iid, ppv );
                pfactory->Release();
            }
        }
        phook->Release();
    }
    
    // release the original interface pointer so the only pointers we'll see
    // for this object will actually point to the delegator.
    rpUnk->Release();
    rpUnk = 0;

    return hr;
}

// This code creates a penguin object on the requested
// machine, then makes calls through various interfaces
// using the supplied credentials.
HRESULT CreateAndUsePenguinAsUser(  const wchar_t* pszMachine,
                                    const wchar_t* pszAuthority,
                                    const wchar_t* pszPrincipal,
                                    const wchar_t* pszPassword )
{
    // Standard client-side code required to activate an object
    // using alternate credentials
    COAUTHIDENTITY caid = { const_cast<wchar_t*>(pszPrincipal),
                            lstrlenW(pszPrincipal),
                            const_cast<wchar_t*>(pszAuthority),
                            lstrlenW(pszAuthority),
                            const_cast<wchar_t*>(pszPassword),
                            lstrlenW(pszPassword),
                            2 };                // Unicode
    COAUTHINFO cai = { RPC_C_AUTHN_WINNT, 0, 0,
                       RPC_C_AUTHN_LEVEL_PKT,
                       RPC_C_IMP_LEVEL_IMPERSONATE,
                       &caid, 0 };
    COSERVERINFO csi = { 0, const_cast<wchar_t*>(pszMachine), &cai, 0 };
    MULTI_QI mqi = { &IID_IAnimal, 0, 0 };
    HRESULT hr = CoCreateInstanceEx( CLSID_CoPenguin, 0,
                                     CLSCTX_ALL, &csi,
                                     1, &mqi );
    
    if ( SUCCEEDED( hr ) )
    {
        // Here's where the UD gets involved to automatically apply
        // the alternate credentials to each interface exposed from the object
        IAnimal* pAnimal = 0;
        hr = WrapWithAlternateCredentials( mqi.pItf,
                                           pszAuthority,
                                           pszPrincipal,
                                           pszPassword,
                                           IID_IAnimal, (void**)&pAnimal );
        if ( SUCCEEDED( hr ) )
        {
            pAnimal->Eat();          // Eat goes out as Bill
            pAnimal->Sleep();        // Sleep goes out as Bill
            ISwimmer* pSwimmer = 0;  // QI goes out as Bill
            hr = pAnimal->QueryInterface( IID_ISwimmer, (void**)&pSwimmer );
            if ( SUCCEEDED( hr ) )
            {
                pSwimmer->Dive();    // Dive goes out as Bill
                pSwimmer->Swim();    // Swim goes out as Bill
                pSwimmer->Release(); // This Release doesn't send packets
            }
            pAnimal->Release();      // Release goes out as Bill,
        }                            // only if OS >= NT4SP4
    }
    return hr;
}

void main()
{
    CreateAndUsePenguinAsUser(  L"OvalOffice",  // machine name
                                L"US",          // authority
                                L"BillClinton", // principal
                                L"notacrook" ); // password
}


Figure 10   DO_MBV_XXX Summary

DO_MBV_XXX Options
MBV Boundary
INPROC
This Process
INPROC | LOCAL
This Machine
INPROC | LOCAL | DIFFERENTMACHINE
No Boundary