Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/search/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
.net 使用Office互操作获取特定的窗口句柄_.net_Office Interop_Window Handles - Fatal编程技术网

.net 使用Office互操作获取特定的窗口句柄

.net 使用Office互操作获取特定的窗口句柄,.net,office-interop,window-handles,.net,Office Interop,Window Handles,我正在使用Office interop创建Word的新实例,方法如下: var word = Microsoft.Office.Interop.Word.Application(); word.Visible = true; word.Activate; 我可以得到这样一个窗口把手: var wordHandle = Process.GetProcessesByName("winword")[0].MainWindowHandle; 问题是,代码工作的前提是没有其他Word运行实例。如果有多

我正在使用Office interop创建Word的新实例,方法如下:

var word = Microsoft.Office.Interop.Word.Application();
word.Visible = true;
word.Activate;
我可以得到这样一个窗口把手:

var wordHandle = Process.GetProcessesByName("winword")[0].MainWindowHandle;

问题是,代码工作的前提是没有其他Word运行实例。如果有多个,它不能保证返回的句柄是针对我启动的实例的。在从我的对象检测到
WindowActivate
事件后,我尝试使用
GetForegroundWindow
,但这都是在设置为作为最顶层窗口运行的WPF应用程序中运行的,因此我只获取WPF窗口的句柄。还有其他方法可以获取word实例的句柄吗?

不确定为什么需要word的句柄,但我以前做过的一种方法是实际更改word窗口标题并搜索它。我这样做是因为我想在控件中托管Word应用程序,但那是另一回事了。:)


获得句柄后,如果愿意,可以恢复标题。

您已经获得了所有Word进程的列表。您可以遍历此列表,获取每个进程的父ID,并与当前进程(即您自己创建Word实例的应用程序)进行匹配。这大概就是我的想法:

IntPtr getChildProcess(string childProcessName)
{
    var currentProcess = Process.GetCurrentProcess();

    var wordProcesses = Process.GetProcessesByName(childProcessName);
    foreach (var childProcess in wordProcesses)
    {
        var parentProcess = ProcessExtensions.Parent(childProcess);
        if (currentProcess.Id == parentProcess.Id)
            return currentProcess.Handle;
    }

    return IntPtr.Zero;
}

ProcessExtensions类在前面的文章中提供。我在自己的代码中使用了这个类,没有任何抱怨。

我将保留我选择的答案为正确的,因为我在写这篇文章时发现它是正确的。此后,我需要为另一个项目做类似的事情,并发现尝试更新应用程序标题似乎不太可靠(Office 2013与2010?谁知道…)。我想出了一个新的解决方案,使窗口标题保持不变

var startingProcesses = Process.GetProcessesByName("winword").ToList();

var word = new Microsoft.Office.Interop.Word.Application(); 

var allProcesses = Process.GetProcessesByName("winword").ToList();

var processDiff = allProcesses.Except(startingProcesses, new ProcessComparer());

var handle = processDiff.First().MainWindowHandle;
这将使用以下自定义比较器来确保进程匹配(找到)

class ProcessComparer:IEqualityComparer
{
公共布尔等于(进程x,进程y)
{
if(ReferenceEquals(x,y))
{
返回true;
}
如果(x==null | | y==null)
{
返回false;
}
返回x.Id等于(y.Id);
}
public int GetHashCode(进程对象)
{
返回obj.Id.GetHashCode();
}
}
这说明了如何从hwnd获取Word.Application对象,这意味着我们可以循环所有活动的Word进程,并检查它们的Word.Application是否与我们自己的Word.Application对象匹配。这样,您不需要对窗口标题执行任何操作

请注意,您只能获取Word.应用程序的进程,该应用程序是可见的,并且打开了一个或多个文档(在后一种情况下,代码会打开一个临时空文档):


我在本例中使用NetOffice,但您可以通过编辑using语句并执行Marshal.ReleaseComObject()而不是Word.Application.Dispose(),轻松地将其更改为使用标准互操作库。

另一种方法,利用插入的宏直接在WINWORD进程内运行的事实:

using System;
using Word = NetOffice.WordApi;
using System.Diagnostics;

namespace WordHwnd
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var app = new Word.Application() { Visible = true })
            {
                var process = GetProcess(app);
                Console.WriteLine(process.MainWindowHandle);

                app.Quit();

            }

            Console.ReadLine();
        }

        private static Process GetProcess(Word.Application app)
        {
            var tempDocument = app.Documents.Add();
            var project = tempDocument.VBProject;
            var component = project.VBComponents.Add(NetOffice.VBIDEApi.Enums.vbext_ComponentType.vbext_ct_StdModule);
            var codeModule = component.CodeModule;
            codeModule.AddFromString("#If Win64 Then\r\n   Declare PtrSafe Function GetCurrentProcessId Lib \"kernel32\" () As Long\r\n#Else\r\n   Declare Function GetCurrentProcessId Lib \"kernel32\" () As Long\r\n#End If");

            var result = app.Run("GetCurrentProcessId");

            var process = Process.GetProcessById((int)result);

            tempDocument.Close(false);

            return process;
        }
    }

}

自word 2013以来,您可以使用从
应用程序中公开的
窗口的
Hwnd
属性

var windowHandle = wordApplication.ActiveWindow.Hwnd;
Hwnd返回一个整数,该整数指示指定窗口的窗口句柄。 使用此
int
可以使用提供窗口句柄低级封装的
NativeWindow

var nativeWindow = new NativeWindow();
nativeWindow.AssignHandle(new IntPtr(windowHandle));

是的,不要那样做。不管你想用这个句柄做什么,肯定有更好的方法。Word 2013和更高版本有一个应用程序。Hwnd propertyYeah,我为什么需要这样做也是另一回事。但我认为,你的建议不仅让我了解了我要去的地方,而且还通过自定义标题使我要去的整个体验变得更美好。同意Eddie Paz的观点,但有一点改变:你应该检查一下(p.MainWindowTitle.Contains(“我的词”))因为word在其开头添加了一些其他字母。仅供参考,链接的问题还有另一个答案,似乎比ProcessExtensions更好。
using System;
using Word = NetOffice.WordApi;
using System.Diagnostics;

namespace WordHwnd
{
    class Program
    {
        static void Main(string[] args)
        {
            using (var app = new Word.Application() { Visible = true })
            {
                var process = GetProcess(app);
                Console.WriteLine(process.MainWindowHandle);

                app.Quit();

            }

            Console.ReadLine();
        }

        private static Process GetProcess(Word.Application app)
        {
            var tempDocument = app.Documents.Add();
            var project = tempDocument.VBProject;
            var component = project.VBComponents.Add(NetOffice.VBIDEApi.Enums.vbext_ComponentType.vbext_ct_StdModule);
            var codeModule = component.CodeModule;
            codeModule.AddFromString("#If Win64 Then\r\n   Declare PtrSafe Function GetCurrentProcessId Lib \"kernel32\" () As Long\r\n#Else\r\n   Declare Function GetCurrentProcessId Lib \"kernel32\" () As Long\r\n#End If");

            var result = app.Run("GetCurrentProcessId");

            var process = Process.GetProcessById((int)result);

            tempDocument.Close(false);

            return process;
        }
    }

}
var windowHandle = wordApplication.ActiveWindow.Hwnd;
var nativeWindow = new NativeWindow();
nativeWindow.AssignHandle(new IntPtr(windowHandle));