首页 > 其他分享 >利用COM组件实现对WORD书签各种操作大全

利用COM组件实现对WORD书签各种操作大全

时间:2024-02-19 15:45:34浏览次数:24  
标签:WORD ref object 书签 Range activeRange doc COM

  有个需求是,程序导出一份word报告,报告中有各种各样的表格,导出时还需要插入图片。

  脑海中迅速闪过好几种组件,openxml组件,com组件,npoi。为了减少程序画复杂表格,我们选用了com组件+word模板的方式,程序只需要对word中的书签进行赋值即可。

  不知道这几种组件的(或者还有其他写入word的组件可以推荐)优缺点各是什么,还请各路大拿评论区指点一二。

  com组件唯一让人不爽的就是他过于依赖word,因为版本带来的不兼容问题,及各种会生成WORD半途会崩溃的问题.而且很难解决。

  不说这么悲伤的事情了,反正坑都踩了,文章后面我会附上各种深坑的解决方案,今天主要分享的是com组件写入word的各种操作。

 1.书签赋值


     /// <summary> /// 给特定书签赋值 /// </summary> /// <param name="bookMarkName"></param> /// <param name="value"></param> public void EditTable(string bookMarkName, string value, Document doc) { try { if (!doc.Bookmarks.Exists(bookMarkName)) return; object s = bookMarkName; Range rng = doc.Bookmarks.get_Item(ref s).Range; rng.Text = value; } catch (Exception e) { KillwordProcess(); throw e; } }

2.获取指定书签的范围


 

     /// <summary> /// 获取指定书签的Range /// </summary> /// <param name="bookMarkName">书签名称</param> public Range GetBookMarkRange(string bookMarkName, Document doc) { object oBookMarkName = bookMarkName; return doc.Bookmarks.get_Item(ref oBookMarkName).Range; }

3.添加书签


 

/// <summary> /// 添加书签 /// </summary> /// <param name="bookMarkName">书签名</param> /// <param name="activeRange">要添加书签的范围</param> public void AddBookMark(string bookMarkName, Range activeRange, Document doc) { object oActiveRange = activeRange; doc.Bookmarks.Add(bookMarkName, ref oActiveRange); }

4.复制书签内容到另一个书签


 

     /// <summary> /// 复制书签内容至另一书签 /// </summary> /// <param name="sourceBookMarkName">源书签</param> /// <param name="toBookMarkName">目标书签</param> public void CopyRange(string sourceBookMarkName, string toBookMarkName, Document doc) { object oSourceBookMarkName = sourceBookMarkName; object oToBookMarkName = toBookMarkName; Range roRange = CopyRange(doc.Bookmarks.get_Item(ref oSourceBookMarkName).Range, doc.Bookmarks.get_Item(ref oToBookMarkName).Range); doc.Bookmarks.get_Item(ref oToBookMarkName).Delete(); AddBookMark(toBookMarkName, roRange, doc); } /// <summary> /// 复制选定范围内容至另一范围 /// </summary> /// <param name="sourceRange">源范围</param> /// <param name="activeRange">目标范围</param> public Range CopyRange(Range sourceRange, Range activeRange) { try { lock (copyLock) { sourceRange.Copy(); activeRange.Paste(); } return activeRange; } catch { KillwordProcess(); throw; } }

5.打开word文件


 

/// <summary> /// 打开文件 /// </summary> /// <param name="Path">文件路径及文件名</param> /// <param name="IsVisible">是否可见</param> public void OpenWord(string Path, bool IsVisible, Document doc) { object oMissing = System.Reflection.Missing.Value; GUIDCaption = Guid.NewGuid().ToString(); app.Visible = IsVisible;//是否实时预览 app.Caption = GUIDCaption; object oPath = Path; doc = app.Documents.Open(ref oPath, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing, ref oMissing); }

6.表格纵向合并


 

/// <summary> /// 纵向合并 /// </summary> /// <param name="bookMarkName"></param> /// <param name="tableIndex"></param> /// <param name="row_a">开始行号</param> /// <param name="col_a">开始列号</param> /// <param name="row_b">结束行号</param> /// <param name="col_b">结束列号</param> public void MergeColumnCell(string bookMarkName, int tableIndex, int row_a, int col_a, int row_b, int col_b, Document doc) { try { object oBookMarkName = bookMarkName; Range activeRange = doc.Bookmarks.get_Item(ref oBookMarkName).Range; var newTable = activeRange.Tables[tableIndex]; newTable.Cell(row_a, col_a).Merge(newTable.Cell(row_b, col_b)); } catch (Exception e) { KillwordProcess(); throw e; } }

