Monitoring Change Notifications in ABO

Custom administration applications sometimes need to know when the IIS metabase is updated so that it can log changes, update information, or make other decisions based on changes to specific metabase nodes or properties.

Example Code

The following example shows you how to use the C++ programming language to register an application to receive IIS metabase change notifications and then display change notifications as it receives them.

#define STRICT 
#define INITGUID 

#include <WINDOWS.H> 
#include <WINBASE.H> 
#include <OLE2.H> 
#include <coguid.h> 

#include <stdio.h> 
#include <stdlib.h> 
#include <signal.h> 

#include "iadmw.h" 
#include "iiscnfg.h" 
#include "notify.h" 
#include "threadid.h" 

HANDLE QuitEvent; 
IMSAdminBase * pcAdmCom = NULL; 

void __cdecl SignalHandler (int Signal) 
{ 
// Signal the event QuitEvent so that the program will exit 
SetEvent (QuitEvent); 

} 

BOOL bHangOnExit = FALSE; 
BOOL bLinger = FALSE; 
// default linger time is 5 seconds 
#define MD_NOTIFY_DEFAULT_LINGER_TIME 5000 
DWORD dwLingerTime = MD_NOTIFY_DEFAULT_LINGER_TIME; 


#define MAX(X,Y) X>Y?X:Y 


int PrintHelp() 
{ 
printf ( 
"Usage:\n" 
"  notify <machine name> [(-a|-f) [(-l|-r) [(-h|-p)]]] \n" 
"  \n"); 
return 2; 
} 


