- Table of Contents
- Copyright
- About the Authors
- About the Contributors
- Acknowledgments
- Tell Us What You Think!
- Introduction
- How to Use This Book
- What You Need to Use This Book
- What's New in Visual C++ 6.0
- Contacting the Main Author
- Part I: Introduction
- Chapter 1. The Visual C++ 6.0 Environment
- Part II: MFC Programming
- Chapter 2. MFC Class Library Overview
- Chapter 3. MFC Message Handling Mechanism
- Chapter 4. The Document View Architecture
- Chapter 5. Creating and Using Dialog Boxes
- Chapter 6. Working with Device Contexts and GDI Objects
- Chapter 7. Creating and Using Property Sheets
- Chapter 8. Working with the File System
- Chapter 9. Using Serialization with File and Archive Objects
- Part III: Internet Programming with MFC
- Chapter 10. MFC and the Internet Server API (ISAPI)
- Chapter 11. The WinInet API
- Chapter 12. MFC HTML Support
- Part IV: Advanced Programming Topics
- Chapter 13. Using the Standard C++ Library
- Chapter 14. Error Detection and Exception Handling Techniques
- Chapter 15. Debugging and Profiling Strategies
- Chapter 16. Multithreading
- Chapter 17. Using Scripting and Other Tools to Automate the Visual C++ IDE
- Part V: Database Programming
- Chapter 18. Creating Custom AppWizards
- Chapter 19. Database Overview
- Chapter 20. ODBC Programming
- Chapter 21. MFC Database Classes
- Chapter 22. Using OLE DB
- Chapter 23. Programming with ADO
- ADO Objects
- Connection Objects
- ADOCommand Objects
- ADORecordset Objects
- ADOFields Collections and ADOField Objects
- ADOParameter Objects and the ADOParameters Collection
- ADOProperty Objects and ADOProperties Collections
- Writing a Visual C++ ADO Application
- Processing ADO Errors
- Enhanced ADO Recordset Functionality
- Executing Commands
- Transactions
- Summary
- Part VI: MFC Support for COM and ActiveX
- Chapter 24. Overview of COM and Active Technologies
- Chapter 25. Active Documents
- Chapter 26. Active Containers
- Chapter 27. Active Servers
- Chapter 28. ActiveX Controls
- Part VII: Using the Active Template Library
- Chapter 29. ATL Architecture
- Chapter 30. Creating COM Objects Using ATL
- Chapter 31. Creating ActiveX Controls Using ATL
- Chapter 32. Using ATL to Create MTS and COM+ Components
- Part VIII: Finishing Touches
- Chapter 33. Adding Windows Help
- Part IX: Appendix
Processing ADO Errors
ADO enables you to work with a wide range of different database components, including ADO implementations, OLE DB providers, ODBC drivers, and the database systems themselves. Partly because of this, and partly because ADO is a new technology and still has a few bugs, errors caused by ADO operations can be reported in several ways. Errors from particular calls can be reported by way of C++ exceptions, HRESULT return values, and/or in the ADOErrors collection of an ADOConnection object. You should be prepared to handle error information from all these sources, particularly while developing new applications.
You've already seen some error handling by using the HRESULT that is returned by ADO calls. In addition, ADOConnection objects contain an ADOErrors collection, which contains ADOError objects that give specific information about any errors that might have occurred on the connection for a single operation. In most cases, ADOError objects are generated only when errors are returned by the database system, not when procedural errors occur in ADO. Any given operation can generate any number of different ADOError objects, including errors that contain information about warnings that were generated. Whenever a new operation generates an error, the ADOErrors collection is cleared before the errors from the new operation are added.
ADO HRESULT Values, FAILED, and SUCCEEDED
In addition to handling any C++ exceptions that might be thrown, your applications should also check the HRESULT code that is returned from ADO operations, as shown in the previous example. Generally, these codes are defined in winerror.h, but there are also several other header files in which these error codes are defined, depending on the component that generated the error. When developing new applications, you might find yourself searching these header files often to find the cause of an error. You should also be aware that these error codes are usually defined in hex, although some header files define HRESULT values using decimal notation.
The FAILED() and SUCCEEDED() macros discussed in Chapter 22, "Using OLE DB," enable easy error handling. Although these macros don't give detailed descriptions of the error that occurred, they enable a developer to quickly and efficiently trap any errors that occur.
ADOErrors Collection Members
The ADOErrors collection contains a Count property, which gives the number of ADOError objects currently in the collection, and an Item property, which is used to access the individual ADOError objects. The ADOErrors collection also supports the Clear() method, which is used to remove any ADOError objects currently in the collection.
Error Object Properties
Error objects do not expose any methods, but do include the following properties that give additional information about specific errors:
- Description provides a text description of the error that is suitable for display to the user.
- HelpContext returns a context ID that can be used to access a specific topic in a Windows help file that is relevant to the error.
- HelpFile returns a fully qualified path to a Windows help file that can contain help for the specific error.
- NativeError contains a database-specific Long value that is returned from the provider.
- Number returns a numeric value that indicates the specific error that occurred.
- Source returns a string indicating the component that generated the error—for example, ADODB.Connection or SQL Server.
- SQLState returns a five-character string containing an ANSI standard SQLSTATE value for the specific error.
ADO C++ Exceptions
Most errors that occur in ADO applications as a result of programming errors, such as bad parameters and such, will generate a C++ exception of some sort. In most cases, an exception of class _com_error will be thrown. However, your application should be prepared to handle other sorts of exceptions.
To handle the exceptions that might be thrown by ADO operations, you should execute your ADO operations within a try block and provide a catch block for an object of type _com_error. This class is used to return errors from the classes that are created by the #import directive, as well as the COM support classes. The _com_error class encapsulates any HRESULT values that might be generated and any IErrorInfo object that might be generated by the underlying OLE DB provider.
The _com_error class provides several member functions that can be used to extract information about an error, including the following:
- Error() returns the HRESULT associated with an error.
- ErrorMessage() returns a text string describing the HRESULT value.
- Description() retrieves a text string describing the error.
- Source() returns the name of the component that generated the error.
- HelpContext() retrieves a Windows help context value that applies to the error.
- HelpFile() retrieves the path to a Windows help file that applies to the error.
- GUID() returns the GUID of the COM interface that generated the error.
The following destructor from our example shows how you can use C++ exception handling to deal with exceptions thrown by ADO. This example traps any errors that might occur when closing an ADOConnection or ADORecordset:
~CChap23Dialog() {
//Added by Chuck Wood to close the connection and recordset
try {
if (m_pSet != NULL) {
m_pSet->Close();
}
if (m_pConn != NULL) {
m_pConn->Close();
}
}
catch (_com_error &ce) {
char message[1024];
strcpy (message, "_com_error exception thrown\n");
sprintf (message, "%sHRESULT = 0x%08lx\n",
message, ce.Error());
sprintf (message, "%sHRESULT description: %s\n",
message, ce.ErrorMessage());
sprintf (message, "%sDescription: %S\n",
message, ce.Description());
sprintf (message, "%sSource: %S\n",
message, ce.Source());
MessageBox(message, "Close Error Occurred");
}
catch (...) {
MessageBox("Unknown error has occurred",
"Close Error Occurred");
}
}
The Errors Collection
The last of the error-reporting mechanisms that we look at here is the ADOErrors collection of the ADO Connection object, which can contain multiple ADOError objects for the last ADO operation on the connection. In most cases, the errors (or warnings) reported in the ADOErrors collection are generated by the database, whereas errors that are generated in other components, such as ADODB, are reported via exception or HRESULT.
The ADOErrors collection is contained only in the ADOConnection object, and not in other objects, such as the ADORecordset. Thus, you need to check the ADOErrors collection of the ADOConnection object that is being used for a particular operation. You can access the connection for an ADOCommand or ADORecordset object by using its ActiveConnection property.
ADO clears the ADOErrors collection before each operation, so the errors in the collec tion refer to only the last operation. You can check the number of ADOError objects in the collection by retrieving the Count property. The individual ADOError objects are then retrieved via the Item property.
The ADOError object provides several properties that you can use to gather more information about the error, including the following:
- Description provides a text description of the error that is suitable for display to the user.
- NativeError contains a database-specific Long value that is returned from the provider.
- Number returns a numeric value that indicates the specific error that occurred.
- Source returns a string indicating the component that generated the error—for example, ADODB.Connection or SQL Server.
- SQLState returns a five-character string containing an ANSI standard SQLSTATE value for the specific error.
- HelpContext returns a context ID that can be used to access a specific topic in a Windows help file that is relevant to the error.
- HelpFile returns a fully qualified path to a Windows help file that might contain help for the specific error.
The following example displays a message box containing output based on the ADOError objects in the ADOErrors collection:
void showError() {
//ADO Error Function written by Chuck Wood
long nCount;
char message[4096];
CComPtr<ADOError> pError = NULL;
CComPtr<ADOErrors> pErrors = NULL;
m_pConn->get_Errors(&pErrors);
pErrors->get_Count(&nCount);
strcpy (message, "");
for(int i = 0; i < nCount; i++ ) {
long number = 0;
BSTR string;
// Retrieve individual error object
pErrors->get_Item(CComVariant(i), &pError );
// Add to error message
sprintf(message, "%s\nError %d of %d) ", message, i+1, nCount );
pError->get_Number(&number);
sprintf(message, "%s\tNumber \t= %ld", message, number);
pError->get_Source(&string);
sprintf(message, "%s\tSource \t= %S", message, string);
pError->get_Description(&string);
sprintf(message, "%s\tDescription \t= %S", message, string);
pError->get_HelpFile(&string);
sprintf(message, "%s\tHelpFile \t= %S", message, string);
pError->get_HelpContext(&number);
sprintf(message, "%s\tHelpContext \t= %ld", message, number);
pError->get_SQLState(&string);
sprintf(message, "%s\tSQLState \t= %s", message, string);
pError->get_NativeError(&number);
sprintf(message, "%s\tNativeError \t= %ld", message, number);
} // end for
MessageBox(message, "ADO error list");
}
Enhanced ADO Recordset Functionality | Next Section

Account Sign In
View your cart