Introduction
Recently I was working on my umpteenth client/server app using Winsock, and once again I found myself embedding Winsock error descriptions in the app. Not being under the usual pressure (read: I hadn't missed the deadline yet) I decided to centralize the Winsock error descriptions in a handy DLL.
Looking around for some authoritative source for Winsock errors, I found a table on this page on MSDN: Windows Sockets Error Codes.
Here are the first few entries from that table:
Return code/value |
Description |
WSAEINTR 10004 |
- Interrupted function call.
- A blocking operation was interrupted by a call to
WSACancelBlockingCall . |
WSAEACCES 10013 |
- Permission denied.
- An attempt was made to access a socket in a way forbidden by its access permissions. An example is using a broadcast address for sendto without broadcast permission being set using
setsockopt(SO_BROADCAST) .
Another possible reason for the WSAEACCES error is that when the bind function is called (on Windows NT 4 SP4 or later), another application, service, or kernel mode driver is bound to the same address with exclusive access. Such exclusive access is a new feature of Windows NT 4 SP4 and later, and is implemented by using the SO_EXCLUSIVEADDRUSE option. |
WSAEFAULT 10014 |
- Bad address.
- The system detected an invalid pointer address in attempting to use a pointer argument of a call. This error occurs if an application passes an invalid pointer value, or if the length of the buffer is too small. For instance, if the length of an argument, which is a
sockaddr structure, is smaller than the sizeof(sockaddr) . |
Looking at this table, it is clear that there are four items of interest for each error code:
- The error code - for example,
WSAEFAULT
.
- The numeric value of the error code - for example, 10014.
- A short description - for example, Bad address..
- A long description - a text string between 50 and 800 characters in length.
Note: the Winsock error codes are defined in winsock2.h.
XWSAError Functions
XWSAError.dll includes functions to retrieve the error code string (given the error code), the numeric error code (given the error code string), the short description, and the long description. Also included are functions to get the maximum length of the returned strings (if you are going to retrieve the long description, it may be simpler just to allocate one buffer for the long description string, and use that buffer for the other strings as well).
Here are the functions available in XWSAError.dll:
XWSA_GetErrorCode()
- Retrieves error code from error code string.
XWSA_GetErrorString()
- Retrieves error code string from error code.
XWSA_GetLongDescription()
- Retrieves long description.
XWSA_GetShortDescription()
- Retrieves short description.
XWSA_GetErrorStringSize()
- Retrieves max size of an error code string.
XWSA_GetLongDescriptionSize()
- Retrieves max size of a long description.
XWSA_GetShortDescriptionSize()
- Retrieves max size of a short description.
Sample Code
The following sample code - taken from the demo app - shows how to use the above functions.
if (bNumeric)
{
int nCode = _ttoi(m_strError);
m_Code.SetWindowText(m_strError);
if (XWSA_GetErrorString(nCode, buf, XWSA_GetLongDescriptionSize()))
{
m_ID.SetWindowText(buf);
if (XWSA_GetShortDescription(nCode, buf, XWSA_GetLongDescriptionSize()))
m_ShortDescription.SetWindowText(buf);
if (XWSA_GetLongDescription(nCode, buf, XWSA_GetLongDescriptionSize()))
m_LongDescription.SetWindowText(buf);
}
else
{
m_ID.SetWindowText(_T("unknown error code"));
}
}
else
{
int nCode = XWSA_GetErrorCode(m_strError);
if (nCode)
{
m_ID.SetWindowText(m_strError);
CString s = _T("");
s.Format(_T("%d"), nCode);
m_Code.SetWindowText(s);
if (XWSA_GetShortDescription(nCode, buf, XWSA_GetLongDescriptionSize()))
m_ShortDescription.SetWindowText(buf);
if (XWSA_GetLongDescription(nCode, buf, XWSA_GetLongDescriptionSize()))
m_LongDescription.SetWindowText(buf);
}
}
How To Use With Visual C++
To integrate XWSAError.dll into your app, you first need to add XWSAError.h to your project. XWSAError.h automatically links to XWSAError.lib, so all you have to do is, add the XWSAError.lib directory to your project (in VC 6.0, go to Project | Settings | Link | Input and add the directory to the Additional Library Path). Next insert the line
#include "XWSAError.h"
in the module where you want to call the functions. Finally, make sure the XWSAError.dll is in the same directory as the app's exe.
How To Use With Visual Basic
To get XWSAError.dll to work with VB apps, the first thing to do is define all the functions using the __stdcall
calling convention:
XWSAERROR_API int __stdcall XWSA_GetErrorString(int nErrorCode,
TCHAR * lpszBuf, int nBufSize);
XWSAERROR_API int __stdcall XWSA_GetErrorCode(const TCHAR * lpszErrorString);
XWSAERROR_API int __stdcall XWSA_GetErrorStringSize();
XWSAERROR_API int __stdcall XWSA_GetShortDescription(int nErrorCode,
TCHAR * lpszBuf, int nBufSize);
XWSAERROR_API int __stdcall XWSA_GetShortDescriptionSize();
XWSAERROR_API int __stdcall XWSA_GetLongDescription(int nErrorCode,
TCHAR * lpszBuf, int nBufSize);
XWSAERROR_API int __stdcall XWSA_GetLongDescriptionSize();
This, combined with the __declspec(dllexport)
used in the XWSAERROR_API
macro, causes the exported functions to have decorated names (as shown by dumpbin):
ordinal hint RVA name
1 0 0000100F _XWSA_GetErrorCode@4
2 1 00001019 _XWSA_GetErrorString@12
3 2 0000101E _XWSA_GetErrorStringSize@0
4 3 00001014 _XWSA_GetLongDescription@12
5 4 00001023 _XWSA_GetLongDescriptionSize@0
6 5 00001028 _XWSA_GetShortDescription@12
7 6 00001032 _XWSA_GetShortDescriptionSize@0
This means that VB programs would have to alias the exported names before calling any of these functions. This is nasty, but we can avoid this problem by adding a module definition file (XWSAError.def):
; XWSAError.def - module definition file
;
; The EXPORTS in this file remove the decoration from the function names,
; and so allow Visual Basic programs to call the XWSAError functions using
; the same names as VC++ programs.
LIBRARY XWSAError
DESCRIPTION "Winsock error lookup"
EXPORTS
XWSA_GetErrorCode
XWSA_GetErrorString
XWSA_GetErrorStringSize
XWSA_GetLongDescription
XWSA_GetLongDescriptionSize
XWSA_GetShortDescription
XWSA_GetShortDescriptionSize
Now the undecorated function names are exported:
ordinal hint RVA name
1 0 0000100F XWSA_GetErrorCode
2 1 00001019 XWSA_GetErrorString
3 2 0000101E XWSA_GetErrorStringSize
4 3 00001014 XWSA_GetLongDescription
5 4 00001023 XWSA_GetLongDescriptionSize
6 5 00001028 XWSA_GetShortDescription
7 6 00001032 XWSA_GetShortDescriptionSize
Now VB programs can call these functions without any extra work, as shown in the following snippet (a sample VB program is included in the download):
Private Declare Function XWSA_GetShortDescriptionSize Lib "XWSAError.dll" () _
As Integer
Private Declare Function XWSA_GetShortDescription Lib "XWSAError.dll"
(ByVal nerror%, ByVal sd$, ByVal sdsize%) As Integer
Private Sub Command1_Click()
Dim nSize As Integer, rc As Integer, error As Integer
Dim ErrorCode As String, ShortDesc As String
nSize = XWSA_GetShortDescriptionSize()
ShortDesc = String$(nSize, Chr$(0))
ErrorCode = Form1.Text1.Text
error = ErrorCode
rc = XWSA_GetShortDescription(error, ShortDesc, Len(ShortDesc))
Form1.Text2.Text = "XWSA_GetShortDescription() returned: " + ShortDesc
End Sub
For more information on using DLL functions in VB, please see Q142840: Visual Basic Requirements for Exported DLL Functions.
The Demo App
The demo app displays the various strings when you enter an error code:
Revision History
Version 1.0 - 2005 January 6
Usage
This software is released into the public domain. You are free to use it in any way you like, except that you may not sell this source code. If you modify it or extend it, please to consider posting new code here for everyone to share. This software is provided "as is" with no expressed or implied warranty. I accept no liability for any damage or loss of business that this software may cause.