MS Office 自动化编程 - 从Word文档中获取文档属性

来源:互联网 发布:篮球比赛赛程软件 编辑:程序博客网 时间:2024/06/03 19:29

学习Office自动化之前先阅读一些COM书籍,对于理解Office自动化有很大帮助。以下示例代码使用VS2010进行编译。目前市面上已有的关于Office自动化的书籍,多是快餐式的,看过之后只能知道最基本的使用。要想更多的了解,非得MSDN不可。下面就是msdn上跟office开发相关的详细资料。

总目录:http://msdn.microsoft.com/en-us/library/bb726434(v=office.12)

 

针对Office2007:http://msdn.microsoft.com/en-us/library/bb726436(v=office.12)

 

Word组件对象详细资料:http://msdn.microsoft.com/msword.tlhen-us/library/bb244515(v=office.12).aspx

可以参看组件对象的详细信息,包括属性,方法等等介绍。

 

使用VC进行自动化编程的基本步骤:

1.初始化COM组件---应用程序调用com库中的函数(除CoGetMalloc和内存分配函数)之前必须初始化com库

2.建立Application对象并使之运行---建立自动化对象以便使用其提供的功能

3.使用Application对象提供的方法、事件实现自动化处理过程

4.关闭自动化对象

 

示例:从Word文档中获取文档属性(文档页数、文档作者等)

 

1.新建基于对话框的项目GetWordPro,并添加一些用于打开,显示Word文档属性的简单控件。

 

2.在项目中引入类型库

Class Wizard->Add Class->MFC class From Type Lib(关于类型库,COM相关书籍有详细介绍)->在Available Tpe libraries中选择 Microsoft Word 12.0Object Library<8.4>

我用的是Office 2007组件,版本不同名称会稍有不同。作为初学,对各个接口不是太了解的情况下,我们选择全部的接口到Generated Classes后finish。等熟悉之后就可以挑选自己需要的接口了。

 

3.在对话框类中声明我们需要的对象

[cpp] view plain copy
  1. //Represents the Microsoft Office Word application.     
  2.     //For example, the ActiveDocument property returns a Document object.    
  3.     CApplication    m_oApp;    
  4.     
  5.     //A collection of all the Document objects that are currently open in Word.    
  6.     CDocuments      m_oDocs;     
  7.     
  8.     CDocument0      m_oDoc;  

4.OnInitDialog()中添加以下代码

