Friday 1 October 2010

Safely including "winsock2.h" and "windows.h" at the same time.

Today, I learned that including "windows.h" and "winsock2.h" at the same time can cause compile-time errors. As soon as I included "winsock2.h" the compiler started complaining about some symbols being redefined.

It turns out that
  • "windows.h" includes "winsock.h" and
  • "winsock.h" and "winsock2.h" contain definitions of some of the same symbols.
So if you include both "windows.h" and "winsock2.h" some symbols may be redefined. I say "may be redefined" because there are ways to prevent this.

Solution #1
The first solution I considered was to make sure "winsock2.h" is included before "windows.h".

This works because "winsock2.h" defines _WINSOCKAPI_ which prevents the compiler from seeing the contents of "winsock.h" ("winsock.h" is guarded by the following):

#ifndef _WINSOCKAPI_
#define _WINSOCKAPI_

...
Contents of winsock.h
...

#endif  /* _WINSOCKAPI_ */

So if _WINSOCKAPI_ is already defined, the entire file is skipped.

I didn't really like this solution because I don't like relying on header files being included in any particular order (and it's just too much hassle).

Solution #2
The second solution, which I discovered while searching on the Internet, is to define WIN32_LEAN_AND_MEAN before including "windows.h".

This works because defining WIN32_LEAN_AND_MEAN prevents "windows.h" from including several header files (including "winsock.h").

I almost used this solution, but I was concerned that it was doing more than I really need. It was preventing "windows.h" from including a number of header files, not just the one I wanted.

Solution #3
The solution I decided to use was to define _WINSOCKAPI_ before including "windows.h".

This works for the same reason Solutions #1 works, it prevents the compiler from seeing the contents of "winsock.h".

Not Perfect
Solution #3 is not quite perfect because I still have to make sure to define _WINSOCKAPI_ before including "windows.h".

The perfect solution I think would be for Microsoft to modify "windows.h" so that the inclusion of "winsock.h" is conditional on a symbol being undefined. For example:

#ifndef WIN32_NO_WINSOCK_H
#include #include <winsock.h>
#endif