INFO: Extracting Error Information from ADO in VC++ with #import

This article has been archived. It is offered "as is" and will no longer be updated.
When ActiveX Data Objects (ADO) encounter an error, often the ErrorsCollection is filled with detail on the cause of the error. This articleprovides sample code for extracting the maximum possible information on anyerrors raised by ADO within Visual C++ using #import as the mechanism toget at ADO.

If ADO itself encounters an error, it does not populate the errorscollection, but instead you have to use the native error mechanism to getthe information. In this case, an exception raised with the _com_errorclass. If the provider or underlying components generate error, then thesewill be populated in the ADO Errors Collection.
More information
Often the Errors Collection returns an HRESULT in either hexadecimalformat, for example, 0x80004005, or as a long value, for example, -2147467259. These HRESULTS can be raised by underlying components such asOLE-DB or even OLE itself. When this is the case, it may be confusing sincethese codes are not documented in the ADO online documentation. However,frequently encountered HRESULTS can be found in the Microsoft Knowledge Base article listed in the REFERENCES section.

The documentation for the ADO Error object indicates that the ErrorsCollection is populated if any error occurs within ADO or its underlyingprovider. This is somewhat incorrect. Depending on the source of the error,or even bugs in the underyling provider to ADO (OLE-DB) or within ADOitself, the errors collection may not be populated. You need to track theHRESULT returned by many ADO methods, as well as if the _com_errorexception has been raised by #import generated classes.

The Errors Collection is available only off the Connection object, so youneed to initialize ADO off of a Connection object. Following is sample codethat demonstrates how to open a connection and report any errorsencountered, as well as handling Exceptions, and cracking the returnedHRESULT:

// Obtain the error message for a given HRESULT   CString LogCrackHR( HRESULT hr )   {      LPVOID  lpMsgBuf;      CString strTmp;      ::FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER |                       FORMAT_MESSAGE_FROM_SYSTEM,                       NULL,                       hr,                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),                       (LPTSTR) &lpMsgBuf,                       0,                       NULL );        // STR_TMP is defined within LOG.CPP to provide safe format string        // for both ANSI and UNICODE        strTmp.Format( "%s", (char *) lpMsgBuf );      // Free the buffer.      ::LocalFree( lpMsgBuf );      return strTmp;   }   // Obtain information from the Errors Collection.   HRESULT LogAdoErrorImport(_ConnectionPtr pConn)   {      ErrorsPtr   pErrors = NULL;      ErrorPtr    pError  = NULL;      CString     strTmp;      HRESULT     hr = (HRESULT) 0L;      long        nCount;      // Don't have an un-handled exception in the handler that      // handles exceptions!      try      {         pErrors = pConn->GetErrors();         nCount = pErrors->GetCount();         for( long i = 0; (!FAILED(hr)) && (i < nCount); i++ )         {            TRACE( "\t Dumping ADO Error %d of %d", i+1, nCount );            hr = pErrors->get_Item((_variant_t)((long)i), &pError );            _bstr_t bstrSource     ( pError->GetSource()      );            _bstr_t bstrDescription( pError->GetDescription() );            _bstr_t bstrHelpFile   ( pError->GetHelpFile()    );            _bstr_t bstrSQLState   ( pError->GetSQLState()    );            TRACE( "\t\t Number      = %ld", pError->GetNumber()       );            TRACE( "\t\t Source      = %s",  (LPCTSTR) bstrSource      );            TRACE( "\t\t Description = %s",  (LPCTSTR) bstrDescription );            TRACE( "\t\t HelpFile    = %s",  (LPCTSTR) bstrHelpFile    );            TRACE( "\t\t HelpContext = %ld", pError->GetHelpContext()  );            TRACE( "\t\t SQLState    = %s",  (LPCTSTR) bstrSQLState    );            TRACE( "\t\t HelpContext = %ld", pError->GetHelpContext()  );            TRACE( "\t\t NativeError = %ld", pError->GetNativeError()  );         }      }      catch( CException *e )      {         TRACE( "*** UNABLE TO LOG EXCEPTION ***" );         e->Delete();      }      catch(...)      {         TRACE( "*** UNABLE TO LOG EXCEPTION ***" );      }      if( pErrors ) pErrors->Release();      if( pError  ) pError->Release();      return hr;   }   void CAdoDemoDlg::OnAdoTest()   {      HRESULT         hr = S_OK;      _ConnectionPtr  pConn;      hr = ::CoInitialize( NULL );      if( !FAILED( hr ) )         hr = pConn.CreateInstance( __uuidof( Connection ) );      // The following exception handling assumes a valid Connection      // object, so drop out if we couldn't create one for any reason.      if ( FAILED(hr) )         return;      try      {         // ... Your code goes here.         pConn->Close();         // For any error condition, dump results to TRACE.         // You may get a failure that does not raise an exception.         // The ADO Errors collection will likely be empty, but         // check anyway.         if( FAILED( hr ) )         {            TRACE( "*** HRESULT ***" );            TRACE( LogCrackHR( hr )  );            LogAdoErrorImport( pConn );         }      }      catch( CException *e )      {         TRACE( "*** Unhandled MFC Exception ***" );         e->Delete();      }      catch( _com_error &e )      {         // Crack _com_error         _bstr_t bstrSource(e.Source());         _bstr_t bstrDescription(e.Description());         TRACE( "Exception thrown for classes generated by #import" );         TRACE( "\tCode = %08lx\n",      e.Error());         TRACE( "\tCode meaning = %s\n", e.ErrorMessage());         TRACE( "\tSource = %s\n",       (LPCTSTR) bstrSource);         TRACE( "\tDescription = %s\n",  (LPCTSTR) bstrDescription);         // Errors Collection may not always be populated.         if( FAILED( hr ) )         {            TRACE( "*** HRESULT ***" );            TRACE( LogCrackHR( hr )  );         }         // Crack Errors Collection.         LogAdoErrorImport(pConn);      }      catch(...)      {         TRACE( "*** Unhandled Exception ***" );      }   }				
For additional information, click the following article numbers to view the articles in the Microsoft Knowledge Base:
167802 SAMPLE: EXCEPTEX Traps MFC and Win32 Structured Exceptions
168354 INFO: Underlying OLE and OLEDB Provider Errors Are Exposed Through ADO

Article ID: 169498 - Last Review: 06/22/2014 18:23:00 - Revision: 5.0

  • kbnosurvey kbarchive kbcode kbdatabase kbinfo KB169498