[cpp] view plain copy
  1. // TODO: Add extra initialization here    
  2.     if (CoInitialize(NULL) != 0)    
  3.     {    
  4.         AfxMessageBox(_T("COM库初始化失败!"));    
  5.         exit(1);    
  6.     }    
  7.     
  8.     if (!m_oApp.CreateDispatch(_T("Word.Application"), NULL))    
  9.     {    
  10.         AfxMessageBox(_T("启动Word程序失败!"));    
  11.         return FALSE;    
  12.     }    
  13.         
  14.     //COM VARIANT类型的封装类    
  15.     COleVariant vopt(DISP_E_PARAMNOTFOUND, VT_ERROR);    
  16.     //This structure is used by IDispatch::Invoke to contain the arguments passed to a method or property.    
  17.     DISPPARAMS dpNoArgs = {NULL, NULL, 0, 0};    
  18.     HRESULT hr;    
  19.     VARIANT vResult;    
  20.     //添加一个新文档    
  21.     m_oDocs = m_oApp.get_Documents();    
  22.     m_oDoc = m_oDocs.Add(vopt, vopt, vopt, vopt);    
  23.     
  24.     //用于保存Word内置属性接口    
  25.     //IDispatch is the COM interface for automation    
  26.     LPDISPATCH lpdispProps;    
  27.     lpdispProps = m_oDoc.get_BuiltInDocumentProperties();    
  28.     
  29.     hr = lpdispProps->Invoke(0x4, IID_NULL, LOCALE_NAME_USER_DEFAULT,    
  30.         DISPATCH_PROPERTYGET, &dpNoArgs, &vResult, NULL, NULL);    
  31.     long lPropCount = vResult.lVal;    
  32.     CComboBox * pComboList = (CComboBox*)GetDlgItem(IDC_PROPERTY_COM);    
  33.     
  34.     char szPropName[255];    
  35.     DISPPARAMS dpItem;    
  36.     VARIANT vArgs[1];    
  37.     vArgs[0].vt = VT_I4;    
  38.     vArgs[0].lVal = 0;    
  39.     dpItem.cArgs = 1;    
  40.     dpItem.cNamedArgs = 0;    
  41.     dpItem.rgvarg = vArgs;    
  42.     
  43.     //向列别添加可选项    
  44.     for (long i = 1; i <= lPropCount; i++)    
  45.     {    
  46.         //获得一个文档属性    
  47.         dpItem.rgvarg[0].lVal = i;    
  48.         hr = lpdispProps->Invoke(0x0, IID_NULL, LOCALE_NAME_USER_DEFAULT,     
  49.             DISPATCH_PROPERTYGET, &dpItem, &vResult, NULL, NULL);    
  50.         LPDISPATCH lpdispProp = vResult.pdispVal;    
  51.         hr = lpdispProp->Invoke(0x3, IID_NULL, LOCALE_NAME_USER_DEFAULT,    
  52.             DISPATCH_PROPERTYGET, &dpNoArgs, &vResult, NULL, NULL);    
  53.         pComboList->InsertString(-1, vResult.bstrVal);    
  54.         lpdispProp->Release();    
  55.     }    
  56.     
  57.     lpdispProps->Release();    
  58.         
  59.     //关闭文档    
  60.     m_oDoc.Close(COleVariant((short)false), vopt, vopt);    
  61.     m_oDoc.ReleaseDispatch();    
  62.     m_oDoc.m_lpDispatch = NULL;    
  63.     
  64.     pComboList->EnableWindow(0);   

这一段的注意点:get_BuiltInDocumentProperties();函数调用返回的是DocumentProperties Collection 对象http://msdn.microsoft.com/en-us/library/aa190807(v=office.10).aspx  。属性值有多个,可以在http://msdn.microsoft.com/en-us/library/microsoft.office.interop.word.wdbuiltinproperty(v=office.14).aspx或者msword.tlh(由导入类型库之后在Debug生成的头文件)中的enum WdBuiltInProperty查看。例子中直接使用了0x3这样的id值,如果只知道方法或者属性的名字的前提下,可以使用http://support.microsoft.com/kb/179494中的方法。

 

5.其他控件的响应函数

[cpp] view plain copy
  1. void CGetWordPropDlg::OnBnClickedChooseword()    
  2. {    
  3.     // TODO: Add your control notification handler code here    
  4.     OPENFILENAME ofn;    
  5.     TCHAR lpStrFileName[MAX_PATH] = _T("");    
  6.     ZeroMemory(&ofn, sizeof(ofn));    
  7.     
  8.     ofn.lStructSize = sizeof(OPENFILENAME);    
  9.     ofn.hwndOwner = this->m_hWnd;    
  10.     ofn.lpstrFilter = _T("Word(.docx)\0*.docx\0");    
  11.     ofn.nMaxFile = MAX_PATH;    
  12.     ofn.lpstrFile = lpStrFileName;    
  13.     ofn.hInstance = AfxGetInstanceHandle();    
  14.     ofn.Flags = OPEN_EXISTING;    
  15.     
  16.     if (GetOpenFileName(&ofn) == IDOK)    
  17.     {    
  18.         CString strFile = ofn.lpstrFile;    
  19.         SetDlgItemText(IDC_FILENAME, strFile);    
  20.         CComboBox* pComboList = (CComboBox*)GetDlgItem(IDC_PROPERTY_COM);    
  21.         pComboList->EnableWindow(TRUE);    
  22.     
  23.         COleVariant vopt(DISP_E_PARAMNOTFOUND, VT_ERROR);    
  24.         if (m_oDoc.m_lpDispatch != NULL)    
  25.         {    
  26.             m_oDoc.Close(COleVariant((short)false), vopt, vopt);    
  27.             m_oDoc.ReleaseDispatch();    
  28.             m_oDoc.m_lpDispatch = NULL;    
  29.         }    
  30.         m_oDoc = m_oDocs.Open(COleVariant(strFile), vopt, COleVariant((short)true), vopt, vopt,    
  31.             vopt,vopt,vopt,vopt, vopt, vopt, vopt, vopt, vopt, vopt,vopt);    
  32.     }    
  33. }    
  34.     
  35.     
  36. void CGetWordPropDlg::OnSelchangePropertyCom()    
  37. {    
  38.     // TODO: Add your control notification handler code here    
  39.     CString sProperty;    
  40.     CComboBox* pComboPropList = (CComboBox*)GetDlgItem(IDC_PROPERTY_COM);    
  41.     pComboPropList->GetLBText(pComboPropList->GetCurSel(), sProperty);    
  42.     
  43.     LPDISPATCH lpdispProps;    
  44.     lpdispProps = m_oDoc.get_BuiltInDocumentProperties();    
  45.     
  46.     VARIANT vResult;    
  47.     DISPPARAMS dpItem;    
  48.     VARIANT vArgs[1];    
  49.     vArgs[0].vt = VT_BSTR;    
  50.     vArgs[0].bstrVal = sProperty.AllocSysString();    
  51.     dpItem.cArgs = 1;    
  52.     dpItem.cNamedArgs = 0;    
  53.     dpItem.rgvarg = vArgs;    
  54.     HRESULT hr = lpdispProps->Invoke(0x0, IID_NULL, LOCALE_NAME_USER_DEFAULT,    
  55.         DISPATCH_PROPERTYGET, &dpItem, &vResult, NULL, NULL);    
  56.     
  57.     SysFreeString(vArgs[0].bstrVal);    
  58.     
  59.     DISPPARAMS dpNoArgs = {NULL, NULL, 0, 0};    
  60.     LPDISPATCH lpdispProp;    
  61.     lpdispProp = vResult.pdispVal;    
  62.     
  63.     hr = lpdispProp->Invoke(0x0, IID_NULL, LOCALE_NAME_USER_DEFAULT,    
  64.         DISPATCH_PROPERTYGET, &dpNoArgs, &vResult, NULL, NULL);    
  65.     
  66.     CString sPropValue = _T("");    
  67.     switch (vResult.vt)    
  68.     {    
  69.     case VT_BSTR:    
  70.         sPropValue = vResult.bstrVal;    
  71.         break;    
  72.     case VT_I4:    
  73.         sPropValue.Format(_T("%d"), vResult.lVal);    
  74.         break;    
  75.     case VT_DATE:    
  76.         {    
  77.             COleDateTime dt(vResult);    
  78.             sPropValue = dt.Format(0, LANG_USER_DEFAULT);    
  79.             break;    
  80.         }    
  81.     default:    
  82.         sPropValue = _T("该属性不可用");    
  83.         break;    
  84.     }    
  85.     SetDlgItemText(IDC_PROPERTY_VALUE, sPropValue);    
  86.     lpdispProp->Release();    
  87.     lpdispProps->Release();    
  88. }    
  89.     
  90.     
  91. void CGetWordPropDlg::OnDestroy()    
  92. {    
  93.     CDialogEx::OnDestroy();    
  94.     
  95.     // TODO: Add your message handler code here    
  96.     COleVariant vopt(DISP_E_PARAMNOTFOUND, VT_ERROR);    
  97.     m_oApp.Quit(COleVariant((short)false), vopt, vopt);    
  98.     CDialogEx::OnCancel();    
  99. }  
在编译的过程中会出现编译的错误,全部指向msword.tlh文件,需要在CApplication.h、CDocuments.h等实用到的头文件中添加红色部分,是因为命名冲突导致的编译失败

