分享
 
 
 

结合ADO、ADOX和MFC的文档/视图/框架架构创建和打开Access数据库

王朝vc·作者佚名  2006-01-09
窄屏简体版  字體: |||超大  

预备阅读

在阅读本文之前,建议先对COM,数据库和MFC的文档/视图/框架有一个基本的了解。推荐阅读下列文章

MFC技术文章

TN025: Document, View, and Frame Creation

微软知识库文章

Q183606 ActiveX Data Objects (ADO) Frequently Asked Questions

Q169496 INFO: Using ActiveX Data Objects (ADO) via #import in VC++

Q317881 HOW TO: Create an Access Database Using ADOX and Visual C# .NET

Q252908 HOWTO: Create a Table with Primary Key Through ADOX

Q201826 PRB: Error 3265 When You Access Properties Collection

Office VBA参考

Creating and Modifying Access Tables

步骤

在计算机上安装MDAC2.5以上版本

打开VC。首先,我们使用MFC应用程序向导创建一个标准的MDI程序,这里我为这个工程起名为Passport,然后在stdafx.h中导入ADOX

#include <shlwapi.h>

#import "c:\Program Files\Common Files\system\ado\Msado15.dll" rename("EOF","adoEOF") rename("DataTypeEnum","adoDataTypeEnum")

#import "c:\Program Files\Common Files\System\ADO\Msadox.dll" rename("EOF", "adoXEOF") rename("DataTypeEnum","adoXDataTypeEnum")

#import "c:\PROGRAM FILES\COMMON FILES\System\ado\MSJRO.DLL"

根据你的计算机上ADO的安装路径,这里的路径可能有所不同。

在文档类中声明数据库连接 ADODB::_ConnectionPtr m_pConn;和记录集 ADODB::_RecordsetPtr m_pSet;,并且重载文档类的DeleteContents() 、OnNewDocument()和OnOpenDocument()函数,用于断开数据库连接,创建数据库和表,以及打开现有的数据库。

(作者的抱怨:CSDN文章中心该改改了,代码排版这么麻烦)

void CPassportDoc::DeleteContents()

{

try

{

if(m_pSet){

ESRecordsetClose(m_pSet);

}

if(m_pConn)

if(m_pConn->State&ADODB::adStateOpen)

m_pConn->Close();

m_pConn=NULL;

}

catch(_com_error &e){

ESErrPrintProviderError(m_pConn);

ESErrPrintComError(e);

}

CDocument::DeleteContents();

}BOOL CPassportDoc::OnNewDocument()

{

if (!CDocument::OnNewDocument())

return FALSE;

CFileDialog dlgFile(FALSE, _T(".mdb"), NULL, OFN_HIDEREADONLY | OFN_PATHMUSTEXIST, _T("Access 数据库 (*.mdb)|*.mdb|全部文件(*.*)|*.*||"));

if (dlgFile.DoModal() != IDOK)

return FALSE;

CString strDBPath=dlgFile.GetPathName();

if(!CreateDB(strDBPath))return FALSE;

//create

CString strConnect;

strConnect.Format(_T("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%s"),strDBPath);

COleVariant Connect(strConnect);

// TODO: add reinitialization code here

// (SDI documents will reuse this document)

try{

m_pConn.CreateInstance(_T("ADODB.Connection"));

m_pSet.CreateInstance(_T("ADODB.Recordset"));

m_pConn->PutCommandTimeout(30);

m_pConn->PutConnectionTimeout(30);

m_pConn->put_CursorLocation(ADODB::adUseClient);

m_pConn->Open(_bstr_t(strConnect),_bstr_t(),_bstr_t(),ADODB::adConnectUnspecified);

::ESRecordsetOpen(_T("Passport"),m_pConn,m_pSet);

SetPathName(strDBPath);

return TRUE;

}

catch(_com_error &e){

ESErrPrintProviderError(m_pConn);

ESErrPrintComError(e);

}

catch(...){

}

m_pConn=NULL;

return FALSE;

}

BOOL CPassportDoc::OnOpenDocument(LPCTSTR lpszPathName)

{

if (!CDocument::OnOpenDocument(lpszPathName))

return FALSE;

ADODB::_ConnectionPtr tempConnn;

CString strConnect;

CString strDBPath=lpszPathName;

strConnect.Format(_T("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%s"),strDBPath);

COleVariant Connect(strConnect);

// TODO: add reinitialization code here

// (SDI documents will reuse this document)

try{

tempConnn.CreateInstance(_T("ADODB.Connection"));

tempConnn->PutCommandTimeout(30);

tempConnn->PutConnectionTimeout(30);

tempConnn->put_CursorLocation(ADODB::adUseClient);

tempConnn->Open(_bstr_t(strConnect),_bstr_t(),_bstr_t(),ADODB::adConnectUnspecified);

SetPathName(strDBPath);

m_pConn=tempConnn;

m_pSet=NULL;

m_pSet.CreateInstance(_T("ADODB.Recordset"));

::ESRecordsetOpen(_T("Passport"),m_pConn,m_pSet);

UpdateAllViews(NULL,UpdateHintRefresh);

return TRUE;

}

catch(_com_error &e){

ESErrPrintProviderError(tempConnn);

ESErrPrintComError(e);

}

catch(...){

}

return FALSE;

}

