Calling managed code from Expression Web 4 HTML\JS Extensibility Add-Ins

Calling managed code from Expression Web 4 HTML\JS Extensibility Add-Ins

  • Comments 6

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!
 

Leave a Comment
  • Please add 7 and 6 and type the answer here:
  • Post
  • 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

  • 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!!!!

  • 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

  • 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!

  • 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.

  • 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.  

Page 1 of 1 (6 items)