Calling C# BHO methods from Javascript
Asked Answered
A

2

11

I'm trying to figure out how to call C# methods in my BHO object from Javascript within the page. I found numerous pages on how to do it in C++/ATL/Com such as:

Browser Helper Objects and Scripts Options

Calling BHO method from Javascript?

I have tried to follow along and implement it correctly in C#, but I can't get it to work probably due to some obvious COM problems that I have which I don't fully understand.

I am using C# 4.0.

Here are the relevant parts of the code:

using SHDocVw;
using mshtml;
using System.Runtime.InteropServices;

[ComVisible(true),
 Guid("300736C4-DCDA-4DB0-90AD-4510A12EBBC6"),
 ClassInterface(ClassInterfaceType.None),
 ProgId("My Extension")]
public class BrowserHelperObject : IObjectWithSite
{
    const int DISPATCH_PROPERTYPUT = 4;
    const int FDEX_NAME_ENSURE = 2;
    const uint LOCALE_USER_DEFAULT = 0x0400;

    WebBrowser browser;

    ...
    public void OnDocumentComplete(dynamic frame, ref dynamic url)
    {
        ...
        var window = browser.Document.parentWindow;

        int pid = 0;
        window.GetDispId("myExtension", FDEX_NAME_ENSURE, ref pid);

        System.Runtime.InteropServices.ComTypes.DISPPARAMS dispParms = new System.Runtime.InteropServices.ComTypes.DISPPARAMS();
        dispParms.cArgs = 1;
        dispParms.cNamedArgs = 0;
        dispParms.rgvarg = ???;
        dispParms.rgdispidNamedArgs = IntPtr.Zero;
        System.Runtime.InteropServices.ComTypes.EXCEPINFO einfo = new System.Runtime.InteropServices.ComTypes.EXCEPINFO();
        window.Invoke(pid, LOCALE_USER_DEFAULT, DISPATCH_PROPERTYPUT, ref dispParms, this, ref einfo);            
        ...
    }
Acreage answered 15/2, 2012 at 4:40 Comment(0)
A
25

I hate to answer my own question, but I really feel like the community ought to know the answer because it is short, simple, and beautiful with C# 4.0 and SO many people seem to have this problem.

Make sure that you correctly expose the Browser Helper Object:

[ComVisible(true),
 Guid("DA8EA345-02AE-434E-82E9-448E3DB7629E"),
 ClassInterface(ClassInterfaceType.None), ProgId("MyExtension"),
 ComDefaultInterface(typeof(IExtension))]
public class BrowserHelperObject : IObjectWithSite, IExtension
{
    ...
    public int Foo(string s) { ... }
    ...
    public void OnDocumentComplete(dynamic frame, ref dynamic url)
    {
        ...
        dynamic window = browser.Document.parentWindow;
        IExpando windowEx = (IExpando)window;
        windowEx.AddProperty("myExtension");
        window.myExtension = this;
        ...
    }
    ...
}

And you will need a definition for your extensions:

[ComVisible(true),
 Guid("4C1D2E51-018B-4A7C-8A07-618452573E42"),
 InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface IExtension
{
    [DispId(1)]
    int Foo(string s);
    ...
}

You can access your Browser Helper Object in javascript thus:

var result = window.myExtension.Foo("bar");

or just

var result = myExtension.Foo("bar");

That's it. Stop banging your head against the wall and go celebrate!

Acreage answered 16/2, 2012 at 5:24 Comment(8)
Don't regret for answering your own question.. Because, i)people look for answer and not for the person who answered, ii) You have an issue posted and You are able to answer it means you have worked on it.. That' seriously a good thing.. congrats....Crackerjack
Hi fixedpoint. Could you post a full working prototype? I tried exactly to repro this and my window.myExtension remains 'undefined' I posted this question with my full source hereAcute
For me this fails as soon as I load some javascript in my page - on pages without any external script references it's fine, as soon as I have an external script reference it fails. Also strange, once it starts failing it keeps on failing on pages it had previously worked for.Eisenach
This isn't working for me either. Working example would be much appreciated!Steatopygia
If it's not working for you try this: the browser object needs to be an instance of 'IWebBrowser' not 'IWebBrowser2'Happy
Probably you didn't include ComDefaultInterface(typeof(IExtension)) on your implementation class, that's why it isn't workingAppenzell
If you, like me, used the code at #5644319 to create your extension, then what @AmelMusic says is what's missing. Thanks man!Mentality
In my case the GUID for IExtension is different. I used C:\>reg query HKLM /s /f IExtension /d /e /c to get output like this HKEY_LOCAL_MACHINE\SOFTWARE\Classes\Interface\{B05651CD-9B10-425E-B616-1FCD828DB3B1} and the guid is in the braces.Morvin
A
0

Also, after you add property you need to make sure to release COM references of window and windowEx

Appenzell answered 9/3, 2015 at 15:49 Comment(1)
Can you please elaborate on this.Morrismorrison

© 2022 - 2024 — McMap. All rights reserved.