#import "C:\\Program Files\\Microsoft Office\\Office12\\MSWORD.OLB" no_namespace raw_interfaces_only rename("FindText","_FindText")rename("Rectangle","_Rectangle") rename("ExitWindows","_ExitWindows")


6.运行结果

 

示例一:保存至Word

经过一些了解之后,就不需要每次都将所有的接口导入工程了。可以根据需要导入,此次导入的接口为:

Application、_Document、Documents、Range。新建基于对话框的MFC工程,引入头文件,关键代码如下:

[cpp] view plain copy
  1. void CWordOperationDlg::OnClickedButton1()  
  2. {  
  3.     // TODO: Add your control notification handler code here  
  4.     CApplication oApp;  
  5.     CDocuments  oDocs;  
  6.     CDocument0  oDoc;  
  7.   
  8.     if (!oApp.CreateDispatch(_T("Word.Application"), NULL))  
  9.     {  
  10.         AfxMessageBox(_T("启动Word程序失败!"));  
  11.         exit(1);  
  12.     }  
  13.   
  14.     //查看自动化过程  
  15.     oApp.put_Visible(true);  
  16.     oDocs = oApp.get_Documents();  
  17.     COleVariant varOPt(DISP_E_PARAMNOTFOUND, VT_ERROR);  
  18.     COleVariant varStartLine, varEndLine;  
  19.     varStartLine.intVal = 2;  
  20.     varEndLine.intVal = 50;  
  21.     //添加一个新文档  
  22.     oDoc = oDocs.Add(varOPt, varOPt, varOPt, varOPt);  
  23.   
  24.     //获取文档区域  
  25.     CRange range =  oDoc.Range(varStartLine, varEndLine);  
  26.     UpdateData(TRUE);  
  27.     range.put_Text(m_edit);  
  28.     //保存docx文档  
  29.     try  
  30.     {  
  31.         oDoc.SaveAs(COleVariant(_T("G:\\softwaredevelopment\\MFC_VC_Windows\\project\\TEMP.DOCX")),  
  32.             varOPt, varOPt, varOPt,  
  33.             varOPt, varOPt, varOPt,  
  34.             varOPt, varOPt, varOPt,  
  35.             varOPt, varOPt, varOPt,  
  36.             varOPt, varOPt, varOPt);  
  37.     }  
  38.     catch (COleException* e)  
  39.     {  
  40.         LPVOID lpMsg;  
  41.         ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |   
  42.             FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, e->m_sc,  
  43.             MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsg, 0, NULL);  
  44.         ::MessageBox(NULL, (LPCTSTR)lpMsg, _T("COM Error"), MB_OK|MB_SETFOREGROUND);  
  45.         ::LocalFree(lpMsg);  
  46.     }  
  47.     catch(COleDispatchException *e)  
  48.     {  
  49.         TCHAR msg[512];  
  50.         wsprintf(msg, _T("程序运行出错'%d',系统提示信息为:\n\n%s"), e->m_scError & 0x0000FFFF,  
  51.             e->m_strDescription);  
  52.         ::MessageBox(NULL, msg, _T("无法保存文件"), MB_OK|MB_SETFOREGROUND);  
  53.     }  
  54.   
  55.     oDoc.Close(varOPt, varOPt, varOPt);  
  56.     oApp.Quit(varOPt, varOPt, varOPt);  
  57. }  

运行结果:


 

示例二:Word表格操作

Word表格由表和单元格组成,对应Table和Cell对象,在以上工程中引入相应接口Table,Tables,Cell,Paragraph,Paragraphs,对表格的添加过程是先建表,再设置单元格。

在以上工程的基础上添加的关键代码:

