Introduction to .NET/SML#

Using OLE/SML#, you can access .NET objects from SML# world.

Let's write a SML# code to access a .NET object implemented in the following C# code( HelloDotNETWorld.cs ).

using System.Runtime.InteropServices;

[InterfaceTypeAttribute(ComInterfaceType.InterfaceIsDual)]
public interface IHelloDotNETWorld
{
   string greeting(string yourName);
}

[ClassInterface(ClassInterfaceType.None)]
public class HelloDotNETWorld : IHelloDotNETWorld
{
   public HelloDotNETWorld(){
       System.Console.WriteLine("I am a .NET object.");
   }

   public string greeting(string yourName)
   {
       return "Hello, " + yourName + " !";
   }
};

Compile this code by C# compiler to generate an assembly ( HelloDotNETWorld.dll ).

$ csc.exe /t:library HelloDotNETWorld.cs

Register the assembly.

$ RegAsm.exe /codebase HelloDotNETWorld.dll

Then, generate a type-library ( HelloDotNETWorld.tlb ).

$ TlbExp.exe HelloDotNETWorld.dll

From this type-library, generate a wrapper SML code ( HelloDotNETWorld.sml ).

$ OLE2SML.exe HelloDotNETWorld.tlb

Finally, SML# code can access this .NET object as follows.

use "OLE.sml";

use "./HelloDotNETWorld.sml";

OLE.initialize [OLE.COINIT_MULTITHREADED];

val object = HelloDotNETWorld.newHelloDotNETWorld ();
val message = OLE.A (#greeting object (OLE.L "world"));
val _ = print message;

You can see a message from .NET world.

$ /usr/local/bin/smlsharp
SML# 0.40 (2010-04-30 22:11:29 --)
# use "./UseHelloDotNETWorld.sml";
         :
structure HelloDotNETWorld : HelloDotNETWorld
val it = () : unit
I am a .NET object.
val object =
    {
      AddRef = fn,
      GetTypeInfo = fn,
      GetTypeInfoCount = fn,
      Release = fn,
      addRef = fn,
      greeting = fn,
      release = fn,
      this = fn
    }
    : HelloDotNETWorld.HelloDotNETWorld
val message = "Hello, world !" : String.string
Hello, world !

In another way,

$ /usr/local/bin/smlsharp ./UseHelloDotNETWorld.sml
I am a .NET object.
Hello, world !

Development of .NET/SML# just have started. Interoperability is limited yet. As we will extend OLE/SML# interface, higher level of interoperability with .NET will be possible.

About deployment.

The above example registers the assembly as follows:

$ RegAsm.exe /codebase HelloDotNETWorld.dll

Although this is an easy procedure to access .NET object on the SML# interactive session, it is not a preferred way. You will see a warning from RegAsm.exe.

RegAsm warning: Registering an unsigned assembly with /codebase can
cause your assembly to interfere with other applications that may be
installed on the same computer. The /codebase switch is intended to
be used only with signed assemblies.Please give your assembly a strong
name and re-register it.

http://msdn.microsoft.com/en-us/library/2h3sywsc.aspx says that an assembly should be located at

  • GAC(global assembly cache)(It points to C:\Windows\assembly)
  • the application's directory, in a subdirectory of the application's directory
  • directories specified in a configuration file

Among these, the easiest is to locate the assembly at the application's directory. In our case, however, the application is SML# runtime smlsharprun.exe, and it is inconvenient to install the assembly to the SML# install directory.

If we can generate an executable file from the SML source code, the application can be located at the same directory with the assembly.

Use smlsharp2exe.sh.

$ smlsharp2exe.sh -o UseHelloDotNETWorld.exe ./UseHelloDotNETWorld.sml

The application ( UseHelloDotNETWorld.exe ) and the assembly ( HelloDotNETWorld.dll ) are located at the same directory now.

$ ls
HelloDotNETWorld.cs   HelloDotNETWorld.tlb     UseHelloDotNETWorld.sml
HelloDotNETWorld.dll  Makefile
HelloDotNETWorld.sml  UseHelloDotNETWorld.exe

This application can load the assembly and access a .NET object.

$ ./UseHelloDotNETWorld.exe
I am a .NET object.
Hello, world !
Last modified:2010/06/11 15:10:02
Keyword(s):
References:[Introduction to .NET/SML#] [mapping .NET/SML#] [Tools]