c++ internet-explorer mfc webbrowser-control hosted-app

c++ - MFC WebBrowser Control: ¿Cuántas líneas(normales) de código se necesitan para simular Ctrl+N?



internet-explorer webbrowser-control (1)

Actualización: Respuesta: se requieren dos líneas normales de código. Gracias Noseratio!

Me golpeé la cabeza en el teclado durante más horas de las que me hubiera gustado intentar simular el comportamiento de IEs Ctrl + N en mi aplicación de control del navegador alojado. Desafortunadamente, debido a complicaciones que he abstraído de los ejemplos de mi código a continuación, no puedo dejar que IE haga Ctlr + N. Entonces tengo que hacerlo manualmente.

Tenga en cuenta que estoy ejecutando un navegador alojado. Por lo general, abrir enlaces en ventanas nuevas lo abrirá dentro de una nueva "pestaña" dentro de mi aplicación (no es realmente una pestaña, sino otra ventana ... pero aparentemente es una pestaña). Sin embargo, Ctrl + N es diferente; aquí se espera que se inicie una ventana de IE totalmente desarrollada cuando se presione.

Creo que mi problema es el de enmarcar las preguntas. Es cierto que soy nuevo en el control WebBrowser y me parece muy asqueroso. A pesar de todo, he buscado en Internet durante el día pasado y no he podido encontrar una solución elegante.

Básicamente, la solución ideal sería llamar a una función "NewWindow" dentro del control WebBrowser o sus bibliotecas afiliadas; sin embargo, todo lo que pude encontrar fueron los métodos * On * NewWindow, que eran manejadores de eventos, no señalizadores de eventos. Lo que entiendo es que la mayoría de las veces, el usuario creará los eventos ... ¿pero qué pasa con la simulación programática?

Traté de buscar un acercamiento a SENDMESSAGE donde pudiera usar los ID que usan los eventos OnNewWindow ... que terminaron en nada más que fallas. Tal vez podría volver para que funcione, pero me gustaría que la confirmación sea que ese enfoque vale la pena.

El siguiente enfoque, que debería haber sido el más elegent, pero lamentablemente no funcionó, fue como el siguiente:

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

Hubiera funcionado maravillosamente si no fuera por el hecho de que la nueva ventana se abriría en segundo plano, parpadeando en la barra de tareas. necesitando hacer clic para llevarlo al frente.

Intenté sortear la limitación de muchas maneras, incluido obtener el despachador del contexto actual, y luego llamar a OnNewWindow2 con ese objeto IDispatch. Luego invocaría QueryInterface en el objeto de envío para un control IWebBrowser. El control webBrowser (presumiblemente bajo el control de la nueva ventana) podría navegar a la página del contexto original. Sin embargo ... esto también fue una solución bastante desordenada y al final causaría caídas.

Finalmente, recurrí a invocar JavaScript manualmente para obtener el comportamiento deseado. ¿¿De Verdad?? ¿Realmente no había una solución más elegante para mi problema que el desorden del código?

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();

Me resulta difícil creer que deba recurrir a tales hackers como este para obtener algo tan simple como abrir una nueva ventana cuando el usuario presiona Ctrl + N.

Por favor, stackoverflow, por favor señale lo claramente obvio que pasé por alto.


Ctrl-N en IE inicia una nueva ventana en la misma sesión. En su caso, window.open o webBrowser.Navigate2 creará una ventana en una sesión nueva, ya que se ejecutará mediante el proceso iexplore.exe que es independiente de su aplicación. La sesión se comparte por proceso, así es como funciona la biblioteca subyacente de UrlMon . Entonces perderá todas las cookies y el caché de autenticación para la nueva ventana. Por otro lado, cuando crea una nueva ventana que aloja WebBrowser control WebBrowser dentro de su propio proceso de aplicación, mantendrá la sesión.

Si dicho comportamiento es correcto para sus necesidades, intente primero su enfoque inicial Navigate2 , precediéndolo con la llamada AllowSetForegroundWindow (ASFW_ANY) . Si la nueva ventana aún no recibe el foco correctamente, puede intentar crear una instancia del objeto COM de InternetExplorer.Application out-of-proc, y usar la misma interfaz IWebBrowser2 para automatizarlo. A continuación se muestra una aplicación simple de C # que funciona bien para mí, la nueva ventana se lleva correctamente al primer plano, sin problemas de enfoque. No debería ser un problema hacer lo mismo con 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); } }