7.插入图片


 

      /// <summary> /// 插入图片 /// </summary> /// <param name="bookMarkName"></param> /// <param name="fileName">图片路径</param> /// <param name="type">图片版式:四周型,嵌入型,环绕型</param> public void InsertPicture(string bookMarkName, string fileName, WdWrapType type) { try { if (!doc.Bookmarks.Exists(bookMarkName)) { return; } object oBookMarkName = bookMarkName; Microsoft.Office.Interop.Word.Range activeRange = doc.Bookmarks.get_Item(ref oBookMarkName).Range; object linkToFile = false; object saveWithDocument = true; InlineShape inlineShape = doc.InlineShapes.AddPicture(fileName, ref linkToFile, ref saveWithDocument, activeRange); inlineShape.ConvertToShape().WrapFormat.Type = type; } catch (Exception ex) { KillwordProcess(); //记录日志 AppCommon.AppLogger.WriteLog("插入图片,错误为:" + ex.ToString(), ((int)AppCommon.Unitity.AppChannelEnmu.SS).ToString()); } }

 8.设置图片大小


 

/// <summary> /// 设置图片大小 /// </summary> /// <param name="filePath"></param> /// <param name="width"></param> /// <param name="height"></param> public string SetPicture(string filePath, int width, int height) { Bitmap bm = new Bitmap(filePath); Bitmap thumb = new Bitmap(width, height); Graphics g = Graphics.FromImage(thumb); g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; g.DrawImage(bm, new System.Drawing.Rectangle(0, 0, width, height), new System.Drawing.Rectangle(0, 0, bm.Width, bm.Height), GraphicsUnit.Pixel); g.Dispose(); string path = ConfigurationManager.AppSettings["MapPath"].ToString() + "/Assets/internal/img/new.png"; thumb.Save(path, System.Drawing.Imaging.ImageFormat.Png); bm.Dispose(); thumb.Dispose(); return path; }

9.书签范围内添加一行


 

/// <summary> /// 在书签范围内插入一行到指定表中 /// </summary> /// <param name="BookMarkName">书签名称</param> /// <param name="tableIndex">表的索引</param> /// <param name="rowIndex">插入行的位置</param> public void InsertRow(string bookMarkName, int tableIndex, int rowIndex) { try { if (!doc.Bookmarks.Exists(bookMarkName)) { return; } object oBookMarkName = bookMarkName; Microsoft.Office.Interop.Word.Range activeRange = doc.Bookmarks.get_Item(ref oBookMarkName).Range; InsertRow(activeRange, tableIndex, rowIndex); } catch (Exception e) { KillwordProcess(); throw e; } } /// <summary> /// 在所选范围内插入一行到指定表中 /// </summary> /// <param name="activeRange">范围对象</param> /// <param name="tableIndex">所选范围内表的索引</param> /// <param name="rowIndex">插入行的位置</param> public void InsertRow(Microsoft.Office.Interop.Word.Range activeRange, int tableIndex, int rowIndex) { try { object NumRows = 1; activeRange.Tables[tableIndex].Rows[rowIndex].Select(); doc.ActiveWindow.Panes[1].Selection.InsertRowsBelow(ref NumRows); } catch (Exception e) { KillwordProcess(); throw e; } }

10.删除书签范围内容


 

/// <summary> /// 删除书签范围内容 /// </summary> /// <param name="bookMarkName">书签名</param> public void DeleteBookMarkRange(string bookMarkName) { try { object oBookMarkName = bookMarkName; if (doc.Bookmarks.Exists(bookMarkName)) { DeleteRange(doc.Bookmarks.get_Item(ref oBookMarkName).Range); } } catch (Exception e) { KillwordProcess(); throw e; } } /// <summary> /// 删除所选范围内容 /// </summary> /// <param name="activeRange">所选范围对象</param> public void DeleteRange(Range activeRange) { try { if (null != activeRange) { object oMissing = Missing.Value; activeRange.Delete(ref oMissing, ref oMissing); foreach (Table dTable in activeRange.Tables) { dTable.Delete(); } } } catch (Exception e) { KillwordProcess(); throw e; } }

11.删除书签范围的行


 

/// <summary> /// 在书签范围内指定表删除行 /// </summary> /// <param name="bookMarkName">书签名称</param> /// <param name="tableIndex">表索引</param> /// <param name="rowIndex">行号</param> public void DeleteRow(string bookMarkName, int tableIndex, int rowIndex) { try { object oBookMarkName = bookMarkName; if (doc.Bookmarks.Exists(bookMarkName)) { Microsoft.Office.Interop.Word.Range activeRange = doc.Bookmarks.get_Item(ref oBookMarkName).Range; DeleteRow(activeRange, tableIndex, rowIndex); } } catch (Exception e) { KillwordProcess(); throw e; } } /// <summary> /// 在所选范围内指定表删除行 /// </summary> /// <param name="activeRange">所选范围对象</param> /// <param name="tableIndex">表索引</param> /// <param name="rowIndex">行号</param> public void DeleteRow(Microsoft.Office.Interop.Word.Range activeRange, int tableIndex, int rowIndex) { try { if (activeRange.Tables[tableIndex].Rows.Count >= rowIndex) { activeRange.Tables[tableIndex].Rows[rowIndex].Delete(); } } catch (Exception e) { KillwordProcess(); throw e; } }

