![]() |
Converting a CInternetException to a printable string |
|
I have recently been doing some Internet programming with the MFC classes, such as CInternetSession. One problem I had to deal with was the fact that these classes will sometimes throw exceptions, and I wanted a printable representation of the error. A bit of forensics showed that wininet.dll contains a MESSAGETABLE resource, although to discover this you have to know that a MESSAGETABLE is resource type 11. So I set up a function to convert WinInet error codes, as encoded in the CInternetException, to a CString.
For example, the OpenURL operation can throw an exception. To handle this, I use a TRY/CATCH construct:
CInternetSession session;
CStdioFile * file;
TRY {
file = session.OpenURL(URL);
}
CATCH(CInternetException, e)
{
CString s = getInetError(e->m_dwError);
// here I add the error message to a CListBox
c_Status.AddString(s);
return;
}
The function getInetError uses FormatMessage to convert the message
CString getInetError(DWORD err)
{
HANDLE h = ::GetModuleHandle(_T("WinINet.dll"));
if(h != NULL)
{ /* got module */
LPTSTR p;
if(::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_HMODULE,
(LPCVOID)h,
err,
0, // default language
(LPTSTR)&p,
0,
NULL) != 0)
{ /* format succeeded */
CString s(p);
s.Replace(_T("\r\n"), _T(""));
return s;
} /* format succeeded */
} /* got module */
CString s;
s.Format(_T("%d"), err);
return s;
} // getInetError
The explanation of the code is as follows:
The WinInet.dll module is already mapped into the address space (else I would not see the exception being thrown or otherwise have a CInternetException. So I use GetModuleHandle (instead of LoadLibrary, which would increment the reference count) to get the module handle. If this is successful, I call FormatMessage using FORMAT_MESSAGE_FROM_HMODULE and this handle to format the error code. If the error code is a valid WinINet error, FormatMessage will succeed. In this case, I want to remove the gratuitous newline that FormatMessage insists on appending, so I replace "\r\n" with the empty string.
If the module handle cannot be obtained, or the FormatMessage fails, the code drops down to formatting the error code as a decimal integer. A LoadString operation could be used to get a nicer formatting string from the STRINGTABLE, e.g.,
CString fmt; fmt.LoadString(IDS_NICE_ERROR_MESSAGE); // "WinINet error %d" CString s; s.Format(fmt, err); return s;
The views expressed in these essays are those of the author, and in no way represent, nor are they endorsed by, Microsoft.