编写一个辅助函数,用于创建数据库、表和索引

BOOL CPassportDoc::CreateDB(LPCTSTR lpszFile)

{

if(::PathFileExists(lpszFile)){

CString strTemp;

strTemp.Format(IDS_TARGET_EXISTS,lpszFile);

AfxMessageBox(lpszFile);

return FALSE;

}

ADODB::_ConnectionPtr tempConnn;

ADOX::_CatalogPtr pCatalog = NULL;

ADOX::_TablePtr pTable = NULL;

ADOX::_IndexPtr pIndexNew = NULL;

ADOX::_IndexPtr pIndex = NULL;

CString strConnect;

CString strDBPath=lpszFile;

strConnect.Format(_T("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%s"),strDBPath);

COleVariant Connect(strConnect);

try{

pCatalog.CreateInstance(_T("ADOX.Catalog"));

pCatalog->Create((LPCTSTR)strConnect);//创建数据库

tempConnn.CreateInstance(_T("ADODB.Connection"));

tempConnn->PutCommandTimeout(30);

tempConnn->PutConnectionTimeout(30);

tempConnn->put_CursorLocation(ADODB::adUseClient);

tempConnn->Open(_bstr_t(strConnect),_bstr_t(),_bstr_t(),ADODB::adConnectUnspecified);

pCatalog->PutActiveConnection(_variant_t((IDispatch *) tempConnn));

pTable.CreateInstance(_T("ADOX.Table"));

pTable->ParentCatalog =pCatalog;

pTable->Name="Passport";

ADOX::ColumnsPtr pCols =pTable->Columns;

pCols->Append(_T("RecordID") ,ADOX::adInteger,0);//自动编号字段

pCols->Append(_T("Name") ,ADOX::adWChar,255);//文本字段

pCols->Append(_T("DateOfBirth") ,ADOX::adDate,0);//日期字段

pCols->Append(_T("OtherInfo"),ADOX::adLongVarWChar,0);//备注字段

pCatalog->Tables->Refresh();

long lCount=pCols->Count;

for(long i=0;i<lCount;i++){

pCols->GetItem(i)->ParentCatalog =pCatalog;//重要!设置Catalog,参见Q201826 PRB: Error 3265 When You Access Properties Collection

ADOX::PropertiesPtr pProperties=pCols->GetItem(i)->Properties;

if(pProperties){//这里是用于调试的属性显示代码

long lp=pProperties->Count;

TRACE("Properties for Col %s\r\n",(LPCTSTR)pCols->GetItem(i)->Name);

for(long j=0;j<lp;j++){

TRACE("\rProperty %s:%s\r\n",g_GetValueString(pProperties->GetItem(j)->Name)

,g_GetValueString(pProperties->GetItem(j)->Value));

}

}

}

pCols->GetItem(_T("RecordID"))->Properties->GetItem(_T("Description"))->Value=_T("记录编号");//注释

pCols->GetItem(_T("RecordID"))->Properties->GetItem(_T("AutoIncrement"))->Value=true;//自动编号

pCols->GetItem(_T("Name"))->Properties->GetItem(_T("Jet OLEDB:Compressed UniCode Strings"))->Value=true;

pCols->GetItem(_T("Name"))->Properties->GetItem(_T("Description"))->Value=_T("姓名");

pCols->GetItem(_T("DateOfBirth"))->Properties->GetItem(_T("Description"))->Value=_T("出生日期");

pCols->GetItem(_T("OtherInfo"))->Properties->GetItem(_T("Jet OLEDB:Compressed UniCode Strings"))->Value=true;

pCols->GetItem(_T("OtherInfo"))->Properties->GetItem(_T("Description"))->Value=_T("其他信息");

pCatalog->Tables->Append(_variant_t ((IDispatch*)pTable));//添加表

pCatalog->Tables->Refresh();//刷新

pIndexNew.CreateInstance(_T("ADOX.Index"));

pIndexNew->Name = "RecordID";//索引名称

pIndexNew->Columns->Append("RecordID",ADOX::adInteger,0);//索引字段

pIndexNew->PutPrimaryKey(-1);//主索引

pIndexNew->PutUnique(-1);//唯一索引

pTable->Indexes->Append(_variant_t ((IDispatch*)pIndexNew));//创建索引

pIndexNew=NULL;

pCatalog->Tables->Refresh();//刷新

return TRUE;

}

catch(_com_error &e){

ESErrPrintProviderError(tempConnn);

ESErrPrintComError(e);

return FALSE;

}

catch(...){

}

return FALSE;

}

