getaddrinfo() breaks applications migrated from Visual Studio 6.0

Here’s a problem CoolSoft Inc faced when migrating CoolApp - their flagship product.
CoolApp is an MFC application that sends some data to a server. It was developed in VC6 and winsock2 and it’s been running for quite a while now. CoolSoft wanted to upgrade CoolApp and recompiled the app in Visual Studio.Net 2003. The migration went fine. The app was also running perfectly. That’s when someone found that CoolApp doesn’t work anymore in Windows 2000 and Windows 98. In fact CoolApp worked only in Windows XP and Windows 2003. It used to work on almost all flavors in its earlier life. CoolApp threw up the following error message in Windows 2000.
“The procedure entry point getaddrinfo could not be located in the dynamic link library WS2_32.dll”
CoolSoft wants to know what the issue is, why wasn’t it occurring earlier and how can this be fixed ?

As per the MSDN Documentation for getaddrinfo, In Windows 2003 and Windows XP the function is defined in ws2tcpip.h and for all other OSs it is defined in wspiapi.h
The ws2tcpip.h file declares the getaddrinfo function and expects the application to link with the ws2_32.dll. However, wspiapi.h provides a hack for this function by defining the function as a macro.

#define getaddrinfo WspiapiGetAddrInfo

The ws2tcpip.h file that was part of Visual Studio 6 or the platform SDKS that came before Visual studio.Net did not have the getaddrinfo function defined. So the definition from wspiapi.h was automatically included. So everything works fine. But with VS.NET 2003 the new ws2tcpip.h is included and the resulting application will depend on getaddrinfo being available in ws2_32.dll. The ws2_32.dll doesn’t have a ‘getaddrinfo’ function in its non XP and non Windows 2003 versions. So when the app is run in any of the pre XP platforms, we get the error message.

To fix this, include the wspiapi.h file explicitly in the source files that call getaddrinfo.

Note : The issue and the workaround applies to the following scenarios too
1) The ‘freeaddrinfo’ function.
2) Apps written and compiled in VS.NET 2002 or higher.

Comments

  • Anonymous
    April 03, 2006
    I'm having this problem with a VS C++ app I wrote that consumes a Web Service gereated with the Add Web Reference Wizard.  The bug occured as soon as I added the Web Service code.  Since I'm not directly calling the getaddrinfo function, how do I #include "wspiapi.h" ??? Where do I include it???
  • Anonymous
    April 03, 2006
    Hi Sherwin,

    I guess ATL is pulling the ws2tcpip.h file from the "AtlSocket.h" header file. You can do the following as a workaround - make a copy of this atlsocket.h file and include the wspiapi.h header file definition in that. Everything else in that file should remain the same. Backup the original atlsocket.h and use the modified version of atlsocket.h. Things should work now.

    Do let me know the results.
  • Anonymous
    August 13, 2006
    The following program failed on Windows 2000+SP4, but works on Windows XP or Windows 2003.

    #include <winsock2.h>
    #include <ws2tcpip.h>

    int init_winsock(void);
    void uninit_winsock(void);

    int main(void)
    {
    char *port = "27015";
    struct addrinfo hints;
    struct addrinfo *aiList = NULL;
    DWORD dwAddress = 0;
    int i, j, k, m;
    char ip[64];
    int retVal;

    if (init_winsock() < 0)
    return 1;

    memset(&hints, 0, sizeof(hints));

    hints.ai_flags = AI_NUMERICHOST;
    hints.ai_family = PF_UNSPEC;
    hints.ai_socktype = 0;
    hints.ai_protocol = 0;
    hints.ai_addrlen = 0;
    hints.ai_canonname = NULL;
    hints.ai_addr = NULL;
    hints.ai_next = NULL;

    sprintf(ip, "255.255.255.255");
    if (getaddrinfo(ip, port, &hints, &aiList) != 0)
       {
      printf("getaddrinfo() failed for %s. errno: %dn",
    ip,
    GetLastError());
    }
    else
    {
    freeaddrinfo(aiList);
    }

    uninit_winsock();
    return 0;
    }

    int init_winsock(void)
    {
    #ifdef WIN32
       WORD wVersionRequested;
       WSADATA wsaData;

           wVersionRequested = MAKEWORD(2, 2);
           WSAStartup(wVersionRequested, &wsaData);
       if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2)
       {
           printf("cannot load WinSock library: %dn", GetLastError());
           return -1;
       }
    #endif
       return 0;
    }

    void uninit_winsock(void)
    {
    #ifdef WIN32
       WSACleanup();
    #endif
    }
  • Anonymous
    November 19, 2007
    Reply to Web Reference issue of Sherwin, remove the follow lines in the project's stdafx.h, and then rebuild your project. It will be ok. // Modify the following defines if you have to target a platform prior to the ones specified below. // Refer to MSDN for the latest info on corresponding values for different platforms. #ifndef WINVER // Allow use of features specific to Windows XP or later. #define WINVER 0x0501 // Change this to the appropriate value to target other versions of Windows. #endif #ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.                   #define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows. #endif #ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later. #define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later. #endif #ifndef _WIN32_IE // Allow use of features specific to IE 6.0 or later. #define _WIN32_IE 0x0600 // Change this to the appropriate value to target other versions of IE. #endif