杨老师:Visual C++ 中操纵 MS Word 123

来源:互联网 发布:安卓版数据恢复软件 编辑:程序博客网 时间:2024/06/11 19:26

对杨老师佩服不已!

又搜到他写的《Visual C++ 中操纵 MS Word 123》。在源代码中,介绍了我一直不太摸得着头脑的CComVariant, COleVariant, _variant_t变量,所以摘记于此,方便查阅。

Visual C++ 中操纵 MS Word 123

步步为营:

Step1:如何启动和关闭 WORD,及 VARIANT 的最基本的使用方法

Step2:和 Step1 同样功能,用 CComVariant 改进了 VARIANT 的使用方式

Step3:在 Step2 的基础上,新建一个 WORD 文档,并从程序中传送一些字符到 WORD

Step4:在 Step3 的基础上,保存 WORD 文档

Step5:一个小应用举例,把输入的汉字按照“笔画”排序

Step6:一个小应用举例,盗窃正在使用的 WORD 文档

以上这6个小程序中,都有详细的注释。大家阅读后慢慢体会并实验,你就可以自由地操纵任何一个 Office 啦。

参考:Microsoft Office Development with Visual Studio


Step1:

#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"));

}

Step2:

#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了"));

}

Step3:

#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了"));

}

Step4:

#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();

sel.TypeText(_T("HELLO\r\n大家好呀"));


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:\\Hello.doc"));//文件名

CComVariant FileFormat(0);//重点,看下面的说明

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了"));

}


Step5:

BOOL CStep5Dlg::OnInitDialog()
{

CDialog::OnInitDialog();


// Set the icon for this dialog.  The framework does this automatically

//  when the application's main window is not a dialog

SetIcon(m_hIcon, TRUE);// Set big icon

SetIcon(m_hIcon, FALSE);// Set small icon


// TODO: Add extra initialization here

SetDlgItemText(IDC_EDIT1,_T("中华人民共和国"));

return TRUE;  // return TRUE  unless you set the focus to a control

}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CStep5Dlg::OnPaint() 
{

if (IsIconic())

{

CPaintDC dc(this); // device context for painting

SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

// Center icon in client rectangle

int cxIcon = GetSystemMetrics(SM_CXICON);

int cyIcon = GetSystemMetrics(SM_CYICON);

CRect rect;

GetClientRect(&rect);

int x = (rect.Width() - cxIcon + 1) / 2;

int y = (rect.Height() - cyIcon + 1) / 2;

// Draw the icon

dc.DrawIcon(x, y, m_hIcon);

}

else

{

CDialog::OnPaint();

}

}


// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.

HCURSOR CStep5Dlg::OnQueryDragIcon()
{

return (HCURSOR) m_hIcon;

}

/***************** 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();

}


Step6:

#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();

}

0 0