转自:http://blogger.org.cn/blog/more.asp?name=fishyqd&id=13038
(1)建立ODBC数据源。
参考方法:http://www.gz9f.com/jiaocai/hcc/hcc6/hcc6-p1/hcc6-p1.htm
牢记:在此之前要把自己的数据库服务器启动,不然在服务器选择的时候看不到自己的服务器。
(2)
在工程的stdafx.h里用#import引入ADO库文件。
#import "C:/Program Files/Common Files/System/ado/msado15.dll" no_namespace rename("BOF","adoBOF") rename("EOF","adoEOF")
牢记:一定要在所有的#include后加入这句话,不然会出现。fatal error C1189: #error : WINDOWS.H already included. MFC apps must not #:nclude <windows.h>
我是参考了如下文章:http://www.allife.org/index.php?job=art&articleid=a_20060116_134912
原文引用如下:
2006年1月16日13:49星期一 [笔记 ]
文章来源: 李世平的专栏 一、问题由来 vc6 和 vc71 的工程向导中都包含非 MFC 的工程,诸如 win32 console project, win32 static library 。非 MFC 工程创建时是不支持 MFC 特性的,然后我们在处理实际问题时有时会用到 MFC 相关类,如 Cstring, Cedit 等等,这是很正常的。可能有人会说,为何不在一开始就创建 MFC 工程呢?问题在于 MFC 工程会产生很多向导生成代码,如基于单文档的工程会有 View,Doc 等类,很多时候我们只需要一个空工程就可以了。 二、常见问题 非 MFC 工程使用 MFC 库时最常见的问题就是 windows.h 重复包含错误,具体如下: fatal error C1189: #error : WINDOWS.H already included. MFC apps must not #include <windows.h> 三、解决办法 非 MFC 工程使用 MFC 库时,可参考以下步骤 1 、工程设置中,将 MFC 的使用由原来的“使用标准 windows 库”改为“在共享 DLL 中使用 MFC ”( VC71 ) 如果是英文版,相关选项是: Microsoft Foundation Classes: Use MFC in a shared dll, no using MFC ( VC6 ) NOTE: 因为我用的是中文版的 vc71, 英文版的 vc6. 2 、头文件包含 不同的 MFC 类需包含的头文件是不一样的。 常用的类,如 Cstring, Cedit 等,包含 afxwin.h 就可以了 如果不清楚包含什么头文件的话,可以同 msdn 进行查询, msdn 中,对于 MFC 类的介绍中,都会给出相应的 header file requirement. 3 、# include 语句一定要写在首行 这一点很重要,通常出现前面讲到的 windows.h 重复包含错误,都是因为 #include 语句没有写在首行。 另外还要注意的是,如果 #include 语句是在一个头文件里,那么对应头文件的包含也要写在首行。示例如下: ============= test.h 文件的内容如下: # include <afxwin.h> // 保证该语句在首行 test.cpp 的文件内容如下: #include “test.h” // 同样也要保证该语句在首行 ============= ps: 这么做的具体原因我也不知道,我是在实际调试中琢磨出这个道理的。我自己在这个问题上花了很多冤枉时间,写下该篇,就是希望大家不要在这个问题上绊脚。 (3)在进行连接之前要初始化OLE环境,初始化语句 ::CoInitialize(NULL); //初始化OLE/COM库环境 AfxOleInit();//初始化OLE/COM库环境(MFC自带的) 这两句话缺一不可,不然会有运行期错误 程序运行结束后记住::CoUninitialize(); //关闭OLE/COM库环境,释放资源 最后推荐一篇文章:http://farwen.com/ReadNews.asp?NewsID=3279 全文引用如下:
ADO数据库编程入门 |
| 2004-11-16 19:55:41 天宇网苑 Keaton 阅读301次 | 1、使用ADO编程的方法有三种: (1)使用预处理指令#import,例如: #import "c:/Program Files/Common Files/System/ado/msado15.dll" no_namespace rename("EOF", "adoEOF") rename("BOF", "adoBOF") 程 序在编译时读取msado15.dll中的类型库信息,自动生成两个该类型库的头文件和实现文件msado15.tlh和msado15.tli(在 Debug或Release目录下)。两个文件中定义了ADO的所有对象和方法,以及一些枚举类型的变量,程序只要直接调用这些方法即可。 (2)通过读取msado15.dll中的类型库信息,建立一个ColeDispatchDriver类的派生类,然后通过它调用ADO对象。 (3)直接使用COM提供的API,例如: CLSID clsid; HRESULT hr = ::CLSIDFromProgID(L"ADODB.Connection", &clsid); if (FAILED(hr)) { ... } ::CoCreateInstance(clsid, NULL, CLSCTX_SERVER, IID_IDispatch, (void **)&pDispatch); if (FAILED(hr)) { ... } 前两种方法类似,第3种方法编程可能最麻烦,但效率最高,程序尺寸最小,并且对ADO的控制能力也最强。 2、以下使用#import方法操作数据库 (1)可以在stdafx.h的所有include指令之后import (2)使用AfxOleInit()初始化COM库,通常在CwinApp::InitInstance的重载函数中添加。 (也可以使用::CoInitialize(NULL),之后在ExitInstance中调用::CoUninitialize) (3)定义_ConnectionPtr变量后调用Connection对象的Open方法建立与服务器的连接。 数据类型_ConnectionPtr实际上是由类模板_com_ptr_t得到的一个具体的实例类。_ConnectionPtr类封装了Connection对象的Idispatch接口指针及其一些必要的操作。可以通过这个指针操纵Connection对象。 例如连接SQLServer数据库,代码如下: // 连接到MS SQL Server _ConnectionPtr pMyConnect = NULL; HRESULT hr = pMyConnect.CreateInstance(__uuidof(Connection)); if (FAILED(hr)) return; _bstr_t strConnect = "Provider=SQLOLEDB; Server=hch; Database=mytest; uid=sa; pwd=sa;"; try { // Open方法连接字串必须四BSTR或者_bstr_t类型 pMyConnect->Open(strConnect, "", "", NULL); } catch(_com_error &e) { MessageBox(e.Description(), "警告", MB_OK|MB_ICONINFORMATION); } (4) //定义_RecordsetPtr变量,调用它Recordset对象的Open,即可打开一个数据集 _RecordsetPtr pRecordset; if (FAILED(pRecordset.CreateInstance(__uuidof(Recordset)))) { return; } try { pRecordset->Open(_variant_t("userinfo"), _variant_t((IDispatch*)pMyConnect), adOpenKeyset, adLockOptimistic, adCmdTable); } catch (_com_error &e) { MessageBox("无法打开userinfo表", "系统提示", MB_OK|MB_ICONINFORMATION); } (5) //定义_RecordsetPtr变量,调用它Recordset对象的Open,即可打开一个数据集 _RecordsetPtr pRecordset; if (FAILED(pRecordset.CreateInstance(__uuidof(Recordset)))) { return; } try { pRecordset->Open(_variant_t("userinfo"), _variant_t((IDispatch*)pMyConnect), adOpenKeyset, adLockOptimistic, adCmdTable); } catch (_com_error &e) { MessageBox("无法打开userinfo表", "系统提示", MB_OK|MB_ICONINFORMATION); } (6) // 读取当前记录集 try { pRecordset->MoveFirst(); while (pRecordset->adoEOF == VARIANT_FALSE) { // Fields是Recordset对象的容器,GetItem方法返回Field对象,Value是Field对象的属性,也可以用GetValue方法 CString sName = (char*)(_bstr_t)(pRecordset->Fields->GetItem(_variant_t("UserName"))->Value); // 或者使用GetValue() //CString sName = (char*)(_bstr_t)(pRecordset->Fields->GetItem(_variant_t("UserName"))->GetValue()); AfxMessageBox(sName); pRecordset->MoveNext(); } } catch (_com_error &e) { MessageBox(e.Description(), "系统提示", MB_OK|MB_ICONINFORMATION); } (7) // 修改记录 try { pRecordset->MoveFirst(); while(pRecordset->adoEOF == VARIANT_FALSE) { pRecordset->Fields->GetItem(_variant_t("Address"))->Value = _bstr_t("北京大学"); pRecordset->Update(); pRecordset->MoveNext(); } } catch (_com_error &e) { MessageBox(e.Description(), "系统提示", MB_OK|MB_ICONINFORMATION); } (8)添加,删除,使用带参数的命令,相应ADO的通知事件,绑定数据,设置过滤条件,索引和排序,事务处理。(略去,请参考其它资料) |
|
| | 相关专题: 原创文章 | 专题信息: | | Textarea中防止尖括号被替换 (2004-12-30 16:29:17)[414 ] | 在视图(CEditView)中设置字体 (2004-12-29 10:52:20)[324 ] | 随机产生23个4位数(每位数字不能重复) (2004-12-28 10:24:56)[266 ] | 输入密码不回显(显示*号)验证密码 (2004-12-28 10:03:15)[433 ] | cin输入字符串时的经典Bug (2004-12-27 15:01:48)[310 ] | [更多... ] |
| | 相关信息: | | 没有相关信息 |
| | 相关评论: | |
发表人:keaton |
| | 下面让我们看看ADO数据库访问技术使用的基本步骤及方法: 首先,要用#import 语句来引用支持ADO的组件类型库(*.tlb),其中类型库可以作为可执行程序(DLL、EXE等)的一部分被定位在其自身程序中的附属资源里,如:被 定位在msado15.dll的附属资源中,只需要直接用#import引用它既可。可以直接在Stdafx.h文件中加入下面语句来实现: #import "c:/program files/common files/system/ado/msado15.dll" / no_namespace / rename ("EOF", "adoEOF") 其 中路径名可以根据自己系统安装的ADO支持文件的路径来自行设定。当编译器遇到#import语句时,它会为引用组件类型库中的接口生成包装 类,#import语句实际上相当于执行了API涵数LoadTypeLib()。#import语句会在工程可执行程序输出目录中产生两个文件,分别 为*.tlh(类型库头文件)及*.tli(类型库实现文件),它们分别为每一个接口产生智能指针,并为各种接口方法、枚举类型,CLSID等进行声明, 创建一系列包装方法。语句no_namespace说明ADO对象不使用命名空间,rename ("EOF", "adoEOF")说明将ADO中结束标志EOF改为adoEOF,以避免和其它库中命名相冲突。 其次,在程序初始过程中需要初始化组件,一般可 以用CoInitialize(NULL);来实现,这种方法在结束时要关闭初始化的COM,可以用下面语句CoUnInitialize();来实现。 在MFC中还可以采用另一种方法来实现初始化COM,这种方法只需要一条语句便可以自动为我们实现初始化COM和结束时关闭COM的操作,语句如下所示: AfxOleInit(); 接着,就可以直接使用ADO的操作了。我们经常使用的只是前面用#import语句引用类型库时,生成的包装 类.tlh中声明的智能指针中的三个,它们分别是_ConnectionPtr、_RecordsetPtr和_CommandPtr。下面分别对它们的 使用方法进行介绍: 1、_ConnectionPtr智能指针,通常用于打开、关闭一个库连接或用它的Execute方法来执行一个不返回结果的命令语句(用法和_CommandPtr中的Execute方法类似)。 ——打开一个库连接。先创建一个实例指针,再用Open打开一个库连接,它将返回一个IUnknown的自动化接口指针。代码如下所示: _ConnectionPtr m_pConnection; // 初始化COM,创建ADO连接等操作 AfxOleInit(); m_pConnection.CreateInstance(__uuidof(Connection)); // 在ADO操作中建议语句中要常用try...catch()来捕获错误信息, // 因为它有时会经常出现一些意想不到的错误。jingzhou xu try { // 打开本地Access库Demo.mdb m_pConnection->Open("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Demo.mdb","","",adModeUnknown); } catch(_com_error e) { AfxMessageBox("数据库连接失败,确认数据库Demo.mdb是否在当前路径下!"); return FALSE; } ——关闭一个库连接。如果连接状态有效,则用Close方法关闭它并赋于它空值。代码如下所示: if(m_pConnection->State) m_pConnection->Close(); m_pConnection= NULL; 2、_RecordsetPtr智能指针,可以用来打开库内数据表,并可以对表内的记录、字段等进行各种操作。 ——打开数据表。打开库内表名为DemoTable的数据表,代码如下: _RecordsetPtr m_pRecordset; m_pRecordset.CreateInstance(__uuidof(Recordset)); // 在ADO操作中建议语句中要常用try...catch()来捕获错误信息, // 因为它有时会经常出现一些意想不到的错误。jingzhou xu try { m_pRecordset->Open("SELECT * FROM DemoTable", // 查询DemoTable表中所有字段 theApp.m_pConnection.GetInterfacePtr(), // 获取库接库的IDispatch指针 adOpenDynamic, adLockOptimistic, adCmdText); } catch(_com_error *e) { AfxMessageBox(e->ErrorMessage()); } —— 读取表内数据。将表内数据全部读出并显示在列表框内,m_AccessList为列表框的成员变量名。如果没有遇到表结束标志adoEOF,则用 GetCollect(字段名)或m_pRecordset->Fields->GetItem(字段名)->Value方法,来获取 当前记录指针所指的字段值,然后再用MoveNext()方法移动到下一条记录位置。代码如下所示: _variant_t var; CString strName,strAge; try { if(!m_pRecordset->BOF) m_pRecordset->MoveFirst(); else { AfxMessageBox("表内数据为空"); return; } // 读入库中各字段并加入列表框中 while(!m_pRecordset->adoEOF) { var = m_pRecordset->GetCollect("Name"); if(var.vt != VT_NULL) strName = (LPCSTR)_bstr_t(var); var = m_pRecordset->GetCollect("Age"); if(var.vt != VT_NULL) strAge = (LPCSTR)_bstr_t(var); m_AccessList.AddString( strName + " --> "+strAge ); m_pRecordset->MoveNext(); } // 默认列表指向第一项,同时移动记录指针并显示 m_AccessList.SetCurSel(0); } catch(_com_error *e) { AfxMessageBox(e->ErrorMessage()); } ——插入记录。可以先用AddNew()方法新增一个空记录,再用PutCollect(字段名,值)输入每个字段的值,最后再Update()更新到库中数据既可。其中变量m_Name和m_Age分别为姓名及年龄编辑框的成员变量名。代码所下所示: try { // 写入各字段值 m_pRecordset->AddNew(); m_pRecordset->PutCollect("Name", _variant_t(m_Name)); m_pRecordset->PutCollect("Age", atol(m_Age)); m_pRecordset->Update(); AfxMessageBox("插入成功!"); } catch(_com_error *e) { AfxMessageBox(e->ErrorMessage()); } —— 移动记录指针。移动记录指针可以通过MoveFirst()方法移动到第一条记录、MoveLast()方法移动到最后一条记录、 MovePrevious()方法移动到当前记录的前一条记录、MoveNext()方法移动到当前记录的下一条记录。但我们有时经常需要随意移动记录指 针到任意记录位置时,可以使用Move(记录号)方法来实现,注意: Move()方法是相对于当前记录来移动指针位置的,正值向后移动、负值向前移动,如:Move(3),当前记录是3时,它将从记录3开始往后再移动3条 记录位置。代码如下所示: try { int curSel = m_AccessList.GetCurSel(); // 先将指针移向第一条记录,然后就可以相对第一条记录来随意移动记录指针 m_pRecordset->MoveFirst(); m_pRecordset->Move(long(curSel)); } catch(_com_error *e) { AfxMessageBox(e->ErrorMessage()); } ——修改记录中字段值。可以将记录指针移动到要修改记录的位置处,直接用PutCollect(字段名,值)将新值写入并Update()更新数据库既可。可以用上面方法移动记录指针,修改字段值代码如下所示: try { // 假设对第二条记录进行修改 m_pRecordset->MoveFirst(); m_pRecordset->Move(1); // 从0开始 m_pRecordset->PutCollect("Name", _variant_t(m_Name)); m_pRecordset->PutCollect("Age", atol(m_Age)); m_pRecordset->Update(); } catch(_com_error *e) { AfxMessageBox(e->ErrorMessage()); } ——删除记录。删除记录和上面修改记录的操作类似,先将记录指针移动到要修改记录的位置,直接用Delete()方法删除它并用Update()来更新数据库既可。代码如下所示: try { // 假设删除第二条记录 m_pRecordset->MoveFirst(); m_pRecordset->Move(1); // 从0开始 m_pRecordset->Delete(adAffectCurrent); // 参数adAffectCurrent为删除当前记录 m_pRecordset->Update(); } catch(_com_error *e) { AfxMessageBox(e->ErrorMessage()); } ——关闭记录集。直接用Close方法关闭记录集并赋于其空值。代码如下所示: m_pRecordset->Close(); m_pRecordset = NULL; 3、CommandPtr智能指针,可以使用_ConnectionPtr或_RecordsetPtr来执行任务,定义输出参数,执行存储过程或SQL语句。 ——执行SQL语句。先创建一个_CommandPtr实例指针,再将库连接和SQL语句做为参数,执行Execute()方法既可。代码如下所示: _CommandPtr m_pCommand; m_pCommand.CreateInstance(__uuidof(Command)); m_pCommand->ActiveConnection = m_pConnection; // 将库连接赋于它 m_pCommand->CommandText = "SELECT * FROM DemoTable"; // SQL语句 m_pRecordset = m_pCommand->Execute(NULL, NULL,adCmdText); // 执行SQL语句,返回记录集 —— 执行存储过程。执行存储过程的操作和上面执行SQL语句类似,不同点仅是CommandText参数中不再是SQL语句,而是存储过程的名字,如 Demo。另一个不同点就是在Execute()中参数由adCmdText(执行SQL语句),改为adCmdStoredProc来执行存储过程。如 果存储过程中存在输入、输出参数的话,需要使用到另一个智能指针_ParameterPtr来逐次设置要输入、输出的参数信息,并将其赋于 _CommandPtr中Parameters参数来传递信息,有兴趣的读者可以自行查找相关书籍或MSDN。执行存储过程的代码如下所示: _CommandPtr m_pCommand; m_pCommand.CreateInstance(__uuidof(Command)); m_pCommand->ActiveConnection = m_pConnection; // 将库连接赋于它 m_pCommand->CommandText = "Demo"; m_pCommand->Execute(NULL,NULL, adCmdStoredProc); 最后,如果想知道详细实现细节的话,可以在下载示例源码后,仔细查看源码既可(内有详细注释)。 | | |