【问题标题】:Get Currently Opened Word Document from Process从进程中获取当前打开的 Word 文档
【发布时间】:2018-01-18 23:25:19
【问题描述】:

目标是获取在我有进程引用的 Microsoft Word 实例中打开的文档的完整路径。

伪代码示例:

Process myWordProcess = something; // This is my process reference
DocumentInformation docInfo = SomeNamespace.GetDocumentInformation(myWordProcess);
string documentPath = docInfo.FullName; // "C:\User\Foo\Documents\Test.docx"

起点是由WINWORD.exe执行的Process对象。

我不是在寻找一种包含解析 process.MainWindowTitle 的方法,而是一种更“合适”的解决方案。

在进行了相当多的初步研究后,我相信需要的是 Windows Accessibility API。

Pinvoke 提到了AccessibleObjectFromWindow 签名。话虽如此,生成的 accessible 对象并没有为我提供比 process 已经提供的更多信息。

这是我从 Pinvoke 中尝试过的:

internal enum OBJID : uint
{
    WINDOW = 0x00000000,
    SYSMENU = 0xFFFFFFFF,
    TITLEBAR = 0xFFFFFFFE,
    MENU = 0xFFFFFFFD,
    CLIENT = 0xFFFFFFFC,
    VSCROLL = 0xFFFFFFFB,
    HSCROLL = 0xFFFFFFFA,
    SIZEGRIP = 0xFFFFFFF9,
    CARET = 0xFFFFFFF8,
    CURSOR = 0xFFFFFFF7,
    ALERT = 0xFFFFFFF6,
    SOUND = 0xFFFFFFF5,
}

public class DocumentLocator
{
    [DllImport("oleacc.dll")]
    internal static extern int AccessibleObjectFromWindow(IntPtr hwnd, uint id, ref Guid iid, [In] [Out] [MarshalAs(UnmanagedType.IUnknown)] ref object ppvObject);

    public static void GetWordInfo(Process process)
    {
        var mainWindowHandle = process.MainWindowHandle;
        var guid = new Guid("{618736E0-3C3D-11CF-810C-00AA00389B71}");

        object obj = null;
        var retVal = AccessibleObjectFromWindow(mainWindowHandle, (uint)OBJID.WINDOW, ref guid, ref obj);
        var accessible = (IAccessible) obj; // Not much information is contained in this object
    }
}

也许解决方案是以某种方式从进程或窗口句柄中获取Document 接口(Office COM Interop,see here for the interface)?或者,也许,首先获得Window,然后获得Document

然后,配备来自 Office Interop 的信息,可以读取 Path 属性。

我愿意接受任何解决方案。

如果您知道如何针对 Excel 或 PowerPoint 执行此操作 - 那也可以,因为我假设可以对 Word 应用相同的过程(在更改几个界面和 GUID 之后)。

【问题讨论】:

    标签: c# winapi com office-interop com-interop


    【解决方案1】:

    借用Microsoft的部分代码,其中的关键方法是GetActiveObject

    using System;
    using System.Runtime.InteropServices;
    using Word = Microsoft.Office.Interop.Word;
    
    namespace ConsoleApp2
    {
        class Program
        {
            static void Main(string[] args)
            {
                object wordAsObject;
                Word.Application word;
    
                try
                {
                    wordAsObject = System.Runtime.InteropServices.Marshal.GetActiveObject("Word.Application");
                    //If there is a running Word instance, it gets saved into the word variable
                    word = (Word.Application)wordAsObject;
    
                    Console.WriteLine("{0}", word.ActiveDocument.FullName);
    
                    Console.ReadKey();
                }
                catch (COMException)
                {
                    //If there is no running instance, it creates a new one
                    //Type type = Type.GetTypeFromProgID("Word.Application");
                    //wordAsObject = System.Activator.CreateInstance(type);
                }
            }
        }
    }
    

    如果需要,您仍然可以参考正在运行的进程

    如果需要,迭代Documents 集合是一件简单的事情。

    foreach (Word.Document doc in word.Documents)
    {
        Console.WriteLine("{0}", doc.FullName);
    }
    

    【讨论】:

    • 哇 - 这比我想象的要容易 - 非常感谢!通过将对象转换为动态对象,我什至可以绕过引用 Interop 程序集(使用一些 try/catch)。这适用于所有 Office 应用程序,我还设法获取了 Visual Studio 实例 (VisualStudio.DTE.15.0) 的当前文档和解决方案。只是出于兴趣,是否有此类 ActiveObjects 的“列表”?它可以帮助为许多其他应用程序(例如 Windows 照片应用程序、当前资源管理器路径等)查找打开的文档。
    • @JDR 我不知道这样的列表,但是如果您在注册表中查看 Computer\HKEY_CLASSES_ROOT\Word.Application 等,这些键提供了一个很好的线索,可以用作文本类名。
    • 谢谢!该注册表位置非常有用。
    【解决方案2】:

    您可以使用以下代码获取所有打开的文档的列表

    Microsoft.Office.Interop.Word.Application WordObj;
    WordObj = (Microsoft.Office.Interop.Word.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Word.Application");
    for (int i = 0; i < WordObj.Windows.Count; i++)
    {
        object idx = i + 1;
        Window WinObj = WordObj.Windows.get_Item(ref idx);
        doc_list.Add(WinObj.Document.FullName);
    }
    

    使用以下代码获取活动文档完整路径

        Microsoft.Office.Interop.Word.Application WordObj;
        WordObj =
     (Microsoft.Office.Interop.Word.Application)System.Runtime.InteropServices.Marshal.GetActiveObject("Word.Application");
        var word = (Word.Application)WordObj;
        string docPath=word.ActiveDocument.FullName;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多