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

学习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.在对话框类中声明我们需要的对象

//Represents the Microsoft Office Word application.   
    //For example, the ActiveDocument property returns a Document object.  
    CApplication    m_oApp;  
  
    //A collection of all the Document objects that are currently open in Word.  
    CDocuments      m_oDocs;   
  
    CDocument0      m_oDoc;

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

// TODO: Add extra initialization here  
    if (CoInitialize(NULL) != 0)  
    {  
        AfxMessageBox(_T("COM库初始化失败!"));  
        exit(1);  
    }  
  
    if (!m_oApp.CreateDispatch(_T("Word.Application"), NULL))  
    {  
        AfxMessageBox(_T("启动Word程序失败!"));  
        return FALSE;  
    }  
      
    //COM VARIANT类型的封装类  
    COleVariant vopt(DISP_E_PARAMNOTFOUND, VT_ERROR);  
    //This structure is used by IDispatch::Invoke to contain the arguments passed to a method or property.  
    DISPPARAMS dpNoArgs = {NULL, NULL, 0, 0};  
    HRESULT hr;  
    VARIANT vResult;  
    //添加一个新文档  
    m_oDocs = m_oApp.get_Documents();  
    m_oDoc = m_oDocs.Add(vopt, vopt, vopt, vopt);  
  
    //用于保存Word内置属性接口  
    //IDispatch is the COM interface for automation  
    LPDISPATCH lpdispProps;  
    lpdispProps = m_oDoc.get_BuiltInDocumentProperties();  
  
    hr = lpdispProps->Invoke(0x4, IID_NULL, LOCALE_NAME_USER_DEFAULT,  
        DISPATCH_PROPERTYGET, &dpNoArgs, &vResult, NULL, NULL);  
    long lPropCount = vResult.lVal;  
    CComboBox * pComboList = (CComboBox*)GetDlgItem(IDC_PROPERTY_COM);  
  
    char szPropName[255];  
    DISPPARAMS dpItem;  
    VARIANT vArgs[1];  
    vArgs[0].vt = VT_I4;  
    vArgs[0].lVal = 0;  
    dpItem.cArgs = 1;  
    dpItem.cNamedArgs = 0;  
    dpItem.rgvarg = vArgs;  
  
    //向列别添加可选项  
    for (long i = 1; i <= lPropCount; i++)  
    {  
        //获得一个文档属性  
        dpItem.rgvarg[0].lVal = i;  
        hr = lpdispProps->Invoke(0x0, IID_NULL, LOCALE_NAME_USER_DEFAULT,   
            DISPATCH_PROPERTYGET, &dpItem, &vResult, NULL, NULL);  
        LPDISPATCH lpdispProp = vResult.pdispVal;  
        hr = lpdispProp->Invoke(0x3, IID_NULL, LOCALE_NAME_USER_DEFAULT,  
            DISPATCH_PROPERTYGET, &dpNoArgs, &vResult, NULL, NULL);  
        pComboList->InsertString(-1, vResult.bstrVal);  
        lpdispProp->Release();  
    }  
  
    lpdispProps->Release();  
      
    //关闭文档  
    m_oDoc.Close(COleVariant((short)false), vopt, vopt);  
    m_oDoc.ReleaseDispatch();  
    m_oDoc.m_lpDispatch = NULL;  
  
    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.其他控件的响应函数

