Visual C++ 6 Unleashed

Visual C++ 6 Unleashed

By MICKEY WILLIAMS and David Bennett

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:

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:

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:

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");
}
						

Share ThisShare This

Informit Network