如何使用 MFC 检索 Office 文档中的宏名称的列表

若要获得 Microsoft Excel 中的 VBA 过程的列表的工作簿、 一个 PowerPoint 演示文稿或 Word 文档,您可以使用类和函数公开结合的应用程序对象模型的应用程序扩展库通过 Microsoft vba。当利用自动化功能打开文档时,您可以访问的文档以循环访问集合的 VBComponentsVBProject 对象 ; VBComponents 集合包括标准模块,以及在项目中包含的类模块。在您有了一个 VBComponent 的引用后您可以检索其属性 (包括代码),并根据需要处理该组件。

注意有关 Microsoft Access 的特殊注意事项: Microsoft Access 是一个例外,因为 Visual Basic,应用程序扩展库的不需要访问数据库项目中的代码。Microsoft Access 对象模型公开方法或属性使您直接与访问代码模块。检索或处理与在 Access 数据库中的模块代码有关的警告之一是,必须先打开该模块。

下面的步骤演示了如何创建一个 MFC 自动化客户端从 Office 文档中检索的 Sub函数 的过程列表。该代码示例说明了对 Office 应用程序的类型库和应用程序扩展库的 vba 中使用类包装,该示例还提供了用于 Microsoft Access 数据库的特殊案例考虑。

  1. 在 Visual 的 c + + 中创建名为 ListMacrosMFC 应用程序向导 EXE 项目。选择 基于对话框的 作为类型,然后接受其他所有默认设置。
  2. 视图 菜单上单击 类向导类向导 对话框中单击 自动化 选项卡,然后执行下列操作:
    • 单击 添加类,并选择 从类型库
    • 浏览以找到该 Microsoft Visual Basic 应用程序扩展类型库 (VBE6EXT.olb),然后单击 打开

      注意VBE6EXT.olb 在默认文件夹是Program Files/Common Files/Microsoft Shared/VBA/VBA6。
    • 在类型库中选择所有类,然后单击 确定 以创建类包装。
  3. 重复上述步骤创建 Microsoft Excel、 PowerPoint、 Microsoft Access 和 Microsoft Word 类型库包装类。选择正确的类型库中的您的 Office 的版本。请参见"参考"部分,稍后在本文中有关查找正确的类型库的信息。
  4. 若要不必类名称冲突添加类包装的每个命名空间通过执行下列操作:
    • Excel9.h 的开头添加以下代码:
      namespace Excel{ 
      
      ,然后添加一个右大括号 (}) 文件的末尾。
    • 下面的代码添加到开头 Excel9.cpp,读取 #endif (不带引号) 的行的下方,并在第一个类的定义之前:
      using namespace Excel;
      
  5. 重复这些步骤以创建所剩余的命名空间: MSWordPPTMSAccessVBAExt
  6. 单击 ResourceView,然后打开 IDD_LISTMACROS_DIALOG 对话框。删除对话框上绘制,并将其替换为以下控件的任何控件:
       Control Type     Properties
       ------------     -------------------------
    
       Button           ID:           ID_Run
                        Caption:      Run
    
       Edit Box         ID:           IDC_FILENAME
    
       List Box         ID:           IDC_MACROLIST
                        Use Tabstops: Checked     
    					
  7. 视图 菜单上单击 类向导、 选择 成员变量 选项卡上、 类名 下拉列表框中选择 CListMacrosDlg,然后执行下列:
    • 在控件列表上双击 $ IDC_FILENAME添加成员变量 对话框中提供的变量名 m_sFilename,然后单击 确定
    • 在控件列表上双击 $ IDC_MACROLIST添加成员变量 对话框中提供的变量名 m_MacroList控制,更改 类别,然后单击 确定
  8. 单击 确定 以关闭 类向导 对话框。
  9. 双击对话框上的 运行 按钮。单击 确定 以添加该成员函数 OnRun。将下面的代码添加到 CListMacrosDlg::OnRun()
    void CListMacrosDlg::OnRun() 
    {
       USES_CONVERSION;
    
       UpdateData(TRUE);
    
    
       COleVariant vOpt(DISP_E_PARAMNOTFOUND, VT_ERROR); //for Optional args
    
       //Determine the PROGID for the filename supplied
       CLSID clsid;
       HRESULT hr = GetClassFile(T2OLE(m_sFilename), &clsid);
       if (FAILED(hr))
       {
          CString sMsg;
          sMsg.Format("Unable to determine progid for file: %s", m_sFilename);
          AfxMessageBox(sMsg);
          return;
       }
    
       LPOLESTR lpOleStr;
       ProgIDFromCLSID(clsid, &lpOleStr);
       CString sProgID = CString(lpOleStr);
       sProgID.MakeUpper();
       
       //If the version independent progid is EXCEL.SHEET, WORD.DOCUMENT, or
       //POWERPOINT.SHOW, then open the file in its associated application.
       //Once the file is open, call GetMacros to place the list of macro
       //names in the list box.
    
       if(sProgID.Find("EXCEL.SHEET",0)>=0)  //Microsoft Excel Workbook
       {
          Excel::_Application oApp;
          oApp.CreateDispatch("Excel.Application");
          Excel::Workbooks oBooks = oApp.GetWorkbooks();
          Excel::_Workbook oBook = oBooks.Open(m_sFilename, vOpt, vOpt, vOpt, 
                                               vOpt, vOpt, vOpt, vOpt, vOpt, 
                                               vOpt, vOpt, vOpt, vOpt);
          LPDISPATCH lpDisp = oBook.GetVBProject();
          GetMacros(lpDisp);
          oBook.Close(COleVariant((short)FALSE), vOpt, vOpt);
          oApp.Quit();
       }
    
       else if(sProgID.Find("WORD.DOCUMENT",0)>=0)    //Microsoft Word Document
       {
          MSWord::_Application oApp;
          oApp.CreateDispatch("Word.Application");
          MSWord::Documents oDocs = oApp.GetDocuments();
          MSWord::_Document oDoc = oDocs.Open(COleVariant(m_sFilename), vOpt,
                                              vOpt, vOpt, vOpt, vOpt, vOpt, 
                                              vOpt, vOpt, vOpt, vOpt, vOpt);
    	   // For Office Word 2003 and Office Word 2007, 16 parameters are required.
        /*  MSWord::_Document oDoc = oDocs.Open(COleVariant(m_sFilename), vOpt,
                                              vOpt, vOpt, vOpt, vOpt, vOpt, 
                                              vOpt, vOpt, vOpt, vOpt, vOpt,
    		                              								  vOpt,vOpt,vOpt,vOpt);
        */
          LPDISPATCH lpDisp = oDoc.GetVBProject();
          GetMacros(lpDisp);
          oDoc.Close(COleVariant((short)FALSE), vOpt, vOpt);
          oApp.Quit(vOpt, vOpt, vOpt);
       }
    
       else if(sProgID.Find("POWERPOINT.SHOW",0)>=0)  //Microsoft PowerPoint
    
                                                      //Presentation
       {
          PPT::_Application oApp;
          oApp.CreateDispatch("Powerpoint.Application");
          PPT::Presentations oAllPres = oApp.GetPresentations();
          PPT::_Presentation oPres = oAllPres.Open(m_sFilename, 0, 0, 0);
          LPDISPATCH lpDisp = oPres.GetVBProject();
          GetMacros(lpDisp);
          oPres.Close();
          oApp.Quit();
       }
    
       else if(sProgID.Find("ACCESS.APPLICATION", 0)>=0)  //Microsoft Access DB
    
       {   //** Special Consideration for Access Code Project
    
           MSAccess::_Application oApp;
           oApp.CreateDispatch("Access.Application");
           MSAccess::DoCmd oDoCmd = oApp.GetDoCmd();
           oApp.OpenCurrentDatabase(m_sFilename, FALSE);
           // For Office Access 2003 and Office Access 2007, 3 parameters are required.
           /*oApp.OpenCurrentDatabase(m_sFilename, FALSE,NULL);*/
    
           MSAccess::_CurrentProject oProj = oApp.GetCurrentProject();
           MSAccess::AllObjects oObjs = oProj.GetAllModules();
    
           CString sModName, sProcName, sItem;
           long lProcKind = 0;
           for(long i=0;i<=oObjs.GetCount()-1;i++)
           {
              MSAccess::AccessObject oObj = oObjs.GetItem(COleVariant(i));
              sModName = oObj.GetName();
              //Module must be open:
              oDoCmd.OpenModule(COleVariant(sModName), vOpt);
              MSAccess::Modules oMods = oApp.GetModules();
              MSAccess::Module oMod = oMods.GetItem(COleVariant(sModName));
              long lLineCount = oMod.GetCountOfLines();
              long j=1;
              while(j<lLineCount)
              {
                 sProcName = oMod.GetProcOfLine(j, &lProcKind);
                 if(!sProcName.IsEmpty()){
                    sItem.Format("%s/t/t%s", sModName, sProcName);
                    m_MacroList.AddString(sItem);
                    j = j + oMod.GetProcCountLines(sProcName, lProcKind); }
                 else {
                    j++;    }
              }
           }
    
           oApp.Quit(0);
       }
    
       else  //Other...
       {
          CString sMsg;
          sMsg.Format("Unable to extract macro names for files with progid %s",
                      sProgID);
          AfxMessageBox(sMsg);
       }
    
    }
    
    					
  10. 添加以下包括到 ListMacrosDlg.cpp:
    #include <afxpriv.h>
    #include "Excel9.h" // for Office Excel 2003 and later, use #include "Excel.h"
    #include "MSWord9.h" // for Office Word 2003 and later, use #include "MSWord.h"
    #include "MSPPT9.h"  // for Office Powerpoint 2003 and later, use #include "msppt.h"
    #include "MSAcc9.h" // for Office Access 2003 and later, use #include "msacc.h"
    #include "VBE6Ext.h"
    					
  11. 单击 ClassView 选项卡,右击 CListMacrosDlg,然后选择 添加成员函数。供应 void函数类型GetMacros(LPDISPATCH lpDisp)函数声明 中,选择 专用,然后单击 确定。为 CListMacrosDlg::GetMacros 添加以下代码:
    void CListMacrosDlg::GetMacros(LPDISPATCH lpDisp)
    {
       long i, j; //counters
    
       //Clear the list box and set the tab stops
       j=m_MacroList.GetCount();
       for (i=j-1;i>=0;i--){
          m_MacroList.DeleteString(i);}
       m_MacroList.SetTabStops(50);
    
       //Iterate the collection of components in the VBA project
       //referenced by lpDisp.
       VBAExt::_VBProject oVBProj;
       oVBProj.AttachDispatch(lpDisp, TRUE);
       VBAExt::_VBComponents oVBComps = oVBProj.GetVBComponents();
       long lCompCount = oVBComps.GetCount();
       long lLineCount;
       long lProcKind = 0;
       VBAExt::_VBComponent oVBComp;
       VBAExt::_CodeModule oCode;
    
       for(i=1; i<=lCompCount; i++)
       {
          oVBComp = oVBComps.Item(COleVariant(i));
          oCode = oVBComp.GetCodeModule();
    
          //If the component contains any lines of code, then
          //retrieve the name of each procedure (Functions and Subs)
          //add it to the list box along with the module name.
          CString sProcName, sItem;
          lLineCount = oCode.GetCountOfLines();
          j=1;
          while(j<lLineCount)
          {
             sProcName = oCode.GetProcOfLine(j, &lProcKind);
             if(!sProcName.IsEmpty()){
                sItem.Format("%s/t/t%s", oVBComp.GetName(), sProcName);
                m_MacroList.AddString(sItem);
                j = j + oCode.GetProcCountLines(sProcName, lProcKind); }
             else {
                j++;    }
          }
       }
    }
    
  12. 将下面的代码行添加到开始处 CListMacrosApp::InitInstance() ListMacros.cpp 中:
    AfxOleInit();
    
  13. 生成项目并运行它。选择一个 (.xls、.doc、.mdb 或.ppt) 文件,该文件包含宏,然后单击 运行。在列表框中显示的宏的列表。

