Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I have now verified the <code>eval</code> approach works consistently with IE9, IE10 and IE11 (error checks skipped for breavity):</p> <pre><code>CComVariant result; CComDispatchDriver disp = m_htmlWindow; // of IHTMLWindow2 disp.Invoke1(L"eval", &amp;CComVariant(L"confirm('See this?')"), &amp;result); result.ChangeType(VT_BSTR); MessageBoxW(V_BSTR(&amp;result)); </code></pre> <p>Feels even better than <code>execScript</code>, because it actually returns the <code>result</code>. It works also in C# with WinForms' <code>WebBrowser</code>:</p> <pre><code>var result = webBrowser1.Document.InvokeScript("eval", new object[] { "confirm('see this?')" }); MessageBox.Show(result.ToString()); </code></pre> <p>That said, <code>execScript</code> still works for IE11 Preview:</p> <pre><code>CComVariant result; m_htmlWindow-&gt;execScript(CComBSTR(L"confirm('See this too?')"), CComBSTR(L"JavaScript"), &amp;result); result.ChangeType(VT_BSTR); MessageBoxW(V_BSTR(&amp;result)); </code></pre> <p>And it still discards the <code>result</code>, as it always did.</p> <p>A bit off-topic, but you don't have to stick with <code>eval</code> for this. This approach allows to execute any named method available inside the namespace of the JavaScript <code>window</code> object of the loaded page (via <a href="http://msdn.microsoft.com/en-us/library/ms221608%28v=vs.85%29.aspx">IDispatch</a> interface). You may call your own function and pass a live COM object into it, rather than a string parameter, e.g.:</p> <pre><code>// JavaScript function AlertUser(user) { alert(user.name); return user.age; } // C++ CComDispatchDriver disp = m_htmlWindow; // of IHTMLWindow2 disp.Invoke1(L"AlertUser", &amp;CComVariant(userObject), &amp;result); </code></pre> <p>I'd prefer the above direct call to <code>eval</code> where possible.</p> <p><strong>[EDITED]</strong></p> <p>It takes some tweaks to make this approach work for out-of-process calls. As @JimEvans pointed out in the comments, <code>Invoke</code> was returning error 0x80020006 ("Unknown name"). However, a <a href="http://pastebin.com/cLR6FeJV">test HTA app</a> worked just fine, what made me think to try <a href="http://msdn.microsoft.com/en-us/library/wwazwk2k%28v=vs.94%29.aspx">IDispatchEx::GetDispId</a> for name resolution. That indeed worked (error checks skipped):</p> <pre><code>CComDispatchDriver dispWindow; htmlWindow-&gt;QueryInterface(&amp;dispWindow); CComPtr&lt;IDispatchEx&gt; dispexWindow; htmlWindow-&gt;QueryInterface(&amp;dispexWindow); DISPID dispidEval = -1; dispexWindow-&gt;GetDispID(CComBSTR("eval"), fdexNameCaseSensitive, &amp;dispidEval); dispWindow.Invoke1(dispidEval, &amp;CComVariant("function DoAlert(text) { alert(text); }")); // inject DISPID dispidDoAlert = -1; dispexWindow-&gt;GetDispID(CComBSTR("DoAlert"), fdexNameCaseSensitive, &amp;dispidDoAlert) ); dispWindow.Invoke1(dispidDoAlert, &amp;CComVariant("Hello, World!")); // call </code></pre> <p>The full C++ test app is here: <a href="http://pastebin.com/ccZr0cG2">http://pastebin.com/ccZr0cG2</a></p> <p><strong>[UPDATE]</strong></p> <p>This update creates <code>__execScript</code> method on a <code>window</code> object of a child <code>iframe</code>, out-of-proc. The code to be injected was optimized to return the target <code>window</code> object for later use (no need to make a series of out-of-proc calls to obtain the <code>iframe</code> object, it's done in the context of the main window):</p> <pre><code>CComBSTR __execScriptCode(L"(window.__execScript = function(exp) { return eval(exp); }, window.self)"); </code></pre> <p>Below is the code for C++ console app (<a href="http://pastebin.com/cLR6FeJV">pastebin</a>), some error checks skipped for breavity. There's also a corresponding <a href="http://pastebin.com/iM5829MM">prototype in .HTA</a>, which is more readable.</p> <pre><code>// // http://stackoverflow.com/questions/18342200/how-do-i-call-eval-in-ie-from-c/18349546// // #include &lt;tchar.h&gt; #include &lt;ExDisp.h&gt; #include &lt;mshtml.h&gt; #include &lt;dispex.h&gt; #include &lt;atlbase.h&gt; #include &lt;atlcomcli.h&gt; #define _S(a) \ { HRESULT hr = (a); if (FAILED(hr)) return hr; } #define disp_cast(disp) \ ((CComDispatchDriver&amp;)(void(static_cast&lt;IDispatch*&gt;(disp)), reinterpret_cast&lt;CComDispatchDriver&amp;&gt;(disp))) struct ComInit { ComInit() { ::CoInitialize(NULL); } ~ComInit() { CoUninitialize(); } }; int _tmain(int argc, _TCHAR* argv[]) { ComInit comInit; CComPtr&lt;IWebBrowser2&gt; ie; _S( ie.CoCreateInstance(L"InternetExplorer.Application", NULL, CLSCTX_LOCAL_SERVER) ); _S( ie-&gt;put_Visible(VARIANT_TRUE) ); CComVariant ve; _S( ie-&gt;Navigate2(&amp;CComVariant(L"http://jsfiddle.net/"), &amp;ve, &amp;ve, &amp;ve, &amp;ve) ); // wait for page to finish loading for (;;) { Sleep(250); READYSTATE rs = READYSTATE_UNINITIALIZED; ie-&gt;get_ReadyState(&amp;rs); if ( rs == READYSTATE_COMPLETE ) break; } // inject __execScript into the main window CComPtr&lt;IDispatch&gt; dispDoc; _S( ie-&gt;get_Document(&amp;dispDoc) ); CComPtr&lt;IHTMLDocument2&gt; htmlDoc; _S( dispDoc-&gt;QueryInterface(&amp;htmlDoc) ); CComPtr&lt;IHTMLWindow2&gt; htmlWindow; _S( htmlDoc-&gt;get_parentWindow(&amp;htmlWindow) ); CComPtr&lt;IDispatchEx&gt; dispexWindow; _S( htmlWindow-&gt;QueryInterface(&amp;dispexWindow) ); CComBSTR __execScript("__execScript"); CComBSTR __execScriptCode(L"(window.__execScript = function(exp) { return eval(exp); }, window.self)"); DISPID dispid = -1; _S( dispexWindow-&gt;GetDispID(CComBSTR("eval"), fdexNameCaseSensitive, &amp;dispid) ); _S( disp_cast(dispexWindow).Invoke1(dispid, &amp;CComVariant(__execScriptCode)) ); // inject __execScript into the child frame WCHAR szCode[1024]; wsprintfW(szCode, L"document.all.tags(\"iframe\")[0].contentWindow.eval(\"%ls\")", __execScriptCode.m_str); dispid = -1; _S( dispexWindow-&gt;GetDispID(__execScript, fdexNameCaseSensitive, &amp;dispid) ); CComVariant vIframe; _S( disp_cast(dispexWindow).Invoke1(dispid, &amp;CComVariant(szCode), &amp;vIframe) ); // inject __execScript and return the iframe's window object _S( vIframe.ChangeType(VT_DISPATCH) ); CComPtr&lt;IDispatchEx&gt; dispexIframe; _S( V_DISPATCH(&amp;vIframe)-&gt;QueryInterface(&amp;dispexIframe) ); dispid = -1; _S( dispexIframe-&gt;GetDispID(__execScript, fdexNameCaseSensitive, &amp;dispid) ); _S( disp_cast(dispexIframe).Invoke1(dispid, &amp;CComVariant("alert(document.URL)")) ); // call the code inside child iframe return 0; } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload