Usar la devolución de llamada de notificación de eventos
En el procedimiento siguiente se describen los pasos que el cliente debe usar para recibir mensajes de notificación de cambios de la RTM_EVENT_CALLBACK. El código de ejemplo siguiente muestra cómo implementar el procedimiento.
Recuperación de los mensajes de notificación de cambios
- Llame a RtmGetChangedDests para recuperar un conjunto de cambios.
- Procese los cambios.
- Libere los destinos mediante RtmReleaseChangedDests.
- Repita los pasos 1, 2 y 3 hasta que RtmGetChangedDests devuelva ERROR_NO_MORE_ITEMS.
En el código de ejemplo siguiente se muestra cómo procesar una devolución de llamada RTM_EVENT_CALLBACK recibida del administrador de tablas de enrutamiento.
#include <windows.h>
#include <ras.h>
// Macro to allocate an RTM_DEST_INFO on the stack
#define ALLOC_RTM_DEST_INFO(NumViews, NumInfos)
(PRTM_DEST_INFO) _alloca(RTM_SIZE_OF_DEST_INFO(NumViews) * NumInfos)
// Routing table manager entity event callback
DWORD
EntityEventCallback (
IN RTM_ENTITY_HANDLE RtmRegHandle,
IN RTM_EVENT_TYPE EventType,
IN PVOID Context1,
IN PVOID Context2
)
{
RTM_ENTITY_HANDLE EntityHandle;
PENTITY_CHARS EntityChars;
PRTM_ENTITY_INFO EntityInfo;
RTM_NOTIFY_HANDLE NotifyHandle;
PRTM_DEST_INFO DestInfos;
ULONG DestInfoSize;
UINT NumDests;
UINT NumViews, i;
UINT MaxHandles;
RTM_ROUTE_HANDLE RouteHandle;
PRTM_ROUTE_INFO RoutePointer;
DWORD ChangeFlags;
DWORD Status;
Print("\nEvent callback called for %p :", RtmRegHandle);
Print("\n\tEntity Event = ");
Status = ERROR_NOT_SUPPORTED;
switch (EventType)
{
case RTM_ENTITY_REGISTERED:
// Get the handle and information of the entity that registered
EntityHandle = (RTM_ENTITY_HANDLE) Context1;
EntityInfo = (PRTM_ENTITY_INFO) Context2;
Print("Registration\n\tEntity Handle = %p\n\tEntity IdInst = %p\n\n",
EntityHandle,
EntityInfo->EntityId);
// Do something if you are interested in the entity
;
Status = NO_ERROR;
break;
case RTM_ENTITY_DEREGISTERED:
// Get the handle and information of the entity that deregistered
EntityHandle = (RTM_ENTITY_HANDLE) Context1;
EntityInfo = (PRTM_ENTITY_INFO) Context2;
Print("Deregistration\n\tEntity Handle = %p\n\tEntity IdInst = %p\n\n",
EntityHandle,
EntityInfo->EntityId);
// Do something if you are interested in the entity
;
Status = NO_ERROR;
break;
case RTM_CHANGE_NOTIFICATION:
// Get the notification registration on which changes exist and
// context supplied in RtmRegisterForChangeNotification
NotifyHandle = (RTM_NOTIFY_HANDLE) Context1;
NotifyContext = (PVOID) Context2; // Unused
Print("Changes Available\n\tNotify Handle = %p\n\tNotify Context = %p\n\n",
NotifyHandle,
NotifyContext);
MaxHandles = RegnProfile.MaxHandlesInEnum;
NumViews = RegnProfile.NumberOfViews;
DestInfoSize = RTM_SIZE_OF_DEST_INFO(NumViews);
// Get all changes to destinations
DestInfos = ALLOC_RTM_DEST_INFO(NumViews, MaxHandles);
do
{
// Try to get as many as possible in one routing table managercall
NumDests = MaxHandles;
Status = RtmGetChangedDests(RtmRegHandle,
NotifyHandle,
&NumDests,
DestInfos);
ASSERT((Status == NO_ERROR) || (Status == ERROR_NO_MORE_ITEMS));
DestInfo = (PRTM_DEST_INFO) DestInfos;
for (i = 0; i < NumDests; i++)
{
// Process the current destination information
// Assuming you asked for unicast view information,
ASSERT(DestInfo->ViewInfo[0].ViewId == RTM_VIEW_ID_UCAST);
// Get the best unicast route for the destination.
NewBestRoute = DestInfo.ViewInfo[0].Route;
// Do whatever you want with above route
...
// Move to the next changed one
DestInfo = (PRTM_DEST_INFO) ((PUCHAR)DestInfo + DestInfoSize);
}
RtmReleaseChangedDests(RtmRegHandle,
NotifyHandle,
NumDests,
DestInfos);
}
while (NumDests > 0);
Status = NO_ERROR;
break;
case RTM_ROUTE_EXPIRED:
// Get handle and a direct pointer to the route whose timer expired
RouteHandle = (RTM_ROUTE_HANDLE) Context1;
RoutePointer = (PRTM_ROUTE_INFO) Context2;
Print("Route Aged Out\n\tRoute Handle = %p\n\tRoute Pointer = %p\n\n",
RouteHandle,
RoutePointer);
// To just let the routing table manager delete the route, return ERROR_NOT_SUPPORTED
// If you return any other value, the routing table manager assumes that you have
// handled the time-out condition in callback for route timer expiration
// Suppose we just want to update the metric and leave the route
Status = RtmLockRoute(RtmRegHandle,
RouteHandle,
TRUE,
TRUE,
NULL);
// Check(Status, 46);
if (Status == NO_ERROR)
{
// Set the metric to indicate that it is unreachable
RoutePointer->PrefInfo.Metric = METRIC_UNREACHABLE;
Status = RtmUpdateAndUnlockRoute(RtmRegHandle,
RouteHandle,
INFINITE, // To stay forever
NULL,
0,
NULL,
&ChangeFlags);
ASSERT(Status == NO_ERROR);
}
// If ERROR_NOT_SUPPORTED not returned, release the handle
RtmReleaseRoutes(RtmRegHandle, 1, &RouteHandle);
Status = NO_ERROR;
break;
}
return Status;
}