学习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);
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