int __cdecl main (int argc, char * argv[]) 
{ 

HRESULT hRes; 
CImpIMSAdminBaseSink *pEventSink = new CImpIMSAdminBaseSink(); 
IConnectionPoint* pConnPoint = NULL; 
IConnectionPointContainer* pConnPointContainer = NULL; 
DWORD dwCookie; 
BOOL bSinkConnected = FALSE; 

DWORD dwThreadingModel = COINIT_MULTITHREADED; 
DWORD dwLocalOrRemote = 0; // 0 is local, 1 is remote 

OLECHAR rgchMachineName[MAX_PATH]; 
IClassFactory * pcsfFactory = NULL; 
COSERVERINFO csiMachineName; 
COSERVERINFO *pcsiParam = NULL; 

// Create an event that will trigger when the program is supposed to exit 
QuitEvent = CreateEvent ( 
NULL,// Security Attributes 
TRUE,// Manual reset selected 
FALSE,// Initial state - unset 
NULL);// Unnamed event 

// Set up the signal handler 
    signal (SIGINT, SignalHandler); 



if ((argc < 2) || (argc > 5)) 
{ 
PrintHelp (); 
return 1; 
} 

// get the threading model (apartment or free) 

if (argc > 2) 
{ 
if (toupper (argv[2] [1]) == 'A') 
{ 
printf ("Initializing Apartment Threaded\n"); 
dwThreadingModel = COINIT_APARTMENTTHREADED; 
} 
else 
printf ("Initializing Free Threaded\n"); 
} 

if (argc > 3) 
{ 
if (toupper (argv[3] [1]) == 'R') 
{ 
printf ("Initializing Remote (No Security)\n"); 
dwLocalOrRemote = 1; 
} 
else 
printf ("Initializing Local (Security)\n"); 
} 


if (argc > 4) 
{ 
if ( (!_stricmp(argv[4],"-h")) || (!_stricmp (argv[4], "/h")) ) 
{ 
printf ("Hanging Variation\n"); 
bHangOnExit = TRUE; 
} 
else if ( (!_strnicmp(argv[4],"-p", strlen ("-p"))) || (!_strnicmp(argv[4],"/p", strlen ("/p"))) ) 
{ 
if (strlen (argv[4]) > 3) 
{ 
DWORD dwTempLingerValue = atol (&(argv[4][3])); 
dwLingerTime = dwTempLingerValue * 1000; 
} 
printf ("Lingering Variation: %u\n", dwLingerTime); 
bLinger = TRUE; 
} 
else 
printf ("No Hanging Variation\n"); 

} 

printf ("Parameter 1: %s\n", argv[1]); 

pcsiParam = &csiMachineName; 
for (int i = 0; argv [1][i] != '\0'; i++) 
rgchMachineName[i] = (OLECHAR) (argv[1][i]); 

rgchMachineName[i] = 0; 

//fill the structure for CoGetClassObject 
csiMachineName.pwszName = rgchMachineName; 

csiMachineName.pAuthInfo = NULL; 
csiMachineName.dwReserved1 = 0; 
csiMachineName.dwReserved2 = 0; 
pcsiParam = &csiMachineName; 

hRes = CoInitializeEx(NULL, dwThreadingModel); 

if (FAILED(hRes)) 
{ 
printf("CoInitializeEx Failed: %d (%#x)\n", hRes, hRes); 
return 1; 
} 

hRes = CoInitializeSecurity( 
NULL,  
-1, 
NULL, 
NULL, 
RPC_C_AUTHN_LEVEL_NONE, 
//0, 
RPC_C_IMP_LEVEL_IMPERSONATE, 
NULL, 
EOAC_NONE, 
0); 

if (FAILED(hRes)) 
{ 
printf("CoInitializeSecurity Failed. Error: %u (%#x)\n", hRes, hRes); 
return 1; 
} 

hRes = CoGetClassObject(GETAdminBaseCLSID(TRUE), CLSCTX_SERVER, pcsiParam, 
IID_IClassFactory, (void**) &pCsfFactory); 

if (FAILED(hRes))  
{ 
puts ("ERROR: CoGetClassObject Failed(probably ADMCOM not registered locally)\n"); 
printf ("\tError Code: %#x\n", hRes); 

return 1; 
} 
else 
{ 
hRes = pcsfFactory->CreateInstance(NULL, IID_IMSAdminBase, (void **) &pCAdmCom); 
if (FAILED(hRes))  
{ 
printf ("ERROR: CreateInstance Failed! Return Code: %#x", hRes); 
pcsfFactory->Release(); 
return 1; 
} 
} 


// First query the object for its Connection Point Container. This 
// essentially asks the object in the server if it is connectable. 
hRes = pcAdmCom->QueryInterface( 
IID_IConnectionPointContainer, 
(PVOID *)&pConnPointContainer); 
if (SUCCEEDED(hRes)) 
{ 
// Find the requested Connection Point. This AddRef's the 
// returned pointer. 
hRes = pConnPointContainer->FindConnectionPoint(IID_IMSAdminBaseSink, &pConnPoint); 
if (SUCCEEDED(hRes)) 
{ 
hRes = pConnPoint->Advise((IUnknown *)pEventSink, &dwCookie); 
printf ("Sink Connect Result: %#x\n", hRes); 
if (SUCCEEDED (hRes)) 
bSinkConnected = TRUE; 
} 
else 
{ 
printf("Failed on calling IConnectionPointContainer::FindConnectionPoint. Error %#x\n", hRes); 
} 

// RELEASE_INTERFACE(pConnPointContainer); 
pConnPointContainer->Release(); 
} 
else 
{ 
printf("Failed to obtain IConnectionPointContainer. Error %#x\n", hRes); 
printf("Trying to obtain IConnectionPointContainer through casting ...\n"); 
pConnPointContainer = (IConnectionPointContainer *)pcAdmCom; 

// Find the requested Connection Point. This AddRef's the 
// returned pointer. 
hRes = pConnPointContainer->FindConnectionPoint(IID_IMSAdminBaseSink, &pConnPoint); 
if (SUCCEEDED(hRes)) 
{ 
hRes = pConnPoint->Advise((IUnknown *)pEventSink, &dwCookie); 
printf ("Sink Connect Result: %#x\n", hRes); 
if (SUCCEEDED (hRes)) 
bSinkConnected = TRUE; 
} 
else 
{ 
printf("Failed on calling IConnectionPointContainer::FindConnectionPoint. Error %#x\n", hRes); 
} 

pConnPointContainer->Release(); 
} 


    printf("\n****************************\n"); 
if (bSinkConnected) 
{ 
DWORD dwRefCount = 0; 

WaitForSingleObject (QuitEvent, INFINITE); 

// Pause to allow the other threads to shut down 
fflush (stdout); 
printf ("Pausing to allow sink threads to quit\n"); 
Sleep (20000); 

hRes = pConnPoint->Unadvise(dwCookie); 

printf("\n"); 

dwRefCount = pConnPoint->Release (); 
printf ("pConnPoint Ref Count after Release: %d\n", dwRefCount); 
dwRefCount = pcAdmCom->Release(); 
printf ("pcAdmCom Ref Count after Release: %d\n", dwRefCount); 
} 
else 
puts ("Not Connected to Sink!\n"); 

return ERROR_SUCCESS; 
}