一、首先在VC下建立简单的对话框程序,然后打开类向导,点右边的Add Class-》from a library,找到word的封装类库,一般在C:/Program Files/Microsoft Office/Office12(我的是word2007),里面有MSWORD8.OLB或MSWORD9.OLB(我的是MSWORD.OLB),打开,选其中的_Application、Documents、 _Document、Selection四个类。
二、然后在用到的.h或.cpp里面添加#include "msword.h",#include "atlbase.h"和#include "comdef.h"。然后在程序的initInstance函数里加入
/*初始化COM组件,此处为msword*/
if(!AfxOleInit())
{
AfxMessageBox("Could not initialize COM services");
return FALSE;
}
准备工作结束。
下面的代码写在窗体的OnInitDialog() 函数里面。(里面的IDC_RICHEDIT1为CRichEditCtrl)
_Application m_App; //Word应用程序对象
Documents m_Docs; //Word所有文档对象
_Document m_doc; //Word文档对象
Selection m_Slection; //文档选择对象
COleVariant vTrue((short)TRUE),
vFalse((short)FALSE),
vOpt((long)DISP_E_PARAMNOTFOUND, VT_ERROR);
//**************************************************************
try
{
if(!m_App.CreateDispatch(_T("Word.Application"))) //启动Word
{
AfxMessageBox(_T("请检查是否安装了Office"));
return FALSE;
}
m_App.SetVisible(false);
m_Docs = m_App.GetDocuments();
CComVariant Template(_T(""));
CComVariant NewTemplate(false),DocumentType(0),Visible;
m_doc=m_Docs.Open(COleVariant("C://remotecaptureguide.doc"),vFalse,vTrue,vFalse,vOpt,vOpt,
vOpt,vOpt,vOpt,vOpt,vOpt,vOpt,vOpt,vOpt,vOpt,vOpt); //打开已有word文档
//m_doc=m_Docs.Add(&Template,&NewTemplate,&DocumentType,&Visible); //添加新的空白文档
}
catch(_com_error &e)
{
MessageBox(e.ErrorMessage());
}
//读取文本
m_Slection=m_App.GetSelection();//Word文档光标输入点
m_Slection.GetSections(); //获取光标点
m_Slection.WholeStory(); //对当前文档全选
SetDlgItemText(IDC_RICHEDIT1,m_Slection.GetText()); //设置文本内容
//销毁对象
m_Slection.ReleaseDispatch(); //释放selection对象
m_Docs.ReleaseDispatch(); //释放Documents对象
m_doc.Close(vOpt,vOpt,vOpt);
m_doc.ReleaseDispatch(); //释放Document对象
m_App.Quit(vOpt,vOpt,vOpt);
m_App.ReleaseDispatch(); //释放应用程序类对象。
---------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------
---------------------------------------------------------------------------------------------------------------------
我们操纵Word需要通过类型库中的MFC类。而这些类,应该都是基于一个叫COleDispatchDriver的类。至少我所了解到的都是这样。
COleDispatchDriver没有基类。COleDispatchDriver类实现OLE自动化中的客户方。OLE调度接口为访问一个对象的方法和属性提供了途径。COleDispatchDriver的成员函数连接,分离,创建和释放一个IDispatch类型的调度连接。其它的成员函数使用变量参数列表来简化调用IDispatch::Invoke。
学习如何自动化控制 Word、Excel 和 Powerpoint 的对象模型的最佳方法是使用这些 Office 应用程序中的宏录制器:
-
-
从工具 菜单上的宏 选项中选择录制新宏 ,然后执行您感兴趣的任务。
-
从工具 菜单上的宏 选项中选择停止录制 。
-
完成录制后,从工具 菜单上的宏 选项中选择宏 ,选择您录制的宏,然后单击编辑 。
您将看到生成的 VBA 代码,该代码可完成您所录制的任务。记住,录制的宏在大多数情况下并不 是最佳代码,但它可以提供快捷可用的示例。
Application :代表 Microsoft Word 应用程序。Application 对象包含可返回最高级对象的属性和方法。例如,ActiveDocument 属性可返回当前活动的Document 对象。
Documents :由 Word 当前打开的所有 Document(文档) 对象所组成的集合。
Document :代表一篇文档。Document 对象是 Documents 集合中的一个元素。Documents 集合包含 Word 当前打开的所有 Document 对象。
Selection: 该对象代表窗口或窗格中的当前所选内容。所选内容代表文档中被选定(或突出显示的)的区域,若文档中没有所选内容,则代表插入点。每个文档窗格只能有一个活动的 Selection 对象,并且整个应用程序中只能有一个活动的 Selection 对象。
例子1 :
#include "msword9.h" //为了使代码集中,方便阅读,所以把头文件放到了这里
void CStep1Dlg::OnOK()
{
_Application app; //定义一个WORD的应用对象
if(!app.CreateDispatch(_T("Word.Application"))) //启动WORD
{
AfxMessageBox(_T("居然你连OFFICE都没有安装吗?"));
return;
}
AfxMessageBox(_T("WORD 已经运行启动啦,你可以用Ctrl+Alt+Del查看"));
app.SetVisible(TRUE); //设置WORD可见。
//当然,如果你想要悄悄地调用WORD的功能,则注释掉这条语句
AfxMessageBox(_T("现在你已经看到WORD的程序界面了吧"));
AfxMessageBox(_T("WORD准备要退出啦"));
VARIANT SaveChanges,OriginalFormat,RouteDocument; //定义调用QUIT时使用的参数
SaveChanges.vt=VT_BOOL; //设置退出WORD时候的保存参数
SaveChanges.boolVal=VARIANT_FALSE; //为不保存任何文档,模板及设置
::VariantInit(&OriginalFormat); //清空变量
RouteDocument.vt=VT_EMPTY; //清空变量的另一种方法
//调用Quit退出WORD应用程序。当然不调用也可以,那样的话WORD还在运行着那
app.Quit(&SaveChanges,&OriginalFormat,&RouteDocument);
app.ReleaseDispatch(); //释放对象指针。切记,必须调用
AfxMessageBox(_T("Step1执行完成。接着请学习Setp2"));
}
例子2:
#include "msword9.h"
#include <AtlBase.h> //新增加了一个头文件,为使用CComVariant替代VARIANT做准备
void CStep2Dlg::OnOK()
{
//以下3行代码,同Step1。就不解释啦
_Application app;
//为了简单,没有判断返回值。如果没有成功,记得检查你有没有AfxOleInit()呀?
app.CreateDispatch(_T("Word.Application"));
app.SetVisible(TRUE);
AfxMessageBox(_T("WORD已经启动,现在要退出啦"));
AfxMessageBox(_T("怎么和Step1没有什么区别呀?"));
AfxMessageBox(_T("嘿嘿,是没什么区别,但是使用方式简单了很多呀。看看源程序吧"));
//准备调用_Application::Quit函数了,需要定义3个参数。
//但是,这次我们使用CComVariant,这是一个模板类。
//在定义的时候直接调用带参数的构造函数,比VARIANT使用简单多了吧
CComVariant SaveChanges(false),OriginalFormat,RouteDocument;
//使用 CComVariant 的不带参数的构造函数,默认就是使用VT_EMPTY,设置为空类型
//另外,除了CComVariant,你还可以使用COleVariant和_variant_t,但我个人最喜欢前者
app.Quit(&SaveChanges,&OriginalFormat,&RouteDocument);
app.ReleaseDispatch();
AfxMessageBox(_T("下面该学习Setp3了"));
}
例子3:
#include "msword9.h"
#include <AtlBase.h>
void CStep3Dlg::OnOK()
{
// 这次,我们要控制在WORD中输入一些字符了 /
/************* WORD 录制的宏,新建一个空文档,然后输入一些文字 ************
Documents.Add Template:= _
"C:/Documents and Settings/Administrator/Application Data/Microsoft/Templates/Normal.dot" _
, NewTemplate:=False, DocumentType:=0
Selection.TypeText Text:="HELLO"
Selection.TypeParagraph
Selection.TypeText Text:="大家好"
***************************************************************************/
_Application app;
app.CreateDispatch(_T("Word.Application"));
app.SetVisible(TRUE);
AfxMessageBox(_T("看好了,就要新建一个空白文档了"));
//通过WORD宏可以知道,由于要使用Documents,于是我们定义一个并从app中取得
Documents docs=app.GetDocuments();
//准备调用Documents::Add函数了,需要定义4个参数。
//从WORD宏可以看出来3个参数的类型为:
//Template字符,NewTemplate布尔,DocumentType数值
//但Add函数还需要一个参数是Visible,傻子也能看出来这个值表示是否显示出新文档
//并且可以给默认值(VT_EMPTY)
CComVariant Template(_T("")); //为了简单,没有使用WORD的文档模板
CComVariant NewTemplate(false),DocumentType(0),Visible;
docs.Add(&Template,&NewTemplate,&DocumentType,&Visible);
AfxMessageBox(_T("下面,程序要向WORD发送字符啦"));
//通过WORD宏可以知道,由于要使用Selection,于是我们定义一个并从app中取得
//Selection表示输入点,即光标闪烁的那个地方
Selection sel=app.GetSelection();
//调用函数Selection::TypeText 向WORD发送字符
sel.TypeText(_T("HELLO/r/n大家好呀"));
AfxMessageBox(_T("看见了吗?我要退出啦"));
sel.ReleaseDispatch(); //Selection 不用了,一定要释放
docs.ReleaseDispatch(); //Documents 也不用了
CComVariant SaveChanges(false),OriginalFormat,RouteDocument;
app.Quit(&SaveChanges,&OriginalFormat,&RouteDocument);
app.ReleaseDispatch();
AfxMessageBox(_T("下面该学习Setp4了"));
}
例子4:
#include "msword9.h"
#include <AtlBase.h>
void CStep4Dlg::OnOK()
{
_Application app;
app.CreateDispatch(_T("Word.Application"));
app.SetVisible(TRUE);
Documents docs=app.GetDocuments();
CComVariant Template(_T(""));
CComVariant NewTemplate(false),DocumentType(0),Visible;
docs.Add(&Template,&NewTemplate,&DocumentType,&Visible);
Selection sel=app.GetSelection();
COleVariant varstrRange("");
COleVariant varConfirmConversions(short(0),VT_BOOL);
COleVariant varLink(short(0),VT_BOOL);
COleVariant varAttachment(short(0),VT_BOOL);
sel.InsertFile("C://My Project//WordOperator//doc//fjjb.doc",varstrRange,varConfirmConversions,varLink,varAttachment);
sel.MoveUp(COleVariant((short)5),COleVariant((short)2),COleVariant((short)0));
sel.TypeText("123456789 ");
sel.MoveRight(COleVariant((short)12),COleVariant((short)1),COleVariant((short)0));
sel.TypeText(_T("HELLO"));
sel.MoveRight(COleVariant((short)1),COleVariant((short)1),COleVariant((short)0));
sel.TypeText("123456789");
AfxMessageBox(_T("好了,我要保存到c://hello.doc中了"));
/**************** 这是在WORD中录制的新建文档直到另存的宏 *************
Documents.Add Template:= _
"C:/Documents and Settings/Administrator/Application Data/Microsoft/Templates/Normal.dot" _
, NewTemplate:=False, DocumentType:=0
Selection.TypeText Text:="Hello"
Selection.TypeParagraph
Selection.TypeText Text:="大家好"
ChangeFileOpenDirectory "C:/"
ActiveDocument.SaveAs FileName:="Hello.doc", FileFormat:=wdFormatDocument _
, LockComments:=False, Password:="", AddToRecentFiles:=True, _
WritePassword:="", ReadOnlyRecommended:=False, EmbedTrueTypeFonts:=False, _
SaveNativePictureFormat:=False, SaveFormsData:=False, SaveAsAOCELetter:= _
False
*********************************************************************/
/**************** 程序思路 ******************************************
另存为的函数是ActiveDocument.SaveAs,显然表示的是对当前活跃的文档进行保存,
在我们的类中没有ActiveDocument,其实它对应的是_Document,而这个可以由
_Application 的GetActiveDocument()得到。你一定会提问:“你怎么知道的?”
呵呵,怎么说那,我怎么知道的那?答案是:猜。其实如果使用的多了,分析、猜
查找都是办法。如果想得到确切的方法,其实可以在VBA的书或微软的网站中搜索
*********************************************************************/
_Document doc=app.GetActiveDocument(); //得到ActiveDocument
CComVariant FileName(_T("c://doc.wps")); //文件名
CComVariant FileFormat(101); //重点,看下面的说明
CComVariant LockComments(false),Password(_T(""));
CComVariant AddToRecentFiles(true),WritePassword(_T(""));
CComVariant ReadOnlyRecommended(false),EmbedTrueTypeFonts(false);
CComVariant SaveNativePictureFormat(false),SaveFormsData(false);
CComVariant SaveAsAOCELetter(false);
/*************** FileFormat 文件格式说明 ****************************
参数FileFormat,在WORD的宏中,使用的是 wdFormatDocument,这是什么那?
其实这是WORD宏中所使用的常量,由匈牙利命名可以知道wd其实是DWORD的意思
知道了是一个正数,那么它到底是多少那?其实有一个办法可以知道,那就是在
WORD宏程序中,加一条语句:MsgBox wdFormatDocument 这样你再运行宏程序,
就能看到这个常量是多少了。呵呵,这个常量是0,我够聪明吧^_^
*********************************************************************/
doc.SaveAs(&FileName,&FileFormat,&LockComments,&Password,
&AddToRecentFiles,&WritePassword,&ReadOnlyRecommended,
&EmbedTrueTypeFonts,&SaveNativePictureFormat,&SaveFormsData,
&SaveAsAOCELetter);
sel.ReleaseDispatch();
doc.ReleaseDispatch();
docs.ReleaseDispatch();
CComVariant SaveChanges(false),OriginalFormat,RouteDocument;
app.Quit(&SaveChanges,&OriginalFormat,&RouteDocument);
app.ReleaseDispatch();
AfxMessageBox(_T("请检查c://hello.doc是否正常产生了。下面该学习Setp5了"));
}
例子5:
/***************** WORD 中录制的宏,按笔画排序(全部选择,菜单表格/排序) ********
MsgBox wdSortFieldStroke '5 使用了常量,所以使用MsgBox得到具体的数值
MsgBox wdSortOrderAscending '0
MsgBox wdSortFieldSyllable '3
MsgBox wdSeparateByTabs '1
MsgBox wdSimplifiedChinese '2052
Selection.WholeStory '全选
Selection.Sort ExcludeHeader:=False, FieldNumber:="段落数", SortFieldType:= _
wdSortFieldStroke, SortOrder:=wdSortOrderAscending, FieldNumber2:="", _
SortFieldType2:=wdSortFieldSyllable, SortOrder2:=wdSortOrderAscending, _
FieldNumber3:="", SortFieldType3:=wdSortFieldSyllable, SortOrder3:= _
wdSortOrderAscending, Separator:=wdSortSeparateByTabs, SortColumn:=False, _
CaseSensitive:=False, LanguageID:=wdSimplifiedChinese
Selection.Copy '把排序后的结果,复制到剪贴板
*********************************************************************************/
#include "msword9.h"
#include <AtlBase.h>
void CStep5Dlg::OnOK()
{
CString str;
GetDlgItemText(IDC_EDIT1,str);
str.TrimLeft(); str.TrimRight();
if(str.IsEmpty()) return;
::CoInitialize(NULL);
_Application app;
app.CreateDispatch(_T("Word.Application"));
//app.SetVisible(FALSE); //这次不调用显示,因为我们要偷偷摸摸的转换:)
Documents docs=app.GetDocuments();
CComVariant Template(""),NewTemplate(false),DocumentType(0),Visible;
docs.Add(&Template,&NewTemplate,&DocumentType,&Visible);
Selection sel=app.GetSelection();
for(int i=0;i<str.GetLength()/2;i++)
{ //这里只考虑了输入为纯汉字的情况,你自己修改为可以支持中英文混合的情况
sel.TypeText(str.Mid(i*2,2)+"/r/n"); //2个字符表示一个汉字,用回车换行分隔
}
sel.WholeStory(); //全部选择
CComVariant ExcludeHeader(false);
CComVariant FieldNumber(_T("段落数")),SortFieldType(5),SortOrder(0);
CComVariant FieldNumber2(_T("")),SortFieldType2(3),SortOrder2(0);
CComVariant FieldNumber3(_T("")),SortFieldtype3(3),SortOrder3(0);
CComVariant SortColumn(false),Separator(1),LanguageID(2052);
CComVariant CaseSensitive(false),BidiSort,IgnoreThe;
CComVariant IgnoreKashida,IgnoreDiacritics,IgnoreHe;
//排序
sel.Sort(&ExcludeHeader,&FieldNumber,&SortFieldType,&SortOrder,
&FieldNumber2,&SortFieldType2,&SortOrder2,&FieldNumber3,
&SortFieldtype3,&SortOrder3,&SortColumn,&Separator,
&CaseSensitive,&BidiSort,&IgnoreThe,&IgnoreKashida,
&IgnoreDiacritics,&IgnoreHe,&LanguageID);
//其实,这里可以直接调用sel.GetText()取得文本。
//但现在选择复制到剪贴板的方式。
sel.Copy(); //复制到剪贴板
if(OpenClipboard())
{ //从剪贴板取出排序后的文字
HGLOBAL hMem=::GetClipboardData(CF_TEXT);
LPCTSTR lp=(LPCTSTR)::GlobalLock(hMem);
str=lp;
::GlobalUnlock(hMem);
CloseClipboard();
str.Replace("/r/n",""); //删除回车换行
SetDlgItemText(IDC_EDIT2,str);
}
sel.ReleaseDispatch();
docs.ReleaseDispatch();
CComVariant SaveChanges(false),OriginalFormat,RouteDocument;
app.Quit(&SaveChanges,&OriginalFormat,&RouteDocument);
app.ReleaseDispatch();
::CoUninitialize();
}
例子6:
#include "msword9.h"
void CStep6Dlg::OnOK()
{
CLSID clsid;
HRESULT hr;
hr=::CLSIDFromProgID(L"Word.Application",&clsid); //通过ProgID取得CLSID
if(FAILED(hr))
{
AfxMessageBox(_T("不会吧,竟然没有安装OFFICE"));
return;
}
IUnknown *pUnknown=NULL;
IDispatch *pDispatch=NULL;
_Application app=NULL;
Selection sel=NULL;
hr=::GetActiveObject(clsid,NULL,&pUnknown); //查找是否有WORD程序在运行
if(FAILED(hr))
{
AfxMessageBox(_T("没有正在运行中的WORD应用程序"));
return;
}
try
{
hr=pUnknown->QueryInterface(IID_IDispatch,(LPVOID *)&app);
if(FAILED(hr)) throw(_T("没有取得IDispatchPtr"));
pUnknown->Release(); pUnknown=NULL;
sel=app.GetSelection();
if(!sel) throw(_T("没有正在编辑的文档"));
sel.WholeStory(); //全部选择
CString str=sel.GetText(); //取得文本
SetDlgItemText(IDC_EDIT1,str); //显示到编辑窗中
}
catch(LPCTSTR lpErr)
{
AfxMessageBox(lpErr);
}
if(pUnknown) pUnknown->Release();
if(sel) sel.ReleaseDispatch();
if(app) sel.ReleaseDispatch();
}
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------
标题设置(Selection对象和Document对象都没有style方法)
可以使用:_ParagraphFormat对象,示例如下:同时把正文也设置成标题
COleVariant vUnit((long)5);
COleVariant vCount((long)1);
COleVariant vExtend((long)1);
COleVariant vStyle((long)-2); // -2为一级标题,...,-10为九级标题
Selection mySel = oWord.GetSelection();
mySel.MoveDown(&vUnit, &vCount, &vExtend); // 假设光标在段落头,选择当前段
_ParagraphFormat pf = mySel.GetParagraphFormat();
pf.SetStyle(&vStyle);
//关联选择对象 ;把正文设置成正文
m_sel.AttachDispatch(m_app.GetSelection());
//输出标题
COleVariant vStyle1((long)-2);
_ParagraphFormat pf1 = m_sel.GetParagraphFormat();
pf1.SetStyle(&vStyle1);
m_sel.TypeText(_T("\t\t\t\t\t\t\t\t期末成绩报告\r\n"));
//输出前言
COleVariant vStyle2((long)-10);
_ParagraphFormat pf2 = m_sel.GetParagraphFormat();
pf2.SetStyle(&vStyle2);
m_sel.TypeText(_T("\n"));
m_sel.TypeText(_T("\t本期末成绩报告主要共分三个部分,第一部分是XXXXXXX,第二部分是XXXXXXXX,第三部分是XXXXXXXX。\r\n"));