Этот ответ объясняет, как получить объект Word.Application из hwnd, что означает, что мы можем циклически пройти через все активные процессы Word и проверить, соответствует ли их Word.Application нашему собственному объекту Word.Application. Таким образом, вам не нужно ничего делать с заголовком окна.
Обратите внимание, что вы можете получить только процесс приложения Word.Application, которое видно и в котором открыт один или несколько документов (в последнем случае код открывает временный пустой документ):
using System;
using System.Linq;
using System.Text;
using Word = NetOffice.WordApi;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Diagnostics;
namespace WordHwnd
{
class Program
{
static void Main(string[] args)
{
using (var app = new Word.Application() { Visible = true })
{
Console.WriteLine(WordGetter.GetProcess(app).MainWindowHandle);
}
Console.ReadLine();
}
}
class WordGetter
{
[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("00020400-0000-0000-C000-000000000046")]
private interface IDispatch
{
}
private const uint OBJID_NATIVEOM = 0xFFFFFFF0;
private static Guid IID_IDispatch = new Guid("{00020400-0000-0000-C000-000000000046}");
[DllImport("Oleacc.dll")]
private static extern int AccessibleObjectFromWindow(int hwnd, uint dwObjectID, byte[] riid, out IDispatch ptr);
private delegate bool EnumChildCallback(int hwnd, ref int lParam);
[DllImport("User32.dll")]
private static extern bool EnumChildWindows(int hWndParent, EnumChildCallback lpEnumFunc, ref int lParam);
[DllImport("User32.dll")]
private static extern int GetClassName(int hWnd, StringBuilder lpClassName, int nMaxCount);
private static bool Find_WwG(int hwndChild, ref int lParam)
{
if (GetClassName(hwndChild) == "_WwG")
{
lParam = hwndChild;
return false;
}
return true;
}
private static string GetClassName(int hwndChild)
{
var buf = new StringBuilder(128);
GetClassName(hwndChild, buf, 128);
return buf.ToString();
}
public static Process GetProcess(Word.Application app)
{
Word.Document tempDoc = null;
//This only works if there is a document open
if (app.Documents.Count == 0)
tempDoc = app.Documents.Add();
var processes = Process.GetProcessesByName("WINWORD");
var appsAndProcesses = processes
.Select(p => new { Process = p, App = WordGetter.GetWordApp(p) })
.Where(x => !Equals(x.App, null));
Process process = null;
foreach (var appAndProcess in appsAndProcesses)
{
if (appAndProcess.App == app)
{
process = appAndProcess.Process;
break;
}
else
{
appAndProcess.App.Dispose();
}
}
tempDoc?.Close(false);
return process;
}
public static Word.Application GetWordApp(Process process)
{
return GetWordApp(process.MainWindowHandle);
}
public static Word.Application GetWordApp(IntPtr hwnd)
{
return GetWordApp((int)hwnd);
}
public static Word.Application GetWordApp(int hwnd)
{
var wwG_Hwnd = 0;
var callback = new EnumChildCallback(Find_WwG);
EnumChildWindows(hwnd, callback, ref wwG_Hwnd);
if (wwG_Hwnd != 0)
{
IDispatch iDispatch;
var result = AccessibleObjectFromWindow(wwG_Hwnd, OBJID_NATIVEOM, IID_IDispatch.ToByteArray(), out iDispatch);
if (result >= 0)
{
var obj = iDispatch.GetType().InvokeMember("Application", BindingFlags.GetProperty, null, iDispatch, null);
return new Word.Application(null, obj);
}
return null;
}
return null;
}
}
}
В этом примере я использую NetOffice, но вы можете легко изменить его для работы со стандартными библиотеками взаимодействия, отредактировав оператор using и выполнив Marshal.ReleaseComObject () вместо Word.Application.Dispose ().