BUG: ADO Recordset GetString() Function Throws an Access Violation in Oleaut32.dll
ID: Q230276
|
The information in this article applies to:
-
ActiveX Data Objects (ADO), versions 2.0, 2.1
-
Microsoft Visual C++, 32-bit Enterprise Edition, version 6.0
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
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.
STATUSMicrosoft has confirmed this to be a problem in the Microsoft products listed
at the beginning of this article.
MORE INFORMATIONSteps to Reproduce Behavior
These steps use the SQL Server Pubs database:
-
Create a Win32 console application (Simple application) in Visual C++.
-
Paste the following code to replace code generated in the .cpp file:
#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=sa; 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;
}
-
Run the code and observe the results.
Resolution
-
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>");
Additional query words:
mdac
Keywords : kbADO kbDatabase kbMDAC kbGrpVCDB kbGrpMDAC
Version : WINDOWS:2.0,2.1,6.0
Platform : WINDOWS
Issue type : kbbug
|