因此,如果您使用 Accessibility API 知道它的 Hwnd,那么有一种很好的技术可以从 Excel.exe 会话中获取 COM 指针跨进程(同一台机器)。具体的 Windows API 函数是AccessibleObjectFromWindow;如果使用 OBJID_NATIVEOM 的参数调用,则 Excel.exe 会将 COM 指针封送回 Excel.Window 对象。很酷。
所以我想知道开发人员是否可以为他们自己的应用程序实现相同的技术。 答案是肯定的,他们在消息泵代码中响应特定消息 WM_GETOBJECT。虽然这对于 C++ 应用程序是可行的,但我对如何为 C# 应用程序执行此操作感到困惑。
我假设答案是做一些事情来访问消息泵处理代码并改变它。也许可以使用一些魔法属性。只要它有效,我对任何一种技术都持开放态度。
这是从 Excel 获取 COM 指针的代码
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);
[DllImport("oleacc.dll", SetLastError = true)]
internal static extern int AccessibleObjectFromWindow(IntPtr hwnd, uint id, ref Guid iid,
[In, Out, MarshalAs(UnmanagedType.IUnknown)] ref object ppvObject);
bool IXlMoniker.GetExcelByHwnd(int lhwndApp2, ref object appRetVal)
{
bool bRetVal = false;
IntPtr lhwndApp = (IntPtr)lhwndApp2;
IntPtr lHwndDesk = FindWindowEx(lhwndApp, IntPtr.Zero, "XLDESK", "");
if (lHwndDesk != IntPtr.Zero)
{
IntPtr lHwndExcel7 = FindWindowEx(lHwndDesk, IntPtr.Zero, "EXCEL7", null);
if (lHwndExcel7 != IntPtr.Zero)
{
Guid IID_IDispatch = new Guid("{00020400-0000-0000-C000-000000000046}");
const uint OBJID_NATIVEOM = 0xFFFFFFF0;
object app = null;
if (AccessibleObjectFromWindow(lHwndExcel7, OBJID_NATIVEOM, ref IID_IDispatch, ref app) == 0)
{
dynamic appWindow = app;
appRetVal = appWindow.Application;
return true;
}
}
}
return bRetVal;
}
这看起来很有希望从 NativeWindow 中处理 WM_GETOBJECT 返回一个 IOleCommandTarget