Share via


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