SOL9 2.0 Class: IPInterfaceChangeNotifier

 SOL9 C++ Class Library  SOL9 Samples  SOL9 Tutorial  SOL9 FAQ  SOL9 ClassTree 

Source code

/*
 * IPInterfaceChangeNotifier.h 
 * Copyright (c) 2011 Antillia.com TOSHIYUKI ARAI. ALL RIGHTS RESERVED. 
 */



// SOL9
// 2009/08/29
//
// 2009/09/26 Added initialNotification parameter to Constructors.
#pragma once

//#include <sol\WSAInitializer.h>
#include <sol\Thread.h>

#include <sol\net\IPInterfaceTable.h>
#include <sol\StringBuffer.h>
#include <sol\LocalDateTime.h>
#include <process.h>


#define WM_IPINTERFACE_CHANGE_NOTIFER_CLOSED     (WM_USER + 2012)

namespace SOL {


class IPInterfaceChangeNotifier :public Thread {

private:
    HANDLE termEvent;

private:
    bool looping;

private:
    HANDLE hNotification;
    
private:
    DWORD threadIdNotified;

private:
    HWND  hwndNotified;

private:
    bool deleteInstance;

private:
    ADDRESS_FAMILY family;

    //2009/09/26
private:
    BOOL initialNotification;

public:
    /**
     * Constructor
     * @param threadId    Thread ID to receive a windows message to notify IPInterfaceChanged event.
     * @param initialNotify Initial Notification.  
     */
    IPInterfaceChangeNotifier(DWORD threadId, bool delInstance=false, 
        ADDRESS_FAMILY f=AF_UNSPEC, BOOL notify=FALSE) 
    :Thread(),
     looping(false),
     hNotification(NULL),
     threadIdNotified(threadId),
     hwndNotified(NULL),
     termEvent(NULL),
     deleteInstance(delInstance),
     family(f),
     initialNotification(notify)
    {
        termEvent = CreateEvent(0, FALSE, FALSE, 0);
    }


public:
    /**
     * Constructor
     * @param hwnd    Window handle to receive a windows message to notify IPInterfaceChanged event.
     * @param initialNotify Initial Notification.  
     */
    IPInterfaceChangeNotifier(HWND hwnd, bool delInstance=false, 
        ADDRESS_FAMILY f=AF_UNSPEC, BOOL notify=FALSE)
    :Thread(),
     looping(false),
     hNotification(NULL),
     threadIdNotified(0),
     hwndNotified(hwnd),
     termEvent(NULL),
     deleteInstance(delInstance),
     family(f),
      initialNotification(notify)
    {
        termEvent = CreateEvent(0, FALSE, FALSE, 0);    
    }


public:
    ~IPInterfaceChangeNotifier() 
    {
        close();
    }


private:
    void close()
    {
        if (termEvent) {
            CloseHandle(termEvent);
            termEvent = NULL;
        }
        if (hNotification) {
            CancelMibChangeNotify2(hNotification);
            hNotification = NULL;
        }
    }


public:
    // Set termEvent to stop the run method loop.
    void stop() 
    {
        SetEvent(termEvent);
        looping  = false;
    }

public:
    // Set termEvent to stop the run method loop.
    HANDLE getStopEvent() 
    {
        return termEvent;
    }

private:
    //Static Callback function for NotifyIpInterfaceChange API.

    static void WINAPI InterfaceChangeCallback(PVOID callerContext,
            PMIB_IPINTERFACE_ROW row,
            MIB_NOTIFICATION_TYPE notificationType)
    {
        IPInterfaceChangeNotifier* notifier = (IPInterfaceChangeNotifier*)callerContext;

        if (notifier) {
            //Call an instance method of class IPInterfaceChangeNotifier.
            notifier ->interfaceChanged(row, notificationType);
        }
    }


public:
    const char* getFamily(int family)
    {
        const char* name = "";

        if (family == AF_INET) {
            name = "IPv4";    
        }
        if (family == AF_INET6) {
            name = "IPv6";
        }
        return name;
    }

public:
    const char* getNotificationType(int type)
    {
        static const char* names[] = {
        "ParameterNotification",
        "AddInstance",
        "DeleteInstance",
        "InitialNotification" 
        };

        const char* name = "";
        if (type >=0 && type < XtNumber(names)) {
            name = names[type];
        }
        return name;
    }

public:
    /*
    When the callback function is received when a change occurs and the Row parameter is not NULL, 
    the pointer to the MIB_IPINTERFACE_ROW structure passed in the Row parameter contains incomplete data. 
    The information returned in the MIB_IPINTERFACE_ROW structure is only enough information that 
    an application can call the GetIpInterfaceEntry function to query complete information on the 
    IP interface that changed.  This comes from Microsoft's document. 
     */
    virtual void interfaceChanged(
            PMIB_IPINTERFACE_ROW row,
            MIB_NOTIFICATION_TYPE notificationType)
    {
        const char* family = "Unknown";
        if (row) {
            //Is row is not NULL?
            family = getFamily(row->Family);

            const char* notification = getNotificationType(notificationType);

            LocalDateTime ldt;
            StringT<char> localTime;
            ldt.nowToSeconds(localTime);
            printf("<%s %sNotification : %s>\n", (const char*)localTime,  family, notification);

            //We have to get complete information for row of MIB_IPINTERFACE_ROW  
            GetIpInterfaceEntry(row);

            display(notification, *row);

            printf("\n");
        }
    }

public:
    // This is a virtual display member function.
    // If needed to display a row data in a window, please redfine this method 
    //in your subclass which inherits this class.
    virtual void display(const char* notification, 
                MIB_IPINTERFACE_ROW& row)
    {
        IPInterfaceTable ipIfTable;

        //Display row data on the command prompt window by using printf.
        ipIfTable.display(row);
    }


public:
    /**
     * Thread procedure to get notification of IPInterfaceChanges. 
     */
    void run()
    {
        HANDLE waitEvents[1];
        waitEvents[0] = this->termEvent;

        this->looping = true;
    
        hNotification = NULL;

        //Path this pointer for the third parameter as a callerContext. 
        //
        if (NotifyIpInterfaceChange(family, 
            (PIPINTERFACE_CHANGE_CALLBACK)InterfaceChangeCallback, 
            this, 
            initialNotification, //FALSE, 2009/09/26 
            &hNotification) == NO_ERROR) {

            while (looping) {
            
                int r = WaitForMultipleObjects(1, waitEvents, FALSE, INFINITE); 
                if (r == WAIT_OBJECT_0 ) {
                    printf("\nTerminateEvent has been set, so break this thread loop\n");
                    break;
                }            
            }
        }

        if (hwndNotified) {
            if (IsWindow(hwndNotified)) {
                PostMessage(hwndNotified, WM_IPINTERFACE_CHANGE_NOTIFER_CLOSED, 0, 0);
            }
        }

        if (deleteInstance) {
            delete this;
        }
    }

};

}

Last modified: 1 Feb 2012

Copyright (c) 2009-2012 Antillia.com ALL RIGHTS RESERVED.