我们操纵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();
}
7、图片查找的demo(无选中功能)
vc操纵word问题:查找到图片后如何得到该图片的长宽信息
一个Word文档中已经有一张BMP图片。VC打开该文档,并Find查找到该图片。
COleVariant covTrue((
short
)TRUE),covFalse((
short
)FALSE),covOptional((
long
)DISP_E_PARAMNOTFOUND,VT_ERROR);
_Application app;
//
定义一个WORD的应用对象
app.CreateDispatch(_T(
"
Word.Application
"
)))
//
启动WORD
app.SetVisible(
true
);
//
设置用户可见
Documents docs=
app.GetDocuments();
docs.Open(
//
打开文档
COleVariant((LPCSTR)m_csPath,VT_BSTR),
covFalse,
//
确定转换
covTrue,
//
只读打开
covFalse,
//
添加到最近使用文件列表
covOptional,
//
PasswordDocument.
covOptional,
//
PasswordTemplate.
covFalse,
//
Revert.
covOptional,
//
WritePasswordDocument.
covOptional,
//
WritePasswordTemplate.
COleVariant(
long
(
1
)),
//
Format. 如果是Word97,这便是最好一个参数
covOptional,
//
编码 下面是Word 2000/2002专用的参数
covTrue)
//
可见
Selection sel
=
app.GetSelection();
Find find
=
sel.GetFind();
find.ClearFormatting();
find.Execute(
//
开始查找图片
COleVariant(_T(
"
^g
"
),VT_BSTR),
covFalse,
covFalse,
covFalse,
covFalse,
covFalse,
covTrue,
COleVariant(
long
(
1
)),
covFalse,
COleVariant(
""
,VT_BSTR),
covFalse,
covFalse,
covFalse,
covFalse,
covFalse);
8、文字查找(有选中功能)
COleVariant covTrue((
short
)TRUE),covFalse((
short
)FALSE),covOptional((
long
)DISP_E_PARAMNOTFOUND,VT_ERROR);
Find t_find
=
sel.GetFind();
t_find.ClearFormatting();
t_find.Execute(COleVariant(_T(
"
的
"
),VT_BSTR),
covFalse,
covFalse,
covFalse,
covFalse,
covFalse,
covTrue,
COleVariant(
long
(
1
)),
covFalse,
COleVariant(
""
,VT_BSTR),
covFalse,
covFalse,
covFalse,
covFalse,
covFalse);
9、带选中功能的
void
DoSelctionPicture()
{
sel.MoveRight(COleVariant(
short
(
1
)),COleVariant(
short
(
1
)),COleVariant(
short
(
0
)));
//
撤销当前的选中状态。
sel.MoveLeft(COleVariant(
short
(
1
)),COleVariant(
short
(
1
)),COleVariant(
short
(
0
)));
//
撤销当前的选中状态。
COleVariant covTrue((
short
)TRUE),covFalse((
short
)FALSE),covOptional((
long
)DISP_E_PARAMNOTFOUND,VT_ERROR);
Find t_find
=
sel.GetFind();
t_find.ClearFormatting();
t_find.Execute(COleVariant(_T(
"
^g
"
),VT_BSTR),
covFalse,
covFalse,
covFalse,
covFalse,
covFalse,
covTrue,
COleVariant(
long
(
1
)),
covFalse,
COleVariant(
""
,VT_BSTR),//要替换的字符串。空
covFalse,
covFalse,
covFalse,
covFalse,
covFalse);
sel.MoveRight(COleVariant(
short
(
1
)),COleVariant(
short
(
1
)),COleVariant(
short
(
1
)));
//
选中。bug:多选中了一个右边的字符。
}
10、扩展
//
sel.MoveRight(COleVariant((short)1),COleVariant((short)1),COleVariant((short)1));
//
左移,以字为单位。
//
m_Sel.MoveDown(COleVariant((short)4),COleVariant((short)1),COleVariant((short)0));
//
下移,以行为单位。
//
m_Sel.MoveLeft(COleVariant((short)2),COleVariant((short)1),COleVariant((short)0));
//
左移,以词组为单位。
//
m_Sel.MoveLeft(COleVariant((short)1),COleVariant((short)1),COleVariant((short)0));
//
左移,以字为单位。
//
m_Sel.MoveStart(COleVariant((short)2),COleVariant((short)1));
//
m_Sel.MoveDown(COleVariant((short)4),COleVariant((short)1),COleVariant((short)1));
//
选中下移,以行为单位。
//
m_Sel.MoveLeft(COleVariant((short)2),COleVariant((short)1),COleVariant((short)1));
//
选中左移,以词组为单位。
//
m_Sel.MoveLeft(COleVariant((short)1),COleVariant((short)1),COleVariant((short)1));
//
选中左移,以字为单位。
//
m_Sel.TypeBackspace();
//
删除选中内容。
11、插入图片【此部分来源: http://blog.csdn.net/halin1983/article/details/4533112 】
VC++6.0向Word文件的指定位置上插入一张图片,需要用到nlineShapes类型的AddPicture方法。
在MSDN中,该方法的声明如下:
**************************************************************************
在文档中添加一幅图片。返回一个 Shape 对象,该对象代表图片,并将其添加至 InlineShapes 集合。
expression.AddPicture(FileName, LinkToFile, SaveWithDocument, Range)
expression 必需。该表达式返回一个 InlineShapes 对象。
FileName String 类型,必需。图片的路径和文件名。
LinkToFile Variant 类型,可选。如果为 True,则将图片链接到创建该对象的文件;如果为 False,则将图片作为该文件的独立副本。默认值是 False。
SaveWithDocument Variant 类型,可选。如果为 True,则将链接的图片与文档一起保存。默认值是 False。
Range Variant 类型,可选。图片置于文本中的位置。如果该区域未折叠,那么图片将覆盖此区域,否则插入图片。如果忽略此参数,则自动放置图片
**************************************************************************
根据该说明的定义,第四个参数Range是用来设置图片位于文本中的位置的。因此,我们可以利用该参数向某一指定位置插入图片。具体方法如下:
Selection sel=m_app.GetSelection();
//
获取文档的selection
InlineShapes inlineshapes =
sel.GetInlineShapes();
inlineshapes.AddPicture(
"
D:\\abc.bmp
"
,COleVariant((
short
)FALSE),COleVariant((
short
)TRUE),&_variant_t(sel.GetRange()));
//
添加图片,并制定其位置为当前光标位置
inlineshapes.ReleaseDispatch();
sel.ReleaseDispatch();
//
注意上面第四个参数的转换方法,用到了_variant_t变量,使用此种方法可以将LPDISPATCH转换成VARIANT*类型
如此就可将图片直接插入到光标当前所在位置
Document对象的保存功能:
LPCWSTR pathstr=L"D:\\abc.doc";
VARIANT path;
path.vt=VT_BSTR;
path.bstrVal=SysAllocString(pathstr);
VARIANT overw;
overw.vt=VT_BOOL;
overw.boolVal=VARIANT_TRUE;
VARIANT name;
name.vt=VT_BSTR;
name.bstrVal=NULL;
m_FramerControl.Save( path,overw,path,path);

