Click here to Skip to main content
15,887,338 members
Articles / Desktop Programming / MFC
Article

Class to Determine a Local Machine's IP Address

Rate me:
Please Sign up or sign in to vote.
2.80/5 (5 votes)
23 Aug 20022 min read 95.2K   1.5K   17   14
This is a class for determining a local machine's IP address using iphlpapi or sockets and to convert between a couple of standard formats

Introduction

I would like to thank Igor Proskuriakov, Len Holgate, and Farooque Khan. My purpose for this class is to programatically determine the IP address that is assigned to a local machine. This class will return the machine's IP address in the form of a CString, a DWORD in host byte order, and a DWORD in network byte order.

IPAddressBase Class Usage

An object of this class will contain an IP address value and perform format conversion. The IP address is stored in a CString. Member functions have been provided to converted the stored CString to a network byte order DWORD or host byte order DWORD. The default constuctor initializes the class's data member m_csAddress to "127.0.0.1".
void SetHBO(DWORD dwInValue);
Member function SetHBO(DWORD dwInValue) takes a DWORD value(in host byte order) and coverts the value to a CString. The CString equivalent is then stored in m_csAddress;
void SetNBO(DWORD dwInValue);
Member function SetNBO(DWORD dwInValue) takes a DWORD value(in network byte order) and coverts the value to a CString. The CString equivalent is then stored in m_csAddress;
void SetString(CString csInString);
Member function SetString(CString csInString) takes a CString and stores the value in m_csAddress;
DWORD GetHBO()const;
Member function GetHBO()const coverts m_csAddress to a DWORD in host byte order and returns that converted value.
DWORD GetNBO()const;
Member function GetNBO()const coverts m_csAddress to a DWORD in network byte order and returns that converted value.
CString GetString()const;
Member function GetString()const returns m_csAddress.

LocalIPQuery Class Usage

This class performs the extraction of the machine's IP address/addresses. This class contains two different methods for extraction that are programmer selectable with conditional compilation. The container that holds the extracted IP address/addresses is a STL vector.

The LIPQ_MULTI method is derived from Farooque Khan's "Using IP Helper API’s" article. This method takes the local machine's TCP/IP table and extracts each active unique IP address on the local machine. The extracted values are stored as IPAddressBase objects in the vector.

The LIPQ_PORTABLE method is from http://tangentsoft.net/wskfaq/examples/ipaddr.html. This method extracts the local machine IP address from a socket it creates. The extracted value is stored as an IPAddressBase object in the vector. This method will only extract a single IP address, but it is portable since it uses sockets.

Selection of the methods is done in the LocalIPQuery.h file.

To use LIPQ_MULTI verify that the LocalIPQuery header file is configured as follows before compiling

// User must choose which method they want to use
//#define USE_THIS	LIPQ_PORTABLE
#define USE_THIS	LIPQ_MULTI
To use LIPQ_PORTABLE verify that the LocalIPQuery header file is configured as follows before compiling
// User must choose which method they want to use
#define USE_THIS	LIPQ_PORTABLE
//#define USE_THIS	LIPQ_MULTI

The Dialog App

The dialog app shows the extracted IP address/addresses and one way of using the LocalIPQuery class with an IP Address Control.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralThings to improve. Pin
Len Holgate21-Aug-02 0:10
Len Holgate21-Aug-02 0:10 
I'll try and be gentle...

1) C++ classes that have documentation that says things like 'must call X before calling this method' are bad. They're fragile, people will use them wrongly because they can. Most of the time there's no need to build classes that are this fragile. In this particular instance you can remove this problem by using the class's constructor for the purpose that it was intended. That is to construct the class! To do this you move all of the code in GetLocalIP() into the ctor. This means that you can no longer return an error value if the code in GetLocalIP() fails because a ctor cant return an error. To overcome this you should throw an exception on failure. You now have a situation where you can create your object and call all of the methods without needing to document that you have to call GetLocalIP() first. If the class encounters errors during its construction then an exception is thrown and the class never exists so methods can never be called.

2) Multiplexing error returns into return values. Bad programmer. So, how does a client of this class know that the call to the now defunct GetLocalIP() method had failed? He parses it for "Error:" ? Don't return things that can be either a valid result or an error indicator, split it up. In this case take a string by reference to return the ip address in, perhaps, and return a boolean, or an error code.