void CGetWordPropDlg::OnBnClickedChooseword()  
{  
    // TODO: Add your control notification handler code here  
    OPENFILENAME ofn;  
    TCHAR lpStrFileName[MAX_PATH] = _T("");  
    ZeroMemory(&ofn, sizeof(ofn));  
  
    ofn.lStructSize = sizeof(OPENFILENAME);  
    ofn.hwndOwner = this->m_hWnd;  
    ofn.lpstrFilter = _T("Word(.docx)\0*.docx\0");  
    ofn.nMaxFile = MAX_PATH;  
    ofn.lpstrFile = lpStrFileName;  
    ofn.hInstance = AfxGetInstanceHandle();  
    ofn.Flags = OPEN_EXISTING;  
  
    if (GetOpenFileName(&ofn) == IDOK)  
    {  
        CString strFile = ofn.lpstrFile;  
        SetDlgItemText(IDC_FILENAME, strFile);  
        CComboBox* pComboList = (CComboBox*)GetDlgItem(IDC_PROPERTY_COM);  
        pComboList->EnableWindow(TRUE);  
  
        COleVariant vopt(DISP_E_PARAMNOTFOUND, VT_ERROR);  
        if (m_oDoc.m_lpDispatch != NULL)  
        {  
            m_oDoc.Close(COleVariant((short)false), vopt, vopt);  
            m_oDoc.ReleaseDispatch();  
            m_oDoc.m_lpDispatch = NULL;  
        }  
        m_oDoc = m_oDocs.Open(COleVariant(strFile), vopt, COleVariant((short)true), vopt, vopt,  
            vopt,vopt,vopt,vopt, vopt, vopt, vopt, vopt, vopt, vopt,vopt);  
    }  
}  
  
  
void CGetWordPropDlg::OnSelchangePropertyCom()  
{  
    // TODO: Add your control notification handler code here  
    CString sProperty;  
    CComboBox* pComboPropList = (CComboBox*)GetDlgItem(IDC_PROPERTY_COM);  
    pComboPropList->GetLBText(pComboPropList->GetCurSel(), sProperty);  
  
    LPDISPATCH lpdispProps;  
    lpdispProps = m_oDoc.get_BuiltInDocumentProperties();  
  
    VARIANT vResult;  
    DISPPARAMS dpItem;  
    VARIANT vArgs[1];  
    vArgs[0].vt = VT_BSTR;  
    vArgs[0].bstrVal = sProperty.AllocSysString();  
    dpItem.cArgs = 1;  
    dpItem.cNamedArgs = 0;  
    dpItem.rgvarg = vArgs;  
    HRESULT hr = lpdispProps->Invoke(0x0, IID_NULL, LOCALE_NAME_USER_DEFAULT,  
        DISPATCH_PROPERTYGET, &dpItem, &vResult, NULL, NULL);  
  
    SysFreeString(vArgs[0].bstrVal);  
  
    DISPPARAMS dpNoArgs = {NULL, NULL, 0, 0};  
    LPDISPATCH lpdispProp;  
    lpdispProp = vResult.pdispVal;  
  
    hr = lpdispProp->Invoke(0x0, IID_NULL, LOCALE_NAME_USER_DEFAULT,  
        DISPATCH_PROPERTYGET, &dpNoArgs, &vResult, NULL, NULL);  
  
    CString sPropValue = _T("");  
    switch (vResult.vt)  
    {  
    case VT_BSTR:  
        sPropValue = vResult.bstrVal;  
        break;  
    case VT_I4:  
        sPropValue.Format(_T("%d"), vResult.lVal);  
        break;  
    case VT_DATE:  
        {  
            COleDateTime dt(vResult);  
            sPropValue = dt.Format(0, LANG_USER_DEFAULT);  
            break;  
        }  
    default:  
        sPropValue = _T("该属性不可用");  
        break;  
    }  
    SetDlgItemText(IDC_PROPERTY_VALUE, sPropValue);  
    lpdispProp->Release();  
    lpdispProps->Release();  
}  
  
  
void CGetWordPropDlg::OnDestroy()  
{  
    CDialogEx::OnDestroy();  
  
    // TODO: Add your message handler code here  
    COleVariant vopt(DISP_E_PARAMNOTFOUND, VT_ERROR);  
    m_oApp.Quit(COleVariant((short)false), vopt, vopt);  
    CDialogEx::OnCancel();  
}
在编译的过程中会出现编译的错误,全部指向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工程,引入头文件,关键代码如下:

void CWordOperationDlg::OnClickedButton1()
{
	// TODO: Add your control notification handler code here
	CApplication oApp;
	CDocuments	oDocs;
	CDocument0	oDoc;

	if (!oApp.CreateDispatch(_T("Word.Application"), NULL))
	{
		AfxMessageBox(_T("启动Word程序失败!"));
		exit(1);
	}

	//查看自动化过程
	oApp.put_Visible(true);
	oDocs = oApp.get_Documents();
	COleVariant varOPt(DISP_E_PARAMNOTFOUND, VT_ERROR);
	COleVariant varStartLine, varEndLine;
	varStartLine.intVal = 2;
	varEndLine.intVal = 50;
	//添加一个新文档
	oDoc = oDocs.Add(varOPt, varOPt, varOPt, varOPt);

	//获取文档区域
	CRange range =  oDoc.Range(varStartLine, varEndLine);
	UpdateData(TRUE);
	range.put_Text(m_edit);
	//保存docx文档
	try
	{
		oDoc.SaveAs(COleVariant(_T("G:\\softwaredevelopment\\MFC_VC_Windows\\project\\TEMP.DOCX")),
			varOPt, varOPt, varOPt,
			varOPt, varOPt, varOPt,
			varOPt, varOPt, varOPt,
			varOPt, varOPt, varOPt,
			varOPt, varOPt, varOPt);
	}
	catch (COleException* e)
	{
		LPVOID lpMsg;
		::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
			FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, e->m_sc,
			MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsg, 0, NULL);
		::MessageBox(NULL, (LPCTSTR)lpMsg, _T("COM Error"), MB_OK|MB_SETFOREGROUND);
		::LocalFree(lpMsg);
	}
	catch(COleDispatchException *e)
	{
		TCHAR msg[512];
		wsprintf(msg, _T("程序运行出错'%d',系统提示信息为:\n\n%s"), e->m_scError & 0x0000FFFF,
			e->m_strDescription);
		::MessageBox(NULL, msg, _T("无法保存文件"), MB_OK|MB_SETFOREGROUND);
	}

	oDoc.Close(varOPt, varOPt, varOPt);
	oApp.Quit(varOPt, varOPt, varOPt);
}

运行结果:


 

示例二:Word表格操作

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

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

//得到段落
	oParas = oDoc.get_Paragraphs();
	oPara = oParas.get_First();
	//得到段落区域
	oRange = oPara.get_Range();
	//设置第一段内容
	oRange.put_Text(_T("标题"));
	oPara.put_Alignment(1);

	COleVariant table_start(short(2));
	oRange = oDoc.Range(table_start, varOPt);
	//添加表格
	oTables = oDoc.get_Tables();
	oTable = oTables.Add(oRange, 3, 3, varOPt, varOPt);
	//设置表格内容
	for (int i = 1; i <= 3; i++)
	{
		for (int j = 1; j <= 3; j++)
		{
			oCell = oTable.Cell(i, j);
			oRange = oCell.get_Range();
			CString txt;
			txt.Format(_T("第%d行第%d列"),i,j);
			oRange.put_Bold(1);
			oRange.put_Text(txt);
		}
	}

操作Word结果:

 

示例二:Word报表解决方法

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

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

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

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

关键部分代码:

