现在问题是能连上数据库,但是删除记录和修改记录存在问题,删除记录时,返回值hr为0表示成功,但是数据库里记录没有删除,不知道问题出在哪里,麻烦大侠帮帮看看,谢谢#define WIN32_LEAN_AND_MEAN
#define _WIN32_WINNT 0x0501
#define WINVER 0x0501#include <Windows.h>
#include <ole2.h>
#include <TCHAR.h>
#define COM_NO_WINDOWS_H    //如果已经包含了Windows.h或不使用其他Windows
//库函数时
#define DBINITCONSTANTS
#define INITGUID
#define OLEDBVER 0x0270 
#include <oledb.h>
#include <oledberr.h>
#include <msdasc.h>#define GRS_ROUNDUP_AMOUNT 8 
#define GRS_ROUNDUP_(size,amount) (((ULONG)(size)+((amount)-1))&~((amount)-1)) 
#define GRS_ROUNDUP(size) GRS_ROUNDUP_(size, GRS_ROUNDUP_AMOUNT) #define GRS_ALLOC(size) HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,size)
#define GRS_FREE(p)  if( NULL != (p) ){HeapFree(GetProcessHeap(),0,p);(p) = NULL;}#define GRS_COM_RELEASE(p) if(p){(p)->Release();(p)=NULL;}
#define GRS_COM_CHECK(a) if(FAILED(a)){::DebugBreak();goto GRS_CLEARUP;}#define GRS_USE_IDBCREATECOMMAND //使用IDBCreateCommand接口创建Session对象 注释后使用习惯的IOpenRowset接口
//#define GRS_USE_IMULTIPLERESULTS //使用IMultipleResults接口得到结果集 注释后直接使用int WINAPI _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
{
 ::CoInitialize(NULL); IDBPromptInitialize* pIDBPromptInitialize = NULL;
 IDBInitialize*   pIDBInitialize   = NULL;
 IDBCreateSession*  pIDBCreateSession  = NULL;
 IOpenRowset*   pIOpenRowSet   = NULL;
 IDBCreateCommand*  pIDBCreateCommand  = NULL;
 ICommandText*   pICommandText   = NULL;
 ICommandProperties*  pICommandProperties  = NULL;
 IMultipleResults*  pIMultipleResults  = NULL;
 IRowset*    pIRowset    = NULL;
 IColumnsInfo*   pIColumnsInfo           = NULL;
 IAccessor*              pIAccessor              = NULL;
 IRowsetChange*   pIRowsetChange   = NULL;
 IRowsetUpdate*   pIRowsetUpdate = NULL; DBPROPSET ps[1];
 DBPROP prop[3];
//==============================================================================================
 //注意改写这个SQL语句,首先保证SQL语句是正确的
 TCHAR* pSQL = _T("SELECT name,id FROM bb");
//============================================================================================== 
 ULONG                   cColumns                = 0;
 DBCOLUMNINFO*   rgColumnInfo            = NULL;
 LPWSTR                  pStringBuffer           = NULL; DBROWCOUNT  cRowsAffected = 0;//注意不要被这个参数迷惑大多数情况下它是没用的
          //并不能通过它知道结果集中实际包含多少行 ULONG                   iCol     = 0;     
 ULONG                   dwOffset                = 0;
 DBBINDING*              rgBindings              = NULL;
 HACCESSOR    phAccessor    = NULL; void*     pData                   = NULL;
 ULONG                   cRowsObtained   = 0;
 HROW*     rghRows                 = NULL;
 ULONG                   iRow     = 0;
 LONG                    cRows                   = 10;//一次读取10行
 DBROWSTATUS    pdwStatus    = 0; //行状态 实际就是DWORD类型
 void*     pCurData    = NULL;
 void*     pNewData    = NULL;
 HROW     hNewRows    = NULL; HRESULT hr; DWORD dwUpdateRows;
 HROW *pUpRow;//============================================================================================================
 //1、初始化部分,数据库连接
 GRS_COM_CHECK(CoCreateInstance(CLSID_DataLinks, NULL, CLSCTX_INPROC_SERVER,
  IID_IDBPromptInitialize, (void **)&pIDBPromptInitialize));
 //下面这句将弹出前面所说的对话框
 GRS_COM_CHECK(pIDBPromptInitialize->PromptDataSource(NULL, ::GetDesktopWindow(),
  DBPROMPTOPTIONS_PROPERTYSHEET, 0, NULL, NULL, IID_IDBInitialize,
  (IUnknown **)&pIDBInitialize));
 GRS_COM_CHECK(pIDBInitialize->Initialize());//根据对话框采集的参数连接到指定的数据库
//============================================================================================================//============================================================================================================
 //2、创建事务部分
 GRS_COM_CHECK( pIDBInitialize->QueryInterface(IID_IDBCreateSession, (void**)&pIDBCreateSession) );
 //创建一个IOpenRowset接口 或者直接创建一个IDBCreateCommand 接口
#ifdef GRS_USE_IDBCREATECOMMAND
 //使用IDBCreateCommand的方式
 GRS_COM_CHECK(pIDBCreateSession->CreateSession(NULL,IID_IDBCreateCommand,(IUnknown**)&pIDBCreateCommand));
#else
 //使用IOpenRowset的方式
 GRS_COM_CHECK(pIDBCreateSession->CreateSession(NULL,IID_IOpenRowset,(IUnknown**)&pIOpenRowSet) );
 GRS_COM_CHECK(pIOpenRowSet->QueryInterface(IID_IDBCreateCommand,(void**)&pIDBCreateCommand) );
#endif
 //与IDBInitialize等价的IDBCreateSession可以释放了,需要时再Query出来就行了            
 GRS_COM_RELEASE(pIDBCreateSession);
//============================================================================================================//============================================================================================================
 //3、创建Command对象
 GRS_COM_CHECK(pIDBCreateCommand->CreateCommand(NULL,IID_ICommandText,(IUnknown**)&pICommandText));
#ifndef GRS_USE_IDBCREATECOMMAND
 //当使用IOpenRowset接口创建Session对象时 IDBCreateCommand接口使用完毕就可以释放了 因为我们有IOpenRowset接口
 GRS_COM_RELEASE(pIDBCreateCommand);
#endif
//============================================================================================================//============================================================================================================
 //4、设置属性 主要是打开可更新的属性
 ZeroMemory(ps,1 * sizeof(DBPROPSET));
 ZeroMemory(prop, 3 * sizeof(DBPROP)); //prop[0].dwPropertyID = DBPROP_UPDATABILITY;  prop[0].dwPropertyID = DBPROP_UPDATABILITY; 
  prop[0].vValue.vt = VT_I4;
  V_I4(&prop[0].vValue) = DBPROPVAL_UP_CHANGE     //打开Update属性
 |DBPROPVAL_UP_DELETE     //打开Delete属性
    |DBPROPVAL_UP_INSERT;     //打开Insert属性
//   prop[0].vValue.lVal=DBPROPVAL_UP_CHANGE     //打开Update属性
//    |DBPROPVAL_UP_DELETE     //打开Delete属性
//    |DBPROPVAL_UP_INSERT;     //打开Insert属性
  prop[0].dwOptions = DBPROPOPTIONS_REQUIRED;
  prop[0].dwStatus = DBPROPSTATUS_OK;
  prop[0].colid = DB_NULLID;// 
     prop[1].dwPropertyID = DBPROP_IRowsetUpdate;
     prop[1].vValue.vt = VT_BOOL;
     prop[1].vValue.boolVal = VARIANT_TRUE;
     prop[1].dwOptions = DBPROPOPTIONS_REQUIRED;
     prop[1].colid = DB_NULLID; ps[0].guidPropertySet = DBPROPSET_ROWSET;       //注意属性集合的名称
 ps[0].cProperties = 2;
 ps[0].rgProperties = prop; GRS_COM_CHECK(pICommandText->QueryInterface(IID_ICommandProperties,(void**)& pICommandProperties));
 GRS_COM_CHECK(pICommandProperties->SetProperties(1,ps));//注意必须在Execute前设定属性
 GRS_COM_RELEASE(pICommandProperties); //没有用了 就释放掉
//============================================================================================================//============================================================================================================
 //5、设置SQL 并执行得到Rowset对象
 GRS_COM_CHECK(pICommandText->SetCommandText(DBGUID_DBSQL,  /*DBGUID_DEFAULT,*/pSQL));
#ifdef GRS_USE_IMULTIPLERESULTS
 GRS_COM_CHECK(pICommandText->Execute(NULL,IID_IMultipleResults,NULL,NULL,(IUnknown**)& pIMultipleResults));
 //-----------------------------------------------------------------------------------------------------------------------
 //例子代码循环的得到每个结果集并处理之
 //循环处理每一个结果集,当然这需要你起码知道你执行的多条SQL语句的顺序
 //特别要注意使用S_OK直接判断返回值,而不是使用SUCCEEDED或FAILED宏来判断,否则会变成死循环
    //while( S_OK == pIMultipleResults->GetResult(NULL,DBRESULTFLAG_DEFAULT,IID_IRowset,cRowsAffected,(IUnknown**)&pIRowset) )
 //{
 // ......//处理每一个IRowset
 // pIRowset->Release();
 // pIRowset = NULL;
 //}
 //-----------------------------------------------------------------------------------------------------------------------
 

解决方案 »

  1.   

    if(S_OK != pIMultipleResults->GetResult(NULL,DBRESULTFLAG_DEFAULT,IID_IRowset,&cRowsAffected,(IUnknown**)&pIRowset) )
     {
      goto GRS_CLEARUP;
     }
    #else//原文中此处为:
    //GRS_COM_CHECK(pICommandText->Execute(NULL,IID_IRowsetChange,NULL,NULL,(IUnknown**)&pIRowsetChange));//2009年11月23日纠正为,请同时注意所有相关修改的地方,这样就可以使用IRowsetChange接口了// GRS_COM_CHECK(pICommandText->Execute(NULL,IID_IRowset,NULL,NULL,(IUnknown**)&pIRowset));
    // GRS_COM_CHECK(pIRowset->QueryInterface(IID_IRowsetChange,(void**)&pIRowsetChange));
      GRS_COM_CHECK(pICommandText->Execute(NULL,IID_IRowsetChange,NULL,NULL,(IUnknown**)&pIRowsetChange));
      GRS_COM_CHECK(pIRowsetChange->QueryInterface(IID_IRowset,(void**)&pIRowset));
      GRS_COM_CHECK(pIRowsetChange->QueryInterface(IID_IRowsetUpdate, (void**)&pIRowsetUpdate));
    #endif
    //============================================================================================================//============================================================================================================
     //取得IRowset接口(注意修改的地方)
     
    //============================================================================================================//============================================================================================================
     //6、得到列信息生成绑定,这里使用了一个非常简单的动态绑定的方法,实际使用中这个地方还要仔细的修改
     //通常需要根据Column Info 的 wType字段使用switch语句详细设定一些特殊类型的绑定方法
     //有时为了方便,可以将绑定结构中的wType字段直接设置为我们想要的类型,让数据提供者在输出数据时直接进行数据类型转换
     //通常我比较喜欢设置为字符串类型,让所有的类型都直接转换成字符串类型,以方便数据的显示
     GRS_COM_CHECK(pIRowsetChange->QueryInterface(IID_IColumnsInfo,(void**)&pIColumnsInfo));
     GRS_COM_CHECK(pIColumnsInfo->GetColumnInfo(&cColumns,&rgColumnInfo,&pStringBuffer));
     //IColumnsInfo接口可以直接释放了,使用时重新检索出来即可
     GRS_COM_RELEASE(pIColumnsInfo);
     //如果成功了,那么rgColumnInfo中已经包含了一个关于列信息数据结构的数组,
     //数组元素的个数即cColumns 也就是最终的列数
     //动态分配绑定结构
     rgBindings = (DBBINDING*)GRS_ALLOC(cColumns * sizeof(DBBINDING));
     for( iCol = 0; iCol < cColumns; iCol++ )
     {
      rgBindings[iCol].iOrdinal   = rgColumnInfo[iCol].iOrdinal;
      rgBindings[iCol].dwPart     = DBPART_VALUE|DBPART_LENGTH|DBPART_STATUS;
      rgBindings[iCol].obStatus   = dwOffset;
      rgBindings[iCol].obLength   = dwOffset + sizeof(DBSTATUS);
      rgBindings[iCol].obValue    = dwOffset+sizeof(DBSTATUS)+sizeof(ULONG);
      rgBindings[iCol].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
      rgBindings[iCol].eParamIO   = DBPARAMIO_NOTPARAM;
      rgBindings[iCol].bPrecision = rgColumnInfo[iCol].bPrecision;
      rgBindings[iCol].bScale     = rgColumnInfo[iCol].bScale;
      rgBindings[iCol].wType      = rgColumnInfo[iCol].wType;
      rgBindings[iCol].cbMaxLen   = rgColumnInfo[iCol].ulColumnSize;  dwOffset = rgBindings[iCol].cbMaxLen + rgBindings[iCol].obValue;
      dwOffset = GRS_ROUNDUP(dwOffset);
     }
    //============================================================================================================//============================================================================================================
     //7、创建访问器
     GRS_COM_CHECK(pIRowsetChange->QueryInterface(IID_IAccessor,(void**)&pIAccessor));
     GRS_COM_CHECK(pIAccessor->CreateAccessor(DBACCESSOR_ROWDATA,cColumns,rgBindings,0,&phAccessor,NULL));
    //============================================================================================================
     //8、得到并访问数据
     //分配cRows行数据的缓冲,然后反复读取cRows行到这里,然后逐行处理之
     pData = GRS_ALLOC(dwOffset * cRows);
      hr = pIRowset->GetNextRows(DB_NULL_HCHAPTER,0,cRows,&cRowsObtained, &rghRows);
     //注意下面的循环 一定使用S_OK判定GetNextRow的值,否则会形成一个死循环,因为到达行集末尾不是一个错误
      do
      {//循环读取数据,每次循环默认读取cRows行,实际读取到cRowsObtained行
      for( iRow = 0; iRow < cRowsObtained; iRow++ )
      {
    hr = pIRowsetChange->DeleteRows(NULL,1,&rghRows[iRow],NULL);
      
      pCurData    = (BYTE*)pData + (dwOffset * iRow);
     //  GRS_COM_CHECK(pIRowset->GetData(rghRows[iRow],phAccessor,pCurData));
       //pCurData中已经包含了结果数据,显示或者进行处理  
       
       //对行集数据进行修改,然后用SetData提交修改
      // GRS_COM_CHECK(pIRowsetChange->SetData(rghRows[iRow],phAccessor,pCurData));   //删除一些行 需要测试时还原下面的行
    // hr = pIRowsetChange->DeleteRows(NULL,1,&rghRows[iRow],&pdwStatus);
       //GRS_COM_CHECK(pIRowsetChange->DeleteRows(NULL,1,&rghRows[iRow],&pdwStatus[0]));   //复制插入一些行的例子
    //     pNewData = (BYTE*)GRS_ALLOC(dwOffset);
    //     CopyMemory(pNewData,pCurData,dwOffset);
    //     GRS_COM_CHECK(pIRowsetChange->InsertRow(NULL,phAccessor,pNewData,&hNewRows));
    // //    //插入成功释放新行的行句柄 以及新行的数据缓冲也一同释放
    //     GRS_COM_CHECK(pIRowset->ReleaseRows(1,&hNewRows,NULL,NULL,NULL));
    //     GRS_FREE(pNewData);  
      }
      //注意下面两次释放代表不同的含义
      if( cRowsObtained )
      {//释放行句柄指向的行
       GRS_COM_CHECK(pIRowset->ReleaseRows(cRowsObtained,rghRows,NULL,NULL,NULL));
      }
      //释放行句柄数组的内存
      CoTaskMemFree(rghRows);
      rghRows = NULL;
      }
      while( !FAILED( pIRowset->GetNextRows(DB_NULL_HCHAPTER,0,cRows,&cRowsObtained, &rghRows) ));//============================================================================================================
     //清理释放部分
    GRS_CLEARUP:
     //GRS_FREE(pCurData); //这行多余 注释或删除之 2009-11-23修改
     GRS_FREE(pData);
     GRS_FREE(rgBindings);
     if(pIAccessor)
     {
      pIAccessor->ReleaseAccessor(phAccessor,NULL);
     }
     GRS_COM_RELEASE(pIAccessor);
     CoTaskMemFree(rgColumnInfo);
     CoTaskMemFree(pStringBuffer);
     GRS_COM_RELEASE(pIColumnsInfo);
     GRS_COM_RELEASE(pIRowsetChange);
     GRS_COM_RELEASE(pIRowset);
     GRS_COM_RELEASE(pIMultipleResults);
     GRS_COM_RELEASE(pICommandText);
     GRS_COM_RELEASE(pICommandProperties);
     GRS_COM_RELEASE(pIDBCreateCommand)
     GRS_COM_RELEASE(pIOpenRowSet);
     GRS_COM_RELEASE(pIDBCreateSession);
     GRS_COM_RELEASE(pIDBInitialize);
     GRS_COM_RELEASE(pIDBPromptInitialize);
    //============================================================================================================ ::CoUninitialize();
     return 0;
    }
      

  2.   

    代码没问题,可能是sql server没装好,连到别的机器上的sql server没问题
      

  3.   

    哎,csdn上,现在越来越让人心寒啊,一个月都没一人看过