.net - 如何在运行的 "Internet Explorer_Server"实例中控制光学变焦?

标签 .net internet-explorer automation

Windows Live Writer 托管一个用于编辑的 Internet Explorer 控件,但没有缩放控件。我希望能够向它发送缩放命令。由于其他应用程序托管 IE 浏览器,因此我认为可以向特定 IE 浏览器实例发送缩放命令的实用程序会非常方便,但我还没有找到。

我看到有一个命令,OLECMDID_OPTICAL_ZOOM ,但我不确定如何向它发送该命令。理想情况下,我想通过 C# 或 Powershell 执行此操作。

注意:问题是询问如何在我未创建的正在运行的应用程序中控制 Web 浏览器控件的缩放,主要示例是 Windows Live Writer 中的编辑器界面。

最佳答案

简短版本:我不完全确定您可以做您想做的事情。

我有一些代码实际上可以获取 WLW 窗口内的 HTML 文档的句柄,并且可以工作,但我发现我实际上无法获取对该文档的父窗口的引用。我不是 Windows 本地人,但我曾经做过一些 PInvoke。可能只是因为我缺乏 native Windows 知识,所以我无法弥补最后的差距。

根据我的整理,获取 IE 窗口引用的一般过程是:

  1. 获取顶级窗口的引用。
  2. 查找其中包含 HTML 文档的窗口(递归搜索)。
  3. 从该窗口获取 HTML 文档对象。
  4. 获取 HTML 文档的父窗口(即 IE 窗口)。

获得该父窗口后,您可以调用 IWebBrowser2.ExecWB 方法来运行 OLE 缩放命令。

问题在于,当您尝试访问 IHTMLDocument2.parentWindow 属性时,它似乎总是抛出 InvalidCastException。来自 what我有read ,当您尝试从文档运行所在的线程以外的线程获取父窗口时,就是这样。

所以,无论如何,我都会向您提供获取 HTML 文档引用的代码,如果您能完成最后一步,您就会得到答案。我自己就是想不通。

这是一个控制台应用程序。您需要引用 IHTMLDocument2 接口(interface)的 Microsoft.mshtml。

using System;
using System.Runtime.InteropServices;

namespace ControlInternetExplorerServer
{
    ////////////////////////
    // LOTS OF PINVOKE STUFF
    ////////////////////////

    [Flags]
    public enum SendMessageTimeoutFlags : uint
    {
        SMTO_NORMAL = 0x0,
        SMTO_BLOCK = 0x1,
        SMTO_ABORTIFHUNG = 0x2,
        SMTO_NOTIMEOUTIFNOTHUNG = 0x8
    }

    public static class NativeMethods
    {
        [DllImport("user32.dll", CharSet = CharSet.Unicode)]
        public static extern IntPtr FindWindow(
            string lpClassName,
            string lpWindowName);

        [DllImport("user32.dll", SetLastError = true)]
        public static extern IntPtr FindWindowEx(
            IntPtr hwndParent,
            IntPtr hwndChildAfter,
            string lpszClass,
            string lpszWindow);

        [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "GetWindow", SetLastError = true)]
        public static extern IntPtr GetNextWindow(IntPtr hwnd, [MarshalAs(UnmanagedType.U4)] int wFlag);

        [DllImport("oleacc.dll", PreserveSig = false)]
        [return: MarshalAs(UnmanagedType.Interface)]
        public static extern object ObjectFromLresult(
            IntPtr lResult,
            [MarshalAs(UnmanagedType.LPStruct)] Guid refiid,
            IntPtr wParam);

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern uint RegisterWindowMessage(string lpString);

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern IntPtr SendMessageTimeout(
            IntPtr windowHandle,
            uint Msg,
            IntPtr wParam,
            IntPtr lParam,
            SendMessageTimeoutFlags flags,
            uint timeout,
            out IntPtr result);

        public static IntPtr FindWindowRecursive(IntPtr parent, string windowClass, string windowCaption)
        {
            var found = FindWindowEx(parent, IntPtr.Zero, windowClass, windowCaption);
            if (found != IntPtr.Zero)
            {
                return found;
            }

            var child = FindWindowEx(parent, IntPtr.Zero, null, null);
            while (child != IntPtr.Zero)
            {
                found = FindWindowRecursive(child, windowClass, windowCaption);
                if (found != IntPtr.Zero)
                {
                    return found;
                }
                child = GetNextWindow(child, 2);
            }
            return IntPtr.Zero;
        }
    }


    //////////////////////
    // THE INTERESTING BIT
    //////////////////////

    public class Program
    {
        public static void Main(string[] args)
        {
            // First parameter is the class name of the window type - retrieved from Spy++
            // Second parameter is the title of the window, which you'll
            // probably want to take in via command line args or something.
            var wlwWindow = NativeMethods.FindWindow("WindowsForms10.Window.8.app.0.33c0d9d", "Untitled - Windows Live Writer");
            if (wlwWindow == IntPtr.Zero)
            {
                Console.WriteLine("Unable to locate WLW window.");
                return;
            }

            // Since you don't know where in the tree it is, you have to recursively
            // search for the IE window. This will find the first one it comes to;
            // ostensibly there's only one, right? RIGHT?
            var ieWindow = NativeMethods.FindWindowRecursive(wlwWindow, "Internet Explorer_Server", null);
            if (ieWindow == IntPtr.Zero)
            {
                Console.WriteLine("Unable to locate IE window.");
                return;
            }

            // Get a handle on the document inside the IE window.
            IntPtr smResult;
            var message = NativeMethods.RegisterWindowMessage("WM_HTML_GETOBJECT");
            NativeMethods.SendMessageTimeout(ieWindow, message, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 1000, out smResult);
            if (smResult== IntPtr.Zero)
            {
                Console.WriteLine("Unable to locate the HTML document object.");
            }

            // Cast the document to the appropriate interface.
            var htmlDoc = (mshtml.IHTMLDocument2)NativeMethods.ObjectFromLresult(smResult, typeof(mshtml.IHTMLDocument2).GUID, IntPtr.Zero);

            // Here's where you would normally get htmlDoc.parentWindow and call ExecWB
            // to execute the zoom operation, but htmlDoc.parentWindow throws an InvalidCastException.
        }
    }
}

关于.net - 如何在运行的 "Internet Explorer_Server"实例中控制光学变焦?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6145712/

相关文章:

javascript - window.getComputedStyle 不适用于除 Chrome 之外的其他浏览器中的速记属性

linux - 无法在 shell 命令行参数中收集与我输入的相同的给定密码

azure - 如何自动从 azure 获取发布配置文件

c# - 在 Excel 2003 中使用 WCF?

c# - CheckedChanged 事件中的问题

c# - 将控件添加到 FlowLayoutPanel 时意外的索引更改

c# - 在 IIS 7 中以编程方式为自定义身份应用程序池设置用户帐户

php - 带有 IE 9 的 jQuery $.ajax POST 请求结果为空数组

jquery - 为什么选择下拉菜单不允许我单击某个项目 IE,但在 Firefox、Chrome 等中却可以正常工作?

c# - 如何在 android/iOS 移动测试中截取屏幕截图 - C#?