12.插入分页符


 

public static void InsertBreak(Document doc, string bookmark) { object oBookMarkName = bookmark; if (doc.Bookmarks.Exists(bookmark)) { object pBreak = (int)WdBreakType.wdPageBreak; doc.Bookmarks.get_Item(ref oBookMarkName).Range.InsertBreak(ref pBreak); } //object oBookMarkName = bookmark; //Range perRange = doc.Bookmarks.get_Item(ref oBookMarkName).Range; //object oEnd = perRange.End; //object oWdBreak = (int)WdBreakType.wdPageBreak; //doc.Range(ref oEnd, ref oEnd).InsertBreak(ref oWdBreak); //doc.Range(ref oEnd, ref oEnd).InsertParagraph(); }

13.结束word进程

异常的时候一定要执行此方法,否则,word进程就会被遗留在内存中,后续如果继续执行,会积累更多的进程,导致进程卡死,内存飙升。

/// <summary> /// 结束word进程 /// </summary> private void KillwordProcess() { try { Process[] myProcesses; //DateTime startTime; myProcesses = Process.GetProcessesByName("WINWORD"); //通过进程窗口标题判断 foreach (Process myProcess in myProcesses) { if (null != GUIDCaption && GUIDCaption.Length > 0 && myProcess.MainWindowTitle.Equals(GUIDCaption)) { myProcess.Kill(); } } } catch (Exception e) { AppCommon.AppLogger.WriteLog("结束Word,错误为:" + e.ToString(), ((int)AppCommon.Unitity.AppChannelEnmu.SS).ToString()); throw e; } }

 14.删除空行

这段代码厉害了,是用来精确控制的,你可以用它获取到word的每一寸区域,这样你想在哪里写值就在哪里写。下面这段代码是用来删除书签范围上方的空行的,代码中会判断上方是空行的区域,

如果上方区域有文字,则

iEnd为文字所在行-1,range.Start表示该书签区域开头所在的行titleRange就是要删除的空行区域 /// <summary> /// 删除Range 上面的空行 /// </summary> /// <param name="range"></param> /// <param name="holdblank">下面保留几个空行,默认保留一个</param> public void DeleteRangeUpBlankRow(Document doc, Range range, int holdblank = 1) { try { int iStart = range.Start - holdblank; int iEnd = range.Start - holdblank; object oStart = range.Start - holdblank; object oEnd = range.Start - holdblank; Range titleRange = doc.Range(ref oStart, ref oEnd); //获取标题范围 从表格范围起始位置开始 每次循环范围向前增加1 while (true) { iStart = iStart - 1; titleRange.SetRange(iStart, iEnd); if (iStart < 0 || IsTitleRangeOver(titleRange)) { titleRange.SetRange(iStart + 1, iEnd); break; } } //删除空行 object oMissing = Missing.Value; titleRange.Delete(ref oMissing, ref oMissing); } catch (Exception e) { KillwordProcess(); throw e; } } /// <summary> /// 判断要删除表的标题范围是否超出 /// </summary> /// <param name="titleRange"></param> /// <returns></returns> public bool IsTitleRangeOver(Range titleRange) {   if (titleRange.Tables.Count > 0)//范围内包含表格   {     return true;   }   if (titleRange.Paragraphs[1].PageBreakBefore == 1)//有分页符   {     return true;   }   if (!string.IsNullOrEmpty(titleRange.Text.Trim()))//内容不为空了   {     return true;   }   return false; }  

常见错误及处理方案:

1.报告生成期间异常:System.Runtime.InteropServices.COMException (0x8001010A): 消息筛选器显示应用程序正在使用中。 (异常来自 HRESULT:0x8001010A (RPC_E_SERVERCALL_RETRYLATER))

  解决方案:出现这种错误有限检查COM组件权限是否正常,检查步骤:

(1)打开组件服务

 

 

 (2)打开DCOM配置

 

 (3)找到word97-2003

 

(4)按照如图依次配置

(5)一般这里我们选择用户名密码 的方式,这个密码必须在web.Config中进行配置

<identity impersonate="true" userName="服务器登录名" password="服务器登陆密码" />

 

  2.System.Runtime.InteropServices.COMException (0x800A1735): 集合所要求的成员不存在。

  解决方案:这个是程序错误,只要调试代码即可发现错误。

3.System.Runtime.InteropServices.COMException (0x800A1710): 无法编辑 Range。

  解决方案:这个说明编辑某个区域的时候,超出了范围,或者找不到这个区域范围,这个也是代码的问题,需要仔细查找,不是很好定位。

 

-------------------------------------------(正文完)-----------------------------------------------------

 

还有一些其他的问题没有收集,大家遇到了可以在评论区发出来,我能帮大家解答的一定尽我所能!

 

好啦,今天的分享就到这里……

 

向着高级,进发!


__EOF__

 

2024-02-19 15:35:55【出处】:https://www.cnblogs.com/Mr-Worlf/p/14185418.html

=======================================================================================

标签:WORD,ref,object,书签,Range,activeRange,doc,COM
From: https://www.cnblogs.com/mq0036/p/18021258

相关文章

  • 如何使用ComPDFKit Web SDK添加在线编辑PDF文档功能
    文档编辑功能提供了一系列的操作页面的能力,使用户能够控制文档结构,并调整文档的布局和格式,确保文档内容以合理有序的方式精准呈现。ComPDFKit文档编辑的优势插入或删除页面: 向文档插入或删除页面,以满足特定的排版要求。文档结构调整: 调整页面排列顺序或旋转方向,以满足特定......
  • google chrome 获取书签的添加日期
    有的时候想找一个书签的添加日期,在浏览器上貌似看不到 设备:win10google书签位置:username是你的用户名C:\Users\username\AppData\Local\Google\Chrome\UserData\Default\Bookmarkspython获取数据importpandasaspdimportjsonimportdatetimewithopen......
  • SciTech-Math-Complex:复数 + Abraham de Moivre French mathematician
    (AbrahamdeMoivre,Frenchmathematician)两个复数乘积的结果:模等于两者模相乘,弧角等于两者弧角相加;\(极坐标\)表示,若:\(\largez_{1}=\rho_{1}(\cos{\theta_{1}}+i*{\sin{\theta_{1}}})\)\(\largez_{2}=\rho_2(\cos{\theta_{1}}+i*\sin{\theta_{2}})\)则:\(......
  • 玩转CompletableFuture线程异步编排,看这一篇就够了
    转载自:https://blog.csdn.net/w306026355/article/details/1097072691、CompletableFuture介绍CompletableFuture可用于线程异步编排,使原本串行执行的代码,变为并行执行,提高代码执行速度。学习异步编排先需要学习线程池和lambda表达式相关知识,学习线程池可以移步我的另一篇博......
  • sensitive-word-admin v1.3.0 发布 如何支持敏感词控台分布式部署?
    拓展阅读sensitive-word-adminv1.3.0发布如何支持分布式部署?sensitive-word-admin敏感词控台v1.2.0版本开源sensitive-word基于DFA算法实现的高性能敏感词工具介绍更多技术交流业务背景如果我们的敏感词部署之后,不会变化,那么其实不用考虑这个问题。但是......
  • 适用于 Amazon Step Functions 的低代码可视化新工作流 Workflow Studio, 现已在 Amaz
    今天,我们非常欣喜地宣布现已在AmazonApplicationCompose中推出AmazonStepFunctionsWorkflowStud。通过这款全新的集成应用,工作流与应用程序资源开发便可整合到统一的可视化基础设施即代码(IaC)生成器。对于使用AmazonStepFunctionsWorkflowStudio创建工作流与......
  • 用python脚本自动发送钉钉消息出现服务器异常的报错: HTTPSConnectionPool(host='oapi.
    一、问题描述执行python脚本发送钉钉消息,出现报错:HTTPSConnectionPool(host='oapi.dingtalk.com',port=443):Maxretriesexceededwithurl:/robot/send?access_token=43df999582e899dc6815c9d6346c9d253060259625c92e4f166e25ea58e5bdb5&timestamp=1708242748918&sign......
  • /vendor/etc/fstab.qcom
    CN:/#cat/vendor/etc/fstab.qcom#Androidfstabfile.#Thefilesystemthatcontainsthefilesystemcheckerbinary(typically/system)cannot#specifyMF_CHECK,andmustcomebeforeanyfilesystemsthatdospecifyMF_CHECK#TODO:Add'check'......
  • Git操作 :从一个分支cherry-pick多个commit到其他分支
    在branch1开发,进行多个提交,这是切换到branch2,想把之前branch1分支提交的commit都【复制】过来,怎么办?首先切换到branch1分支,然后查看提交历史记录,也可以用sourceTree查看,也可以用命令gitlog例如我的gitlog如下:commit1xxx_id1commit2xxx_id2commit3xxx_id3我想把comm......
  • computed
    Computedpropertiesareuniquedatatypesthatwillreactivelyupdateonlywhenthesourcedatausedwithinthepropertyisupdated.Bydefiningadatapropertyasacomputedproperty,wecanperformthefollowingactivities:Applycustomlogicontheor......