+
17
-

回答

在 C# 中,要实现与一个正在运行的 Word 程序进行交互(读取和修改内容),核心技术是 Office Interop (互操作)COM (Component Object Model)

简单来说,您的 C# 程序将作为一个“遥控器”,去连接并操作那个已经打开的 Word 应用程序。

以下是详细的步骤、核心代码和注意事项。

前提条件

安装 Microsoft Office: 你的电脑上必须安装了 Microsoft Word。

添加 COM 引用: 在你的 C# 项目中,需要添加对 Word 对象模型的引用。

在 Visual Studio 的“解决方案资源管理器”中,右键点击你的项目下的 “引用” (References)。

选择 “添加引用...” (Add Reference...)。

在弹出的对话框中,选择 “COM” 标签页。

向下滚动,找到并勾选 “Microsoft Word XX.X Object Library” (XX.X 是你的 Office 版本号,例如 16.0 代表 Office 2016/2019/365)。

点击“确定”。

核心逻辑与步骤

整个过程可以分解为以下几步:

获取正在运行的 Word 实例: 我们不能 new Application(),因为那会创建一个新的、不可见的 Word 进程。我们需要连接到用户已经打开的那个。

获取当前活动的文档: 从 Word 实例中,找到用户当前正在编辑的那个文档。

执行读取/修改操作: 使用 Word 的对象模型(如 Find, Range, Paragraphs 等)来执行操作。

释放资源: 操作完成后,必须正确地释放 COM 对象,否则可能会导致 Word 进程无法正常退出。

完整代码示例

下面是一个控制台应用程序的完整示例,它会尝试连接到正在运行的 Word,然后执行一个“查找和替换”的操作。

using System;
using System.Runtime.InteropServices;
// 1. 引入 Word Interop 的命名空间
using Word = Microsoft.Office.Interop.Word;

namespace WordManipulator
{
    class Program
    {
        static void Main(string[] args)
        {
            // 定义 Word 应用程序和文档对象变量
            Word.Application wordApp = null;
            Word.Document activeDoc = null;

            Console.WriteLine("正在尝试连接到已打开的 Microsoft Word 实例...");

            try
            {
                // 2. 核心步骤:获取当前活动的 Word 应用程序实例
                // GetActiveObject 会查找一个正在运行的 COM 对象
                wordApp = (Word.Application)Marshal.GetActiveObject("Word.Application");
                Console.WriteLine("成功连接到 Word!");

                // 3. 获取当前正在编辑的文档
                activeDoc = wordApp.ActiveDocument;
                if (activeDoc == null)
                {
                    Console.WriteLine("错误:Word 正在运行,但没有活动的文档。");
                    return;
                }

                Console.WriteLine($"当前活动文档: {activeDoc.Name}");
                Console.WriteLine("-------------------------------------------");

                // --- 开始执行修改操作 ---

                // 示例 1: 读取文档的全部内容
                string allContent = activeDoc.Content.Text;
                Console.WriteLine("文档前 100 个字符内容预览:");
                Console.WriteLine(allContent.Substring(0, Math.Min(100, allContent.Length)));
                Console.WriteLine("-------------------------------------------");


                // 示例 2: 查找并替换文本 (最常用的操作)
                Console.WriteLine("执行查找和替换操作...");
                // 获取文档内容的 Range 对象
                Word.Range contentRange = activeDoc.Content;
                Word.Find findObject = contentRange.Find;

                // 清除之前的查找格式(非常重要)
                findObject.ClearFormatting();
                findObject.Replacement.ClearFormatting();

                // 定义要查找和替换的内容
                string findText = "你好";
                string replaceWithText = "您好,世界!";

                // 定义查找和替换的参数
                object matchCase = false;
                object matchWholeWord = true;
                object matchWildcards = false;
                object matchSoundsLike = false;
                object matchAllWordForms = false;
                object forward = true;
                object wrap = Word.WdFindWrap.wdFindContinue;
                object format = false;
                // 注意 C# 中需要传递的参数
                object replace = Word.WdReplace.wdReplaceAll; // wdReplaceAll 表示全部替换

                // 执行替换
                bool found = findObject.Execute(
                    ref findText, ref matchCase, ref matchWholeWord,
                    ref matchWildcards, ref matchSoundsLike, ref matchAllWordForms,
                    ref forward, ref wrap, ref format, ref replaceWithText,
                    ref replace
                );

                if (found)
                {
                    Console.WriteLine($"成功将所有的 '{findText}' 替换为 '{replaceWithText}'。");
                }
                else
                {
                    Console.WriteLine($"在文档中未找到 '{findText}'。");
                }
            }
            catch (COMException)
            {
                // 如果 GetActiveObject 找不到 Word 实例,会抛出 COMException
                Console.WriteLine("错误:未能找到正在运行的 Microsoft Word 实例。请先打开一个 Word 文档。");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"发生未知错误: {ex.Message}");
            }
            finally
            {
                // 4. 关键步骤:释放 COM 对象资源
                // 如果不释放,Word 进程可能会在后台残留,无法关闭
                if (activeDoc != null) Marshal.ReleaseComObject(activeDoc);
                if (wordApp != null) Marshal.ReleaseComObject(wordApp);

                // 将对象设置为 null,以便垃圾回收器可以回收
                activeDoc = null;
                wordApp = null;

                // 注意:我们只是释放了对 COM 对象的引用,并不会关闭 Word 程序本身
            }

            Console.WriteLine("操作完成。按任意键退出。");
            Console.ReadKey();
        }
    }
}

如何使用上面的代码:

创建一个新的 C# 控制台应用项目。

按照“前提条件”中的步骤添加对 Word Object Library 的引用。

将上面的代码完整地复制到 Program.cs 文件中。

打开一个 Word 文档,并在里面输入一些包含 "你好" 的文本。

保持 Word 文档打开并处于编辑状态

运行你的 C# 控制台程序。

观察控制台的输出,并切换回 Word 文档,你会发现所有的 "你好" 都已经被替换成了 "您好,世界!"。

重要注意事项

错误处理: Marshal.GetActiveObject("Word.Application") 在 Word 未运行时会抛出 COMException。必须使用 try...catch 来捕获这个异常,否则程序会崩溃。

资源释放: 这是最重要的一点。 COM 对象不是由 .NET 的垃圾回收器 (GC) 自动管理的。每次操作后,必须在 finally 块中使用 Marshal.ReleaseComObject() 来显式地减少 COM 对象的引用计数。否则,即使你的程序结束了,Word.exe 进程也可能卡在后台无法退出,造成内存泄漏。

UI 线程冻结: 如果你在一个有界面的程序(如 WinForms 或 WPF)中执行这些操作,长时间的 Word 操作会冻结你的 UI。在这种情况下,应将 Word 操作放在一个单独的线程或后台任务(如 Task.Run)中进行。

Find.Execute 参数: Find.Execute 方法有大量的可选参数。在 C# 中调用时,即使你不使用它们,也需要为它们传递 Type.Missing 或者预定义的 object 变量。上面代码中的写法是比较规范的方式。

权限问题: 在某些系统环境下,一个普通权限的程序可能无法操作另一个由管理员权限启动的程序。通常情况下,只要都是由同一用户启动,就不会有问题。

网友回复

我知道答案,我要回答