为什么 OLE DB IRowset.GetNextRows 访问冲突
Why OLE DB IRowset.GetNextRows access violation
我正在使用 OLE DB 从 SQL 服务器检索一些数据,代码的概要是
m_spCmd->SetCommandText(DBGUID_DEFAULT,L"SELECT * FROM sys.DM_OS_PERFORMANCE_COUNTERS"); // S_OK
CComPtr<IRowset> result;
m_spCmd->Execute(nullptr,__uuidof(IRowset),nullptr,nullptr,(IUnknown**)&result); // S_OK
DBCOUNTITEM fetched;
HROW *hrow;
result->GetNextRows(DB_NULL_HCHAPTER,0,1,&fetched,&hrow); // A
at A ,我得到了一个 access violation exception
(这意味着某些东西是空的, result
本身不是空的)。我想我错过了代码中的一些步骤,那是什么?非常感谢!!!
更新
- sqlcmd.h
#pragma once
#include <windows.h>
#include <msdaguid.h>
#include <msdasql.h>
#include <oledb.h>
#include <oledberr.h>
#include <iostream>
#include <atlbase.h>
#include <atldbcli.h>
using namespace std;
struct SQLCmd
{
SQLCmd();
~SQLCmd();
private:
template<typename T> void print(T);
private:
CComPtr<IDBInitialize> m_spDb;
CComPtr<IDBProperties> m_spDbProperty;
CComPtr<ISessionProperties> m_spSsProperty;
CComPtr<ICommandText> m_spCmd;
CComPtr<ISQLErrorInfo> m_spErr;
CComPtr<IAccessor> m_spAccessor;
CComPtr<IDBCreateSession> m_spCrsession;
HRESULT hr;
};
- sqlcmd.cpp
#include "sqlcmd.h"
template<>
void SQLCmd::print(CComPtr<IRowset> ptr)
{
DBORDINAL count;
DBCOLUMNINFO *info;
OLECHAR *buf;
auto accessor = CComQIPtr<IAccessor>(ptr);
auto colinfo = CComQIPtr<IColumnsInfo>(ptr);
colinfo->GetColumnInfo(&count,&info,&buf);
/*
DBBINDING *bindings = new DBBINDING[count];
memset(bindings,0,sizeof(DBBINDING)*count);
DBBINDSTATUS *bindingstatus = new DBBINDSTATUS[count];
memset(bindingstatus,0,sizeof(DBBINDSTATUS)*count);
DBBYTEOFFSET offset = 0;
int rowsize = 0;
for(int i = 0 ; i < count ; i++)
{
auto &[pwszName,pTypeInfo,iOrdinal,dwFlags,ulColumnSize,wType,bPrecision,bScale,columnid] = info[i];
bindings[i].iOrdinal = iOrdinal;
bindings[i].obValue = offset;
bindings[i].wType = wType;
bindings[i].dwPart = DBPART_VALUE;
bindings[i].bPrecision = bPrecision;
bindings[i].bScale = bScale;
offset += ulColumnSize;
rowsize += ulColumnSize;
printf("%ws %lld %d\n",pwszName,ulColumnSize,wType);
}
HACCESSOR haccessor;
hr = accessor->CreateAccessor(DBACCESSOR_ROWDATA,count,bindings,rowsize,&haccessor,bindingstatus);
printf("CreateAccessor %x %llx\n",hr,haccessor);
for(int i = 0 ; i < count ; i++)
if(DBBINDSTATUS_OK != bindingstatus[i])
printf("%d - %d\n",i,bindingstatus[i]);*/
DBCOUNTITEM fetched;
HROW *hrow;
printf("before GetNextRows\n");
hr = ptr->GetNextRows(DB_NULL_HCHAPTER,0,1,&fetched,&hrow);
printf("GetNextRows %x %lld\n",hr,fetched);
}
SQLCmd::SQLCmd()
{
GUID msoledbsql;
CLSIDFromString(L"{5A23DE84-1D7B-4A16-8DED-B29C09CB648D}",&msoledbsql);
m_spDb.CoCreateInstance(msoledbsql);
m_spDbProperty = CComQIPtr<IDBProperties>(m_spDb);
CDBPropSet set(DBPROPSET_DBINIT);
set.AddProperty(DBPROP_AUTH_INTEGRATED,L"SSPI");
set.AddProperty(DBPROP_INIT_CATALOG,L"master");
set.AddProperty(DBPROP_INIT_DATASOURCE,L"localhost");
m_spDbProperty->SetProperties(1,&set);
m_spDb->Initialize();
auto m_spCrsession = CComQIPtr<IDBCreateSession>(m_spDb);
if (!!m_spCrsession)
{
hr = m_spCrsession->CreateSession(nullptr,__uuidof(ISessionProperties),(IUnknown**)&m_spSsProperty);
auto _ = CComQIPtr<IDBCreateCommand>(m_spSsProperty);
if (!!_)
hr = _->CreateCommand(nullptr,__uuidof(ICommandText),(IUnknown**)&m_spCmd);
}
CComPtr<IRowset> result;
hr = m_spCmd->SetCommandText(DBGUID_DEFAULT,L"SELECT * FROM sys.DM_OS_PERFORMANCE_COUNTERS");
printf("SetCommandText 0x%x\n",hr);
DBROWCOUNT rowcount;
hr = m_spCmd->Execute(nullptr,__uuidof(IRowset),nullptr,&rowcount,(IUnknown**)&result);
printf("Execute 0x%x %lld\n",hr,rowcount);
if (!!result)
{
print(result);
}
}
SQLCmd::~SQLCmd()
{
if (!!m_spDb) m_spDb->Uninitialize();
}
- test.cpp
#include "sqlcmd.h"
int main()
{
CoInitialize(nullptr);
SQLCmd cmd;
}
- 编译
cl /nologo /EHsc /std:c++latest test.cpp sqlcmd.cpp /link /debug
- 运行
>test
SetCommandText 0x0
Execute 0x0 -1
before GetNextRows
IRowset::GetNextRows documentation:这样说
If *prghRows is not a null pointer on input, it must be a pointer to
consumer-allocated memory large enough to return the handles of the
requested number of rows. If the consumer-allocated memory is larger
than needed, the provider fills in as many row handles as specified by
pcRowsObtained; the contents of the remaining memory are undefined.
所以你不能在输入时传递一个随机指针。您必须将其设置为有效或 NULL:
HROW* hrow = NULL;
我正在使用 OLE DB 从 SQL 服务器检索一些数据,代码的概要是
m_spCmd->SetCommandText(DBGUID_DEFAULT,L"SELECT * FROM sys.DM_OS_PERFORMANCE_COUNTERS"); // S_OK
CComPtr<IRowset> result;
m_spCmd->Execute(nullptr,__uuidof(IRowset),nullptr,nullptr,(IUnknown**)&result); // S_OK
DBCOUNTITEM fetched;
HROW *hrow;
result->GetNextRows(DB_NULL_HCHAPTER,0,1,&fetched,&hrow); // A
at A ,我得到了一个 access violation exception
(这意味着某些东西是空的, result
本身不是空的)。我想我错过了代码中的一些步骤,那是什么?非常感谢!!!
更新
- sqlcmd.h
#pragma once
#include <windows.h>
#include <msdaguid.h>
#include <msdasql.h>
#include <oledb.h>
#include <oledberr.h>
#include <iostream>
#include <atlbase.h>
#include <atldbcli.h>
using namespace std;
struct SQLCmd
{
SQLCmd();
~SQLCmd();
private:
template<typename T> void print(T);
private:
CComPtr<IDBInitialize> m_spDb;
CComPtr<IDBProperties> m_spDbProperty;
CComPtr<ISessionProperties> m_spSsProperty;
CComPtr<ICommandText> m_spCmd;
CComPtr<ISQLErrorInfo> m_spErr;
CComPtr<IAccessor> m_spAccessor;
CComPtr<IDBCreateSession> m_spCrsession;
HRESULT hr;
};
- sqlcmd.cpp
#include "sqlcmd.h"
template<>
void SQLCmd::print(CComPtr<IRowset> ptr)
{
DBORDINAL count;
DBCOLUMNINFO *info;
OLECHAR *buf;
auto accessor = CComQIPtr<IAccessor>(ptr);
auto colinfo = CComQIPtr<IColumnsInfo>(ptr);
colinfo->GetColumnInfo(&count,&info,&buf);
/*
DBBINDING *bindings = new DBBINDING[count];
memset(bindings,0,sizeof(DBBINDING)*count);
DBBINDSTATUS *bindingstatus = new DBBINDSTATUS[count];
memset(bindingstatus,0,sizeof(DBBINDSTATUS)*count);
DBBYTEOFFSET offset = 0;
int rowsize = 0;
for(int i = 0 ; i < count ; i++)
{
auto &[pwszName,pTypeInfo,iOrdinal,dwFlags,ulColumnSize,wType,bPrecision,bScale,columnid] = info[i];
bindings[i].iOrdinal = iOrdinal;
bindings[i].obValue = offset;
bindings[i].wType = wType;
bindings[i].dwPart = DBPART_VALUE;
bindings[i].bPrecision = bPrecision;
bindings[i].bScale = bScale;
offset += ulColumnSize;
rowsize += ulColumnSize;
printf("%ws %lld %d\n",pwszName,ulColumnSize,wType);
}
HACCESSOR haccessor;
hr = accessor->CreateAccessor(DBACCESSOR_ROWDATA,count,bindings,rowsize,&haccessor,bindingstatus);
printf("CreateAccessor %x %llx\n",hr,haccessor);
for(int i = 0 ; i < count ; i++)
if(DBBINDSTATUS_OK != bindingstatus[i])
printf("%d - %d\n",i,bindingstatus[i]);*/
DBCOUNTITEM fetched;
HROW *hrow;
printf("before GetNextRows\n");
hr = ptr->GetNextRows(DB_NULL_HCHAPTER,0,1,&fetched,&hrow);
printf("GetNextRows %x %lld\n",hr,fetched);
}
SQLCmd::SQLCmd()
{
GUID msoledbsql;
CLSIDFromString(L"{5A23DE84-1D7B-4A16-8DED-B29C09CB648D}",&msoledbsql);
m_spDb.CoCreateInstance(msoledbsql);
m_spDbProperty = CComQIPtr<IDBProperties>(m_spDb);
CDBPropSet set(DBPROPSET_DBINIT);
set.AddProperty(DBPROP_AUTH_INTEGRATED,L"SSPI");
set.AddProperty(DBPROP_INIT_CATALOG,L"master");
set.AddProperty(DBPROP_INIT_DATASOURCE,L"localhost");
m_spDbProperty->SetProperties(1,&set);
m_spDb->Initialize();
auto m_spCrsession = CComQIPtr<IDBCreateSession>(m_spDb);
if (!!m_spCrsession)
{
hr = m_spCrsession->CreateSession(nullptr,__uuidof(ISessionProperties),(IUnknown**)&m_spSsProperty);
auto _ = CComQIPtr<IDBCreateCommand>(m_spSsProperty);
if (!!_)
hr = _->CreateCommand(nullptr,__uuidof(ICommandText),(IUnknown**)&m_spCmd);
}
CComPtr<IRowset> result;
hr = m_spCmd->SetCommandText(DBGUID_DEFAULT,L"SELECT * FROM sys.DM_OS_PERFORMANCE_COUNTERS");
printf("SetCommandText 0x%x\n",hr);
DBROWCOUNT rowcount;
hr = m_spCmd->Execute(nullptr,__uuidof(IRowset),nullptr,&rowcount,(IUnknown**)&result);
printf("Execute 0x%x %lld\n",hr,rowcount);
if (!!result)
{
print(result);
}
}
SQLCmd::~SQLCmd()
{
if (!!m_spDb) m_spDb->Uninitialize();
}
- test.cpp
#include "sqlcmd.h"
int main()
{
CoInitialize(nullptr);
SQLCmd cmd;
}
- 编译
cl /nologo /EHsc /std:c++latest test.cpp sqlcmd.cpp /link /debug
- 运行
>test
SetCommandText 0x0
Execute 0x0 -1
before GetNextRows
IRowset::GetNextRows documentation:这样说
If *prghRows is not a null pointer on input, it must be a pointer to consumer-allocated memory large enough to return the handles of the requested number of rows. If the consumer-allocated memory is larger than needed, the provider fills in as many row handles as specified by pcRowsObtained; the contents of the remaining memory are undefined.
所以你不能在输入时传递一个随机指针。您必须将其设置为有效或 NULL:
HROW* hrow = NULL;