其他说明

  • 此示例中阐释的代码检索只 Sub函数 的过程。如果您要检索 属性获取属性让,或 属性 Set 过程,则必须修改代码。ProcOfLine 的第二个参数可以是下列之一 (该代码示例使用 0 等效于 vbext_pk_Proc):
    Constant        Value     Description
    -------------   -----     ------------------------------------------------
    vbext_pk_Get    3         Procedure that returns the value of a property 
    vbext_pk_Let    1         Procedure that assigns a value to a property
    
    vbext_pk_Set    2         Procedure that sets a reference to an object 
    vbext_pk_Proc   0         All procedures other than property procedures
    					
  • 如果在 VBA 模块是受密码保护,显示要求输入密码对话框。如果您不知道该密码,该程序不能列出该过程。
  • 上面的示例中的 打开 (和 OpenCurrentDatabase) 方法用于与 Office 2000 类型库。Office XP 类型库都有其他需要传递给这些方法的参数。请参见"参考"一节的其他信息。
已标记关键词 清除标记
相关推荐
程序员的必经之路! 【限时优惠】 现在下单,还享四重好礼: 1、教学课件免费下载 2、课程案例代码免费下载 3、专属VIP学员群免费答疑 4、下单还送800元编程大礼包 【超实用课程内容】  根据《2019-2020年中国开发者调查报告》显示,超83%的开发者都在使用MySQL数据库。使用量大同时,掌握MySQL早已是运维、DBA的必备技能,甚至部分IT开发岗位也要求对数据库使用和原理有深入的了解和掌握。 学习编程,你可能会犹豫选择 C++ 还是 Java;入门数据科学,你可能会纠结于选择 Python 还是 R;但无论如何, MySQL 都是 IT 从业人员不可或缺的技能!   套餐中一共包含2门MySQL数据库必学的核心课程(共98课时)   课程1:《MySQL数据库从入门到实战应用》   课程2:《高性能MySQL实战课》   【哪些人适合学习这门课程?】  1)平时只接触了语言基础,并未学习任何数据库知识的人;  2)对MySQL掌握程度薄弱的人,课程可以让你更好发挥MySQL最佳性能; 3)想修炼更好的MySQL内功,工作中遇到高并发场景可以游刃有余; 4)被面试官打破沙锅问到底的问题问到怀疑人生的应聘者。 【课程主要讲哪些内容?】 课程一:《MySQL数据库从入门到实战应用》 主要从基础篇,SQL语言篇、MySQL进阶篇三个角度展开讲解,帮助大家更加高效的管理MySQL数据库。 课程二:《高性能MySQL实战课》主要从高可用篇、MySQL8.0新特性篇,性能优化篇,面试篇四个角度展开讲解,帮助大家发挥MySQL的最佳性能的优化方法,掌握如何处理海量业务数据和高并发请求 【你能收获到什么?】  1.基础再提高,针对MySQL核心知识点学透,用对; 2.能力再提高,日常工作中的代码换新貌,不怕问题; 3.面试再加分,巴不得面试官打破沙锅问到底,竞争力MAX。 【课程如何观看?】  1、登录CSDN学院 APP 在我的课程中进行学习; 2、移动端:CSDN 学院APP(注意不是CSDN APP哦)  本课程为录播课,课程永久有效观看时长 【资料开放】 课件、课程案例代码完全开放给你,你可以根据所学知识,自行修改、优化。  下载方式:电脑登录课程观看页面,点击右侧课件,可进行课程资料的打包下载。
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页