目錄
预备阅读
步骤
总结
首頁 資料庫 mysql教程 结合ADO、ADOX和MFC的文档/视图/框架架构创建和打开Access数据库

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

Jun 07, 2016 pm 03:39 PM
mfc 建和 文件 架構 框架 結合 視圖

本文描述了如何在MFC的文档/视图/框架架构中使用ADO和ADOX来创建和打开数据库。 预备阅读 MFC技术文章 TN025: Document, View, and Frame Creation 微软知识库文章 Q183606 ActiveX Data Objects (ADO) Frequently Asked Questions Q169496 INFO: Using Acti

本文描述了如何在MFC的文档/视图/框架架构中使用ADO和ADOX来创建和打开数据库。

预备阅读

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

步骤

  1. 在计算机上安装MDAC2.5以上版本
  2. 打开VC。首先,我们使用MFC应用程序向导创建一个标准的MDI程序,这里我为这个工程起名为Passport,然后在stdafx.h中导入ADOX
    #include
    #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的安装路径,这里的路径可能有所不同。
  3. 在文档类中声明数据库连接 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;
    }
  4. 编写一个辅助函数,用于创建数据库、表和索引
    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   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     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;
    }
  5. 辅助的数据库函数。由于这些函数是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;
    }
  6. 错误处理代码
    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      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++可以作为参考。

本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

Video Face Swap

Video Face Swap

使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱工具

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

禪工作室 13.0.1

禪工作室 13.0.1

強大的PHP整合開發環境

Dreamweaver CS6

Dreamweaver CS6

視覺化網頁開發工具

SublimeText3 Mac版

SublimeText3 Mac版

神級程式碼編輯軟體(SublimeText3)

golang框架架構的學習曲線有多陡峭? golang框架架構的學習曲線有多陡峭? Jun 05, 2024 pm 06:59 PM

Go框架架構的學習曲線取決於對Go語言和後端開發的熟悉程度以及所選框架的複雜性:對Go語言的基礎知識有較好的理解。具有後端開發經驗會有所幫助。複雜度不同的框架導致學習曲線差異。

如何評估Java框架商業支援的性價比 如何評估Java框架商業支援的性價比 Jun 05, 2024 pm 05:25 PM

評估Java框架商業支援的性價比涉及以下步驟:確定所需的保障等級和服務等級協定(SLA)保證。研究支持團隊的經驗和專業知識。考慮附加服務,如昇級、故障排除和效能最佳化。權衡商業支援成本與風險緩解和提高效率。

PHP 框架的學習曲線與其他語言框架相比如何? PHP 框架的學習曲線與其他語言框架相比如何? Jun 06, 2024 pm 12:41 PM

PHP框架的學習曲線取決於語言熟練度、框架複雜性、文件品質和社群支援。與Python框架相比,PHP框架的學習曲線較高,而與Ruby框架相比,則較低。與Java框架相比,PHP框架的學習曲線中等,但入門時間較短。

綜述!全面概括基礎模型對於推動自動駕駛的重要作用 綜述!全面概括基礎模型對於推動自動駕駛的重要作用 Jun 11, 2024 pm 05:29 PM

写在前面&笔者的个人理解最近来,随着深度学习技术的发展和突破,大规模的基础模型(FoundationModels)在自然语言处理和计算机视觉领域取得了显著性的成果。基础模型在自动驾驶当中的应用也有很大的发展前景,可以提高对于场景的理解和推理。通过对丰富的语言和视觉数据进行预训练,基础模型可以理解和解释自动驾驶场景中的各类元素并进行推理,为驾驶决策和规划提供语言和动作命令。基础模型可以根据对驾驶场景的理解来实现数据增强,用于提供在常规驾驶和数据收集期间不太可能遇到的长尾分布中那些罕见的可行

PHP 框架的輕量級選項如何影響應用程式效能? PHP 框架的輕量級選項如何影響應用程式效能? Jun 06, 2024 am 10:53 AM

輕量級PHP框架透過小體積和低資源消耗提升應用程式效能。其特點包括:體積小,啟動快,記憶體佔用低提升響應速度和吞吐量,降低資源消耗實戰案例:SlimFramework創建RESTAPI,僅500KB,高響應性、高吞吐量

golang框架文件最佳實踐 golang框架文件最佳實踐 Jun 04, 2024 pm 05:00 PM

編寫清晰全面的文件對於Golang框架至關重要。最佳實踐包括:遵循既定文件風格,例如Google的Go程式設計風格指南。使用清晰的組織結構,包括標題、子標題和列表,並提供導覽。提供全面且準確的信息,包括入門指南、API參考和概念。使用程式碼範例說明概念和使用方法。保持文件更新,追蹤變更並記錄新功能。提供支援和社群資源,例如GitHub問題和論壇。建立實際案例,如API文件。

golang框架文件使用說明 golang框架文件使用說明 Jun 05, 2024 pm 06:04 PM

如何使用Go框架文檔?確定文件類型:官網、GitHub儲存庫、第三方資源。了解文件結構:入門指南、深入教學、參考手冊。根據需要定位資訊:使用組織結構或搜尋功能。理解術語和概念:仔細閱讀並理解新的術語和概念。實戰案例:使用Beego創建一個簡單的Web伺服器。其他Go框架文件:Gin、Echo、Buffalo、Fiber。

如何為不同的應用場景選擇最佳的golang框架 如何為不同的應用場景選擇最佳的golang框架 Jun 05, 2024 pm 04:05 PM

根據應用場景選擇最佳Go框架:考慮應用類型、語言特性、效能需求、生態系統。常見Go框架:Gin(Web應用)、Echo(Web服務)、Fiber(高吞吐量)、gorm(ORM)、fasthttp(速度)。實戰案例:建構RESTAPI(Fiber),與資料庫互動(gorm)。選擇框架:效能關鍵選fasthttp,靈活Web應用選Gin/Echo,資料庫互動選gorm。

See all articles