word_0">MFC对word操作
背景说明
当对程序的内容进行输出时,比如自定义对象属性描述或者注释(详细设计)生成文档时,如果采用手动输入会比较麻烦,并且当程序变动时,需要再一次修改对应文档,作为程序员做重复性工作非常难受。代码的意义就是为了自动化流程,减少重复性工作。这里以MFC框架下对word进行读写操作为例,其他语言也有类似接口。
word_3">MFC与word接口
前期准备工作可以参考MFC程序创建word,创建表格,写入数据。我用的是Office365,编辑器是vs2022。借助模板插入标签的方法来写入(实际上借助标签来定位并插入文字图片)主要是完成了如下工作,
- 插入图片及文本
- 设定页脚页眉
- 插入表格
- 设定表格宽度
- 设置表格内容和字体
- 读取表格内容以及标题
但是暂时没有解决的
- 对目录进行更新目录或者域时总是失败
- 无法设置表格的标题
- 页眉插入图片失败
- 页脚设置页面数(比如page 1 of 100)失败,只能显示页面数1,2这种格式
具体使用了接口如下
代码段
需要注意的是,MFC的COM组件操作word的表格或者行数时都是从1开始的,这与我们编写代码从0计算不一样。
头文件
#pragma once
#include "msword/CApplication.h"
#include "msword/CBookmark0.h"
#include "msword/CBookmarks.h"
#include "msword/CCell.h"
#include "msword/CCells.h"
#include "msword/CColumn.h"
#include "msword/CColumns0.h"
#include "msword/CDocument0.h"
#include "msword/CDocuments.h"
#include "msword/CFontWord.h"
#include "msword/CTable0.h"
#include "msword/CTables0.h"
#include "msword/CRange.h"
#include "msword/CSelection.h"
#include "msword/CnlineShape.h"
#include "msword/CHeaderFooter.h"
#include "msword/CHeadersFooters.h"
#include "msword/CPageSetup.h"
#include "msword/CnlineShapes.h"
#include "msword/CShading.h"
#include "msword/CParagraphFormat.h"
#include "msword/CSection.h"
#include "msword/CSections.h"
#include "msword/CPageNumber.h"
#include "msword/CPageNumbers.h"
#include "msword/CParagraph.h"
#include "msword/CParagraphs.h"
#include "msword/CBorder.h"
#include "msword/CBorders.h"
#include "msword/CRows.h"
#include "msword/CRow.h"
#include "msword/CTableOfContents.h"class WordOperation
{
public:CApplication m_wordApp;CDocuments m_docs;CDocument0 m_docx;CBookmarks m_bookmarks;CBookmark0 m_bookmark;CRange m_range;CCell m_cell;CTables0 m_Tables;CTable0 m_Table;CSelection m_sel;CFontWord m_Font;CRows m_Rows;CColumns0 m_Columns;//第一个Section对应的页脚CHeaderFooter m_footer;//第一个Section对应的页眉CHeaderFooter m_Header;/// <summary>/// word中对应的目录/// </summary>CTableOfContents0 m_tableOfContents;
public:WordOperation(CString templateStr);~WordOperation();/// <summary>/// 将文档保存/// </summary>void SaveFile();/// <summary>/// 写入文本/// </summary>/// <param name="Text">要写入的内容</param>void WriteText(CString Text);/// <summary>/// 新建一段内容/// </summary>/// <param name="nCount">新建行数</param>void NewLine(int nCount = 1);/// <summary>/// 向新建段落写入内容/// </summary>/// <param name="Text">需要写入的内容</param>/// <param name="nCount">新建段落行数</param>void WriteTextToNewLine(CString Text, int nCount = 1);/// <summary>/// 将鼠标移到最后一行/// </summary>void EndLine();/// <summary>/// 插入分页符/// </summary>void InsertPageBreak();/// <summary>/// 设置字体样式/// </summary>/// <param name="blod">是否是粗体</param>/// <param name="Italic">是否斜体 默认值:非斜体</param>/// <param name="UnderLine">是否有下划线 默认值:无下划线</param>void SetFont(BOOL blod,BOOL Italic=FALSE,BOOL UnderLine = FALSE);/// <summary>/// 设置字体/// </summary>/// <param name="FontName">字体名称</param>/// <param name="FontSize">字体大小 默认值:9</param>/// <param name="FontColor">设置字体颜色 默认值:0</param>/// <param name="FontBackColor">设置字体背景色 默认值:0</param>void SetFont(CString FontName, int FontSize = 9, long FontColor = 0, long FontBackColor = 0);/// <summary>/// 获取当前表格指定行数和列数单元格文本/// </summary>/// <param name="Row">要获取单元格的行</param>/// <param name="column">要获取单元格的列</param>/// <returns></returns>CString GetCellText(int Row, int column);/// <summary>/// 设置表格宽度/// </summary>/// <param name="Column">表示设置对象Table的第Column列</param>/// <param name="columnWidth">需要设置的列宽数值:columnWidth</param>void SetTableColumnWidth(int Column, float columnWidth);/// <summary>/// 为文档添加目录/// </summary>void AddTableOfContents();/// <summary>/// 设置表格行数的高度/// <param name="Row">表示设置对象Table的第Row行</param>/// <param name="RowHeigh">行高</param>/// </summary>void SetTableRowHeigh(int Row, float RowHeigh);/// <summary>/// 设置表格的对齐方式/// </summary>/// <param name="Alignment">设置对齐的方式 1:居中对齐 2:右对齐 3:左对齐</param>void SetTableAlignment(int Alignment);/// <summary>/// 创建表格/// </summary>/// <param name="Row">表格的行数</param>/// <param name="Column">表格的列数</param>/// <param name="tableName">表格名称</param>void CreateTable(int Row, int Column,CString tableName);/// <summary>/// 将单元格拆分/// </summary>void SplitTable(int RowSource, int ColumnSource, int RowNum, int ColumnNum);/// <summary>/// 合并单元格/// </summary>void MergeTable(int RowSource, int ColumnSource, int RowGoal, int ColumnGoal);/// <summary>/// 设置表格的单元格字体/// </summary>/// <param name="Row">单元格所在的行</param>/// <param name="Column">单元格所在的列</param>/// <param name="FontName">字体名称</param>/// <param name="FontSize">字体大小</param>/// <param name="FontColor">字体颜色</param>/// <param name="FontBackColor">字体背景色</param>void SetTableFont(int Row, int Column, CString FontName, int FontSize, long FontColor = 0, long FontBackColor = 0);/// <summary>/// 将光标移动到标签指定范围/// </summary>/// <param name="bookmarkText">标签名称</param>void SetCurToBookmark(CString bookmarkText);/// <summary>/// 设置表格的单元格内容/// </summary>/// <param name="Row">单元格所在的行</param>/// <param name="Column">单元格所在的列</param>/// <param name="Text">写入单元格内容</param>void WriteCellText(int Row, int Column, CString Text);/// <summary>/// 设置表格背景颜色/// </summary>/// <param name="Row">单元格所在行</param>/// <param name="Column">单元格所在列</param>/// <param name="ShadingColor">背景色</param>void SetTableShading(int Row, int Column, long ShadingColor = 0);/// <summary>/// 保存word/// </summary>/// <param name="FileName">保存路径</param>/// <param name="SaveType">保存类型</param>/// <returns></returns>BOOL SaveAs(CString FileName, int SaveType);/// <summary>/// 插入指定路径的图片/// </summary>/// <param name="fileName">图片所在路径</param>void InsertShapes(CString fileName);/// <summary>/// 插入位图图片/// </summary>/// <param name="pBitmap">位图指针</param>void InsertShapes(CBitmap* pBitmap);/// <summary>/// 设置页眉/// </summary>/// <param name="HeaderText">页眉内容</param>void SetWordPageHeaderContent(CString HeaderText);/// <summary>/// 设置页脚/// </summary>/// <param name="FooterText">页脚内容</param>void SetWordPageFooterContent(CString FooterText);/// <summary>/// 获取指定表格前面的内容/// </summary>/// <param name="index">表格的排序</param>/// <returns></returns>CString GetTableBeforeName(int index);/// <summary>/// 获取当前文档中表格的数量/// </summary>/// <returns>文档中表格的数量</returns>int GetTableCount();/// <summary>/// 获取当前文档中所有表格的行数/// </summary>/// <returns></returns>int GetAllTableRowCount();/// <summary>/// 获取表格中指定行和列的单元格内容/// </summary>/// <param name="row">指定行</param>/// <param name="column">指定列</param>/// <returns>返回指定单元格内容</returns>CString GetTableCellText(int row, int column);/// <summary>/// 获取表格的行数/// </summary>/// <returns></returns>int GetTableColumnsNum();/// <summary>/// 获取表格的列数目/// </summary>/// <returns></returns>int GetTableRowsNum();
};
cpp文件:
#include "stdafx.h"
#include "WordOperation.h"
#include <comutil.h>
void WordOperation::CreateTable(int row, int column, CString tableName)
{CComVariant DefaultBehavior(1), AutoFitBehavior(2);if (!m_Tables.m_lpDispatch){AfxMessageBox("创建表格对象失败");return;}else{m_Tables.Add(m_sel.get_Range(), row, column, &DefaultBehavior, &AutoFitBehavior);m_Table = m_Tables.Item(m_Tables.get_Count());CBorders borders = m_Table.get_Borders();//设置表格边框COleVariant covboderSingleLine((short)1), covboderOutSideLine((short)13);borders.put_InsideLineStyle(1);//设置内部框线为单线条borders.put_OutsideLineStyle(12);//设置外部框线为双线条long TableWidth = m_Table.get_PreferredWidth();m_Rows = m_Table.get_Rows();m_Columns = m_Table.get_Columns();SetTableAlignment(1);/*LPTSTR lpsz = tableName.GetBuffer();m_Table.get_Title();m_Table.put_Title(lpsz);//这里会报错,设置标题会莫名奇妙的失败*///tableName.ReleaseBuffer();//m_Table.put_PreferredWidth(300);}
}
/// <summary>
/// 拆分单元格
/// </summary>
/// <param name="RowSource">需要被拆分单元格的行</param>
/// <param name="ColumnSource">需要被拆分单元格的列</param>
/// <param name="RowNum">拆分的单元格行数</param>
/// <param name="ColumnNum">拆分的单元格列数</param>
void WordOperation::SplitTable(int RowSource, int ColumnSource, int RowNum, int ColumnNum)
{COleVariant RowNumVariant((short)RowNum), ColumnNumVariant((short)ColumnNum);CCell(m_Table.Cell(RowSource, ColumnSource)).Split(RowNumVariant,ColumnNumVariant);
}
/// <summary>
/// 获取当前表格指定行数和列数单元格文本
/// </summary>
/// <param name="Row">要获取单元格的行</param>
/// <param name="column">要获取单元格的列</param>
/// <returns></returns>
CString WordOperation::GetCellText(int Row, int column)
{CCell m_cell = CCell(m_Table.Cell(Row, column)); //如果被合并的单元格无法访问,这里会直接抛出“所要求的集合不存在",并且无法捕获这个异常CRange cellRange = CCell(m_Table.Cell(Row, column)).get_Range();CString Celltext = cellRange.get_Text();int indexR = Celltext.Find("\r");//去除字符串中的\r\nCelltext = Celltext.Left(indexR);Celltext.TrimLeft();Celltext.TrimRight();return Celltext;
}
/// <summary>
/// 合并单元格
/// </summary>
/// <param name="RowSource">发起合并单元格的行</param>
/// <param name="ColumnSource">发起合并单元的列</param>
/// <param name="RowGoal">需要被合并单元格的行</param>
/// <param name="ColumnGoal">需要被合并单元格的列</param>
void WordOperation::MergeTable(int RowSource, int ColumnSource, int RowGoal, int ColumnGoal)
{CCell(m_Table.Cell(RowSource, ColumnSource)).Merge(m_Table.Cell(RowGoal, ColumnGoal));CCell(m_Table.Cell(RowSource, ColumnSource)).put_VerticalAlignment(1);//合并后居中
}
void WordOperation::SetTableFont(int row, int column, CString FontName, int FontSize, long FontColor, long FontBackColor)
{CCell ce = m_Table.Cell(row, column);ce.Select();CFontWord ft = m_sel.get_Font();ft.put_Name(FontName);ft.put_Size(FontSize);ft.put_Color(FontColor);CRange r = m_sel.get_Range();r.put_HighlightColorIndex(FontBackColor);
}
void WordOperation::SetTableColumnWidth(int column, float columnWidth)
{CColumn(m_Columns.Item(column)).put_PreferredWidth(columnWidth);
}
void WordOperation::SetTableAlignment(int Alignment)
{CRange curTableRange = m_Table.get_Range();CParagraphFormat curTableFormat = curTableRange.get_ParagraphFormat();curTableFormat.put_Alignment(Alignment);//CColumn(m_Columns.Item(column)).SetWidth();
}
void WordOperation::SetTableRowHeigh(int row, float RowHeigh)
{CRow(m_Rows.Item(row)).put_Height(RowHeigh);
}
void WordOperation::WriteCellText(int row, int column, CString Text)
{CCell ce = m_Table.Cell(row, column);ce.Select();m_sel.TypeText(Text);
}
void WordOperation::SetTableShading(int Row, int Column, long ShadingColor)
{CCell ce = m_Table.Cell(Row, Column);ce.Select();CShading s = ce.get_Shading();s.put_BackgroundPatternColor(ShadingColor);
}
void WordOperation::SaveFile()
{if (!m_docx.m_lpDispatch){AfxMessageBox("Documents 对象没有建立 保存失败");return;}else{m_docx.Save();return;}
}
void WordOperation::WriteText(CString Text)
{m_sel.TypeText(Text);
}
void WordOperation::NewLine(int nCount)
{if (nCount <= 0){nCount = 0;}else{for (int i = 0; i < nCount; i++){m_sel.TypeParagraph();//新建一段}}
}
void WordOperation::WriteTextToNewLine(CString text, int nCount)
{NewLine(nCount);WriteText(text);
}
void WordOperation::AddTableOfContents()
{}
void WordOperation::SetCurToBookmark(CString bookmarkText)
{m_bookmark = m_bookmarks.Item(&_variant_t(bookmarkText));m_range = m_bookmark.get_Range();long start = m_range.get_Start();long end = m_range.get_End();m_sel.SetRange(start, end);
}
void WordOperation::EndLine()
{m_sel = m_wordApp.get_Selection();m_sel.EndKey(COleVariant((short)6), COleVariant((short)0));
}
void WordOperation::InsertPageBreak()
{m_sel = m_wordApp.get_Selection();m_sel.InsertBreak(COleVariant((long)7));
}
void WordOperation::SetFont(BOOL Bold, BOOL Italic, BOOL underLine)
{if (!m_sel.m_lpDispatch){AfxMessageBox("编辑对象失败,导致字体不能设置");return;}else{m_sel.put_Text("F");m_Font = m_sel.get_Font();//获得字体编辑对象 m_Font.put_Bold(Bold); m_Font.put_Italic(Italic);m_Font.put_Underline(underLine);m_sel.put_Font(m_Font);}
}
void WordOperation::SetFont(CString FontName, int FontSize, long FontColor, long FontBackColor)
{if (!m_sel.m_lpDispatch){AfxMessageBox("Select 为空,字体设置失败!");return;}m_sel.put_Text("a");m_Font = m_sel.get_Font();m_Font.put_Name(FontName);m_Font.put_Size(FontSize);m_Font.put_Color(FontColor);m_Font.put_ColorIndex(FontBackColor);m_sel.put_Font(m_Font);
}
void WordOperation::InsertShapes(CString imagePath)
{COleVariant vTrue((short)TRUE), vFalse((short)FALSE), vOpt((long)DISP_E_PARAMNOTFOUND, VT_ERROR);CnlineShapes m_iShapes = m_sel.get_InlineShapes();CnlineShape m_ishape = m_iShapes.AddPicture(imagePath,vFalse,vTrue,vOpt);}
void WordOperation::InsertShapes(CBitmap* pBitmap)
{if (OpenClipboard(NULL)){EmptyClipboard();SetClipboardData(CF_BITMAP, pBitmap->m_hObject);CloseClipboard();m_sel.Paste();}}
BOOL WordOperation::SaveAs(CString FileName, int SaveType)
{CComVariant vTrue(TRUE);CComVariant vFalse(FALSE);CComVariant vOpt;CComVariant cFileName(FileName);CComVariant FileFormat(SaveType);COleVariant covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR);COleVariant covFalse((short)FALSE);if (!m_docx.m_lpDispatch){AfxMessageBox("Document 对象没有建立 另存为失败");return FALSE;}else{//保存之前更新一下目录//m_tableOfContents.UpdatePageNumbers(); 这个总是提示参数数目不对,不知道哪里的问题m_docx.SaveAs(COleVariant(FileName),covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional, covOptional);//m_docx.Close(covFalse, covOptional, covOptional);AfxMessageBox(_T("生成 ") + FileName + _T(" 成功"));}return TRUE;
}
void WordOperation::SetWordPageHeaderContent(CString HeaderText)
{CRange headRange = m_Header.get_Range();headRange.put_Text(HeaderText);
}
void WordOperation::SetWordPageFooterContent(CString FooterText)
{CRange footRangeEcFir = m_footer.get_Range();footRangeEcFir.put_Text(FooterText);CPageNumbers m_pageNumbers = m_footer.get_PageNumbers();COleVariant covAlignCenter((short)1), covAlignInside((short)3), covAlignNumberLeft((short)0), covAlginOutSide((short)4), covAlignRight((short)2), covFalse((short)FALSE);m_pageNumbers.Add(covAlignRight, covFalse);
}
int WordOperation::GetTableRowsNum()
{m_Rows = m_Table.get_Rows();return m_Rows.get_Count();
}
int WordOperation::GetTableColumnsNum()
{m_Columns = m_Table.get_Columns();return m_Columns.get_Count();
}
CString WordOperation::GetTableCellText(int row, int column)
{m_cell = m_Table.Cell(row, column);CRange cellRange = m_cell.get_Range();return cellRange.get_Text();
}
int WordOperation::GetTableCount()
{return m_Tables.get_Count();
}
int WordOperation::GetAllTableRowCount()
{int RowCount = 0;for (int tableIndex = 1; tableIndex < GetTableCount(); tableIndex++){CTable0 tempTable = m_Tables.Item(tableIndex);if (!tempTable.m_lpDispatch){CRows tablesRows = tempTable.get_Rows();RowCount += tablesRows.get_Count();}}return RowCount;
}
/// <summary>
/// 根据当前表格搜索前方标题,一直找到内容为止,这里的内容就认为是表的标题
/// </summary>
/// <param name="index">表格的排序</param>
/// <returns>表格标题</returns>
CString WordOperation::GetTableBeforeName(int index)
{CString tableName = "";m_Table = m_Tables.Item(index);CRange tableRange = m_Table.get_Range();CParagraphs tableParagraphs = tableRange.get_Paragraphs();CParagraph tableFirstPara = tableParagraphs.get_First();int startIndex = 1;while (tableName.IsEmpty() || tableName == "\r" || tableName == "\t\r" || tableName == " \r"){COleVariant covCount((short)startIndex);CParagraph tableBeforePara = tableFirstPara.Previous(covCount);CRange previousTextRange = tableBeforePara.get_Range();tableName = previousTextRange.get_Text();tableName.Trim();startIndex++;}/*int tableStart = tableRange.get_Start();int tableEnd = tableRange.get_End();CParagraphs paragraphs = m_docx.get_Paragraphs();int paragraphCount = paragraphs.get_Count();*//*for (int iPara = 1; iPara < paragraphCount; iPara++){CParagraph para = paragraphs.Item(iPara);CRange para_Range = para.get_Range();int para_RangeStart = para_Range.get_Start();int para_RangeEnd = para_Range.get_End();if (para_RangeStart >= tableStart){break;}CString paraRangeText = para_Range.get_Text();if (paraRangeText != "\r" && paraRangeText != "\t\r" && paraRangeText != " \r"){tableName = paraRangeText;}}*/return tableName;
}
WordOperation::WordOperation(CString templateStr)
{COleVariant covZero((short)0), covTrue((short)TRUE), covFalse((short)FALSE), covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR), covDocxType((short)0), start_line, end_line, dot(templateStr);if (!m_wordApp.CreateDispatch(_T("Word.Application"))){AfxMessageBox(_T("本机没有安装word产品!"));return;}m_wordApp.put_Visible(FALSE);CString wordVersion = m_wordApp.get_Version();m_docs = m_wordApp.get_Documents();if (!m_docs.m_lpDispatch){AfxMessageBox("Documents创建失败!", MB_OK | MB_ICONWARNING);return;}m_docx = m_docs.Add(dot, covOptional, covOptional, covOptional);if (!m_docx.m_lpDispatch){AfxMessageBox("Document获取失败", MB_OK | MB_ICONWARNING);return;}m_bookmarks = m_docx.get_Bookmarks();m_Tables = m_docx.get_Tables();m_sel = m_wordApp.get_Selection();if (!m_sel.m_lpDispatch){AfxMessageBox("Selection获取失败");}CSections m_wordSections = m_docx.get_Sections();CSection m_wordSection = m_wordSections.get_First();CHeadersFooters m_wordSecHeaderFooters = m_wordSection.get_Headers();CHeadersFooters m_wordFooters = m_wordSection.get_Footers();m_footer = m_wordFooters.Item(1);m_Header = m_wordSecHeaderFooters.Item(1);m_tableOfContents = m_docx.get_TablesOfContents();if (!m_tableOfContents.m_lpDispatch){AfxMessageBox("目录获取失败");}else{/*m_tableOfContents.get_Application();long lowLevel = m_tableOfContents.get_LowerHeadingLevel();long uperLevel = m_tableOfContents.get_UpperHeadingLevel();CRange m_tableOfConRange = m_tableOfContents.get_Range();m_sel.SetRange(m_tableOfConRange.get_Start(),m_tableOfConRange.get_End());m_tableOfContents.UpdatePageNumbers(); // 无法定位到具体的目录,这个只能手动更新了*/}//CHeaderFooter m_footObj = m_wordSecHeaderFooters.Item(2);//BOOL m_isFootObjHeader = m_footObj.get_IsHeader();//CRange headRange = m_Header.get_Range();//CRange footRange = m_footObj.get_Range();//CRange footRangeEcFir = m_footer.get_Range();//BOOL m_bisHeader = m_Header.get_IsHeader();//BOOL m_bIsHeader = m_footer.get_IsHeader();/*int index = m_Headfoot.get_Index();LPDISPATCH pageNums = m_Headfoot.get_PageNumbers();LPDISPATCH parent = m_Headfoot.get_Parent();LPDISPATCH tm = m_Headfoot.get_Shapes();*///CString strHeader = headRange.get_Text();//CString strFooter = footRange.get_Text();//CString strFootRange = footRangeEcFir.get_Text();//footRangeEcFir.put_Text("测试页脚部分");/*int curPageNum = m_sel.get_Information(3).bVal;CString curPageStr = "";curPageStr.Format("%d", curPageNum);footRangeEcFir.InsertAfter("Page");*///footRangeEcFir.get_Fields(COleVariant((long)wdFieldFormText))//footRangeEcFir.InsertAfter(curPageStr);//headRange.put_Start(0);/*CRange headLogoRange=headRange.get_ShapeRange();COleVariant vTrue((short)TRUE), vFalse((short)FALSE), vOpt((long)DISP_E_PARAMNOTFOUND, VT_ERROR);CnlineShapes m_iShapes = headRange.get_InlineShapes();int numShapes = m_iShapes.get_Count();CnlineShape shape_Insert = m_iShapes.Item(1);CRange shape_Range = shape_Insert.get_Range();m_sel.SetRange(shape_Range.get_Start(), shape_Range.get_End());CnlineShape m_ishape = m_iShapes.AddPicture(_T("C:\\Users\\yhwan\\Pictures\\logo\\RSIC.png"), vFalse, vTrue, vOpt);m_ishape.put_Width(100);m_ishape.put_Height(36);*///headRange.put_Text("测试页眉");/*headRange.InsertBefore("测试头部前插入");headRange.InsertAfter("测试头部后插");*///footRange.put_Text("页脚测试");
}WordOperation::~WordOperation()
{COleVariant covZero((short)0), covTrue((short)TRUE), covFalse((short)FALSE), covOptional((long)DISP_E_PARAMNOTFOUND, VT_ERROR), covDocxType((short)0), start_line, end_line;m_docx.Close(covFalse, covOptional, covOptional);//m_docx.Close(covFalse, covOptional, covOptional);m_wordApp.Quit(covOptional, covOptional, covOptional);m_range.ReleaseDispatch();m_Tables.ReleaseDispatch();m_bookmarks.ReleaseDispatch();m_sel.ReleaseDispatch();m_wordApp.ReleaseDispatch();
}