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.