【问题标题】:Cant create HTML document from Hwnd using C#无法使用 C# 从 Hwnd 创建 HTML 文档
【发布时间】:2018-07-19 01:11:45
【问题描述】:

我们有一个现有的软件,它使用 shellwidnows 访问 Internet Explorer 页面并修改表单上的数据。但是,我们正在将其移植到 Citrix 无缝应用程序中,并且 shell 窗口在那里不起作用。

我在互联网上环顾四周,找到了一种从现有 IE 窗口创建 HtmlDocument 的方法。

但是,我在尝试运行“SendMessageTimeout”时遇到了问题。它运行没有错误,但是当它应该是一个非零数量时,返回的结果是 0。因此,我无法进入创建 HTML 文档的下一阶段。

导致问题的行是: IntPtr 结果 = SendMessageTimeout(htmlWindow, lMsg, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 1000, out lRes);

这是完整的代码。由于公司惯例,我正在使用 VS 2008。我是 C# 新手,所以一些约定和样式可能不正确。感谢您的帮助。

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using mshtml;
using System.Diagnostics;

public delegate bool IECallBack(int hwnd, int lParam);
public delegate bool IEChildCallBack(int hWndParent, int lpEnumFunc, int lParam);

namespace GetIEWindows
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        [DllImport("Oleacc.Dll")]
        public static extern int ObjectFromLresult(UIntPtr lResult, UUID _riid, int wParam, mshtml.HTMLDocument _ppvObject);

        [DllImport("user32.dll", EntryPoint = "FindWindowEx")]
        private static extern int FindWindowEx(int parentWindow, int childWindow, string _ClassName, string _WindowName);

        [DllImport("user32.dll", EntryPoint = "FindWindow")]
        private static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

        [DllImport("user32.Dll")]
        public static extern int EnumWindows(IECallBack x, long y);

        [DllImport("user32.Dll")]
        public static extern int EnumChildWindows(int parent, IECallBack x, long y);

        [DllImport("user32.dll", SetLastError = true)]
        static extern IntPtr GetWindow(IntPtr hWnd, GetWindow_Cmd uCmd);

        [DllImport("User32.Dll")]
        public static extern void GetWindowText(IntPtr h, StringBuilder s, long nMaxCount);

        [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
        static extern int GetWindowTextLength(IntPtr hWnd);

        [DllImport("User32.Dll")]
        public static extern void GetClassName(int h, StringBuilder s, int
        nMaxCount);

        [DllImport("User32.Dll")]
        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 UIntPtr result);

        enum GetWindow_Cmd : uint
        {
            GW_HWNDFIRST = 0,
            GW_HWNDLAST = 1,
            GW_HWNDNEXT = 2,
            GW_HWNDPREV = 3,
            GW_OWNER = 4,
            GW_CHILD = 5,
            GW_ENABLEDPOPUP = 6
        }

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

        public const int SMTO_ABORTIFHUNG = 0x2;


        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
        public struct UUID
        {
            public long Data1;
            public int Data2;
            public int Data3;
            [MarshalAs(System.Runtime.InteropServices.UnmanagedType.ByValArray, SizeConst = 8)]
            public byte[] Data4;
        }

        public static mshtml.HTMLDocument GetHTMLContent(IntPtr htmlWindow)
        {
            HTMLDocument htmlDocument = new mshtml.HTMLDocument();
            HTMLDocument thedoc = new mshtml.HTMLDocument();
            IHTMLDocument htmlDoc = null;

            Guid guid = new Guid("626FC520-A41E-11cf-A731-00A0C9082637");
            int foundWindow = htmlWindow.ToInt32();
            string htmlContent = "";


            UUID IID_IHTMLDocument = new UUID();
            UIntPtr lRes;
            uint lMsg = 0;
            int hr = 0;

            if (foundWindow != 0)
            {
                // Register the message 
                lMsg = RegisterWindowMessage("WM_HTML_GETOBJECT");
                //lMsg = RegisterWindowMessage("WM_GETTEXT");

                // Get the object 
                IntPtr result = SendMessageTimeout(htmlWindow, lMsg, IntPtr.Zero, IntPtr.Zero, SendMessageTimeoutFlags.SMTO_ABORTIFHUNG, 1000, out  lRes);
                if (result.ToInt32() != 0)
                {
                    if (lRes != UIntPtr.Zero)
                    {
                        // Initialize the interface ID 
                        IID_IHTMLDocument.Data1 = 0x626FC520;
                        IID_IHTMLDocument.Data2 = 0xA41E;
                        IID_IHTMLDocument.Data3 = 0x11CF;


                        IID_IHTMLDocument.Data4 = new byte[8];
                        IID_IHTMLDocument.Data4[0] = 0xA7;
                        IID_IHTMLDocument.Data4[1] = 0x31;
                        IID_IHTMLDocument.Data4[2] = 0x0;
                        IID_IHTMLDocument.Data4[3] = 0xA0;
                        IID_IHTMLDocument.Data4[4] = 0xC9;
                        IID_IHTMLDocument.Data4[5] = 0x8;
                        IID_IHTMLDocument.Data4[6] = 0x26;
                        IID_IHTMLDocument.Data4[7] = 0x37;


                        // Get the object from lRes 
                        try
                        {
                            hr = ObjectFromLresult(lRes, IID_IHTMLDocument, 0, thedoc);
                            //htmlDoc = (mshtml.IHTMLDocument)ObjectFromLresult(, IID_IHTMLDocument, 0, htmlDoc);
                        }
                        catch (Exception e)
                        {
                            MessageBox.Show("Did not get IHTMLDocument: " + e.Message);
                        }
                    }
                }
            }
            return thedoc;
        }

        public static void getHWnd()
        {
            string currentTitle;
            string windowName = null;
            string windowClass = "#32770";
            HTMLDocument pageToBeEdited;
            IntPtr hWnd = FindWindow(windowClass, windowName);
            while (hWnd.ToInt32() != 0) {
                int length       = GetWindowTextLength(hWnd);
                StringBuilder sb = new StringBuilder(length + 1);

                GetWindowText(hWnd, sb, sb.Capacity);

                currentTitle = sb.ToString();
                if (currentTitle.Contains("Internet Explorer")) {
                    pageToBeEdited = GetHTMLContent(hWnd);
                    return;
                }
                hWnd = GetWindow(hWnd, GetWindow_Cmd.GW_HWNDNEXT);
            }

            return;

        }
        private void btnRun_Click(object sender, EventArgs e)
        {
            getHWnd();
        }


    }
}