辅助的数据库函数。由于这些函数是Jiangsheng以前为一个项目写的。所以命名有些奇怪。借鉴了MFC类CDaoRecordset的部分代码

#define _countof(array) (sizeof(array)/sizeof(array[0]))

BOOL ESRecordsetOpen(

LPCTSTR lpszSQL

,ADODB::_ConnectionPtr pConnection

,ADODB::_RecordsetPtr& rst

,ADODB::CursorTypeEnum CursorType//=adOpenDynamic

,ADODB::LockTypeEnum LockType//=ado20::adLockOptimistic

,long lOptions//=adCmdUnspecified

)

{

_bstr_t bstrQuery;

const TCHAR _afxParameters2[] = _T("PARAMETERS ");

const TCHAR _afxSelect2[] = _T("SELECT ");

const TCHAR _afxTransform2[] = _T("TRANSFORM ");

const TCHAR _afxTable2[] = _T("TABLE ");

// construct the default query string

if ((_tcsnicmp(lpszSQL, _afxSelect2, _countof(_afxSelect2)-1) != 0) &&

(_tcsnicmp(lpszSQL, _afxParameters2, _countof(_afxParameters2)-1) != 0) &&

(_tcsnicmp(lpszSQL, _afxTransform2, _countof(_afxTransform2)-1) != 0) &&

(_tcsnicmp(lpszSQL, _afxTable2, _countof(_afxTable2)-1) != 0)){

CString strTemp;

strTemp.Format("SELECT * FROM (%s)",lpszSQL);

bstrQuery=(LPCTSTR)strTemp;

}

else

bstrQuery=lpszSQL;

if(rst!=NULL){

rst->CursorLocation=ADODB::adUseClient;

rst->Open(bstrQuery,_variant_t(pConnection.GetInterfacePtr(),true),CursorType,LockType,lOptions);

}

TRACE("Open Recordset:%s\n",lpszSQL);

return ESRecordsetIsOpen(rst);

}

BOOL ESRecordsetIsOpen(const ADODB::_RecordsetPtr& rst)

{

if(rst!=NULL){

return rst->State&ADODB::adStateOpen;

}

return FALSE;

}

void ESRecordsetClose(ADODB::_RecordsetPtr& rst)

{

if(rst!=NULL){

if(rst->State&ADODB::adStateOpen)

rst->Close();

}

}

CString g_GetValueString(const _variant_t& val)

{

CString strVal;

_variant_t varDest(val);

if(!g_varIsValid(val)){

return strVal;

}

if(val.vt==VT_BOOL){

if(val.boolVal==VARIANT_FALSE){

return _T("否");

}

else

return _T("是");

}

else{

}

if(varDest.vt!=VT_BSTR){

HRESULT hr=::VariantChangeType(&varDest,&varDest,VARIANT_NOUSEROVERRIDE|VARIANT_LOCALBOOL,VT_BSTR);

if(FAILED(hr)){

return strVal;

}

}

strVal=(LPCTSTR)_bstr_t(varDest);

return strVal;

}

错误处理代码

void ESErrPrintComError(_com_error &e)

{

_bstr_t bstrSource(e.Source());

_bstr_t bstrDescription(e.Description());

CString strTemp;

strTemp.Format(_T("′错误\n\t错误代码: %08lx\n\t含义: %s\n\t来自 : %s\n\t描述 : %s\n"),

e.Error(),e.ErrorMessage(),(LPCSTR) bstrSource,(LPCSTR) bstrDescription);

// Print COM errors.

::AfxMessageBox(strTemp);

#ifdef _DEBUG

AfxDebugBreak();

#endif

}

void ESErrPrintProviderError(ADODB::_ConnectionPtr pConnection)

{

if(pConnection==NULL) return;

try{

// Print Provider Errors from Connection object.

// pErr is a record object in the Connection's Error collection.

ADODB::ErrorPtr pErr = NULL;

ADODB::ErrorsPtr pErrors=pConnection->Errors;

if(pErrors){

if( (pErrors->Count) > 0){

long nCount = pErrors->Count;

// Collection ranges from 0 to nCount -1.

for(long i = 0;i < nCount;i++){

pErr = pErrors->GetItem(i);

CString strTemp;

strTemp.Format(_T("\t 错误代码: %x\t%s"), pErr->Number, pErr->Description);

}

}

}

}

catch(_com_error &e){

ESErrPrintComError(e);

}

}

总结

在文档/视图/框架架构中集成数据库访问总体来说还是难度不大的。微软提供了很多示例的代码,大部分工作只是把示例代码从其他语言改写到VC。主要的工作是对MFC的文档/视图/框架架构的理解,在适当的时候调用这些代码。

尽管我在打开数据库的同时也打开了一个记录集,但是我并未给出显示记录集内容的代码,这超出了本文的范围。我可以给出的提示是使用现成的数据列表控件来显示,微软知识库文章Q229029 SAMPLE: AdoDataGrid.exe Demonstrates How to Use ADO with DataGrid Control Using Visual C++可以作为参考。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有