What do we have in this chapter?
Winsock Tutorial
Winsock: Story 1Winsock: Story 2Winsock: Story 3Winsock: Example 1Winsock: Example 2Winsock: Example 3Winsock: Example 4Winsock: Example 5Winsock: Example 6Winsock: Example 7Winsock: Example 8Winsock: Example 9Winsock: Example 10Winsock: Example 11Winsock: Example 12Winsock: Reference 1Winsock: Reference 2Winsock: Reference 3Winsock: Reference 4Another Complete and Advanced C & Winsock2 Programming Tutorial |
My Training Period: xy hours
Machine’s OS is standalone Windows Xp Pro with SP2 except whenever mentioned. Compiler used was Visual C++ 2003 .Net 1.1. Beware the codes that span more than one line. Program examples have been tested for Non Destructive Test. All information compiled for Windows 2000 (NT5.0) above and...
Skills to be acquired:
Sending and Receiving (writing and reading) Data
The following code demonstrates the send() and recv() functions (TCP packet). For server program:
|
|
In this code, two integers are used to keep track of the number of bytes that are sent and received. The send() and recv() functions both return an integer value of the number of bytes sent or received, respectively, or an error. Each function also takes the same parameters: the active socket, a char buffer, and the number of bytes to send or receive, and any flags to use. Use recvfrom() and sendto() functions for the connectionless socket such as for the User Datagram Protocol (UDP). The following is our complete send, receive and read data for the client and server program examples. Firstly we run the server program to listen for connection.
send() and recv() Server Program Example
// Microsoft Development Environment 2003 - Version 7.1.3088
// Copyright (r) 1987-2002 Microsoft Corporation. All Right Reserved
// Microsoft .NET Framework 1.1 - Version 1.1.4322
// Copyright (r) 1998-2002 Microsoft Corporation. All Right Reserved
//
// Run on Windows XP Pro machine, version 2002, SP 2
//
// <windows.h> already included
// WINVER = 0x0501 for Xp already defined in windows.h
// Server program, using TCP
#include <stdio.h>
#include <winsock2.h>
int main()
{
WORD wVersionRequested;
WSADATA wsaData;
int wsaerr;
// Using MAKEWORD macro, Winsock version request 2.2
wVersionRequested = MAKEWORD(2, 2);
wsaerr = WSAStartup(wVersionRequested, &wsaData);
if (wsaerr != 0)
{
/* Tell the user that we could not find a usable WinSock DLL.*/
printf("Server: The Winsock dll not found!\n");
return 0;
}
else
{
printf("Server: The Winsock dll found!\n");
printf("Server: The status: %s.\n", wsaData.szSystemStatus);
}
/* Confirm that the WinSock DLL supports 2.2.*/
/* Note that if the DLL supports versions greater */
/* than 2.2 in addition to 2.2, it will still return */
/* 2.2 in wVersion since that is the version we */
/* requested. */
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2 )
{
/* Tell the user that we could not find a usable WinSock DLL.*/
printf("Server: The dll do not support the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
WSACleanup();
return 0;
}
else
{
printf("Server: The dll supports the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
printf("Server: The highest version this dll can support: %u.%u\n", LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion));
}
//////////Create a socket////////////////////////
//Create a SOCKET object called m_socket.
SOCKET m_socket;
// Call the socket function and return its value to the m_socket variable.
// For this application, use the Internet address family, streaming sockets, and
// the TCP/IP protocol.
// using AF_INET family, TCP socket type and protocol of the AF_INET - IPv4
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// Check for errors to ensure that the socket is a valid socket.
if (m_socket == INVALID_SOCKET)
{
printf("Server: Error at socket(): %ld\n", WSAGetLastError());
WSACleanup();
return 0;
}
else
{ printf("Server: socket() is OK!\n"); }
////////////////bind//////////////////////////////
// Create a sockaddr_in object and set its values.
sockaddr_in service;
// AF_INET is the Internet address family.
service.sin_family = AF_INET;
// "127.0.0.1" is the local IP address to which the socket will be bound.
service.sin_addr.s_addr = inet_addr("127.0.0.1");
// 55555 is the port number to which the socket will be bound.
service.sin_port = htons(55555);
// Call the bind function, passing the created socket and the sockaddr_in structure as parameters.
// Check for general errors.
if (bind(m_socket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR)
{
printf("Server: bind() failed: %ld.\n", WSAGetLastError());
closesocket(m_socket);
return 0;
}
else
{
printf("Server: bind() is OK!\n");
}
// Call the listen function, passing the created socket and the maximum number of allowed
// connections to accept as parameters. Check for general errors.
if (listen(m_socket, 10) == SOCKET_ERROR)
printf("Server: listen(): Error listening on socket %ld.\n", WSAGetLastError());
else
{
printf("Server: listen() is OK, I'm waiting for connections...\n");
}
// Create a temporary SOCKET object called AcceptSocket for accepting connections.
SOCKET AcceptSocket;
// Create a continuous loop that checks for connections requests. If a connection
// request occurs, call the accept function to handle the request.
printf("Server: Waiting for a client to connect...\n" );
printf("***Hint: Server is ready...run your client program...***\n");
// Do some verification...
while (1)
{
AcceptSocket = SOCKET_ERROR;
while (AcceptSocket == SOCKET_ERROR)
{
AcceptSocket = accept(m_socket, NULL, NULL);
}
// else, accept the connection...
// When the client connection has been accepted, transfer control from the
// temporary socket to the original socket and stop checking for new connections.
printf("Server: Client Connected!\n");
m_socket = AcceptSocket;
break;
}
int bytesSent;
int bytesRecv = SOCKET_ERROR;
char sendbuf[200] = "This string is a test data from server";
// initialize to empty data...
char recvbuf[200] = "";
// Send some test string to client...
printf("Server: Sending some test data to client...\n");
bytesSent = send(m_socket, sendbuf, strlen(sendbuf), 0);
if (bytesSent == SOCKET_ERROR)
printf("Server: send() error %ld.\n", WSAGetLastError());
else
{
printf("Server: send() is OK.\n");
printf("Server: Bytes Sent: %ld.\n", bytesSent);
}
// Receives some test string from client...and client
// must send something lol...
bytesRecv = recv(m_socket, recvbuf, 200, 0);
if (bytesRecv == SOCKET_ERROR)
printf("Server: recv() error %ld.\n", WSAGetLastError());
else
{
printf("Server: recv() is OK.\n");
printf("Server: Received data is: \"%s\"\n", recvbuf);
printf("Server: Bytes received: %ld.\n", bytesRecv);
}
WSACleanup();
return 0;
}
Sample output:
Figure 1
The server program is listening to and waiting for connection. While this program is running, run the following client program.
send() and recv() Client Program Example
// Microsoft Development Environment 2003 - Version 7.1.3088
// Copyright (r) 1987-2002 Microsoft Corporation. All Right Reserved
// Microsoft .NET Framework 1.1 - Version 1.1.4322
// Copyright (r) 1998-2002 Microsoft Corporation. All Right Reserved
//
// Run on Windows XP Pro machine, version 2002, SP 2
//
// <windows.h> already included
// WINVER = 0x0501 for Xp already defined in windows.h
// A sample of client program using TCP
#include <stdio.h>
#include <winsock2.h>
int main()
{
// Initialize Winsock.
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != NO_ERROR)
printf("Client: Error at WSAStartup().\n");
else
printf("Client: WSAStartup() is OK.\n");
// Create a socket.
SOCKET m_socket;
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (m_socket == INVALID_SOCKET)
{
printf("Client: socket() - Error at socket(): %ld\n", WSAGetLastError());
WSACleanup();
return 0;
}
else
printf("Client: socket() is OK.\n");
// Connect to a server.
sockaddr_in clientService;
clientService.sin_family = AF_INET;
// Just test using the localhost, you can try other IP address
clientService.sin_addr.s_addr = inet_addr("127.0.0.1");
clientService.sin_port = htons(55555);
if (connect(m_socket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR)
{
printf("Client: connect() - Failed to connect.\n");
WSACleanup();
return 0;
}
else
{
printf("Client: connect() is OK.\n");
printf("Client: Can start sending and receiving data...\n");
}
// Send and receive data.
int bytesSent;
int bytesRecv = SOCKET_ERROR;
// Be careful with the array bound, provide some checking mechanism...
char sendbuf[200] = "This is a test string from client";
char recvbuf[200] = "";
// Receives some test string to server...
while(bytesRecv == SOCKET_ERROR)
{
bytesRecv = recv(m_socket, recvbuf, 200, 0);
if (bytesRecv == 0 || bytesRecv == WSAECONNRESET)
{
printf("Client: Connection Closed.\n");
break;
}
if (bytesRecv < 0)
return 0;
else
{
printf("Client: recv() is OK.\n");
printf("Client: Received data is: \"%s\"\n", recvbuf);
printf("Client: Bytes received is: %ld.\n", bytesRecv);
}
}
// Sends some test data to server...
bytesSent = send(m_socket, sendbuf, strlen(sendbuf), 0);
if(bytesSent == SOCKET_ERROR)
printf("Client: send() error %ld.\n", WSAGetLastError());
else
{
printf("Client: send() is OK - Bytes sent: %ld\n", bytesSent);
printf("Client: The test string sent: \"%s\"\n", sendbuf);
}
WSACleanup();
return 0;
}
Sample output:
Figure 2
And the previous server console output is shown below that complete the server-client communication.
Figure 3
Try running the client program from different machines and change the server IP address accordingly. Another more flexible client-server program example is given at the end of this note.
Notes for ATM
The following are important issues associated with connection setup, and must be considered when using Asynchronous Transfer Mode (ATM) with Windows Sockets 2:
The accept() and WSAAccept() functions do not necessarily set the remote address and address length parameters. Therefore, when using ATM, the caller should use the WSAAccept() function and place ATM_CALLING_PARTY_NUMBER_IE in the ProviderSpecific member of the QOS structure, which itself is included in the lpSQOS parameter of the callback function used in accordance with WSAAccept().
When using the accept() function, realize that the function may return before connection establishment has traversed the entire distance between sender and receiver. This is because the accept() function returns as soon as it receives a CONNECT ACK message; in ATM, a CONNECT ACK message is returned by the next switch in the path as soon as a CONNECT message is processed (rather than the CONNECT ACK being sent by the end node to which the connection is ultimately established). As such, applications should realize that if data is sent immediately following receipt of a CONNECT ACK message, data loss is possible, since the connection may not have been established all the way between sender and receiver.
connect()
Item |
Description |
Function |
connect(). |
Use |
Establishes a connection to a specified socket. |
Prototype |
int connect(SOCKET s, const struct sockaddr* name, int namelen); |
Parameters |
s - [in] Descriptor identifying an unconnected socket. name - [in] Name of the socket in the sockaddr structure to which the connection should be established. namelen - [in] Length of name, in bytes. |
Return value |
See below. |
Include file |
<winsock2.h> |
Library |
ws2_32.lib |
Remark |
See below. |
Table 1 |
Return Values
If no error occurs, connect() returns zero. Otherwise, it returns SOCKET_ERROR, and a specific error code can be retrieved by calling WSAGetLastError(). On a blocking socket, the return value indicates success or failure of the connection attempt. With a non-blocking socket, the connection attempt cannot be completed immediately. In this case, connect() will return SOCKET_ERROR, and WSAGetLastError() will return WSAEWOULDBLOCK. In this case, there are three possible scenarios:
Use the select() function to determine the completion of the connection request by checking to see if the socket is writeable.
If the application is using WSAAsyncSelect() to indicate interest in connection events, then the application will receive an FD_CONNECT notification indicating that the connect operation is complete (successfully or not).
If the application is using WSAEventSelect() to indicate interest in connection events, then the associated event object will be signaled indicating that the connect operation is complete (successfully or not).
Until the connection attempt completes on a non-blocking socket, all subsequent calls to connect() on the same socket will fail with the error code WSAEALREADY, and WSAEISCONN when the connection completes successfully. Due to ambiguities in version 1.1 of the Windows Sockets specification, error codes returned from connect() while a connection is already pending may vary among implementations. As a result, it is not recommended that applications use multiple calls to connect() to detect connection completion. If they do, they must be prepared to handle WSAEINVAL and WSAEWOULDBLOCK error values the same way that they handle WSAEALREADY, to assure robust execution. If the error code returned indicates the connection attempt failed (that is, WSAECONNREFUSED, WSAENETUNREACH, WSAETIMEDOUT) the application can call connect() again for the same socket.
Error code |
Meaning |
WSANOTINITIALISED |
A successful WSAStartup() call must occur before using this function. |
WSAENETDOWN |
The network subsystem has failed. |
WSAEADDRINUSE |
The socket's local address is already in use and the socket was not marked to allow address reuse with SO_REUSEADDR. This error usually occurs when executing bind(), but could be delayed until this function if the bind was to a partially wildcard address (involving ADDR_ANY) and if a specific address needs to be committed at the time of this function. |
WSAEINTR |
The blocking Windows Socket 1.1 call was canceled through WSACancelBlockingCall(). |
WSAEINPROGRESS |
A blocking Windows Sockets 1.1 call is in progress, or the service provider is still processing a callback function. |
WSAEALREADY |
A non-blocking connect call is in progress on the specified socket. In order to preserve backward compatibility, this error is reported as WSAEINVAL to Windows Sockets 1.1 applications that link to either Winsock.dll or Wsock32.dll. |
WSAEADDRNOTAVAIL |
The remote address is not a valid address (such as ADDR_ANY). |
WSAEAFNOSUPPORT |
Addresses in the specified family cannot be used with this socket. |
WSAECONNREFUSED |
The attempt to connect was forcefully rejected. |
WSAEFAULT |
The name or the namelen parameter is not a valid part of the user address space, the namelen parameter is too small, or the name parameter contains incorrect address format for the associated address family. |
WSAEINVAL |
The parameter s is a listening socket. |
WSAEISCONN |
The socket is already connected (connection-oriented sockets only). |
WSAENETUNREACH |
The network cannot be reached from this host at this time. |
WSAENOBUFS |
No buffer space is available. The socket cannot be connected. |
WSAENOTSOCK |
The descriptor is not a socket. |
WSAETIMEDOUT |
Attempt to connect timed out without establishing a connection. |
WSAEWOULDBLOCK |
The socket is marked as non-blocking and the connection cannot be completed immediately. |
WSAEACCES |
Attempt to connect datagram socket to broadcast address failed because setsockopt() option SO_BROADCAST is not enabled. |
Table 2 |
Remarks
The connect() function is used to create a connection to the specified destination. If socket s, is unbound, unique values are assigned to the local association by the system, and the socket is marked as bound.
For connection-oriented sockets (for example, type SOCK_STREAM), an active connection is initiated to the foreign host using name (an address in the namespace of the socket). If a socket is opened, a setsockopt() call is made, and then a sendto() call is made, Windows Sockets performs an implicit bind() function call. When the socket call completes successfully, the socket is ready to send and receive data. If the address member of the structure specified by the name parameter is all zeroes, connect will return the error WSAEADDRNOTAVAIL. Any attempt to reconnect an active connection will fail with the error code WSAEISCONN.
For connection-oriented, non-blocking sockets, it is often not possible to complete the connection immediately. In such a case, this function returns the error WSAEWOULDBLOCK. However, the operation proceeds.
When the success or failure outcome becomes known, it may be reported in one of two ways, depending on how the client registers for notification.
If the client uses the select() function, success is reported in the writefds set and failure is reported in the exceptfds set.
If the client uses the functions WSAAsyncSelect() or WSAEventSelect(), the notification is announced with FD_CONNECT and the error code associated with the FD_CONNECT indicates either success or a specific reason for failure.
For a connectionless socket (for example, type SOCK_DGRAM), the operation performed by connect() is merely to establish a default destination address that can be used on subsequent send()/ WSASend() and recv()/ WSARecv() calls. Any datagrams received from an address other than the destination address specified will be discarded. If the address member of the structure specified by name is all zeroes, the socket will be disconnected. Then, the default remote address will be indeterminate, so send()/ WSASend() and recv()/ WSARecv() calls will return the error code WSAENOTCONN. However, sendto()/ WSASendTo() and recvfrom()/ WSARecvFrom() can still be used. The default destination can be changed by simply calling connect again, even if the socket is already connected. Any datagrams queued for receipt are discarded if name is different from the previous connect. For connectionless sockets, name can indicate any valid address, including a broadcast address. However, to connect to a broadcast address, a socket must use setsockopt() to enable the SO_BROADCAST option. Otherwise, connect will fail with the error code WSAEACCES. When a connection between sockets is broken, the sockets should be discarded and recreated. When a problem develops on a connected socket, the application must discard and recreate the needed sockets in order to return to a stable point. |
connect() Sever Program Example
The following example demonstrates the use of the connect() function for client and server. Firstly run the server program and then the client.
// Microsoft Development Environment 2003 - Version 7.1.3088
// Copyright (r) 1987-2002 Microsoft Corporation. All Right Reserved
// Microsoft .NET Framework 1.1 - Version 1.1.4322
// Copyright (r) 1998-2002 Microsoft Corporation. All Right Reserved
//
// Run on Windows XP Pro machine, version 2002, SP 2
//
// <windows.h> already included
// WINVER = 0x0501 for Xp already defined in windows.h
// Server program, using TCP
#include <stdio.h>
#include <winsock2.h>
int main()
{
WORD wVersionRequested;
WSADATA wsaData;
int wsaerr;
// Using MAKEWORD macro, Winsock version request 2.2
wVersionRequested = MAKEWORD(2, 2);
wsaerr = WSAStartup(wVersionRequested, &wsaData);
if (wsaerr != 0)
{
/* Tell the user that we could not find a usable WinSock DLL.*/
printf("Server: The Winsock dll not found!\n");
return 0;
}
else
{
printf("Server: The Winsock dll found!\n");
printf("Server: The status: %s.\n", wsaData.szSystemStatus);
}
/* Confirm that the WinSock DLL supports 2.2.*/
/* Note that if the DLL supports versions greater */
/* than 2.2 in addition to 2.2, it will still return */
/* 2.2 in wVersion since that is the version we */
/* requested. */
if (LOBYTE(wsaData.wVersion) != 2 || HIBYTE(wsaData.wVersion) != 2 )
{
/* Tell the user that we could not find a usable WinSock DLL.*/
printf("Server: The dll do not support the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
WSACleanup();
return 0;
}
else
{
printf("Server: The dll supports the Winsock version %u.%u!\n", LOBYTE(wsaData.wVersion), HIBYTE(wsaData.wVersion));
printf("Server: The highest version this dll can support: %u.%u\n", LOBYTE(wsaData.wHighVersion), HIBYTE(wsaData.wHighVersion));
}
//////////Create a socket////////////////////////
//Create a SOCKET object called m_socket.
SOCKET m_socket;
// Call the socket function and return its value to the m_socket variable.
// For this application, use the Internet address family, streaming sockets, and the TCP/IP protocol.
// using AF_INET family, TCP socket type and protocol of the AF_INET - IPv4
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
// Check for errors to ensure that the socket is a valid socket.
if (m_socket == INVALID_SOCKET)
{
printf("Server: Error at socket(): %ld\n", WSAGetLastError());
WSACleanup();
return 0;
}
else
{
printf("Server: socket() is OK!\n");
}
////////////////bind//////////////////////////////
// Create a sockaddr_in object and set its values.
sockaddr_in service;
// AF_INET is the Internet address family.
service.sin_family = AF_INET;
// "127.0.0.1" is the local IP address to which the socket will be bound.
// Try your machine IP address...
service.sin_addr.s_addr = inet_addr("127.0.0.1");
// 55555 is the port number to which the socket will be bound…
// Try other non-standard ports ( > 1024). Max = 2 power to 16 = 65536
service.sin_port = htons(55555);
// Call the bind function, passing the created socket and the sockaddr_in structure as parameters.
// Check for general errors.
if (bind(m_socket, (SOCKADDR*)&service, sizeof(service)) == SOCKET_ERROR)
{
printf("Server: bind() failed: %ld.\n", WSAGetLastError());
closesocket(m_socket);
return 0;
}
else
{
printf("Server: bind() is OK!\n");
}
// Call the listen function, passing the created socket and the maximum number of allowed
// connections to accept as parameters. Check for general errors.
if (listen(m_socket, 10) == SOCKET_ERROR)
printf("Server: listen(): Error listening on socket %ld.\n", WSAGetLastError());
else
{
printf("Server: listen() is OK, I'm waiting for connections...\n");
}
// Create a temporary SOCKET object called AcceptSocket for accepting connections.
SOCKET AcceptSocket;
// Create a continuous loop that checks for connections requests. If a connection
// request occurs, call the accept function to handle the request.
printf("Server: Waiting for a client to connect...\n" );
printf("***Hint: Server is ready...run your client program...***\n");
// Do some verification...
while (1)
{
AcceptSocket = SOCKET_ERROR;
while (AcceptSocket == SOCKET_ERROR)
{
AcceptSocket = accept(m_socket, NULL, NULL);
}
// else, accept the connection...
// When the client connection has been accepted, transfer control from the
// temporary socket to the original socket and stop checking for new connections.
printf("Server: Client Connected!\n");
m_socket = AcceptSocket;
break;
}
WSACleanup();
return 0;
}
Sample output:
Figure 4
While the server program is in listening mode, run the following client program.
connect() Client Program Example
The following is the client program to test the previous connect() function.
#include <stdio.h>
#include <winsock2.h>
int main()
{
// Initialize Winsock
WSADATA wsaData;
int iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
if (iResult != NO_ERROR)
printf("Client: Error at WSAStartup().\n");
else
printf("Client: WSAStartup() is OK.\n");
// Create a SOCKET for connecting to server
SOCKET ConnectSocket;
ConnectSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (ConnectSocket == INVALID_SOCKET)
{
printf("Client: Error at socket(): %ld\n", WSAGetLastError());
WSACleanup();
return 0;
}
else
printf("Client: socket() is OK.\n");
// The sockaddr_in structure specifies the address family,
// IP address, and port of the server to be connected to.
sockaddr_in clientService;
clientService.sin_family = AF_INET;
clientService.sin_addr.s_addr = inet_addr("127.0.0.1");
clientService.sin_port = htons(55555);
// Connect to server...
if (connect(ConnectSocket, (SOCKADDR*)&clientService, sizeof(clientService)) == SOCKET_ERROR)
{
printf("Client: Failed to connect.\n");
WSACleanup();
return 0;
}
else
printf("Client: connect() is OK.\n");
printf("Client: Connected to server...\n");
WSACleanup();
return 0;
}
Sample output:
Figure 5
And the previous server program’s console output is shown below.
Figure 6
Notes for IrDA Sockets:
The af_irda.h header file must be explicitly included.
If an existing IrDA connection is detected at the media-access level, WSAENETDOWN is returned.
If active connections to a device with a different address exist, WSAEADDRINUSE is returned.
If the socket is already connected or an exclusive/multiplexed mode change failed, WSAEISCONN is returned.
If the socket was previously bound to a local service name to accept incoming connections using bind(), WSAEINVAL is returned. Note that once a socket is bound, it cannot be used for establishing an outbound connection.
IrDA implements the connect function with addresses of the form sockaddr_irda. Typically, a client application will create a socket with the socket() function, scan the immediate vicinity for IrDA devices with the IRLMP_ENUMDEVICES socket option, and choose a device from the returned list, form an address and then call connect(). There is no difference between blocking and non-blocking semantics.
Further reading and digging:
Linux Sockets: Story and program examples.
A complete info on Windows socket reference from MSDN which include managed and unmanaged API doc.
Structure, enum, union and typedef story can be found struct, enum, union & typedef tutorial.
For Multi bytes, Unicode characters and Localization please refer to Multibyte, Unicode and wide characters (Story) and Win32 Windows & Users tutorial (Implementation).
Windows data type information is Win32 - Windows data types.
Check the best selling C / C++ and Windows books at Amazon.com.