FIX: ADO Recordset GetString() Function Throws an Access Violation in Oleaut32.dll (230276)



The information in this article applies to:

  • ActiveX Data Objects (ADO) 2.0
  • ActiveX Data Objects (ADO) 2.1
  • Microsoft Visual C++, 32-bit Enterprise Edition 6.0

This article was previously published under Q230276

SYMPTOMS

Calling the GetString() function on a _RecordsetPtr object may cause the following error to occur:
Unhandled Exception in <application name> (OLEAUT32.DLL) : 0xC0000005: Access Violation

CAUSE

The #import-generated wrapper function GetString() passes an uninitialized BSTR pointer to the ADO raw_GetString() function as an out parameter. The raw_GetString() function incorrectly calls the SysFreeString() function on the parameter if it is not pointing to NULL.

RESOLUTION

This problem was corrected in ADO 2.5.

For earlier versions of ADO, call the raw_GetString directly and pass a BSTR pointer that points to NULL as the output parameter, or create a wrapper function as described in the "More Information" section.

STATUS

Microsoft has confirmed that this is a problem in the Microsoft products that are listed at the beginning of this article.

This problem was corrected in ADO 2.5.

MORE INFORMATION

Steps to Reproduce the Behavior

These steps use the SQL Server Pubs database:
  1. Create a Win32 console application (Simple application) in Visual C++.
  2. Paste the following code to replace code generated in the .cpp file:

    Note You must change User ID=<username> and Password =<strong password> to the correct values before you run this code. Make sure that User ID has the appropriate permissions to perform this operation on the database.
    #include "stdafx.h"
    #include <iostream.h>
    
    #import "C:\Program Files\Common Files\System\ado\msado15.dll" no_namespace rename( "EOF", "adoEOF" )
    
    struct InitOle {
      InitOle()  { ::CoInitialize(NULL); }
      ~InitOle() { ::CoUninitialize();   }
    } _init_InitOle_;
    
    int main(int argc, char* argv[])
    {
    
    	try {
    		_ConnectionPtr pCon(__uuidof(Connection));
    		_RecordsetPtr pRs(__uuidof(Recordset));
    
    		pCon->ConnectionString = L"Provider=SQLOLEDB.1; Server=(local);Initial Catalog=pubs; User Id=<username>; Password=<strong password>;";
    		pCon->Open(L"",L"",L"",-1);
    
    		pRs->Open(L"SELECT * FROM authors",pCon.GetInterfacePtr(),adOpenStatic,adLockOptimistic,-1);
    
    		_bstr_t btRecordset;
    		btRecordset = pRs->GetString(adClipString,-1,L",",L"\r\n",L"<NULL>");
    		cout << (char*) btRecordset << endl;
    	}
    	catch (_com_error& e)
    	{
    		cout << e.ErrorMessage() << endl;
    	}
    
    	return 0;
    }
    
    						
  3. Run the code and observe the results.

Resolution

  • Use ADO 2.5 -or-

  • Call the raw_GetString() function directly with a BSTR pointer that is initialized to point to NULL.

    Use the following code to replace the call to GetString():
    		BSTR bstrResult = NULL;
    		_bstr_t btColDelim(L",");
    		_bstr_t btRowDelim(L"\r\n");
    		_bstr_t btNullExp(L"<NULL>");
    		HRESULT hr = pRs->raw_GetString(adClipString,-1,btColDelim,btRowDelim,btNullExp,&bstrResult);
    		if (FAILED(hr)) _com_issue_errorex(hr, pRs, __uuidof(pRs));
    		btRecordset = bstrResult;
    
    						
    -or-
  • Create an inline function similar to GetString() that calls the raw_GetString function, but initialize the BSTR variable to NULL.

    Note: Do not modify the generated .tli file to make the changes directly to the GetString() wrapper implementation because this file is gegenerated at compile time. Instead, use the function below or copy and paste the GetString() function from the .tli file and modify it as follows:
    inline _bstr_t GetString2 ( _RecordsetPtr pRs, enum StringFormatEnum StringFormat, long NumRows, _bstr_t ColumnDelimeter, _bstr_t RowDelimeter, _bstr_t NullExpr ) 
    {
        BSTR _result = NULL;
        HRESULT _hr = pRs->raw_GetString(StringFormat, NumRows, ColumnDelimeter, RowDelimeter, NullExpr, &_result);
        if (FAILED(_hr)) _com_issue_errorex(_hr, pRs, __uuidof(pRs));
        return _bstr_t(_result, false);
    }
    
    						
    You can call this function in the main() function as follows:
    		btRecordset = GetString2(pRs,adClipString,-1,L",",L"\r\n",L"<NULL>");
    						

Modification Type:MajorLast Reviewed:11/4/2003
Keywords:kbADO250Fix kbbug kbDatabase kbfix kbMDACNoSweep KB230276 kbAudDeveloper