如果,你是用VC++的话,可以使用ADO。
例子如下:
// ADOSample.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <objbase.h>
#include <oledb.h>
#include <atlbase.h>
#include <windows.h>
#include <comdef.h>#import "c:\\Program Files\\Common Files\\System\\ADO\\msado15.dll"  no_namespace rename("EOF", "EndOfFile")
#import "C:\Program Files\Microsoft SQL Server\80\Tools\Binn\sqldmo.dll" void dump_com_error(_com_error &e)
   {
printf("Error\n");
printf("\a\tCode = %08lx\n", e.Error());
printf("\a\tCode meaning = %s", e.ErrorMessage());
_bstr_t bstrSource(e.Source());
_bstr_t bstrDescription(e.Description());
printf("\a\tSource = %s\n", (LPCSTR) bstrSource);
printf("\a\tDescription = %s\n", (LPCSTR) bstrDescription);
   }
int main(int argc, char* argv[])
{
printf("Hello World!\n");
::CoInitialize(NULL); 
try 
      { _ConnectionPtr pCon=NULL;
_RecordsetPtr    pRs=NULL;

pCon.CreateInstance(__uuidof(Connection)); 
pCon->Open("Export","dongsong","dongsong",adConnectUnspecified); 

pRs.CreateInstance(__uuidof(Recordset));
pRs->CursorLocation=adUseClient; 
pRs->Open("select name from sysobjects where type='u'",
_variant_t((IDispatch *) pCon, true),adOpenStatic, adLockReadOnly, adCmdUnknown);
   while (!(pRs->EndOfFile))
   {
    
printf("%s\n",(char*)_bstr_t(pRs->Fields->Item["name"]->Value));

pRs->MoveNext();
   }
}catch (_com_error &e)
      {
      dump_com_error(e);
      }
::CoUninitialize();
return 0;
}

