Dot-Net

如何在正在執行的“Internet Explorer_Server”實例中控制光學變焦?

  • July 15, 2014

Windows Live Writer 擁有一個用於編輯的 Internet Explorer 控制項,但沒有縮放控制項。我希望能夠向它發送縮放命令。由於其他應用程序託管 IE 瀏覽器,我認為可以向特定 IE 瀏覽器實例發送縮放命令的實用程序非常方便,但我還沒有找到。

我已經看到有一個命令OLECMDID_OPTICAL_ZOOM,但我不確定如何將該命令發送給它。理想情況下,我想從 C# 或 Powershell 執行此操作。

注意:問題是關於在我沒有創建的正在執行的應用程序中控制 Web 瀏覽器控制項的縮放,主要範例是 Windows Live Writer 中的編輯器表面。

簡短版本:我不完全確定你能做你想做的事。

我有一些程式碼實際上獲得了 WLW 視窗內 HTML 文件的句柄,並且可以正常工作,但我發現我實際上無法獲得對文件父視窗的引用。我不是 Windows 本地人,但我在我的時間裡做過一些 PInvoke。可能只是我缺乏本地 Windows 知識正在阻止我彌合最後的差距。

根據我的總結,獲取 IE 視窗引用的一般過程是:

  1. 獲取頂級視窗的參考。
  2. 在那裡找到包含 HTML 文件的視窗(遞歸搜尋)。
  3. 從該視窗獲取 HTML 文件對象。
  4. 獲取 HTML 文件的父視窗(即 IE 視窗)。

擁有該父視窗後,您可以呼叫 IWebBrowser2.ExecWB 方法來執行 OLE 縮放命令。

問題是當您嘗試訪問**IHTMLDocument2.parentWindow 屬性時,它似乎總是拋出 InvalidCastException 。**從讀過的內容來看,當您嘗試從文件正在執行的執行緒之外的執行緒中獲取父視窗時,這就是交易。

所以,無論如何,我會把獲取 HTML 文件參考的程式碼放在你身上,如果你能在最後一步橋接,你就會得到答案。我只是無法弄清楚自己。

這是一個控制台應用程序。對於 IHTMLDocument2 介面,您需要對 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.
       }
   }
}

引用自:https://stackoverflow.com/questions/6145712