MFC Web 浏览器控件:模拟 Ctrl+N 需要多少(正常)代码行



更新: 答:需要两行正常的代码。谢谢鼻子比!

我在键盘上敲了几个小时,而不是试图在我的托管浏览器控制应用程序中模拟 IE Ctrl+N 行为。 不幸的是,由于我在下面的代码示例中抽象出来的复杂情况,我不能让 IE 自己做 Ctlr+N。所以我必须手动完成。

请记住,我正在运行托管浏览器。因此,通常,在新窗口中打开链接实际上会在我的应用程序的新"选项卡"中打开它(它不是真正的选项卡,而是另一个窗口......但从外观上看,它是一个标签)。但是,Ctrl+N 是不同的 - 在这里,预计按下时将启动一个成熟的 IE 窗口。

我认为我的问题是构建问题 - 诚然,我是WebBrowser控件的新手,我发现它很糟糕。无论如何,过去一天我在互联网上搜索了一下,但无法想出一个优雅的解决方案。

基本上,理想的解决方案是在WebBrowser控件或其附属库中调用"NewWindow"函数;但是,我只能找到*On*NewWindow方法的位置,这些方法是事件处理程序,而不是事件信号器。我知道大多数时候,用户将创建事件......但是程序化模拟呢?

我尝试研究一种 SENDMESSAGE 方法,我可以在其中使用 OnNewWindow 事件使用的 ID......最终只剩下崩溃。也许我可以回去让它工作,但我想确认这种方法甚至值得我花时间。

下一个方法,应该是最优雅的,但遗憾的是没有成功,如下所示:

Navigate2(GetLocationURL().GetBuffer(), BrowserNavConstants::navOpenInNewWindow);

如果不是因为新窗口将在后台打开并在任务栏中闪烁,它会非常出色。 需要单击才能将其带到前面。

我试图以多种方式绕过限制,包括获取当前上下文的调度程序,然后使用该 IDispatch 对象调用 OnNewWindow2。然后,我将在 IWebBrowser 控件的调度对象上调用 QueryInterface。然后,WebBrowser 控件(可能在新窗口的控制下)可以导航到原始上下文的页面。然而。。。这也是一个非常混乱的解决方案,最终会导致崩溃。

最后,我求助于手动调用JavaScript来获得所需的行为。真??真的没有比下面的混乱代码更优雅的解决方案来解决我的问题了吗?

        if ((pMsg->wParam == 'N') && (GetKeyState(VK_CONTROL) & 0x8000) && !(GetKeyState(VK_SHIFT) & 0x8000) && !(GetKeyState(VK_MENU) & 0x8000))
        {
            LPDISPATCH pDisp = CHtmlView::GetHtmlDocument();
            IHTMLDocument2 *pDoc;
            if (SUCCEEDED(pDisp->QueryInterface(IID_IHTMLDocument2, (void **)&pDoc))) 
            {
                IHTMLWindow2* pWnd;
                pDoc->get_parentWindow(&pWnd);
                BSTR bStrLang = ::SysAllocString(L"JavaScript");
                CString sCode(L"window.open("");
                sCode.Append(GetLocationURL().GetBuffer());
                sCode.Append(L"");");
                BSTR bStrCode = sCode.AllocSysString();
                COleVariant retVal;
                pWnd->execScript(bStrCode, bStrLang, retVal);
                ::SysFreeString(bStrLang);
                ::SysFreeString(bStrCode);
                pDoc->Release();
            }
            pDisp->Release();

发现很难相信我必须求助于这样的黑客行为才能获得像用户按 Ctrl+N 时打开新窗口这样简单的东西。

堆叠溢出,请指出我忽略的明显的事情。

IE

中的Ctrl-N在同一会话上启动一个新窗口。在您的情况下,window.openwebBrowser.Navigate2将在新会话上创建一个窗口,因为它将由与您的应用程序分开iexplore.exe进程运行。会话按进程共享,这就是基础UrlMon库的工作方式。因此,您将丢失新窗口的所有 cookie 和身份验证缓存。另一方面,当您创建一个在您自己的应用进程中托管WebBrowser控制权的新窗口时,您将保留会话。

如果此类行为可以满足您的需求,请先尝试初始Navigate2方法,并在该方法之前进行 AllowSetForegroundWindow(ASFW_ANY) 调用。如果新窗口仍未正确接收焦点,可以尝试创建进程外 COM 对象的实例InternetExplorer.Application并使用相同的 IWebBrowser2 接口自动执行该对象。下面是一个简单的 C# 应用程序,对我来说效果很好,新窗口被正确地带到前台,没有焦点问题。对 MFC 执行相同的操作应该不是问题。

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace IeApp
{
    public partial class MainForm : Form
    {
        // get the underlying WebBrowser ActiveX object;
        // this code depends on SHDocVw.dll COM interop assembly,
        // generate SHDocVw.dll: "tlbimp.exe ieframe.dll",
        // and add as a reference to the project
        public MainForm()
        {
            InitializeComponent();
        }
        private void NewWindow_Click(object sender, EventArgs e)
        {
            AllowSetForegroundWindow(ASFW_ANY);
            // could do: var ie =  new SHDocVw.InternetExplorer()
            var ie = (SHDocVw.InternetExplorer)Activator.CreateInstance(Type.GetTypeFromProgID("InternetExplorer.Application"));
            ie.Visible = true;
            ie.Navigate("http://www.example.com");
        }
        const int ASFW_ANY = -1;
        [DllImport("user32.dll")]
        static extern bool AllowSetForegroundWindow(int dwProcessId);
    }
}

相关内容

  • 没有找到相关文章

最新更新