为什么OLE DB IRowset.GetNextRows访问冲突 更新

问题描述

我正在使用OLE DB从SQL Server检索一些数据,代码的轮廓是

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,(IUnknown**)&result); // S_OK
DBCOUNTITEM fetched;
HROW *hrow;
result->GetNextRows(DB_NULL_HCHAPTER,1,&fetched,&hrow);  // A

在A处,我得到一个access violation exception(这意味着某内容为空,result本身不为空)。我想我错过了代码中的某些步骤,那是什么?非常感谢!!!

更新

  1. 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;
};
  1. 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,sizeof(DBBINDING)*count);

  DBBINDSTATUS *bindingstatus = new DBBINDSTATUS[count];
  memset(bindingstatus,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,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,&hrow);  
  printf("GetNextRows %x %lld\n",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,&rowcount,(IUnknown**)&result);
  printf("Execute 0x%x %lld\n",rowcount);
  if (!!result)
  {
    print(result);
  } 
}

SQLCmd::~SQLCmd()
{
  if (!!m_spDb) m_spDb->Uninitialize();
}
  1. test.cpp
#include "sqlcmd.h"
int main()
{
  CoInitialize(nullptr);
  SQLCmd cmd;
}
  1. 编译
cl /nologo /EHsc /std:c++latest test.cpp sqlcmd.cpp /link /debug
  1. 运行
>test
SetCommandText 0x0
Execute 0x0 -1
before GetNextRows

解决方法

IRowset::GetNextRows documentation:这样说

如果* prghRows不是输入的空指针,则它必须是指向的指针 消费者分配的内存足够大,可以返回 请求的行数。如果使用者分配的内存更大 提供程序会填充所需的行句柄 pcRows获得;剩余内存的内容不确定。

因此您不能在输入上传递随机指针。您必须将其设置为有效值或NULL:

HROW* hrow = NULL;

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...