【问题讨论】:

    标签: c#


    【解决方案1】:

    对于任何感兴趣的人,问题已通过使用不同的 getHWnd 方式解决:

    public static IntPtr getHWnd(string title)
        {
            IntPtr hWnd = FindWindow(null, title);
            BringWindowToTop(hWnd);
            SetActiveWindow(hWnd);
            SetForegroundWindow(hWnd);
            Thread.Sleep(500);
            foreach (Process process in Process.GetProcessesByName("IExplore"))
            {
                if (process.MainWindowTitle.ToLower().Contains(title.ToLower()))
                {
                    hWnd = process.MainWindowHandle;
                    break;
                }
            }
    
            EnumProc proc = new EnumProc(EnumWindows);
            EnumChildWindows(hWnd, proc, ref hWnd);
            return hWnd;
    
        }
    
        public HTMLDocument GetHTMLDocument(IntPtr hWnd)
        {
            HTMLDocument document = null;
            int iMsg = 0;
            int iRes = 0;
    
            iMsg = RegisterWindowMessage("WM_HTML_GETOBJECT");
            if (iMsg != 0)
            {
                SendMessageTimeout(hWnd, iMsg, 0, 0, SMTO_ABORTIFHUNG, 1000, out iRes);
                if (iRes != 0)
                {
                    int hr = ObjectFromLresult(iRes, ref IID_IHTMLDocument, 0, ref document);
                }
            }
            return document;
        }
    
        private static int EnumWindows(IntPtr hWnd, ref IntPtr lParam)
        {
            int iRet = 1;
            StringBuilder classname = new StringBuilder(128);
            GetClassName(hWnd, classname, classname.Capacity);
            if ((bool)(string.Compare(classname.ToString(), "Internet Explorer_Server") == 0))
            {
                lParam = hWnd;
                iRet = 0;
            }
            return iRet;
        }
    

    【讨论】:

    • RegisterWindowMessage() 返回一个 Uint 你如何将它分配给 iMsg?
    • 它适用于ie窗口。当我尝试对嵌入式即控制执行相同操作时,我有“呼叫被被调用者拒绝。(来自 HRESULT 的异常:0x80010001 (RPC_E_CALL_REJECTED))”
    【解决方案2】:

    以下是使用 Hwnd 获取 HTMLDocument 的方法:

        using System;
        using System.Collections.Generic;
        using System.ComponentModel;
        using System.Data;
        using System.Diagnostics;
        using System.Drawing;
        using System.Runtime.InteropServices;
        using System.Text;
        using System.Windows.Forms;
        using mshtml;
    
        namespace HookBrowser
        {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
            }
    
            #region API CALLS
    
            [DllImport("user32.dll", EntryPoint = "GetClassNameA")]
            public static extern int GetClassName(IntPtr hwnd, StringBuilder lpClassName, int nMaxCount);
    
            /*delegate to handle EnumChildWindows*/
            public delegate int EnumProc(IntPtr hWnd, ref IntPtr lParam);
    
            [DllImport("user32.dll")]
            public static extern int EnumChildWindows(IntPtr hWndParent, EnumProc lpEnumFunc, ref  IntPtr lParam);
            [DllImport("user32.dll", EntryPoint = "RegisterWindowMessageA")]
            public static extern int RegisterWindowMessage(string lpString);
            [DllImport("user32.dll", EntryPoint = "SendMessageTimeoutA")]
            public static extern int SendMessageTimeout(IntPtr hwnd, int msg, int wParam, int lParam, int fuFlags, int uTimeout, out int lpdwResult);
            [DllImport("OLEACC.dll")]
            public static extern int ObjectFromLresult(int lResult, ref Guid riid, int wParam, ref IHTMLDocument2 ppvObject);
            public const int SMTO_ABORTIFHUNG = 0x2;
            public Guid IID_IHTMLDocument = new Guid("626FC520-A41E-11CF-A731-00A0C9082637");
    
            #endregion
    
            public IHTMLDocument2 document;
    
            private void button1_Click(object sender, EventArgs e)
            {
                document = documentFromDOM();
                /// check that we have hold of the IHTMLDocument2...
                if (!(bool)(document == null))
                {
                    this.Text = document.url;
                }
            }
    
            private IHTMLDocument2 documentFromDOM()
            {
                Process[] processes = Process.GetProcessesByName("iexplore");
                if (processes.Length > 0)
                {
                    IntPtr hWnd = processes[0].MainWindowHandle;
                    int lngMsg = 0;
                    int lRes;
    
                    EnumProc proc = new EnumProc(EnumWindows);
                    EnumChildWindows(hWnd, proc, ref hWnd);
                    if (!hWnd.Equals(IntPtr.Zero))
                    {
                        lngMsg = RegisterWindowMessage("WM_HTML_GETOBJECT");
                        if (lngMsg != 0)
                        {
                            SendMessageTimeout(hWnd, lngMsg, 0, 0, SMTO_ABORTIFHUNG, 1000, out lRes);
                            if (!(bool)(lRes == 0))
                            {
                                int hr = ObjectFromLresult(lRes, ref IID_IHTMLDocument, 0, ref document);
                                if ((bool)(document == null))
                                {
                                    MessageBox.Show("NoLDocument Found!", "Warning");
                                }
                            }
                        }
                    }
                }
                return document;
            }
    
            private int EnumWindows(IntPtr hWnd, ref IntPtr lParam)
            {
                int retVal = 1;
                StringBuilder classname = new StringBuilder(128);
                GetClassName(hWnd, classname, classname.Capacity);
                /// check if the instance we have found is Internet Explorer_Server
                if ((bool)(string.Compare(classname.ToString(), "Internet Explorer_Server") == 0))
                {
                    lParam = hWnd;
                    retVal = 0;
                }
                return retVal;
            }
        }
    }
    

    请参阅此链接了解更多信息:

    http://www.xtremevbtalk.com/code-library/295336-internet-explorer-dom-using-objectfromlresult.html

    【讨论】:

    • 请不要只发布链接作为答案,而是将相关步骤放入您的实际答案中。外部可能不可用或更改,使您的答案无用。因此,请edit您的答案,并将链接中的相关步骤复制到您的答案中,从而保证您的答案在本站100%的生命周期内! ;-) 您始终可以将答案底部的链接作为您材料的来源...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-03-04
    • 2021-04-10
    • 1970-01-01
    • 2022-10-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多