void CWordReportDlg::OnBnClickedButton1()
{
	// TODO: Add your control notification handler code here
	CTable0		table;
	CTables0	tables;
	if (!m_oApp.CreateDispatch(_T("Word.Application"), NULL))
	{
		AfxMessageBox(_T("Create Word service failed!"));
		exit(1);
	}

	m_oApp.put_Visible(true);
	m_oDocs = m_oApp.get_Documents();
	COleVariant vopt(DISP_E_PARAMNOTFOUND, VT_ERROR);
	COleVariant start_line, end_line;
	COleVariant dot(_T("G:\\softwaredevelopment\\MFC_VC_Windows\\project\\template.dot"));
	//使用模板建立文档
	m_oDoc = m_oDocs.Add(&dot, &vopt, &vopt, &vopt);
	//获取文档书签
	m_oBookmarks = m_oDoc.get_Bookmarks();
	//依次设置标签
	COleVariant tem1(_T("rol1"));
	m_oBookmark = m_oBookmarks.Item(&tem1);
	m_oRange = m_oBookmark.get_Range();
	//设置标题
	m_oRange.put_Text(_T("标题1"));
	
	COleVariant tem2(_T("rol2"));
	m_oBookmark = m_oBookmarks.Item(&tem2);
	m_oRange = m_oBookmark.get_Range();
	//设置标题
	m_oRange.put_Text(_T("标题2"));

	COleVariant tem3(_T("rol3"));
	m_oBookmark = m_oBookmarks.Item(&tem3);
	m_oRange = m_oBookmark.get_Range();
	//设置标题
	m_oRange.put_Text(_T("标题3"));

	//设置报表时间
	COleVariant tem4(_T("time"));
	m_oBookmark = m_oBookmarks.Item(&tem4);
	m_oRange = m_oBookmark.get_Range();
	//设置标题
	m_oRange.put_Text(_T("2012年5月20日"));

	//设置单元格内容
	tables = m_oDoc.get_Tables();
	table = tables.Item(1);
	CCell cell;
	for (int i = 2; i <= 9; i++)
	{
		for (int j = 1; j <= 3; j++)
		{
			cell = table.Cell(i,j);
			m_oRange = cell.get_Range();
			m_oRange.put_Text(_T("template"));
		}
	}
}


void CWordReportDlg::OnBnClickedButton2()
{
	// TODO: Add your control notification handler code here
	if (m_oDocs.m_lpDispatch == NULL)
	{
		AfxMessageBox(_T("can't preview!"));
		return;
	}
	else
	{
		if (!m_oApp.get_PrintPreview())
		{
			m_oApp.put_PrintPreview(TRUE);
		}
		else
		{
			m_oApp.put_PrintPreview(FALSE);
		}
	}
}


void CWordReportDlg::OnBnClickedButton3()
{
	// TODO: Add your control notification handler code here
	if (m_oDocs.m_lpDispatch == NULL)
	{
		AfxMessageBox(_T("Nothing! can't save!"));
		return;
	}
	else
	{
		OPENFILENAME ofn;
		TCHAR lpStrFileName[MAX_PATH] = _T("");
		ZeroMemory(&ofn, sizeof(ofn));

		ofn.lStructSize = sizeof(OPENFILENAME);
		ofn.hwndOwner = this->m_hWnd;
		ofn.lpstrFilter = _T("Word(.docx)\0*.docx\0");
		ofn.nMaxFile = MAX_PATH;
		ofn.lpstrFile = lpStrFileName;
		ofn.hInstance = AfxGetInstanceHandle();
		ofn.Flags = OPEN_EXISTING;

		COleVariant varOPt(DISP_E_PARAMNOTFOUND, VT_ERROR);
		if (GetSaveFileName(&ofn) == IDOK)
		{
			CString sFile = ofn.lpstrFile;
			try
			{
				m_oDoc.SaveAs(COleVariant(sFile),
					varOPt, varOPt, varOPt,
					varOPt, varOPt, varOPt,
					varOPt, varOPt, varOPt,
					varOPt, varOPt, varOPt,
					varOPt, varOPt, varOPt);
			}
			catch (COleException* e)
			{
				LPVOID lpMsg;
				::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
					FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, e->m_sc,
					MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsg, 0, NULL);
				::MessageBox(NULL, (LPCTSTR)lpMsg, _T("COM Error"), MB_OK|MB_SETFOREGROUND);
				::LocalFree(lpMsg);
			}
			catch(COleDispatchException *e)
			{
				TCHAR msg[512];
				wsprintf(msg, _T("程序运行出错'%d',系统提示信息为:\n\n%s"), e->m_scError & 0x0000FFFF,
					e->m_strDescription);
				::MessageBox(NULL, msg, _T("无法保存文件"), MB_OK|MB_SETFOREGROUND);
			}

			COleVariant vopt(DISP_E_PARAMNOTFOUND, VT_ERROR);
			m_oApp.Quit(COleVariant((short)true), vopt, vopt);
		}
	}
}

程序运行结果:


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

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

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值