Module-script two-way interaction -- in C#

Add-in Express™ Support Service
That's what is more important than anything else

Module-script two-way interaction -- in C#
 
Todd Price




Posts: 14
Joined: 2014-08-13
In this forum post:

http://www.add-in-express.com/forum/read.php?FID=10&TID=12439&MID=63414

...you demonstrate a way to call a method in VB.NET (inside a toolbar add-in) from the javascript injected into a browser page. I'm trying to do equivalent of this block of code (from the referenced PDF documentation - "Step #7. Intercepting IE Events") in C#:



Dim scriptEngine As Object = Me.HTMLDocument.Script scriptEngine.GetType().InvokeMember("myAddon",_ BindingFlags.SetProperty, Nothing, scriptEngine, New Object() {Me})


But "this.HTMLDocument" in C# has no member "Script" that can be reflected upon. Can you show me an equivalent way of calling a C# method from javascript?

Thanks.
Posted 13 Aug, 2014 19:56:38 Top
Andrei Smolin


Add-in Express team


Posts: 18793
Joined: 2006-05-11
Todd,

Just enter the code line below and compile it:

object scriptEngine = this.HTMLDocument.Script;


Andrei Smolin
Add-in Express Team Leader
Posted 14 Aug, 2014 01:31:45 Top
Todd Price




Posts: 14
Joined: 2014-08-13
Thanks Andrei. Now I'm getting an error on the second line in this code:


            object scriptEngine = this.HTMLDocument.Script;
            scriptEngine.GetType().InvokeMember("PageVault", BindingFlags.SetProperty, null, scriptEngine, new object[] { this });


The error is:


System.Runtime.InteropServices.COMException (0x80020006): Unknown name. (Exception from HRESULT: 0x80020006 (DISP_E_UNKNOWNNAME))


And PageVault is the name of the class that the code is executing in. i.e. "this" is "PageVault".

EDIT: My main question is this: what is this code trying to do? Assign a value to an object in javascript so we can make a call to a method in C# / .NET?
Posted 14 Aug, 2014 17:22:58 Top
Andrei Smolin


Add-in Express team


Posts: 18793
Joined: 2006-05-11
Hello Todd,

If scriptEngine were typed, you could replace the InvokeMember statement above with this code line (using early binding):

scriptEngine.PageVault = this;

Since PageVault is a class, not a field/property declared by the script, assigning "this" to it is a mistake.

Todd Price writes:
My main question is this: what is this code trying to do? Assign a value to an object in javascript so we can make a call to a method in C# / .NET?


Exactly. The add-on sets a variable defined in the script so that the script's function can invoke a method defined in the add-on. The late-binding call could be replaced with scriptEngine.myAddon = this

To All. We talk about this code sample (it is published in the manual; you can download the manual at http://www.add-in-express.com/downloads/documentation.php):

'VB.NET
Imports System.Windows.Forms
Imports AddinExpress.IE
Imports System.Reflection
'...
Private Sub IEToolbar_DownloadComplete() Handles MyBase.DownloadComplete
    If Not ThisIsMyPage(Me.HTMLDocument.url) Then Return
    Try
        Dim scriptEngine As Object = Me.HTMLDocument.Script
        scriptEngine.GetType().InvokeMember("myAddon",_
            BindingFlags.SetProperty, Nothing, scriptEngine, New Object() {Me})
    Catch ex As Exception
    End Try

'<html><head><script type="text/javascript">
'var myAddon = null;
'function MyFunction() 
'{
'    if(myAddon != null)
'    {
'        myAddon.MyMethod("okay");
'    }
'    else
'        alert("The add-on isn't registered");
'}
'</script></head><body>
'<input type="button" name="button1" value="Click me!" onclick="MyFunction();">
'</body></html>
End Sub

Public Sub MyMethod(param As String)
    MessageBox.Show(New MyWinApiWindow(Me.ParentHandle), param)
End Sub



Andrei Smolin
Add-in Express Team Leader
Posted 15 Aug, 2014 04:58:48 Top
Todd Price




Posts: 14
Joined: 2014-08-13
Andrei, I'm still confused on how to translate the VB example into C#. What's not clear is what "Me" is referring to in the last parameter of the InvokeMember method call. Wouldn't that refer to the class defining the add-in? And the equivalent in C# would be "this"?

EDIT: I should add that my main intent is to be able to inject javascript into a loaded page/document (which we've already done successfully), but provide feedback as to what the script is doing in the UI of our toolbar. i.e. we need to pass a message from JavaScript to C#. If there is a better way to do this let me know.

Thanks for your help.
Posted 15 Aug, 2014 08:04:20 Top
Andrei Smolin


Add-in Express team


Posts: 18793
Joined: 2006-05-11
Todd,

You're correct about "this" being a C# equivalent to "Me" in VB.NET.

Todd Price writes:
The error is:

System.Runtime.InteropServices.COMException (0x80020006): Unknown name. (Exception from HRESULT: 0x80020006 (DISP_E_UNKNOWNNAME))

And PageVault is the name of the class that the code is executing in. i.e. "this" is "PageVault".


I referred to the PageVault part of this statement: scriptEngine.PageVault = this. The VB.NET code given above sets a variable called myAddon. Your statement was "And PageVault is the name of the class that the code is executing in. i.e. "this" is "PageVault"." This is exactly what concerns me: you are trying to set "this" to a class, not to a variable. I don't think this is correct.


Andrei Smolin
Add-in Express Team Leader
Posted 15 Aug, 2014 08:42:35 Top
Todd Price




Posts: 14
Joined: 2014-08-13
But in the VB version of this script:


        Dim scriptEngine As Object = Me.HTMLDocument.Script 
        scriptEngine.GetType().InvokeMember("myAddon",_ 
            BindingFlags.SetProperty, Nothing, scriptEngine, New Object() {Me})


...you're setting a property of the script engine named "myAddon" equal to the value "Me", which is a class. No?

The main question is: how do I translate this correctly into C#?
Posted 15 Aug, 2014 08:46:41 Top
Andrei Smolin


Add-in Express team


Posts: 18793
Joined: 2006-05-11
Or, now I see. That variable is set to an instance of the class executing this code line. If this is what you need to do, then you write scriptEngine.GetType().InvokeMember("PageVault", BindingFlags.SetProperty, null, scriptEngine, new object[] { this }). This assumes that a) the variable is called PageVault and b) "this" points to a class instance that you need to assign to that variable.

If I were to rewrite that sample in C#, I'd write: scriptEngine.GetType().InvokeMember("myAddon", BindingFlags.SetProperty, null, scriptEngine, new object[] { this })


Andrei Smolin
Add-in Express Team Leader
Posted 15 Aug, 2014 08:53:55 Top
Todd Price




Posts: 14
Joined: 2014-08-13
OK, so then I'm back to where I started, since that's exactly what I did:


            object scriptEngine = this.HTMLDocument.Script;
            scriptEngine.GetType().InvokeMember("PageVault", BindingFlags.SetProperty, null, scriptEngine, new object[] { this.IEApp });


But it throws this exception:


System.Runtime.InteropServices.COMException (0x80020006): Unknown name. (Exception from HRESULT: 0x80020006 (DISP_E_UNKNOWNNAME))
Posted 15 Aug, 2014 09:26:59 Top
Andrei Smolin


Add-in Express team


Posts: 18793
Joined: 2006-05-11
The error means "No such property exists". How PageVault is declared?

Try using BindingFlags.SetField instead of BindingFlags.SetProperty.


Andrei Smolin
Add-in Express Team Leader
Posted 15 Aug, 2014 09:31:49 Top