[cpp] view plain copy
  1. //得到段落  
  2.     oParas = oDoc.get_Paragraphs();  
  3.     oPara = oParas.get_First();  
  4.     //得到段落区域  
  5.     oRange = oPara.get_Range();  
  6.     //设置第一段内容  
  7.     oRange.put_Text(_T("标题"));  
  8.     oPara.put_Alignment(1);  
  9.   
  10.     COleVariant table_start(short(2));  
  11.     oRange = oDoc.Range(table_start, varOPt);  
  12.     //添加表格  
  13.     oTables = oDoc.get_Tables();  
  14.     oTable = oTables.Add(oRange, 3, 3, varOPt, varOPt);  
  15.     //设置表格内容  
  16.     for (int i = 1; i <= 3; i++)  
  17.     {  
  18.         for (int j = 1; j <= 3; j++)  
  19.         {  
  20.             oCell = oTable.Cell(i, j);  
  21.             oRange = oCell.get_Range();  
  22.             CString txt;  
  23.             txt.Format(_T("第%d行第%d列"),i,j);  
  24.             oRange.put_Bold(1);  
  25.             oRange.put_Text(txt);  
  26.         }  
  27.     }  

操作Word结果:

 

示例二:Word报表解决方法

由以上示例可以看出对Word的操作是相当繁琐的,针对于此,利用Word的模板,只需填入关键文字,就能得到一份精美的Word文档。

同理,首先将报表的格式固定做成模板,程序向单元格填入数据。而利用“书签”就能快速定位正确的输出位置。在类型库中,对应的接口为Bookmarks、Bookmark。
1、先准备好Wrod模板

2、新建MFC基于对话框工程WordReport

3、根据需要引入类型库中的接口

关键部分代码:

