Implementing IAppHostPathMapper in C

Few days ago I was required to implement IAppHostPathMapper interface in native C to map configuration path MACHINE/WEBROOT/APPHOST to DefaultAppPool.config and struggled with finding good documentation. With help of some incomplete, hard to find documentation and some head banging here is what worked for me. Hopefully this will be useful for few others J.

#include <ahadmin.h>

//
// PathMapper object structure with VTable pointer and reference counter
// Add other private data in this structure
//
typedef struct TestPathMapper
{
    IAppHostPathMapperVtbl * lpVtbl;
    ULONG                    cRef;
} TestPathMapper;

//
// Method definitions
//
STDMETHODIMP TestPathMapper_QueryInterface(TestPathMapper *, REFIID, LPVOID FAR *);
STDMETHODIMP_(ULONG) TestPathMapper_AddRef(TestPathMapper *);
STDMETHODIMP_(ULONG) TestPathMapper_Release(TestPathMapper *);
STDMETHODIMP TestPathMapper_MapPath(TestPathMapper *, BSTR, BSTR, BSTR *);

//
// IAppHostPathMapper VTable structure
//
static const IAppHostPathMapperVtbl vtblTestPathMapper =
{
    TestPathMapper_QueryInterface,
    TestPathMapper_AddRef,
    TestPathMapper_Release,
    TestPathMapper_MapPath
};

STDMETHODIMP
TestPathMapper_QueryInterface(
    TestPathMapper * pThis,
    REFIID           riid,
    LPVOID FAR *     lppvObj
)
{
    if ( !pThis || pThis->lpVtbl != &vtblTestPathMapper || !lppvObj )
    {
        return E_INVALIDARG;
    }

    if ( !memcmp(riid, &IID_IUnknown, sizeof( IID ) ) ||
         !memcmp(riid, &IID_IAppHostPathMapper, sizeof( IID ) ) )
    {
        pThis->lpVtbl->AddRef( pThis );
        *lppvObj = pThis;

        return S_OK;
    }

    *lppvObj = NULL;
    return E_NOINTERFACE;
}

STDMETHODIMP_(ULONG)
TestPathMapper_AddRef(
    TestPathMapper * pThis
)
{
    if (!pThis || pThis->lpVtbl != &vtblTestPathMapper)
    {
        return 1;
    }

    return InterlockedIncrement( &pThis->cRef );
}

STDMETHODIMP_(ULONG)
TestPathMapper_Release(
    TestPathMapper * pThis
)
{
    LONG cRef;   
    if ( !pThis || pThis->lpVtbl != &vtblTestPathMapper )
    {
        return 1;
    }

    cRef = InterlockedDecrement( &pThis->cRef );
    if (cRef == 0)
    {
        pThis->lpVtbl->Release(pThis);
        pThis->lpVtbl = NULL;
        free( pThis );
    }

    return cRef;
}

STDMETHODIMP
TestPathMapper_MapPath(
    TestPathMapper * pThis,
    BSTR             bstrConfigPath,
    BSTR             bstrMappedPhysicalPath,
    BSTR *           pbstrNewPhysicalPath
)
{
    BSTR bstrNewPath  = NULL;
    if ( !pThis || pThis->lpVtbl != &vtblTestPathMapper )
    {
        return E_INVALIDARG;
    }

    if( wcscmp( bstrConfigPath, L"MACHINE/WEBROOT/APPHOST" ) == 0 )
    {
        bstrNewPath = SysAllocString( L"%systemdrive%\\inetpub\\temp\\apppools\\DefaultAppPool.config" );
    }
    else
    {
        bstrNewPath = SysAllocString( bstrMappedPhysicalPath );
    }

    if( bstrNewPath == NULL )
    {
        return E_OUTOFMEMORY;
    }

    *pbstrNewPhysicalPath = bstrNewPath;
    return S_OK;
}

int _tmain(
    int argc,
    _TCHAR* argv[]
)
{
    HRESULT   hr        = S_OK;
    DWORD     dwCount   = 0;
    VARIANT   varUnknown;

    TestPathMapper *            pTestPathMapper    = NULL;
    IAppHostAdminManager *      pAMgr              = NULL;
    IAppHostElement *           pElement           = NULL;
    IAppHostElementCollection * pElementCollection = NULL;   

    BSTR bstrPathMapper       = SysAllocString( L"pathMapper" );
    BSTR bstrConfigPath       = SysAllocString( L"MACHINE/WEBROOT/APPHOST" );
    BSTR bstrSitesSectionName = SysAllocString( L"system.webServer/caching" );

    if( bstrPathMapper == NULL || bstrConfigPath == NULL || bstrSitesSectionName == NULL )
    {
        hr = E_OUTOFMEMORY;
        goto Finished;
    }

    hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
    if( FAILED(hr) )
    {
        goto Finished;
    }

    hr = CoCreateInstance( &CLSID_AppHostAdminManager,
                           NULL,
                           CLSCTX_INPROC_SERVER,
                           &IID_IAppHostAdminManager,
                           (void**) &pAMgr );
    if( FAILED( hr ) )
    {
        goto Finished;
    }

    //
    // Create pathMapper structure
    //
    pTestPathMapper = (TestPathMapper *)malloc( sizeof( TestPathMapper ) );
    if( pTestPathMapper == NULL )
    {
        hr = E_OUTOFMEMORY;
        goto Finished;
    }

    pTestPathMapper->lpVtbl = &vtblTestPathMapper;
    pTestPathMapper->cRef   = 1;

    VariantInit(&varUnknown);

    V_VT(&varUnknown)      = VT_UNKNOWN;
    V_UNKNOWN(&varUnknown) = pTestPathMapper;

    //
    // Set pathMapper metadata
    //
    hr = pAMgr->lpVtbl->SetMetadata( pAMgr, bstrPathMapper, varUnknown );
    if( FAILED( hr ) )
    {
        goto Finished;
    }

    //
    // Get the sites section and get number of sites
    //
    hr = pAMgr->lpVtbl->GetAdminSection( pAMgr, bstrSitesSectionName, bstrConfigPath, &pElement );
    if( FAILED( hr ) || pElement == NULL )
    {
        goto Finished;
    }

    hr = pElement->lpVtbl->get_Collection( pElement, &pElementCollection );
    if( FAILED( hr ) || pElementCollection == NULL )
    {
        goto Finished;
    }

    hr = pElementCollection->lpVtbl->get_Count( pElementCollection, &dwCount );
    if( FAILED( hr ) )
    {
        goto Finished;
    }

    wprintf( L"%d\n", dwCount );

Finished:

    VariantClear(&varUnknown);

    if( pElementCollection != NULL )
    {
        pElementCollection->lpVtbl->Release( pElementCollection );
        pElementCollection = NULL;
    }

    if( pElement != NULL )
    {
        pElement->lpVtbl->Release( pElement );
        pElement = NULL;
    }

    if( pAMgr != NULL )
    {
        pAMgr->lpVtbl->Release( pAMgr );
        pAMgr = NULL;
    }

    SysFreeString( bstrPathMapper );
    SysFreeString( bstrConfigPath );
    SysFreeString( bstrSitesSectionName );

    CoUninitialize();
    return 0;
}

Thanks.
Kanwal

Leave a Reply

Your email address will not be published. Required fields are marked *