3) Names of methods. MemberStringToComponents() we're dealing with an IP address, why does a client of the class need to know, or care that this is stored as a string member of the class. A better name might be something like AsComponents(). Likewise, GetHBOIPAddress(), could be AsDWORDInHostByteOrder() or probably something better.... We know it's an IP Address because that's what the class does....

4) Make the class minimal and complete. You probably dont need the host and network byte order methods as winsock provides a conversion that people can use... So you could probably ditch one of them.

5) Know what exists and use it rather than rolling your own. StringToInt(), atoi(), nuf said.

6) m_converter? Hmm, nah. For a start all of the methods should be static as they dont reference any instance data. Then we have the question, why are these better placed in their own class? why not part of the IP address class? And even if we decide to leave them as their own class now that they're static we can access them directly rather than having a member variable...

6) Code duplication, two copies of StringToInt()? Bad programmer. Remove one.

7) Unnecessary work. Why do you convert the network byte order address to a string and then the string to a network byte order dword and then the string to a host byte order dword?

8) nErrFlag, what's all that about then. Why not just use indentation within the if's rather than setting an error flag (which isnt really a "flag" anyway as it can have more than 2 values...) and switching on that (sometimes, but not always) and then ignoring it. Anyway, we could end up with something cleaner, like, perhaps, the code below (which hasnt seen a compiler).
bool LocalIPQuery::GetLocalIP()
{
   bool ok = false;

   WSAData wsaData;
   if (WSAStartup(MAKEWORD(1, 1), &wsaData) == 0) 
   {
      char ac[80];
      if (gethostname(ac, sizeof(ac)) != SOCKET_ERROR) 
      {
         m_csHostName = ac;
         struct hostent *phe = gethostbyname(ac);
         
         if (phe) 
	 {
            // need a check here to ensure that it is an in_addr...
            // why do we loop and convert all addresses, overwriting as we go?

            for (int i = 0; phe->h_addr_list[i] != 0; ++i) 
            {
               m_csLocalAddress = inet_ntoa((in_addr)phe->h_addr_list[i]);

               ok = true;
            }

            m_dwHostByteOrderLocalAddress = m_Converter.StringToHBO(csReturn);
            m_dwNetworkByteOrderLocalAddress = m_Converter.StringToNBO(csReturn);
        }

	WSACleanup();
   }
   return ok;
}

9) If you must use hungarian warts use them consistently. In StringToInt() why is the loop index nLoop (crap name, but, well, whatever), yet Return and StringLength arent nReturn and nStringLength...

10) Err, return this->m_csLocalAddress; what's with that then?

So, overall, 2/10, must try harder.

Read these books on general coding and these ones on C++ then rewrite your article and we'll go through the process again.

Wink | ;)

Len Holgate
www.jetbyte.com
The right code, right now.
GeneralRe: Things to improve. Pin
Igor Proskuriakov21-Aug-02 6:47
Igor Proskuriakov21-Aug-02 6:47 
GeneralRe: Things to improve. Pin
Len Holgate21-Aug-02 6:57
Len Holgate21-Aug-02 6:57 
GeneralRe: Things to improve. Pin
niverson24-Aug-02 14:32
niverson24-Aug-02 14:32 
GeneralRe: Things to improve. Pin
Len Holgate24-Aug-02 23:03
Len Holgate24-Aug-02 23:03 
GeneralRe: Things to improve. Pin
vmihalj13-Aug-03 22:59
vmihalj13-Aug-03 22:59 
GeneralUseless Pin
Igor Proskuriakov20-Aug-02 3:38
Igor Proskuriakov20-Aug-02 3:38 
GeneralRe: Useless Pin
Daniel Turini20-Aug-02 4:00
Daniel Turini20-Aug-02 4:00 
GeneralRe: Useless Pin
Igor Proskuriakov21-Aug-02 6:39
Igor Proskuriakov21-Aug-02 6:39 
GeneralRe: Useless Pin
niverson20-Aug-02 4:17
niverson20-Aug-02 4:17 
General192.168.x.x Pin
Swinefeaster19-Aug-02 10:52
Swinefeaster19-Aug-02 10:52 
GeneralRe: 192.168.x.x Pin
niverson19-Aug-02 13:40
niverson19-Aug-02 13:40 
GeneralRe: 192.168.x.x Pin
David Simmonds20-Aug-02 5:00
David Simmonds20-Aug-02 5:00 
GeneralRe: 192.168.x.x Pin
Neville Franks20-Aug-02 12:07
Neville Franks20-Aug-02 12:07 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.