Solved

::FormatMessage Error lookup for OLE-DB

Posted on 2000-05-05
7
349 Views
Last Modified: 2013-12-04
I am using ::FormatMessage(blah, blah, blah, blah....,) to return a text description of the current error (HRESULT) in my DCOM application by pointing it to the system error list. However for OLEDB generated errors, (if my error comes from the database layer) ::FormatMessage return null. I feel there should be a way to extract meaninful text for a bad HRESULT, even if the error comes from the database.
Please help. Any information will be appreciated. Thanks.
0
Comment
Question by:hakeem042997
  • 4
  • 3
7 Comments
 
LVL 15

Expert Comment

by:NickRepin
ID: 2783273
It is complex enough.

How a Consumer Retrieves an OLE DB Error Object
http://msdn.microsoft.com/library/psdk/dasdk/olpr2fn8.htm

SQLOLEDB Example: Retrieving Error Information
http://msdn.microsoft.com/library/psdk/dasdk/9_ol41pq.htm


My version is based on the example above

#define _SQLERR(descr,iface) \
   { const type_info& t=typeid(*this); \
   SqlDB::LogSqlError(t.name(),__LINE__,descr,p##iface,IID_##iface); }

//********
   hr=pIDBProperties->SetProperties(SZA(PropSet),PropSet);
   if(FAILED(hr)) {
      _SQLERR(L"Unable to set DB properties",IDBProperties)
      pIDBProperties->Release();
      return false;
   }

//*********

void SqlDB::LogSqlError(LPCSTR cname,DWORD line,LPWSTR descr,
   IUnknown* pObjectWithError,
   REFIID IID_InterfaceWithError)
{
   ISupportErrorInfo* pISupportErrorInfo=0;
   if(FAILED(pObjectWithError->QueryInterface(IID_ISupportErrorInfo,
      (void**) &pISupportErrorInfo))) return;

   if(FAILED(pISupportErrorInfo->InterfaceSupportsErrorInfo(
         IID_InterfaceWithError))) {
      pISupportErrorInfo->Release();
      return;
   }

   pISupportErrorInfo->Release();

   IErrorInfo* pIErrorInfoAll=0;
   GetErrorInfo(0,&pIErrorInfoAll);

   if(pIErrorInfoAll) {
      IErrorRecords* pIErrorRecords=0;

      // Test to see if it's a valid OLE DB IErrorInfo interface
      // exposing a list of records.
      if(SUCCEEDED(pIErrorInfoAll->QueryInterface(IID_IErrorRecords,
            (void**) &pIErrorRecords))) {

         ULONG nRecs;
         pIErrorRecords->GetRecordCount(&nRecs);

         // Within each record, retrieve information from each
         // of the defined interfaces.
         for(UINT nRec=0;nRec<nRecs;nRec++) {

            // From IErrorRecords, get the SqlDB and a reference
            // to the ISQLErrorInfo interface.

            ERRORINFO errorinfo;
            pIErrorRecords->GetBasicErrorInfo(nRec,&errorinfo);

             OStr s;
             s<<descr<<L" ("<<cname<<L", "<<line<<L"): "<<
                L"SQLOLE herr="<<hex<<errorinfo.hrError;

            ISQLErrorInfo* pISQLErrorInfo=0;
            ISQLServerErrorInfo* pISQLServerErrorInfo=0;

            pIErrorRecords->GetCustomErrorObject(nRec,
               IID_ISQLErrorInfo,(IUnknown**)&pISQLErrorInfo);

            if(pISQLErrorInfo) {
               BSTR  bstrSQLSTATE=0;
               LONG  lNativeError;
               pISQLErrorInfo->GetSQLInfo(&bstrSQLSTATE,&lNativeError);

               s<<L", native="<<dec<<lNativeError<<L" \""<<
                  SafeStrW(bstrSQLSTATE)<<L"\"";

               SysFreeString(bstrSQLSTATE);

               pISQLErrorInfo->QueryInterface(IID_ISQLServerErrorInfo,
                  (void**) &pISQLServerErrorInfo);

               pISQLErrorInfo->Release();
            }

            if(pISQLServerErrorInfo) {
               SSERRORINFO* pSSErrorInfo=0;
               OLECHAR*     pSSErrorStrings=0;

               pISQLServerErrorInfo->GetErrorInfo(&pSSErrorInfo,
                  &pSSErrorStrings);

               if(pSSErrorInfo)
                  s<<L", err state="<<dec<<int(pSSErrorInfo->bState)<<
                     L" severity="<<dec<<int(pSSErrorInfo->bClass);

               pIMalloc->Free(pSSErrorInfo);
               pIMalloc->Free(pSSErrorStrings);

               pISQLServerErrorInfo->Release();
            }

            IErrorInfo* pIErrorInfoRecord=0;

            if(SUCCEEDED(pIErrorRecords->GetErrorInfo(nRec,
                  GetUserDefaultLCID(),&pIErrorInfoRecord))) {
               BSTR bstrDescription=0;
               BSTR bstrSource=0;
               pIErrorInfoRecord->GetSource(&bstrSource);
               pIErrorInfoRecord->GetDescription(&bstrDescription);

               if(bstrSource) {
                  s<<L", src=\""<<bstrSource<<L"\"";
                  SysFreeString(bstrSource);
               }
               if(bstrDescription) {
                  s<<L", desc=\""<<bstrDescription<<L"\"";
                  SysFreeString(bstrDescription);
               }

               pIErrorInfoRecord->Release();
            }

            _ERROR(LPCTSTR(s),logG)
         } // for

         pIErrorRecords->Release();

      } // if(SUCCEEDED(pIErrorInfoAll->QueryInterface(IID_IErrorRecords
      else {
         BSTR bstrDescription=0;
         BSTR bstrSource=0;
         pIErrorInfoAll->GetSource(&bstrSource);
         pIErrorInfoAll->GetDescription(&bstrDescription);

         if(bstrSource || bstrDescription) {
            _ERROR(descr<<L" ("<<cname<<L", "<<line<<L"): "<<
               L"OLE error, src=\""<<SafeStrW(bstrSource)<<L", desc\""<<
               SafeStrW(bstrDescription)<<L"\"",logG)
            SysFreeString(bstrSource);
            SysFreeString(bstrDescription);
         }
      }
      pIErrorInfoAll->Release();
    }
}

0
 

Author Comment

by:hakeem042997
ID: 2794241
I'm afraid what I'm looking for is a ::FormatMessage(,,,,,) call where the
module point to an oledb or mts dll.

Already, I can copy the bad hresult to an HRPLUS application and it will give me the correct error string that 'am looking for, namely that a bad object context is associated with the application.

How do I do this with FormaMessage?
0
 
LVL 15

Expert Comment

by:NickRepin
ID: 2794370
I showed how it must be done.
The code above gives the full description of the error from the data source (SQL server, Oracle etc).
FormatMessage is the wrong way.

0
6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

 

Author Comment

by:hakeem042997
ID: 2796550
Dear NickRepin:

It's interesting that at the point where I handle the error, I get the expected hresult, so I still think ::FormatMessage() will be sufficient. But anyway, I found a solution on MSDN website. Please take a look at the following link:
http://msdn.microsoft.com/library/psdk/certsrv/crtsv_using_8rar.htm

I feel what I need now is find out what the appropriate dll (module) is that contains OLEDB error information. The microsoft sample uses a dll named ntdsbmsg.dll, only I couldn't locate this dll on my machine.

Thanks for your time.
0
 

Author Comment

by:hakeem042997
ID: 2796991
Dear NickRepin:

It's interesting that at the point where I handle the error, I get the expected hresult, so I still think ::FormatMessage() will be sufficient. But anyway, I found a solution on MSDN website. Please take a look at the following link:
http://msdn.microsoft.com/library/psdk/certsrv/crtsv_using_8rar.htm

I feel what I need now is find out what the appropriate dll (module) is that contains OLEDB error information. The microsoft sample uses a dll named ntdsbmsg.dll, only I couldn't locate this dll on my machine.

Thanks for your time.
0
 
LVL 15

Expert Comment

by:NickRepin
ID: 2797766
This article is related to the Certificate Services, but not to OLE DB.

I gave you the MS article related to OLE DB which shows how OLE DB errors MUST be handled.

I gave you my own code which shows how it must be done.

Sorry, I have nothing more to add to my completely correct answer.
0
 
LVL 15

Accepted Solution

by:
NickRepin earned 300 total points
ID: 2926055
OLE DB can handle many DB providers - Microsoft SQL server, Oracle, Access....

Each of these providers has its own set of error messages.

Moreover, for example, MS SQL server error may come from the database itself ("primary key constraint violation") or from the net-library which provides a communication channel between the server and the client ("connection timeout"). There are several net-libraries for the SQL server - TCP/IP, named pipes, etc. Each of them has its own error messages.

So, the text message for any given error code may contain in several dlls, and only the provider knows in which dll exactly, and the provider passes this info to OLE DB. You may extract the text message using my answer above.
0

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

zlib is a free compression library (a DLL) on which the popular gzip utility is built.  In this article, we'll see how to use the zlib functions to compress and decompress data in memory; that is, without needing to use a temporary file.  We'll be c…
After several hours of googling I could not gather any information on this topic. There are several ways of controlling the USB port connected to any storage device. The best example of that is by changing the registry value of "HKEY_LOCAL_MACHINE\S…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

707 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now