Jaa


Calling managed code from Expression Web 4 HTMLJS Extensibility Add-Ins

A few folks have asked how to call managed code from the HTML\JavaScript extensibility layer within Expression Web 4.

Hope this helps!

John

1. Create a c# Class library project in Visual Studio, for this sample call it 'web'

2. mark the class as ComVisible

namespace web
{
    [ComVisible(true)]
    public class Class1
    {
    }
}

3. This will cause a compile time error, you will need to add the following using statement:
using System.Runtime.InteropServices;

4. Next implement Extensibility.IDTExtensibility2 in your class:

namespace web
{
    [ComVisible(true)]
    public class Class1 : Extensibility.IDTExtensibility2
    {
    }
}

5. This will cause a compile time error, you will need to add a reference to:
C:\Program Files (x86)\Common Files\microsoft shared\MSEnv\PublicAssemblies\extensibility.dll
or for 32 bit machines
C:\Program Files\Common Files\microsoft shared\MSEnv\PublicAssemblies\extensibility.dll

6. You will still have a compile time error, you will need to stub out this interface:
     #region IDTExtensibility2 Members
    [ComVisible(true)]
    public class Class1 : Extensibility.IDTExtensibility2
    {
        public void OnAddInsUpdate(ref Array custom) {
            throw new NotImplementedException();
        }

        public void OnBeginShutdown(ref Array custom) {
            throw new NotImplementedException();
        }

        public void OnConnection(object Application, Extensibility.ext_ConnectMode ConnectMode, object AddInInst, ref Array custom){}

        public void OnDisconnection(Extensibility.ext_DisconnectMode RemoveMode, ref Array custom) {
            throw new NotImplementedException();
        }

        public void OnStartupComplete(ref Array custom) {
            throw new NotImplementedException();
        }
    }
    #endregion

7. At this point you should be able to build, the last thing you will want to do is create a method to call from your add-in, something like this should suffice for testing:
        #region JavaScript implementation
        public Class1(){} //CTor
        public String Version() { return "1.0"; } //Version info
        public String TestFunction() { return "MyTestFunction"; } //My test method to call
        #endregion

8. Next up is adding a JavaScript mapping in your manifest. A few bits of information will be needed

a. your DLL name on disk
b. your namespace
c. your class name

 

edit your manifest and a load element within the <addin> element, something like:

<addin>
<name>My</name>
<description>My</description>
<version>1.0</version>
<load type="web.Class1, web" name="utils" />
<panel id="My" title="My" src="my.html" />
</addin>

 

Looking at the load element in depth:

type="web.Class1, web"
web.class1, web == <namespace>.<classname>, <dll name on disk>

AND

name="utils"
utils is the namespace you wish to use in JavaScript to eventually call your methods (more later, but eventually we will call utils.TestFunction() from JavaScript).

9. Given you are following the code above you should create this manifest on disk as addin.xml, copy your web.dll right next to it.

10. create the html page, for this blog I use my.html, with the contents to follow, place it next to the addin.xml and your dll

<html>
<head></head>
<body onload="document.write(utils.TestFunction())">
</body>
</html>

 

11. copy all of your files (addin.xml, web.dll, my.html to a new directory call 'my' (or any name you prefer) in
%appdata%\Microsoft\Expression\Web 4\Addins

12. Run Web 4

13. Under the panels meny you should see My, click that and you will see the return value from
public String TestFunction() { return "MyTestFunction"; }
placed into your document, in this case "MyTestFunction".

There are many usages that come to mind when looking at this functionality, passing a file location of a JPG and resizing it in managed code and then returning the URI or file path back to javascript is one example.

Hope you guys find this useful, if you have any problems I wanted to call out a few common issues I have seen people fall into
1. Make sure your class is public
2. make sure your methods are public

Enjoy!

Comments

  • Anonymous
    August 10, 2010
    I was asked to convert this to vb which seemed simple enough, however it came up with the following error in the ew log: Error: Could not load type 'WebLib.Utilities' from assembly 'WebLib, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'. Here's the conversion: Imports System Imports System.Collections.Generic Imports System.Linq Imports System.Text Imports System.Runtime.InteropServices Namespace WebLib   <ComVisible(True)> _   Public Class Utilities       Implements Extensibility.IDTExtensibility2 #Region "IDTExtensibility2 Members"       Public Sub OnAddInsUpdate(ByRef custom As Array) Implements Extensibility.IDTExtensibility2.OnAddInsUpdate           Throw New NotImplementedException()       End Sub       Public Sub OnBeginShutdown(ByRef custom As Array) Implements Extensibility.IDTExtensibility2.OnBeginShutdown           Throw New NotImplementedException()       End Sub       Public Sub OnConnection(ByVal Application As Object, ByVal ConnectMode As Extensibility.ext_ConnectMode, ByVal AddInInst As Object, ByRef custom As Array) Implements Extensibility.IDTExtensibility2.OnConnection       End Sub       Public Sub OnDisconnection(ByVal RemoveMode As Extensibility.ext_DisconnectMode, ByRef custom As Array) Implements Extensibility.IDTExtensibility2.OnDisconnection           Throw New NotImplementedException()       End Sub       Public Sub OnStartupComplete(ByRef custom As Array) Implements Extensibility.IDTExtensibility2.OnStartupComplete           Throw New NotImplementedException()       End Sub #End Region #Region "JavaScript implementation"       Public Sub New()       End Sub       Public Function Version() As String           Return "1.0"       End Function #End Region #Region "String Helpers"       Public Function ToTitleCase(ByVal strText As String) As String           Dim strConvertedText As String = ""           Try               Dim cultureInfo As System.Globalization.CultureInfo = System.Threading.Thread.CurrentThread.CurrentCulture               Dim TextInfo As System.Globalization.TextInfo = cultureInfo.TextInfo               strConvertedText = TextInfo.ToTitleCase(strText.ToLower())           Catch               strConvertedText = strText           End Try           Return strConvertedText       End Function #End Region   End Class End Namespace Thanks, -krr

  • Anonymous
    August 11, 2010
    Played around with this, repro'd the problem and did finally get it to work... One thing I saw was the namespace VS and VB was giving my .DLL was doubled up (weird). You can check this in .NET Reflector (or just email me your DLL and I can look). But for grins try WebLib.WebLib.Utilities as your namespace in addin.xml (load tag). Note I also changed the property settings in VS to insure Com Visible (VS2010: Properties Application tab, then Click Assembly information. Also on the Properties-Compile tab check the Register for COM interop), lastly I signed the DLL (not sure if this is actually needed) - Properties Signing tab. Let me know!!!!

  • Anonymous
    August 12, 2010
    Well, that was strange. I did have the doubled up namespace problem. I had already set the Com Visible and the Register for COM interop, however I didn't sign the dll so it appears that's not needed. It all boiled down to the doubled up namespace. I do have yet another question. Where is the information for the xweb.legacyapp object? It's not listed on the Expression Web SDK page that I can find. Thanks so much for all your help. -krr

  • Anonymous
    August 12, 2010
    No prob, glad to help! The namespace is indeed odd, took me a while to figure that one out! Regarding LegacyDoc, I am not sure they actually posted help on that (sadly). That said the frontpage OM is online and should map rather closely, let me know and I can see if I can find the MSDN link!

  • Anonymous
    August 12, 2010
    I added references to Microsoft.Expression.Interop.WebDesigner and Microsoft.Expression.Interop.WebDesignerPage, then used the object browser to examine them. It looks like these map fairly well.

  • Anonymous
    May 19, 2011
    I sent you an email via the blog.  We can't get this to work at all and we have been creating adds from FrontPage 98 to Expression web 2.