Как управлять оптическим увеличением в работающем экземпляре Internet Explorer_Server? - PullRequest
8 голосов
/ 27 мая 2011

Windows Live Writer содержит элемент управления Internet Explorer для редактирования, но нет элемента управления масштабированием.Я хотел бы иметь возможность отправить команду масштабирования к нему.Поскольку другие приложения содержат браузер IE, я бы подумал, что утилита, которая может отправлять команды масштабирования в определенные экземпляры браузера IE, была бы действительно полезной, но я не нашел ее.

Я видел, что есть команда, OLECMDID_OPTICAL_ZOOM , но я не уверен, как отправить эту команду ему.В идеале я хотел бы сделать это из C # или Powershell.

Примечание : Вопрос состоит в том, как задать управление масштабированием в элементе управления веб-браузера в запущенном приложении, которое я не создавалосновным примером является поверхность редактора в Windows Live Writer.

Ответы [ 3 ]

5 голосов
/ 08 июня 2011

Короткая версия: я не совсем уверен, что вы можете делать то, что пытаетесь сделать.

У меня есть некоторый код, который фактически получает указатель на HTML-документ внутриОкно WLW, и это работает, но я обнаружил, что не могу получить ссылку на родительское окно документа.Я не являюсь родным парнем Windows, но я сделал несколько PInvoke в свое время.Возможно, из-за недостатка собственных знаний Windows я не смогу преодолеть этот последний пробел.

Из того, что я собрал, общий процесс получения ссылки на окно IE выглядит так:

  1. Получить ссылку на окно верхнего уровня.
  2. Найти там окно, содержащее документ HTML (рекурсивный поиск).
  3. Получить объект документа HTML из этого окна.
  4. Получите родительское окно документа HTML (которое является окном IE).

Как только у вас будет это родительское окно, вы можете вызвать метод IWebBrowser2.ExecWB для запуска вашегоКоманда масштабирования OLE.

Проблема состоит в том, что свойство IHTMLDocument2.parentWindow всегда вызывает InvalidCastException при попытке доступа к нему.С что у меня прочитано , вот в чем дело, когда вы пытаетесь получить родительское окно из потока, отличного от того, в котором работает документ.

Такв любом случае, я оставлю на вас код, который получает ссылку на HTML-документ, и если вы сможете преодолеть этот крошечный последний шаг, у вас будет свой ответ.Я просто не мог понять это сам.

Это консольное приложение.Вам понадобится ссылка на Microsoft.mshtml для интерфейса IHTMLDocument2.

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.
        }
    }
}
1 голос
/ 04 июня 2011

Я думал об этом, и мне пришло в голову, что мы могли бы использовать старую технику из дней Win32 (Pre OLE, COM + и все такое прочее) под названием 'Sendkeys'

По сути то, что вынужно использовать API-интерфейс win32, чтобы найти дескриптор окна главного окна живого писателя, а затем переходить по иерархии объектов приложения до тех пор, пока не найдете веб-элемент управления.

Как только у вас есть дескриптор этогообъект (spy ++ покажет вам, доступен ли он или нет), вы теоретически должны быть в состоянии затем послать ему любую комбинацию клавиш, которая вам нравится, которая, в свою очередь, будет обрабатываться обработчиком сообщений приложений, как если бы нажатие клавиши происходило из самого приложения.

Я попробовал этот подход, но он зависит от того, действительно ли само приложение обрабатывает нажатие клавиши и выполняет необходимые функции в своем коде.Как я выяснил, протестировав его, в родительском приложении, по-видимому, нет кода обработки, который реагирует на масштабирование, поэтому я не уверен, сработает ли этот подход.

Однако расширение наэто немного, нетрудно написать плагины для Live Writer, когда у вас есть SDK, поэтому я думаю, что путь для решения этой проблемы будет смесью:

Подключаемый модуль Live Writerпринимать команды, отправленные с удаленного агента

Удаленный агент, использующий метод в том же ключе, что и ключи отправки для отправки сообщений плагину

Код в плагине, на основе кода в моемПример проекта, который находит элемент управления браузера на месте, а затем вызывает его методы масштабирования, где это необходимо.

У меня нет времени, чтобы просмотреть это в данный момент: - (

1 голос
/ 02 июня 2011

Это довольно просто ....

Необходимо переопределить обычный элемент управления веб-браузера, создав производный класс.

Этот производный класс затем используется для доступа к базовой реализации activeXродительского элемента управления веб-обозревателя, после чего вы можете получить доступ к методу ExecWB, который, к сожалению, не доступен публично в стандартном объекте.любые общедоступные методы, например, для увеличения, а затем передавайте их непосредственно в интерфейс ActiveX.

Я написал небольшую программу winforms, чтобы показать, как это делается, я загрузил проект в мой MSN skyдиск здесь:

Увеличение веб-браузера

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...