解决方案 »

  1.   

    利用DB-LIBRARY:
    DBINIT();
    DBSETLUSER(LOGIN,‘SA’);
    DBSETLPWD(LOGIN,‘PASS’);
    DBPROC = DBOPEN(LOGIN,‘SERVERNAME’);
      

  2.   

    Visual C++ 中 的ODBC 编 程  ---- 一 . 概 述 ---- ODBC 是 一 种 使 用SQL 的 程 序 设 计 接 口。 使 用ODBC 让 应 用 程 序 的 编 写 者 避 免 了 与 数 据 源 相 联 的 复 杂 性。 这 项 技 术 目 前 已 经 得 到 了 大 多 数DBMS 厂 商 们 的 广 泛 支 持。 ---- Microsoft Developer Studio 为 大 多 数 标 准 的 数 据 库 格 式 提 供 了32 位ODBC 驱 动 器。 这 些 标 准 数 据 格 式 包 括 有:SQL Server、Access、Paradox、dBase、FoxPro、Excel、Oracle 以 及Microsoft Text。 如 果 用 户 希 望 使 用 其 他 数 据 格 式, 用 户 需 要 相 应 的ODBC 驱 动 器 及DBMS。 ---- 用 户 使 用 自 己 的DBMS 数 据 库 管 理 功 能 生 成 新 的 数 据 库 模 式 后, 就 可 以 使 用ODBC 来 登 录 数 据 源。 对 用 户 的 应 用 程 序 来 说, 只 要 安 装 有 驱 动 程 序, 就 能 注 册 很 多 不 同 的 数 据 库。 登 录 数 据 库 的 具 体 操 作 参 见 有 关ODBC 的 联 机 帮 助。 ---- 二 .MFC 提 供 的ODBC 数 据 库 类 ---- Visual C++ 的MFC 基 类 库 定 义 了 几 个 数 据 库 类。 在 利 用ODBC 编 程 时, 经 常 要 使 用 到 CDatabase( 数 据 库 类),CRecordSet( 记 录 集 类) 和CRecordView( 可 视 记 录 集 类)。 其 中: ---- CDatabase 类 对 象 提 供 了 对 数 据 源 的 连 接, 通 过 它 你 可 以 对 数 据 源 进 行 操 作。 ---- CRecordSet 类 对 象 提 供 了 从 数 据 源 中 提 取 出 的 记 录 集。CRecordSet 对 象 通 常 用 于 两 种 形 式: 动 态 行 集(dynasets) 和 快 照 集(snapshots)。 动 态 行 集 能 保 持 与 其 他 用 户 所 做 的 更 改 保 持 同 步。 快 照 集 则 是 数 据 的 一 个 静 态 视 图。 每 一 种 形 式 在 记 录 集 被 打 开 时 都 提 供 一 组 记 录, 所 不 同 的 是, 当 你 在 一 个 动 态 行 集 里 滚 动 到 一 条 记 录 时, 由 其 他 用 户 或 是 你 应 用 程 序 中 的 其 他 记 录 集 对 该 记 录 所 做 的 更 改 会 相 应 地 显 示 出 来。 ---- CRecordView 类 对 象 能 以 控 制 的 形 式 显 示 数 据 库 记 录。 这 个 视 图 是 直 接 连 到 一 个CRecordSet 对 象 的 表 视 图。 ---- 三 . 应 用ODBC 编 程 ---- 应 用Visual C++ 的AppWizard 可 以 自 动 生 成 一 个ODBC 应 用 程 序 框 架。 方 法 是: 打 开File 菜 单 的New 选 项, 选 取Projects, 填 入 工 程 名, 选 择MFC AppWizard (exe), 然 后 按AppWizard 的 提 示 进 行 操 作。 当AppWizard 询 问 是 否 包 含 数 据 库 支 持 时, 如 果 你 想 读 写 数 据 库, 那 么 选 定Database view with file support; 而 如 果 你 想 访 问 数 据 库 的 信 息 而 不 想 回 写 所 做 的 改 变, 那 么 选 定Database view without file support 选 项 就 比 较 合 适 了。 选 择 了 数 据 库 支 持 之 后Database Source 按 钮 会 激 活, 选 中 它 去 调 用Data Options 对 话 框。 在Database Options 对 话 框 中 会 显 示 已 向ODBC 注 册 的 数 据 库 资 源, 选 定 你 所 要 操 作 的 数 据 库, 如:Super_ES, 单 击OK 后 会 出 现Select Database Tables 对 话 框, 其 中 列 举 了 你 所 选 中 的 数 据 库 中 包 含 的 全 部 表, 选 择 你 希 望 操 作 的 表 后, 单 击OK。 在 选 定 了 数 据 库 和 数 据 表 之 后, 你 可 以 按 照 惯 例 继 续 进 行AppWizard 操 作。 ---- 特 别 需 要 指 出 的 是: 在 生 成 的 应 用 程 序 框 架View 类( 如:CSuper_ESView) 中 包 含 一 个 指 向CSuper_ESSet 对 象 的 指 针m_pSet, 该 指 针 由AppWizard 建 立, 目 的 是 在 视 表 单 和 记 录 集 之 间 建 立 联 系, 使 得 记 录 集 中 的 查 询 结 果 能 够 很 容 易 地 在 视 表 单 上 显 示 出 来。 有 关m_pSet 的 详 细 用 法 可 以 参 见Visual C++ Online Book。 ---- 程 序 与 数 据 语 言 建 立 联 系, 使 用CDatebase::OpenEx() 或CDatabase::Open() 函 数 来 进 行 初 始 化。 数 据 库 对 象 必 须 在 你 使 用 它 构 造 一 个 记 录 集 对 象 之 前 被 初 始 化。 ---- 下 面 举 例 说 明 在Visual C++ 环 境 中ODBC 的 编 程 技 巧: ---- 1 . 查 询 记 录 ---- 查 询 记 录 使 用CRecordSet::Open() 和CRecordSet::Requery() 成 员 函 数。 在 使 用CRecordSet 类 对 象 之 前, 必 须 使 用CRecordSet::Open() 函 数 来 获 得 有 效 的 记 录 集。 一 旦 已 经 使 用 过CRecordSet::Open() 函 数, 再 次 查 询 时 就 可 以 应 用CRecordSet::Requery() 函 数。 在 调 用CRecordSet::Open() 函 数 时, 如 果 已 经 将 一 个 已 经 打 开 的CDatabase 对 象 指 针 传 给CRecordSet 类 对 象 的m_pDatabase 成 员 变 量, 则 使 用 该 数 据 库 对 象 建 立ODBC 连 接; 否 则 如 果m_pDatabase 为 空 指 针, 就 新 建 一 个CDatabase 类 对 象 并 使 其 与 缺 省 的 数 据 源 相 连, 然 后 进 行CRecordSet 类 对 象 的 初 始 化。 缺 省 数 据 源 由GetDefaultConnect() 函 数 获 得。 你 也 可 以 提 供 你 所 需 要 的SQL 语 句, 并 以 它 来 调 用CRecordSet::Open() 函 数, 例 如:  Super_ESSet.Open(AFX_DATABASE_USE_DEFAULT,strSQL);---- 如 果 没 有 指 定 参 数, 程 序 则 使 用 缺 省 的SQL 语 句, 即 对 在GetDefaultSQL() 函 数 中 指 定 的SQL 语 句 进 行 操 作:  CString CSuper_ESSet::GetDefaultSQL()
    {return _T("[BasicData],[MainSize]");}---- 对 于GetDefaultSQL() 函 数 返 回 的 表 名, 对 应 的 缺 省 操 作 是SELECT 语 句, 即:  SELECT * FROM BasicData,MainSize---- 查 询 过 程 中 也 可 以 利 用CRecordSet 的 成 员 变 量m_strFilter 和m_strSort 来 执 行 条 件 查 询 和 结 果 排 序。m_strFilter 为 过 滤 字 符 串, 存 放 着SQL 语 句 中WHERE 后 的 条 件 串;m_strSort 为 排 序 字 符 串, 存 放 着SQL 语 句 中ORDER BY 后 的 字 符 串。 如:  Super_ESSet.m_strFilter="TYPE='电动机'";
    Super_ESSet.m_strSort="VOLTAGE";
    Super_ESSet.Requery();
     对应的SQL语句为:
    SELECT * FROM BasicData,MainSize 
    WHERE TYPE='电动机'
    ORDER BY VOLTAGE---- 除 了 直 接 赋 值 给m_strFilter 以 外, 还 可 以 使 用 参 数 化。 利 用 参 数 化 可 以 更 直 观, 更 方 便 地 完 成 条 件 查 询 任 务。 使 用 参 数 化 的 步 骤 如 下: ---- (1) . 声 明 参 变 量:  CString p1;
    float p2;---- (2) . 在 构 造 函 数 中 初 始 化 参 变 量  p1=_T("");
    p2=0.0f;
    m_nParams=2;---- (3) . 将 参 变 量 与 对 应 列 绑 定  pFX- >SetFieldType(CFieldExchange::param)
    RFX_Text(pFX,_T("P1"),p1);
    RFX_Single(pFX,_T("P2"),p2);---- 完 成 以 上 步 骤 之 后 就 可 以 利 用 参 变 量 进 行 条 件 查 询 了:  m_pSet- >m_strFilter="TYPE=? AND VOLTAGE=?";
    m_pSet- >p1=" 电 动 机";
    m_pSet- >p2=60.0;
    m_pSet- >Requery();---- 参 变 量 的 值 按 绑 定 的 顺 序 替 换 查 询 字 串 中 的"?" 适 配 符。 ---- 如 果 查 询 的 结 果 是 多 条 记 录 的 话, 可 以 用CRecordSet 类 的 函 数Move(),MoveNext(),MovePrev(),MoveFirst() 和MoveLast() 来 移 动 光 标。 ---- 2 . 增 加 记 录 ---- 增 加 记 录 使 用AddNew() 函 数, 要 求 数 据 库 必 须 是 以 允 许 增 加 的 方 式 打 开:  m_pSet- >AddNew(); //在表的末尾增加新记录
    m_pSet- >SetFieldNull(&(m_pSet- >m_type), FALSE);
    m_pSet- >m_type=" 电 动 机";
    ... //输入新的字段值
    m_pSet- > Update(); //将新记录存入数据库
    m_pSet- >Requery(); //重建记录集---- 3 . 删 除 记 录 ---- 直 接 使 用Delete() 函 数, 并 且 在 调 用Delete() 函 数 之 后 不 需 调 用Update() 函 数:  m_pSet- >Delete();
    if (!m_pSet- >IsEOF())
    m_pSet- >MoveNext();
    else
    m_pSet- >MoveLast();---- 4 . 修 改 记 录 ---- 修 改 记 录 使 用Edit() 函 数:  m_pSet- >Edit(); //修改当前记录
    m_pSet- >m_type="发电机";
           //修改当前记录字段值
    ...
    m_pSet- >Update(); //将修改结果存入数据库
    m_pSet- >Requery();---- 5 . 撤 消 操 作 ---- 如 果 用 户 选 择 了 增 加 或 者 修 改 记 录 后 希 望 放 弃 当 前 操 作, 可 以 在 调 用Update() 函 数 之 前 调 用:  CRecordSet::Move(AFX_MOVE_REFRESH);---- 来 撤 消 增 加 或 修 改 模 式, 并 恢 复 在 增 加 或 修 改 模 式 之 前 的 当 前 记 录。 其 中 的 参 数AFX_MOVE_REFRESH 的 值 为 零。 ---- 6 . 数 据 库 连 接 的 复 用 ---- 在CRecordSet 类 中 定 义 了 一 个 成 员 变 量m_pDatabase:  CDatabase* m_pDatabase;---- 它 是 指 向 对 象 数 据 库 类 的 指 针。 如 果 在CRecordSet 类 对 象 调 用Open() 函 数 之 前, 将 一 个 已 经 打 开 的CDatabase 类 对 象 指 针 传 给m_pDatabase, 就 能 共 享 相 同 的CDatabase 类 对 象。 如:  CDatabase m_db;
    CRecordSet m_set1,m_set2;
    m_db.Open(_T("Super_ES"));//建立ODBC连接
    m_set1.m_pDatabase=&m_db;
           //m_set1复用m_db对象
    m_set2.m_pDatabse=&m_db;
            // m_set2复用m_db对象
      

  3.   


    ---- 7 .SQL 语 句 的 直 接 执 行 ---- 虽 然 通 过CRecordSet 类, 我 们 可 以 完 成 大 多 数 的 查 询 操 作, 而 且 在CRecordSet::Open() 函 数 中 也 可 以 提 供SQL 语 句, 但 是 有 的 时 候 我 们 还 想 进 行 一 些 其 他 操 作, 例 如 建 立 新 表, 删 除 表, 建 立 新 的 字 段 等 等, 这 时 就 需 要 使 用 到CDatabase 类 的 直 接 执 行SQL 语 句 的 机 制。 通 过 调 用CDatabase::ExecuteSQL() 函 数 来 完 成SQL 语 句 的 直 接 执 行: BOOL CDB::ExecuteSQLAndReportFailure(const CString& strSQL)
    {
    TRY
    {
    m_pdb- >ExecuteSQL(strSQL);//直接执行SQL语句
    }
    CATCH (CDBException,e)
    {
    CString strMsg;
    strMsg.LoadString(IDS_EXECUTE_SQL_FAILED);
    strMsg+=strSQL;
    return FALSE;
    }
    END_CATCH 
    return TRUE;
    }---- 应 当 指 出 的 是, 由 于 不 同DBMS 提 供 的 数 据 操 作 语 句 不 尽 相 同, 直 接 执 行SQL 语 句 可 能 会 破 坏 软 件 的DBMS 无 关 性, 因 此 在 应 用 中 应 当 慎 用 此 类 操 作。 ---- 8 . 动 态 连 接 表 ---- 表 的 动 态 连 接 可 以 利 用 在 调 用CRecordSet::Open() 函 数 时 指 定SQL 语 句 来 实 现。 同 一 个 记 录 集 对 象 只 能 访 问 具 有 相 同 结 构 的 表, 否 则 查 询 结 果 将 无 法 与 变 量 相 对 应。  void CDB::ChangeTable()
    {
    if (m_pSet- >IsOpen()) m_pSet- >Close();
    switch (m_id)
    {
    case 0:
    m_pSet- >Open(AFX_DB_USE_DEFAULT_TYPE, 
    "SELECT * FROM SLOT0"); //连接表SLOT0
    m_id=1;
    break;
    case 1:
    m_pSet- >Open(AFX_DB_USE_DEFAULT_TYPE, 
    "SELECT * FROM SLOT1"); //连接表SLOT1
    m_id=0;
    break;
    }
    }---- 9 . 动 态 连 接 数 据 库 ---- 由 于 与 数 据 库 的 连 接 是 通 过CDatabase 类 对 象 来 实 现 的, 所 以 我 们 可 以 通 过 赋 与CRecordSet 类 对 象 参 数m_pDatabase 以 连 接 不 同 数 据 库 的CDatabase 对 象 指 针, 就 可 以 动 态 连 接 数 据 库。  void CDB::ChangeConnect()
    {
    CDatabase* pdb=m_pSet- >m_pDatabase;
    pdb- >Close();

    switch (m_id)
    {
    case 0:
    if (!pdb- >Open(_T("Super_ES")))
                   //连接数据源Super_ES
    {
    AfxMessageBox("数据源Super_ES打开失败,"
    "请检查相应的ODBC连接", MB_OK|MB_ICONWARNING);
    exit(0);
    }
    m_id=1;
    break;
    case 1:
    if (!pdb- >Open(_T("Motor")))
                    //连接数据源Motor
    {
    AfxMessageBox("数据源Motor打开失败,"
    "请检查相应的ODBC连接", MB_OK|MB_ICONWARNING);
    exit(0);
    }
    m_id=0;
    break;
    }
    }
      

  4.   

    1.配置ODBC,建立ODBC和SQL SERVER的连接ODBCTEST
    2.在VC++通过该ODBC调用SQL SERVER的STORED PROCEDURE(szTypes )
    #include "stdafx.h"
    #include "DatabaseServer.h"
    #include <stdarg.h>#ifdef _DEBUG
    #undef THIS_FILE
    static char THIS_FILE[]=__FILE__;
    #define new DEBUG_NEW
    #endif//////////////////////////////////////////////////////////////////////
    // Construction/Destruction
    //////////////////////////////////////////////////////////////////////CDatabaseServer::CDatabaseServer()
    {

    }CDatabaseServer::~CDatabaseServer()
    {}bool CDatabaseServer::getConnectionString(char *szConnectionString)
    {
    char szServerName[MAX_COMPUTERNAME_LENGTH + 1];
    DWORD dwSize=sizeof(szServerName) ;
    if(!GetComputerName(szServerName,&dwSize))
    return false ;
    if(!szConnectionString)
    return false ; char szUserName[] = "SA";
    char szPassword[] = "";
    char szDatabase[] = "IPLOMA";//ADD YOU DATEBASE NAME

    sprintf(szConnectionString,"DSN=ODBCTEST;uid=%s;pwd=%s;",szServerName,szDatabase,szUserName,szPassword); //建立CONNECTION STRING return true;
    }VARIANT CDatabaseServer::getExecStoredProcedure(char *szTypes,SAFEARRAY *pSPFields)
    {
        _variant_t vtResultRows;
        try
        {
    _CommandPtr   pCmdPtr;
            _RecordsetPtr pRecordset;
            HRESULT hr ;  hr = pCmdPtr.CreateInstance(__uuidof(Command)); char szConnectionString[255];
    getConnectionString(szConnectionString);
    _variant_t vtConnectionString(szConnectionString);
    pCmdPtr->put_ActiveConnection(vtConnectionString);        pCmdPtr->CommandType = adCmdStoredProc; //CALL SQL SP
    pCmdPtr->CommandText =  szTypes ; //YOU SP NAME
    hr = pCmdPtr->Parameters->Refresh();    long lBound,uBound ;
       HRESULT hresult ;
       // Getting Safe Array's Lower and Upper Bounds
       hresult = SafeArrayGetLBound(pSPFields, 1, &lBound);
           hresult = SafeArrayGetUBound(pSPFields, 1, &uBound);    variant_t vtParamVal;
    _variant_t Index;
    Index.vt = VT_I2;
    Index.iVal = 1 ;
       for (long iElements=lBound;iElements<=uBound;iElements++)
       {
    hresult = SafeArrayGetElement(pSPFields, &iElements, &vtParamVal);
    pCmdPtr->GetParameters()->GetItem(Index)->PutValue(vtParamVal) ;
    Index.iVal++ ;
       }    //Execute current Stored Procedure
            _variant_t vEffected ;
    pRecordset = pCmdPtr->Execute(&vEffected,NULL,NULL);
    if (pRecordset->BOF || pRecordset->EndOfFile)
    throw ;
    // Get result set in the form of array
            vtResultRows = pRecordset->GetRows(-1);
            return vtResultRows.Detach() ;
    }
    catch(_com_error &e)
        {
    ATLTRACE((LPCSTR)e.Description());
        }
    vtResultRows.vt = VT_EMPTY ;
        return vtResultRows.Detach();
    }long CDatabaseServer::setExecStoredProcedure(char *szTypes,SAFEARRAY *pSPFields)
    {
        _variant_t vtResultRows;
        try
        {
            _CommandPtr   pCmdPtr;
            _RecordsetPtr pRecordset;
            HRESULT hr ;  hr = pCmdPtr.CreateInstance(__uuidof(Command)); char szConnectionString[255];
    getConnectionString(szConnectionString);
    _variant_t vtConnectionString(szConnectionString);
    pCmdPtr->put_ActiveConnection(vtConnectionString);        pCmdPtr->CommandType = adCmdStoredProc;
    pCmdPtr->CommandText =  szTypes ;
    hr = pCmdPtr->Parameters->Refresh();    long lBound,uBound;
       HRESULT hresult;
       // Getting Safe Array's Lower and Upper Bounds
       hresult = SafeArrayGetLBound(pSPFields, 1, &lBound);
           hresult = SafeArrayGetUBound(pSPFields, 1, &uBound);    variant_t vtParamVal;
    _variant_t Index;
    Index.vt = VT_I2;
    Index.iVal = 1 ;
       for (long iElements=lBound;iElements<=uBound;iElements++)
       {
    hresult = SafeArrayGetElement(pSPFields, &iElements, &vtParamVal);
    pCmdPtr->GetParameters()->GetItem(Index)->PutValue(vtParamVal) ;
    Index.iVal++ ;
       }        _variant_t vEffected ;
    pCmdPtr->Execute(&vEffected,NULL,NULL);

    // We Are Expecting That Stored Procedures Return ID for Entity to which 
    // NSERT/UPDATE/DELETE  operation is being performed
            return (long)pCmdPtr->Parameters->Item["RETURN_VALUE"]->Value  ;
        }
        catch(_com_error &e)
        {
           ATLTRACE((LPCSTR)e.Description());
        }
        return 0;
    }
      

  5.   

    在VC中使用ADO开发数据库应用程序
    一、ADO概述 
    ADO是Microsoft为最新和最强大的数据访问范例 OLE DB 而设计的,是一个便于使用的应用程序层接口。ADO 使您能够编写应用程序以通过 OLE.DB 提供者访问和操作数据库服务器中的数据。ADO 最主要的优点是易于使用、速度快、内存支出少和磁盘遗迹小。ADO 在关键的应用方案中使用最少的网络流量,并且在前端和数据源之间使用最少的层数,所有这些都是为了提供轻量、高性能的接口。之所以称为 ADO,是用了一个比较熟悉的暗喻,OLE 自动化接口。 
     
    OLE DB是一组”组件对象模型”(COM) 接口,是新的数据库低层接口,它封装了ODBC的功能,并以统一的方式访问存储在不同信息源中的数据。OLE DB是Microsoft UDA(Universal Data Access)策略的技术基础。OLE DB 为任何数据源提供了高性能的访问,这些数据源包括关系和非关系数据库、电子邮件和文件系统、文本和图形、自定义业务对象等等。也就是说,OLE DB 并不局限于 ISAM、Jet 甚至关系数据源,它能够处理任何类型的数据,而不考虑它们的格式和存储方法。在实际应用中,这种多样性意味着可以访问驻留在 Excel 电子数据表、文本文件、电子邮件/目录服务甚至邮件服务器,诸如 Microsoft Exchange 中的数据。但是,OLE DB 应用程序编程接口的目的是为各种应用程序提供最佳的功能,它并不符合简单化的要求。您需要的API 应该是一座连接应用程序和 OLE DB 的桥梁,这就是 ActiveX Data Objects (ADO)。 
     
    二、在VC中使用ADO 
    1、引入ADO库文件  
    使用ADO前必须在工程的stdafx.h文件里用直接引入符号#import引入ADO库文件,以使编译器能正确编译。代码如下所示: 
     
    代码1:用#import引入ADO库文件 
     
    #import "c:\program files\common files\system\ado\msado15.dll"  
     
    no_namespaces rename("EOF" adoEOF") 
     
    这行语句声明在工程中使用ADO,但不使用ADO的名字空间,并且为了避免常数冲突,将常数EOF改名为adoEOF。现在不需添加另外的头文件,就可以使用ADO接口了。 
     
    2、初始化OLE/COM库环境 
    必须注意的是,ADO库是一组COM动态库,这意味应用程序在调用ADO前,必须初始化OLE/COM库环境。在MFC应用程序里,一个比较好的方法是在应用程序主类的InitInstance成员函数里初始化OLE/COM库环境。 
     
     代码2:初始化OLE/COM库环境 
     
    BOOL CADOApp::InitInstance() 
     {  
    if(!AfxOleInit()) 
      { 
     
    AfxMessageBox(“OLE初始化出错!”); 
     
    return FALSE; 
     
    }  
     
    ……  
     

     
    函数AfxOleInit在每次应用程序启动时初始化OLE/COM库环境。 
     
    同DAO和CDatabase一样,ADO由几个接口组成: 
     
    _ConnectionPtr,_CommandPtr和_RecordsetPtr. 
     
    不同于DAO和Cdatabase的是,ADO基于COM的接口,因此,假如你没有接触过COM,你应该在使用ADO前先找有关书籍了解一下COM。 
     
    3、ADO接口简介 
    ADO库包含三个基本接口:_ConnectionPtr接口、_CommandPtr接口和_RecordsetPtr接口。 
     
    _ConnectionPtr接口返回一个记录集或一个空指针。通常使用它来创建一个数据连接或执行一条不返回任何结果的SQL语句,如一个存储过程。使用_ConnectionPtr接口返回一个记录集不是一个好的使用方法。通常同CDatabase一样,使用它创建一个数据连接,然后使用其它对象执行数据输入输出操作。 
     
    _CommandPtr接口返回一个记录集。它提供了一种简单的方法来执行返回记录集的存储过程和SQL语句。在使用_CommandPtr接口时,你可以利用全局_ConnectionPtr接口,也可以在_CommandPtr接口里直接使用连接串。如果你只执行一次或几次数据访问操作,后者是比较好的选择。但如果你要频繁访问数据库,并要返回很多记录集,那么,你应该使用全局_ConnectionPtr接口创建一个数据连接,然后使用_CommandPtr接口执行存储过程和SQL语句。 
     
    _RecordsetPtr是一个记录集对象。与以上两种对象相比,它对记录集提供了更多的控制功能,如记录锁定,游标控制等。同_CommandPtr接口一样,它不一定要使用一个已经创建的数据连接,可以用一个连接串代替连接指针赋给_RecordsetPtr的connection成员变量,让它自己创建数据连接。如果你要使用多个记录集,最好的方法是同Command对象一样使用已经创建了数据连接的全局_ConnectionPtr接口,然后使用_RecordsetPtr执行存储过程和SQL语句。 
    4、使用_ConnectionPtr接口 
     _ConnectionPtr是一个连接接口,它类似于CDatabase和CDaoDatabase。它们的工作原理相似。首先创建一个_ConnectionPtr接口实例,接着指向并打开一个ODBC数据源或OLE DB数据提供者(Provider)。以下代码和CDaoDatabase分别创建一个基于DSN和非DSN的数据连接。 
      
    代码3:使用CDaoDatabase(基于DSN) 
     
    CDaoDatabase MyDb = new CDaoDatabase(); 
     
    MyDb.Open(NULL,FALSE,FALSE,"ODBC;DSN=samp;UID=admin;PWD=admin"); 
       
     
    代码4:使用CDaoDatabase(基于非DSN) 
     
    CDaoDatabase MyDb = new CDaoDatabase(); 
     
    MyDb.Open(NULL,FALSE,FALSE,"ODBC;DRIVER={SQL Server};SERVER=server; 
     
    DATABASE=samp;UID=admin;PWD=admin"); 
     
       
    代码5:使用_ConnectionPtr(基于DSN) 
     
    _ConnectionPtr MyDb; 
     
    MyDb.CreateInstance(__uuidof(Connection)); 
     
    MyDb->Open("DSN=samp;UID=admin;PWD=admin","","",-1); 
     
       
    代码6:使用_ConnectionPtr (基于非DSN) 
     
    _ConnectionPtr MyDb; 
     
    MyDb.CreateInstance(__uuidof(Connection)); 
     
    MyDb->Open("Provider=SQLOLEDB;SERVER=server;DATABASE=samp;UID=admin; 
     PWD=admin","","",-1); 
       
    5、使用_RecordsetPtr接口 
     RecordsetPtr接口的使用方法和CDaoDatabase类似,通过以下代码的比较,你会发现使用_RecordsetPtr接口非常简单(以下代码使用上面已经创建的数据连接): 
     代码7:使用CDaoDatabase执行SQL语句 
     
    CDaoRecordset MySet = new CDaoRecordset(MyDb); 
     
    MySet->Open(AFX_DAO_USE_DEFAULT_TYPE,"SELECT * FROM t_samp"); 
     
    Now using ADO: 
     
       
    代码8:使用_RecordsetPtr执行SQL语句 
     
    _RecordsetPtr MySet; 
     
    MySet.CreateInstance(__uuidof(Recordset)); 
     
    MySet->Open("SELECT * FROM some_table", 
     
    MyDb.GetInterfacePtr(),adOpenDynamic,adLockOptimistic,adCmdText); 
     
    现在我们已经有了一个数据连接和一个记录集,接下来就可以使用数据了。从以下代码可以看到,使用ADO的_RecordsetPtr接口,就不需要象DAO那样频繁地使用大而复杂的数据结构VARIANT,并强制转换各种数据类型了,这也是ADO的优点之一。假定程序有一个名称为m_List的的ListBox控件,下面代码我们用_RecordsetPtr接口获取记录集数据并填充这个ListBox控件: 
        
    代码9:使用DAO访问数据 
     
    VARIANT * vFieldValue; 
     
    COleVariant covFieldValue; 
     
    CString Holder; 
     
    while(!MySet->IsEOF()) 

     
    MySet->GetFieldValue("FIELD_1", covFieldValue); 
     
    vFieldValue = (LPVARIANT)covFieldValue; 
     
    if(vFieldValue->vt!-VT_NULL) 
     

     
    Holder.Format("%s",vFieldValue->pbVal); 
     
    m_List.AddString(Holder); 
     
      } 
     
    MySet.MoveNext(); 
       
     } 
       
    代码10:使用ADO访问数据 
     
    _variant_t Holder 
     
    try{ 
     
    while(!MySet->adoEOF) 
     
    {  
    Holder = MySet->GetCollect("FIELD_1"); 
     
    if(Holder.vt!=VT_NULL) 
     
    m_List.AddString((char*)_bstr_t(Holder)); 
     
    MySet->MoveNext(); 
     

     

     
    catch(_com_error * e) 
     

     
    CString Error = e->ErrorMessage(); 
     
    AfxMessageBox(e->ErrorMessage()); 
     

     
    catch(...) 
     

    MessageBox("ADO发生错误!"); 
     

     
    必须始终在代码中用try和catch来捕获ADO错误,否则ADO错误会使你的应用程序崩溃。当ADO发生运行时错误时(如数据库不存在),OLE DB数据提供者将自动创建一个_com_error对象,并将有关错误信息填充到这个对象的成员变量. 
     
      
    6、使用_CommandPtr接口  
    _CommandPtr接口返回一个Recordset对象,并且提供了更多的记录集控制功能,以下代码示例了使用_CommandPtr接口的方法: 
      
    代码11:使用_CommandPtr接口获取数据 
     
    _CommandPtr pCommand; 
     
    _RecordsetPtr MySet; 
     
    pCommand.CreateInstance(__uuidof(Command)); 
     
    pCommand->ActiveConnection=MyDb; 
     
    pCommand->CommandText="select * from some_table"; 
     
    pCommand->CommandType=adCmdText;  
     
    pCommand->Parameters->Refresh(); 
     
    MySet=pCommand->Execute(NULL,NULL,adCmdUnknown); 
     
    _variant_t TheValue = MySet->GetCollect("FIELD_1"); 
     
    CString sValue=(char*)_bstr_t(TheValue); 
     
    7、关于数据类型转换  
    由于COM对象是跨平台的,它使用了一种通用的方法来处理各种类型的数据,因此CString 类和COM对象是不兼容的,我们需要一组API来转换COM对象和C++类型的数据。_vatiant_t和_bstr_t就是这样两种对象。它们提供了通用的方法转换COM对象和C++类型的数据。 
     
    8、小结  
    数据访问发展的趋势是OLE DB.使用OLE DB最简单的方法是ADO.ADO的对象层次模型封装了数据库访问细节,为C++程序员提供了一种非常好的数据访问策略。