[cpp] view plain copy
  1. void CWordReportDlg::OnBnClickedButton1()  
  2. {  
  3.     // TODO: Add your control notification handler code here  
  4.     CTable0     table;  
  5.     CTables0    tables;  
  6.     if (!m_oApp.CreateDispatch(_T("Word.Application"), NULL))  
  7.     {  
  8.         AfxMessageBox(_T("Create Word service failed!"));  
  9.         exit(1);  
  10.     }  
  11.   
  12.     m_oApp.put_Visible(true);  
  13.     m_oDocs = m_oApp.get_Documents();  
  14.     COleVariant vopt(DISP_E_PARAMNOTFOUND, VT_ERROR);  
  15.     COleVariant start_line, end_line;  
  16.     COleVariant dot(_T("G:\\softwaredevelopment\\MFC_VC_Windows\\project\\template.dot"));  
  17.     //使用模板建立文档  
  18.     m_oDoc = m_oDocs.Add(&dot, &vopt, &vopt, &vopt);  
  19.     //获取文档书签  
  20.     m_oBookmarks = m_oDoc.get_Bookmarks();  
  21.     //依次设置标签  
  22.     COleVariant tem1(_T("rol1"));  
  23.     m_oBookmark = m_oBookmarks.Item(&tem1);  
  24.     m_oRange = m_oBookmark.get_Range();  
  25.     //设置标题  
  26.     m_oRange.put_Text(_T("标题1"));  
  27.       
  28.     COleVariant tem2(_T("rol2"));  
  29.     m_oBookmark = m_oBookmarks.Item(&tem2);  
  30.     m_oRange = m_oBookmark.get_Range();  
  31.     //设置标题  
  32.     m_oRange.put_Text(_T("标题2"));  
  33.   
  34.     COleVariant tem3(_T("rol3"));  
  35.     m_oBookmark = m_oBookmarks.Item(&tem3);  
  36.     m_oRange = m_oBookmark.get_Range();  
  37.     //设置标题  
  38.     m_oRange.put_Text(_T("标题3"));  
  39.   
  40.     //设置报表时间  
  41.     COleVariant tem4(_T("time"));  
  42.     m_oBookmark = m_oBookmarks.Item(&tem4);  
  43.     m_oRange = m_oBookmark.get_Range();  
  44.     //设置标题  
  45.     m_oRange.put_Text(_T("2012年5月20日"));  
  46.   
  47.     //设置单元格内容  
  48.     tables = m_oDoc.get_Tables();  
  49.     table = tables.Item(1);  
  50.     CCell cell;  
  51.     for (int i = 2; i <= 9; i++)  
  52.     {  
  53.         for (int j = 1; j <= 3; j++)  
  54.         {  
  55.             cell = table.Cell(i,j);  
  56.             m_oRange = cell.get_Range();  
  57.             m_oRange.put_Text(_T("template"));  
  58.         }  
  59.     }  
  60. }  
  61.   
  62.   
  63. void CWordReportDlg::OnBnClickedButton2()  
  64. {  
  65.     // TODO: Add your control notification handler code here  
  66.     if (m_oDocs.m_lpDispatch == NULL)  
  67.     {  
  68.         AfxMessageBox(_T("can't preview!"));  
  69.         return;  
  70.     }  
  71.     else  
  72.     {  
  73.         if (!m_oApp.get_PrintPreview())  
  74.         {  
  75.             m_oApp.put_PrintPreview(TRUE);  
  76.         }  
  77.         else  
  78.         {  
  79.             m_oApp.put_PrintPreview(FALSE);  
  80.         }  
  81.     }  
  82. }  
  83.   
  84.   
  85. void CWordReportDlg::OnBnClickedButton3()  
  86. {  
  87.     // TODO: Add your control notification handler code here  
  88.     if (m_oDocs.m_lpDispatch == NULL)  
  89.     {  
  90.         AfxMessageBox(_T("Nothing! can't save!"));  
  91.         return;  
  92.     }  
  93.     else  
  94.     {  
  95.         OPENFILENAME ofn;  
  96.         TCHAR lpStrFileName[MAX_PATH] = _T("");  
  97.         ZeroMemory(&ofn, sizeof(ofn));  
  98.   
  99.         ofn.lStructSize = sizeof(OPENFILENAME);  
  100.         ofn.hwndOwner = this->m_hWnd;  
  101.         ofn.lpstrFilter = _T("Word(.docx)\0*.docx\0");  
  102.         ofn.nMaxFile = MAX_PATH;  
  103.         ofn.lpstrFile = lpStrFileName;  
  104.         ofn.hInstance = AfxGetInstanceHandle();  
  105.         ofn.Flags = OPEN_EXISTING;  
  106.   
  107.         COleVariant varOPt(DISP_E_PARAMNOTFOUND, VT_ERROR);  
  108.         if (GetSaveFileName(&ofn) == IDOK)  
  109.         {  
  110.             CString sFile = ofn.lpstrFile;  
  111.             try  
  112.             {  
  113.                 m_oDoc.SaveAs(COleVariant(sFile),  
  114.                     varOPt, varOPt, varOPt,  
  115.                     varOPt, varOPt, varOPt,  
  116.                     varOPt, varOPt, varOPt,  
  117.                     varOPt, varOPt, varOPt,  
  118.                     varOPt, varOPt, varOPt);  
  119.             }  
  120.             catch (COleException* e)  
  121.             {  
  122.                 LPVOID lpMsg;  
  123.                 ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |   
  124.                     FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, e->m_sc,  
  125.                     MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsg, 0, NULL);  
  126.                 ::MessageBox(NULL, (LPCTSTR)lpMsg, _T("COM Error"), MB_OK|MB_SETFOREGROUND);  
  127.                 ::LocalFree(lpMsg);  
  128.             }  
  129.             catch(COleDispatchException *e)  
  130.             {  
  131.                 TCHAR msg[512];  
  132.                 wsprintf(msg, _T("程序运行出错'%d',系统提示信息为:\n\n%s"), e->m_scError & 0x0000FFFF,  
  133.                     e->m_strDescription);  
  134.                 ::MessageBox(NULL, msg, _T("无法保存文件"), MB_OK|MB_SETFOREGROUND);  
  135.             }  
  136.   
  137.             COleVariant vopt(DISP_E_PARAMNOTFOUND, VT_ERROR);  
  138.             m_oApp.Quit(COleVariant((short)true), vopt, vopt);  
  139.         }  
  140.     }  
  141. }  

程序运行结果:


http://blog.csdn.net/leohels/article/details/7582881

http://blog.csdn.net/leohels/article/details/7584571

0 0