User Guide: Wolfram Mathematica ® Tutorial Collection
User Guide: Wolfram Mathematica ® Tutorial Collection
User Guide: Wolfram Mathematica ® Tutorial Collection
Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
.NET/Link . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
What Is .NET? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
What Is MathLink? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
How Does .NET/Link Compare to J/Link? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
.NET/Link
Welcome to .NET/Link, a product that integrates Mathematica and Microsoft's .NET platform.
.NET/Link lets you call .NET from Mathematica in a completely transparent way, and allows you
to use and control the Mathematica kernel from a .NET program. For Mathematica users,
.NET/Link makes the entire .NET world an automatic extension to the Mathematica environ-
ment. For .NET programmers, .NET/Link turns Mathematica into a scripting shell that lets you
experiment with, build, and test .NET classes a line at a time. It also makes .NET an ideal
environment for writing programs that use the computational services of Mathematica.
.NET/Link’s most unique feature is that it lets you load arbitrary .NET types into Mathematica
and then create .NET objects, call methods, properties, and so on, directly from the Mathemat-
ica language. Thus, you can use Mathematica to “script” the functionality of an arbitrary .NET
program~in effect, write a .NET program in Mathematica. Essentially anything you can do from
.NET, you can now do from Mathematica perhaps even more easily because you are working in
a true interpreted environment.
.NET/Link also lets you do some very useful things that do not appear to directly involve the
.NET runtime. These include calling C-style DLL functions directly from Mathematica, and creat-
ing and scripting COM objects, much like Visual Basic can do.
.NET/Link is designed for end-users and developers alike. The same features that let Mathemat-
ica users transparently call any .NET method also let developers create sophisticated commer-
cial add-ons to Mathematica. Programmers who want to write custom front ends for Mathemat-
ica or use Mathematica as a computational engine for another program will find using .NET with
.NET/Link is easier than using the traditional MathLink interface from C or C++.
Finally, .NET/Link comes with full source code. You can examine the code to supplement the
documentation, get tips for your own programs, better understand how to use advanced fea-
tures, or just see how it works.
Some familiarity with both the .NET Framework and Mathematica is assumed in this manual. In
Part 2, which covers writing .NET programs that call Mathematica, major examples are gener-
ally provided in both C# and Visual Basic .NET versions, although overall the documentation is
perhaps slightly more C#-centric. Naturally, when writing .NET programs that use .NET/Link,
you can use any .NET-aware language, not just C# and Visual Basic .NET.
2 .NET/Link User Guide
Some familiarity with both the .NET Framework and Mathematica is assumed in this manual. In
Part 2, which covers writing .NET programs that call Mathematica, major examples are gener-
ally provided in both C# and Visual Basic .NET versions, although overall the documentation is
perhaps slightly more C#-centric. Naturally, when writing .NET programs that use .NET/Link,
you can use any .NET-aware language, not just C# and Visual Basic .NET.
"Calling .NET from Mathematica" shows how you use .NET/Link to call .NET from Mathematica
and "Calling Mathematica from .NET" shows how to call Mathematica from .NET.
What Is .NET?
.NET is a new development platform for Windows programming. It replaces essentially every-
thing that came before it, including an entire alphabet soup of programming technologies such
as MFC, COM, ActiveX, ATL, ASP, ADO, and many others. Although Microsoft emphasizes XML
Web Services in conjunction with .NET, XML Web Services are only a small part of the .NET
platform, and the success of .NET is not dependent on the widespread adoption of XML Web
Services.
.NET represents the future of Windows programming, and Microsoft is rapidly shifting more and
more of its technology and products to a .NET foundation.
At the core of .NET is a runtime engine, similar to that used by Java, that loads and executes
programs compiled into special bytecodes that the runtime understands. This runtime is called
the Common Language Runtime (CLR), but we will often refer to it as the .NET runtime. A key
feature of this system is that many languages can be compiled into CLR bytecodes and exe-
cuted by the runtime. This means that .NET is language-neutral, supporting any programming
language for which a .NET compiler is available. Microsoft provides compilers for C#, Visual
Basic .NET, JScript, Visual J# .NET, and C++ With Managed Extensions. Many other compilers
exist, including ones for Fortran, Perl, Python, Eiffel, COBOL. You can even create a class in one
.NET language, say Visual Basic .NET, and subclass it in another language.
Although .NET is language-neutral, probably the two most important .NET languages are Visual
Basic .NET, a modification of the Visual Basic language, and C#, a new language that is similar
in many ways to Java.
.NET/Link User Guide 3
What Is MathLink?
MathLink is Wolfram Research’s protocol for sending data and commands back and forth
between Mathematica and other programs. MathLink is the underlying glue that lets .NET and
Mathematica talk to each other. When calling .NET from Mathematica, .NET/Link completely
hides the low-level details of the MathLink communication, allowing Mathematica programmers
to load and use .NET classes as if they were part of the Mathematica environment itself. When
writing .NET programs that call Mathematica, .NET/Link provides a higher-level layer of function-
ality than the traditional C MathLink programming interface.
.NET/Link and J/Link provide a very similar programming model. Familiarity with one will be
very helpful when working with the other.
4 .NET/Link User Guide
Introduction
.NET/Link provides Mathematica users with the ability to interact with arbitrary .NET types
directly from Mathematica. You can create objects and call methods and properties directly in
the Mathematica language. You do not need to write any .NET code, or prepare in any way the
.NET types you want to use. You also do not need to know anything about MathLink. In effect,
all of .NET becomes a transparent extension to Mathematica, almost as if every existing and
future .NET type were written in the Mathematica language itself.
We call this facility “installable .NET” because it generalizes the ability that Mathematica has
always had to plug in extensions written in other languages through the Install function.
Compared to other languages like C or C++, however, .NET/Link makes the intermediate steps
go away completely, which is why we say that .NET becomes a transparent extension to
Mathematica.
To Mathematica users, then, the “installable .NET” feature of .NET/Link opens up the universe
of .NET types as an extension to Mathematica; for .NET users, it allows the extraordinarily
powerful and versatile Mathematica environment to be used as a shell for interactively develop-
ing, experimenting with, and testing .NET programs.
This guide discusses calling from Mathematica into the .NET runtime. You will see how to load
.NET assemblies and types into Mathematica, create objects of these types, call methods and
properties, and so on. You will also learn how to use .NET/Link to call COM objects as well as
standard C-style DLL functions.
.NET/Link User Guide 5
Simple Examples:
ProcessPriority.nb
GUI Examples:
Circumcircle.nb
PackageHelper.nb
SimpleAnimationWindow.nb
RealTimeAlgebra.nb
AsteroidsGame.nb
Calling DLLs:
BZip2Compression.nb
EnumWindows.nb
WindowsAPI.nb
ExcelPieChart.nb
Needs@“NETLink`“D
6 .NET/Link User Guide
InstallNET@D;
If you are actively developing .NET classes and other types to use in Mathematica, you will
need to restart the .NET runtime before you can reload a modified version of a class. Use the
ReinstallNET function to quit and restart the .NET runtime. Most users will have no need to
ever quit or restart .NET and should avoid calling ReinstallNET or UninstallNET. Remember
that the .NET runtime is shared by potentially many programs in your Mathematica session.
Shutting down or restarting the .NET runtime could have unexpected consequences for those
programs.
InstallNET@D launch the .NET runtime and prepare it for use from
Mathematica
ReinstallNET@D quit and restart the .NET runtime
NETLink@D give the LinkObject that is being used to communicate
with the .NET runtime
.NET Assemblies
Programs and libraries for .NET are packaged into units called assemblies. An assembly can be
defined as a versioned, self-describing binary (DLL or EXE) containing a collection of types
(classes, interfaces, structs, and so on) and optional resources. An assembly can span multiple
files (a multi-file assembly), or a single file can contain more than one assembly, but in the
typical case an assembly consists of a single DLL or EXE file. Although .NET assemblies can
have the DLL extension, internally they are quite different from old C-style DLLs. Conceptually,
though, a .NET DLL is similar to a C-style DLL in that they are both libraries of code intended to
be loaded and called by other programs. An EXE assembly is an executable program that can
be launched directly, but it also can export types like a DLL for use by other programs.
Assemblies can be located anywhere on your system. The .NET Framework maintains a special
location on your system where assemblies can be stored so that they can easily be found by all
.NET programs on the system. This location is called the Global Assembly Cache (GAC), and is
.NET/Link User Guide 7
Assemblies can be located anywhere on your system. The .NET Framework maintains a special
location on your system where assemblies can be stored so that they can easily be found by all
.NET programs on the system. This location is called the Global Assembly Cache (GAC), and is
found in the assembly subdirectory of your root Windows directory. The assemblies that are
part of the .NET Framework itself are located in the GAC, and many .NET programs that you
install will put assemblies there. There is no requirement that an assembly be placed into the
GAC, and .NET/Link can use assemblies located anywhere on your system.
Because all .NET types are packaged into assemblies, to load a type into Mathematica you first
need to load its assembly. You use the LoadNETAssembly function to load an assembly into
.NET/Link. Assemblies can be loaded by specifying various types of information about the
assembly, such as a full path to the assembly file, or by a full or partial name of the assembly.
Assembly names will be discussed in more detail later, but for now it suffices to say that assem-
bly names are assigned by their creators, and may bear no resemblance to the name of the
actual assembly file. An example of a simple assembly name is System.XML, which is the
assembly in the .NET Framework that handles XML-related functionality. Assemblies are often
named after the most important namespace they define. The actual file name of the SysÖ
tem.XML assembly is System.XML.dll, and it is located somewhere nested deep down inside
the GAC.
.NET/Link does not need to be explicitly instructed to load all assemblies. It will automatically
load any of the .NET Framework assemblies, meaning all of the assemblies containing types
whose names start with System. (e.g., System.Windows.Forms.Form, System.Drawing.RectÖ
angle, System.Data.DataSet, and so on). Most of the types that you will use in .NET/Link
programming are found in the system assemblies. You will have to manually load other assem-
blies. The LoadNETAssembly function, described later in this tutorial, is the Mathematica func-
tion you use to load assemblies into .NET/Link and prepare them to be used from Mathematica.
.NET Types
A type is the fundamental unit of .NET programming. Every type falls into one of the following
categories: classes, interfaces, structs ("value types"), enumerations, and delegates. Every
object in .NET is an instance of some type. Although the set of types is broader than just
classes, you might find it easier to think of types as being classes.
Types are defined in assemblies. To load and use a type in .NET/Link, you must first load the
assembly in which it resides and then load the type itself. Often these steps can be combined
into a single operation. LoadNETType , described later , is the Mathematica function that you use
to load types into .NET/Link so they can be used from Mathematica.
8 .NET/Link User Guide
Types are defined in assemblies. To load and use a type in .NET/Link, you must first load the
assembly in which it resides and then load the type itself. Often these steps can be combined
into a single operation. LoadNETType , described later , is the Mathematica function that you use
to load types into .NET/Link so they can be used from Mathematica.
LoadNETAssembly
LoadNETAssembly is the function you use to load assemblies into .NET/Link so that the types
they contain can be used from Mathematica. LoadNETAssembly has a number of different argu-
ment sequences. Although all these different possible arguments might seem confusing, the
basic principle is to allow virtually any way of specifying enough information about the assem-
bly so that .NET/Link can locate it.
Loading assemblies.
Here is an example of using LoadNETAssembly to load an assembly that is part of the .NET
Framework.
In[3]:= LoadNETAssembly@“System.Web“D
Out[3]= [email protected], 1D
The return value of LoadNETAssembly is a NETAssembly expression. This is not a .NET object
itself, just a special expression that can be used in .NET/Link to refer to a loaded assembly in
various functions that take an assembly specification as an argument.
The name used in the previous example is the simple name of the assembly. The actual full
name, or display name, of the assembly is longer and contains version information, among
other things. You can use the full name if you want to force a certain version to be loaded (note
that if you execute this on your machine, it will fail unless you have exactly the same version of
the .NET Framework installed).
.NET/Link User Guide 9
The name used in the previous example is the simple name of the assembly. The actual full
name, or display name, of the assembly is longer and contains version information, among
other things. You can use the full name if you want to force a certain version to be loaded (note
that if you execute this on your machine, it will fail unless you have exactly the same version of
the .NET Framework installed).
We were able to load this assembly based on only its name, without any location information,
because it is located in the GAC.
As another example of LoadNETAssembly, say you have obtained an assembly or created one of
your own in some .NET language and want to load it into .NET/Link to use from Mathematica.
The assembly is in the file c:\MyProgram\Bin\Debug\MyAssembly.dll. Here is how you
would load it.
LoadNETAssembly@“c:\\MyProgram\\Bin\\Debug\\MyAssembly.dll“D
Loading an assembly by specifying its path is useful for assemblies that you have created
yourself.
In this way, application developers can bundle private assemblies in their application layout and
not require that their users perform any special installation steps such as copying assemblies
into the GAC.
10 .NET/Link User Guide
LoadNETType
LoadNETType is the Mathematica function that loads .NET types so that they can be used from
Mathematica. It is often not necessary to explicitly call LoadNETType . Whenever a .NET object is
returned to Mathematica, its type is loaded. This means that if you want to create a new object
of a certain type, you can just call NETNew and the type will be loaded when the object is
returned to Mathematica. The most common reason for calling LoadNETType directly is if you
want to use a static method or property from a type. In that case, you are not creating an
object with NETNew, so you must manually load the type.
Loading types.
In[5]:= LoadNETType@“System.Windows.Forms.Form“D
Out[5]= [email protected], 1D
The return value of LoadNETType is a NETType expression. This is not a .NET object itself, just a
special expression that can be used in .NET/Link to refer to a .NET type in various functions
that take a type specification as an argument.
Note that you must supply the full type name, including the namespace prefix
(System.Windows.Forms in this example). For the load to succeed, the assembly in which the
type resides must be already loaded using LoadNETAssembly. As mentioned earlier, assemblies
for all System types are automatically loaded as needed by .NET/Link, so there was no need to
load the System.Windows.Forms assembly manually in the previous example.
.NET/Link User Guide 11
.NET/Link always creates a definition for Foo in a context that mirrors its fully qualified class-
name: MyCompany`Utilities`MyClass`Foo. This is done to avoid conflicting with symbols
named Foo that might be present in other contexts. However, you might find it clumsy to have
to call Foo by typing the full context name every time, as in MyCompany`Utilities`MyClass`Ö
Foo[args]. The option AllowShortContext -> True (this is the default setting) causes
.NET/Link to also make definitions for Foo accessible in a shortened context, one that consists
of just the class name without the hierarchical namespace prefix. In our example, this means
that you could call Foo as simply MyClass`Foo[args]. If you need to avoid use of the short
context because there is already a context of the same name in your Mathematica session, you
can use AllowShortContext -> False. This forces all names to be put only in the “deep” con-
text. Note that even with AllowShortContext -> True, names for statics are also put into the
deep context, so you can always use the deep context to refer to a symbol if you desire.
of just the class name without the hierarchical namespace prefix. In our example, this means
that
12 you could
.NET/Link Usercall
GuideFoo as simply MyClass`Foo[args]. If you need to avoid use of the short
context because there is already a context of the same name in your Mathematica session, you
can use AllowShortContext -> False. This forces all names to be put only in the “deep” con-
text. Note that even with AllowShortContext -> True, names for statics are also put into the
deep context, so you can always use the deep context to refer to a symbol if you desire.
AllowShortContext, then, lets you control the context where the symbol names are defined.
The other option, StaticsVisible, controls whether this context is made visible (put on
$ContextPath) or not. The default is StaticsVisible -> False, so you have to use a context
name when referring to a symbol, as in MyClass`Foo[args]. With StaticsVisible -> True,
MyClass` will be put on $ContextPath, so you could just write Foo[args]. Having the default
be True would be a bit dangerous~every time you load a class a potentially large number of
names would suddenly be created and made visible in your Mathematica session, opening up
the possibility for all sorts of “shadowing” problems if symbols of the same names were already
present (see Contexts for a discussion of contexts and shadowing problems).
For these reasons StaticsVisible -> True is recommended only for classes that you have
written, or ones whose contents you are familiar with. In such cases, it can save you some
typing, make your code more readable, and prevent the all-too-easy bug of forgetting to type
the classname prefix. A classic example would be implementing the venerable “addtwo” Math-
Link example program. In C#, it might look like this.
With the default StaticsVisible -> False, you would have to call addtwo as
AddTwo`AddTwo@3, 4D. Setting StaticsVisible -> True lets you write the more obvious
AddTwo@3, 4D.
Be reminded that these options are only for static methods and fields. As discussed later, non-
statics are handled in a way that makes context and visibility issues go away completely.
Note that this table gives type names as they are used in the .NET Framework. Different lan-
guages often have their own keywords that map to these underlying types. In C#, for example,
the keyword int is an alias to the Int32 type, and in Visual Basic .NET the Int32 type is called
Integer.
.NET arrays are mapped to Mathematica lists of the appropriate depth. Thus, when you call a
method that takes a double@D (in C# notation), you might pass it 81.0, 2.0, N@PiD, 1.23<.
Similarly, a method that returns a two-deep array of integers (int@, D in C# notation) might
return to Mathematica the expression 881, 2, 3<, 85, 3, 1<<.
Creating Objects
14 .NET/Link User Guide
Creating Objects
To construct .NET objects, use the NETNew function. The first argument to NETNew is the object’s
type, specified either as a NETType expression returned from LoadNETType or as a string giving
the fully qualified type name (i.e., including the namespace prefix). If you wish to supply any
arguments to the object’s constructor, they follow as a sequence after the type.
The return value from NETNew is a strange expression that looks like it has the head NETObÖ
ject, except that it is enclosed in angle brackets. The angle brackets are used to indicate that
the form in which the expression is displayed is quite different from its internal representation.
These expressions will be referred to as NETObject expressions. NETObject expressions are
displayed in a way that shows their type name, but you should consider them opaque, meaning
that you cannot pick them apart or peer into their insides. You can only use them in .NET/Link
functions that take NETObject expressions.
NETNew invokes a .NET constructor appropriate for the types of the arguments being passed in,
and then returns to Mathematica what is, in effect, a reference to the object. That is how you
should think of NETObject expressions~as references to .NET objects very much like object
references in a .NET language like C# or Visual Basic .NET. What is returned to Mathematica is
not large no matter what type of object you are constructing. In particular, the object’s data
(that is, its fields) are not sent back to Mathematica. The actual object remains on the .NET
side, and Mathematica gets a reference to it.
.NET/Link User Guide 15
The previous examples specified the class by giving its name as a string. You can also use a
NETType expression, which is a special expression returned by LoadNETType that identifies a
class. When you specify the class name as a string, the class is loaded if it has not already been.
NETNew is not the only way to get a reference to a .NET object in Mathematica. Many methods
and properties return objects, and when you call such a method or property, a NETObject
expression is created. Such objects can be used in the same way as ones you explicitly con-
struct with NETNew.
Syntax
The Mathematica syntax for calling .NET methods and accessing fields is very similar to the
syntax used in C# and Visual Basic .NET. The box below compares the Mathematica and C#
ways of calling constructors, methods, properties, fields, static methods, static properties, and
static fields. You can see that Mathematica programs that use .NET are written in almost
exactly the same way as C# (or VB .NET) programs, except Mathematica uses [] instead of ()
for arguments and @ instead of the . (dot) as the “member access” operator.
An exception is that for static methods, Mathematica uses the context mark ` in place of the
dot used by C# and VB. This parallels the usage in those languages also, as their use of the dot
in this circumstance is really as a scope resolution operator (like :: in C++). Although Mathemat-
ica does not use this terminology, its scope resolution operator is the context mark. .NET name-
space names map directly to Mathematica’s hierarchical contexts.
16 .NET/Link User Guide
Constructors
C Ò: MyClass obj = new MyClass(args);
Mathematica: obj = NETNew["MyClass", args];
Methods
C Ò: obj.MethodName(args);
Mathematica: obj@MethodName[args]
Properties and fields
C Ò: obj.PropertyOrFieldName = 1;
value = obj.PropertyOrFieldName;
Mathematica: obj@PropertyOrFieldName = 1;
value = obj@PropertyOrFieldName;
Static methods
C Ò: MyClass.StaticMethod(args);
Mathematica: MyClass`StaticMethod[args];
Static properties and fields
C Ò: MyClass.StaticPropertyOrField = 1;
value = MyClass.StaticPropertyOrField;
Mathematica: MyClass`StaticPropertyOrField = 1;
value = MyClass`StaticPropertyOrField;
You may already be familiar with ü as a Mathematica operator for applying a function to an
argument: f ü x is equivalent to the more commonly used f @xD. .NET/Link does not usurp ü for
some special operation~it is really just normal function application slightly disguised. This
means that you do not have to use ü at all. The following are equivalent ways of invoking a
method.
H* These are equivalent *L
obj ü Method@argsD;
obj@Method@argsDD;
The first form preserves the natural mapping of the syntax of most .NET languages into Mathe-
matica and will be used exclusively in this manual.
When you call methods, properties, or fields and get results back, .NET/Link automatically
converts arguments and results to and from their Mathematica representations according to the
table presented earlier.
In object-oriented languages, method and field names are scoped by the object on which they
are called. In other words, when you write obj.Meth(), .NET languages know that you are
calling the method named Meth that resides in obj’s class, even though there may be other
methods named Meth in other classes. .NET/Link preserves this scoping for Mathematica sym-
bols so that there is never a conflict with existing symbols of the same name. When you write
.NET/Link User Guide 17
In object-oriented languages, method and field names are scoped by the object on which they
are called. In other words, when you write obj.Meth(), .NET languages know that you are
calling the method named Meth that resides in obj’s class, even though there may be other
methods named Meth in other classes. .NET/Link preserves this scoping for Mathematica sym-
bols so that there is never a conflict with existing symbols of the same name. When you write
obj@Meth[], there is no conflict with any other symbols named Meth in the system~the sym-
bol Meth used by Mathematica in the evaluation of this call is the one set up by .NET/Link for
this class. Here is an example using a field. First, we create a Point object.
In[9]:= pt = NETNew@“System.Drawing.Point“D
Out[9]= «[email protected] »
The Point class has fields named X and Y, which hold its coordinates. A user’s session might
also have symbols named X or Y in it, however. Let us set up a definition for X that will tell us
when it is evaluated.
In[10]:= X := Print@“gotcha“D
Now set a value for the field named X (this would be written as pt.X = 42 in C# or VB).
In[11]:= pt ü X = 42;
You will notice that “gotcha” was not printed. There is no conflict between the symbol X in the
Global` context that has the Print definition and the symbol X that is used during the evalua-
tion of this line of code. .NET/Link protects the names of members on the right-hand side of @
so that they do not conflict with, or rely on, any definitions that might exist for these symbols in
visible contexts.
In summary, for nonstatic methods, properties, and fields, you never have to worry about
name conflicts and shadowing, no matter what context you are in or what the $ContextPath is
at the moment. This is not true for static members, however. Static methods and fields are
called by their full name, without an object reference, so there is no object out front to scope
the name. Here is a simple example of a static method call that invokes the .NET garbage
collector. We need to call LoadNETType before we call a static method to make sure the class
has been loaded.
In[12]:= LoadNETType@“System.GC“D;
GC`Collect@D;
The name scoping issue is not usually a problem with static members because they are defined
in their own contexts (GC` in this example). These contexts are usually not on $ContextPath,
so you do not have to worry that there is a symbol of the same name in the Global` context or
in a package that has been read. If there is already a context named GC` in your session, and it
has its own function Collect, you can always avoid a conflict by using the fully-hierarchical
18 .NET/Link User Guide
The name scoping issue is not usually a problem with static members because they are defined
in their own contexts (GC` in this example). These contexts are usually not on $ContextPath,
so you do not have to worry that there is a symbol of the same name in the Global` context or
in a package that has been read. If there is already a context named GC` in your session, and it
has its own function Collect, you can always avoid a conflict by using the fully-hierarchical
context name that corresponds to the full type name for a static member.
In[14]:= System`GC`Collect@D;
But when you call a static method in such a class, the hierarchical context name is symbolic, so
you must convert the underscore to U.
MyUClass`StaticMethod@D;
The same rule applies to method and field names. To refer to such names in code, use the U.
Here is how to call a property named Some_Property.
NETTypeInfo
It is often convenient to be able to quickly display information about the methods, properties,
fields, and so on that exist in a given .NET type. .NET/Link provides the NETTypeInfo function
to obtain this information.
.NET/Link User Guide 19
NETTypeInfo @typeNameD print information about all the members in the given type
NETTypeInfo @typeName,membersD print information about just the desired types of members
in the given type
NETTypeInfo @ print information about the desired types of members
typeName,members,“pat“D whose names match a string pattern
NETTypeInfo @objD print information about all the members in the object's type
NETTypeInfo @NETAssemblyD print information about all the types in the given assembly
NETTypeInfo will load the type if it has not already been loaded.
NETTypeInfo@“System.Diagnostics.Process“D
The second argument to NETTypeInfo is an optional list of the members you want to see dis-
played. The possible values are “Type“ (gives general info about the type itself),
“Constructors“, “Methods“, “Properties“, “Fields“, and “Events“. This will show just
the properties and methods.
NETTypeInfo@“System.Diagnostics.Process“, 8“Methods“, “Properties“<D
This will show just properties with names that begin with "Peak".
The default behavior is to display the members in C# syntax. If you want to see them in Visual
Basic .NET syntax, use the LanguageSyntax option.
NETTypeInfo@“System.Diagnostics.Process“, LanguageSyntax Ø “VisualBasic“D
Options to NETTypeInfo .
NETTypeInfo is also useful for seeing what types are in an assembly. To investigate an assem-
bly, pass a NETAssembly expression as the first argument. The easiest way to get a
NETAssembly expression is to call LoadNETAssembly (even if the assembly is already loaded).
The following line will show a lot of types.
20 .NET/Link User Guide
NETTypeInfo is also useful for seeing what types are in an assembly. To investigate an assem-
bly, pass a NETAssembly expression as the first argument. The easiest way to get a
NETAssembly expression is to call LoadNETAssembly (even if the assembly is already loaded).
The following line will show a lot of types.
NETTypeInfo@LoadNETAssembly@“System.Data“DD
When acting on a NETAssembly , the second argument to NETTypeInfo is an optional list of the
types you want to see displayed. The possible values are “Classes“, “Interfaces“,
“Structures“, “Delegates“, and “Enums“. This will show just the classes and interfaces with
the word "Data" in their names.
NETTypeInfo@LoadNETAssembly@“System.Data“D, 8“Classes“, “Interfaces“<, “*Data*“D
NETObjectQ is convenient when you need to test whether an expression is a .NET object refer-
ence. It is often used as a pattern test in function definitions.
f[x_?NETObjectQ] := ...
.NET/Link uses special expressions with heads NETType (returned by LoadNETType ) and
NETAssembly (returned by LoadNETAssembly) to represent .NET types and assemblies in
Mathematica. As noted earlier, you can pass these expressions to functions that take types or
assemblies as arguments (such as NETNew). There are times when you might want not a
NETType expression, but an actual .NET Type object reference for a given type, and likewise for
an assembly. You can use GetTypeObject to get the Type object corresponding to a NETType
expression, and GetAssemblyObject to get the .NET Assembly object.
.NET/Link User Guide 21
Notice above that the NETType expression is much more informative about what type it
represents than the Type object. This is one reason why .NET/Link uses special NETType and
NETAssembly expressions instead of just Type and Assembly objects.
Once you have a Type object, you can use methods and properties of the Type class to learn
about it.
There are some exceptions to this last rule, meaning that sometimes when an object is
returned to Mathematica a new and different NETObject expression is created for it, even
though this same object has previously been sent to Mathematica. Specifically, any time an
object’s hash value (as determined by the object’s built-in GetHashCode() method) has
changed since the last time it was seen in Mathematica, the NETObject expression created will
be different. You do not really need to be concerned with the details of this, except to remem-
ber that Mathematica's SameQ function is not a valid way to compare NETObject expressions to
decide whether they refer to the same object. You must use the SameObjectQ function.
returned to Mathematica a new and different NETObject expression is created for it, even
though
22 this User
.NET/Link same object has previously been sent to Mathematica. Specifically, any time an
Guide
object’s hash value (as determined by the object’s built-in GetHashCode() method) has
changed since the last time it was seen in Mathematica, the NETObject expression created will
be different. You do not really need to be concerned with the details of this, except to remem-
ber that Mathematica's SameQ function is not a valid way to compare NETObject expressions to
decide whether they refer to the same object. You must use the SameObjectQ function.
SameObjectQ @obj1,obj2D return True if the NETObject expressions obj1 and obj2
refer to the same .NET object, return False otherwise
Here is an example.
In[1]:= pt = NETNew@“System.Drawing.Point“, 1, 1D
Out[1]= «[email protected] »
The variable pt refers to a .NET Point object. Now put it into a container so you can get it
back out later.
Now change the value of one of its coordinates. For a Point object, this changes its hash value.
In[4]:= pt ü X = 2;
Now compare the NETObject expression given by pt and the NETObject expression created
when you ask for the first element of the ArrayList to be returned to Mathematica. Even
though these are both references to the same .NET object, the NETObject expressions are
different. Recall that the ArrayList class defines an indexer (in C# terminology), so you can
use the @D notation to refer to an element by index.
Because you cannot use SameQ (===) to decide whether two object references in Mathematica
refer to the same .NET object, .NET/Link provides the SameObjectQ function for this purpose.
You may be wondering why the SameObjectQ function is useful. Can’t you just call an object’s
Equals() method? It certainly gives the correct result for this example.
.NET/Link User Guide 23
In[7]:= pt ü Equals@vec@0DD
Out[7]= True
The problem with this technique is that Equals() does not always compare object references.
Any class is free to override Equals() to provide any desired behavior for comparing two
objects of that class. Some classes make Equals() compare the “contents” of the objects, such
as the String class, which uses it for string comparison. The function that provides the correct
test is the static method ReferenceEquals().
You can think of SameObjectQ as a convenience function that does the same thing as explicitly
calling ReferenceEquals().
In an unusual case where you need to compare object references for equality a very large
number of times, the slowness of SameObjectQ compared to SameQ could become an issue. The
only thing that could cause two NETObject expressions that refer to the exact same .NET
object to not be SameQ is if the hash value of the object changed between the times that the
two NETObject expressions were created. If you know this has not happened, you can safely
use SameQ to test whether they refer to the same object.
ReleaseNETObject
The .NET runtime has a built-in facility called “garbage collection” for freeing up memory occu-
pied by objects that are no longer in use by a program. Objects become eligible for garbage
collection when no references to them exist anywhere, except perhaps in other objects that are
also unreferenced. When an object is returned to Mathematica, either as a result of a call to
NETNew or as the return value of a method or property, the .NET/Link code holds a special
reference to the object on the .NET side to ensure that it cannot be garbage-collected while it is
in use by Mathematica. If you know that you no longer need to use a given .NET object in your
Mathematica session, you can explicitly tell .NET/Link to release its reference. The function that
does this is ReleaseNETObject. In addition to releasing the Mathematica-specific reference in
.NET, ReleaseNETObject clears out internal definitions that were created in Mathematica for
the object. Any subsequent attempt to use this object in Mathematica will fail.
Now tell .NET that you no longer need to use this object from Mathematica.
24 .NET/Link User Guide
Now tell .NET that you no longer need to use this object from Mathematica.
In[10]:= ReleaseNETObject@frmD
It is now an error to refer to frm because the object’s symbolic representation has been
removed from the Mathematica session. This is what you see if you try to use the released
object.
ReleaseNETObject@objD let .NET know that you are done using obj in Mathematica
NETBlock@exprD all novel .NET objects returned to Mathematica during the
evaluation of expr will be released when expr finishes
BeginNETBlock@D all novel .NET objects returned to Mathematica between
now and the matching EndNETBlock[] will be released
EndNETBlock @D release all novel objects seen since the matching
BeginNETBlock[]
LoadedNETObjects@D return a list of all objects that are in use in Mathematica
An important fact about the references .NET/Link maintains for objects sent to Mathematica is
that only one reference is kept for each object, no matter how many times it is returned to
Mathematica. It is your responsibility to make sure that after you call ReleaseNETObject, you
never attempt to use that object through any reference that might exist to it in your Mathemat-
ica session.
If you call ReleaseNETObject@ frm1D, it is not the Mathematica symbol frm1 that is affected but
the .NET object that frm1 refers to. Therefore, using frm2 is also an error (or any other way to
refer to this same Form object).
Calling ReleaseNETObject is often unnecessary in casual use. If you are not making heavy use
of .NET in your session, then you will not usually need to be concerned about keeping track of
what objects may or may not be needed anymore~you can just let them pile up. There are
times, though, when memory use in .NET will be important, and you may need the extra con-
trol that ReleaseNETObject provides.
.NET/Link User Guide 25
Calling ReleaseNETObject is often unnecessary in casual use. If you are not making heavy use
of .NET in your session, then you will not usually need to be concerned about keeping track of
what objects may or may not be needed anymore~you can just let them pile up. There are
times, though, when memory use in .NET will be important, and you may need the extra con-
trol that ReleaseNETObject provides.
NETBlock
ReleaseNETObject is provided mainly for developers who are writing code for others to use.
Because it is not possible to predict how code will be used, developers should always be sure
that their code cleans up any unnecessary references it creates. Probably the most useful
function for this is NETBlock.
NETBlock automates the process of releasing objects encountered during the evaluation of an
expression. Often, a Mathematica program will need to create some .NET objects with NETNew;
operate with them, perhaps causing other objects to be returned to Mathematica as the results
of method calls; and finally return some result such as a number or string. Every .NET object
encountered by Mathematica during this operation is needed only during the lifetime of the
program, much like the local variables provided in Mathematica by Block and Module, and in
C#, C++, Java, and many other languages by block scoping constructs (e.g., {}). NETBlock
allows you to mark a block of code as having the property that any new objects returned to
Mathematica during the evaluation are to be treated as temporary and released when NETBlock
finishes.
It is important to note that the preceding sentence said “new objects.” NETBlock will not cause
every object encountered during the evaluation to be released~only those that are being
encountered for the first time. Objects that have already been seen by Mathematica will not be
affected. This means that you do not have to worry that NETBlock will aggressively release an
object that is not truly temporary to that evaluation.
It is not enough simply to call ReleaseNETObject on every object you create with NETNew,
because many .NET methods and properties return objects. You might not be interested in
these return values. You might never assign them to a named variable because they may be
chained together with other calls (as in obj@ReturnsObject[]@Foo[]), but you still need to
release them. Using NETBlock is an easy way to be sure that all novel objects are released
when a block of code finishes.
MyFunc@args__D :=
NETBlock@
Module@8locals<,
...
D
D
It is very common to write a function that creates a number of NETObject expressions and then
returns one of them, the rest being temporary. To facilitate this, if the return value of a
NETBlock is a single NETObject, it will not be released.
MyOtherFunc@args__D :=
NETBlock@
Module@8obj<,
...
obj = NETNew@“System.Windows.Forms.Form“D;
...
Return@objD
H* OK: obj will not be released when NETBlock finishes. *L
D
D
If you want more control over which objects are allowed to escape from a NETBlock, you can
use the KeepNETObject function. Calling KeepNETObject on a single object or sequence of
objects means they will not be released when the first enclosing NETBlock ends. If there is an
outer enclosing NETBlock, the objects will be freed when it ends, however, so if you want the
objects to escape a nested set of NETBlocks, you must call KeepNETObject at each level. Alter-
natively, you can call KeepNETObject@obj, ManualD, where the Manual argument tells
.NET/Link that the object should not be released by any enclosing NETBlocks. The only way
such object will be released is if you manually call ReleaseNETObject on it.
KeepNETObject@obj1,obj2,...D do not release the given objects when the NETBlock ends
KeepNETObject@obj1,ManualD do not release the given object when any NETBlock ends
Here is an example that uses KeepNETObject to allow you to return a list of two objects without
releasing them.
.NET/Link User Guide 27
MyOtherFunc[args__] :=
Module[{obj1, obj2, obj3},
NETBlock[
obj1 = NETNew[“System.Windows.Forms.Form“;
obj2 = NETNew[“System.Windows.Forms.Button“];
obj3 = NETNew[“SomeTemporaryObject“];
...
KeepNETObject[obj1, obj2];
{obj1, obj2}
]
]
BeginNETBlock and EndNETBlock can be used to provide the same functionality as NETBlock
across more than one evaluation. EndNETBlock releases all novel .NET objects returned to
Mathematica since the previous matching BeginNETBlock. These functions are mainly of use
during development, when you might want to set a mark in your session, do some work, and
then release all novel objects returned to Mathematica since that point. BeginNETBlock and
EndNETBlock can be nested. Every BeginNETBlock should have a matching EndNETBlock ,
although it is not a serious error to forget to call EndNETBlock , even if you have nested levels
of them~you will only fail to release some objects.
LoadedNETObjects
LoadedNETObjects@D returns a list of all .NET objects that are currently referenced in Mathemat-
ica. This includes all objects explicitly created with NETNew and all those that were returned to
Mathematica as the result of a .NET method or property. It does not include objects that have
been released with ReleaseNETObject or through NETBlock. LoadedNETObjects is intended
mainly for debugging. It is very useful to call it before and after some function you are working
on. If the list grows, your function leaks references, and you need to examine its use of
NETBlock and/or ReleaseNETObject.
Enums
Enumerations in .NET are a special kind of class, with each member of the enumeration repre-
sented as a static constant field in the class. Although the values of enumeration constants are
integers, .NET/Link does not convert them into integers when they are returned to Mathemat-
ica. This is because enum values are probably only going to be passed back into some other
.NET method~it is not likely that you will want to operate on them as integers in Mathematica.
In this case, it is more meaningful to have them appear in Mathematica as objects of a class
instead of just cryptic integer values.
Suppose you have a Button object btn that you want to anchor in a form so that it stays in a
fixed position with respect to one or more edges as the form is resized. To do this, you set the
28 .NET/Link User Guide
Suppose you have a Button object btn that you want to anchor in a form so that it stays in a
fixed position with respect to one or more edges as the form is resized. To do this, you set the
button’s Anchor property to a value from the AnchorStyles enum. First load the
AnchorStyles type, as is always necessary when you want to access a static member of the
type.
In[16]:= LoadNETType@“System.Windows.Forms.AnchorStyles“D
Out[16]= [email protected], 6D
You refer to a member of this enum just like any other static field.
In[17]:= AnchorStyles`Top
Out[17]= «[email protected] »
The enum is represented in Mathematica by a strongly typed object reference that is more
meaningful to a programmer than the raw integer value, which happens to be 1. We can use
the NETObjectToExpression function to convert the object reference to its integer value.
In[18]:= NETObjectToExpression@AnchorStyles`TopD
Out[18]= 1
For any argument that is typed as an enum, you can pass either an instance of the enum class
or a raw integer value. This means that the above line could also be written as the following,
although it is obviously much less readable.
Some enums have the [Flags] attribute, which indicates that its values can be combined by a
bitwise OR. The AnchorStyles enum has this attribute because you might want to anchor a
component to more than one edge of its parent container. Here is an example of what that
looks like in C#.
// C# code
btn.Anchor = AnchorStyles.Top | AnchorStyles.Left;
To do this in Mathematica, you need to get the integer values of the enum, so you use
NETObjectToExpression. (This is just about the only case where you would want to operate on
enum values as integers in Mathematica. )
.NET/Link User Guide 29
// C#
public static char HexUnescape(string pattern, ref int index);
// Visual Basic
Public Shared Function HexUnescape(ByVal pattern As String, ByRef index As
Integer) As Char
This method takes a string (the pattern parameter) and a starting index and reads the next
character in the string, decoding a %xx-format hexadecimal representation if necessary. It also
advances the index value to just past the end of the decoded character. Like most methods
that use ref or out parameters, this method needs to return more than one piece of informa-
tion~the decoded character and also the next position in the string. Because the index parame-
ter's starting value is used by the method, it must be a ref parameter and not merely an out
parameter.
You call methods with out or ref parameters from Mathematica in exactly the same way they
are called from most .NET languages, including C# and Visual Basic .NET. For a ref parameter,
you call the method with a symbol that has an initial value of the correct type (an integer in this
case). When the method returns, the symbol will have a new value assigned to it.
This decodes the %20 character (the familiar encoding for a space character [decimal 32] in a
URL).
30 .NET/Link User Guide
In[50]:= LoadNETType@“System.Uri“D;
pos = 3;
Uri`HexUnescape@“abc%20def“, posD
Out[52]= 32
Because pos was passed to a ref parameter slot, it has been assigned a new value, that of the
index of the first character after the %20.
In[53]:= pos
Out[53]= 6
A common mistake when calling ref parameters is to forget to assign an initial value. Here is
an example of this error.
In[54]:= Clear@posD;
Uri`HexUnescape@“abc%20def“, posD
NET::methodargs : Improper arguments supplied for method named HexUnescape.
Out[55]= $Failed
If a parameter is marked as out instead of ref, the initial value is ignored, so it doesn’t matter
what value, if any, the symbol had upon entering the method. As mentioned above, Visual
Basic .NET has no notion of an out-only parameter, so ByRef parameters in methods written in
Visual Basic will always need an initial value of the correct type, even if the method does not
use the incoming value.
Like Visual Basic .NET (but unlike C#), .NET/Link allows you to pass a literal value instead of a
symbol to an out or ref parameter. In such cases, any changes made to the parameter’s value
are lost. Here is an example.
In[56]:= Uri`HexUnescape@“abc%20def“, 3D
Out[56]= 32
.NET/Link User Guide 31
You could say, then, that .NET objects are by default returned to Mathematica “by reference”,
except for a few special cases. These special cases are numbers, strings, arrays, and booleans.
You could say that these exceptional cases are returned “by value”. The table under
"Conversion of Types Between .NET and Mathematica" shows how these special .NET object
types are mapped into Mathematica values.
In summary, every .NET object that has a meaningful value representation in Mathematica is
converted into this value, simply because that is the most useful behavior. There are times,
however, when you might want to override this default behavior. Probably the most common
reason for doing this is to avoid unnecessary traffic of large expressions over MathLink.
ReturnAsNETObject
Consider the case where you have a static method in class MyClass called arrayAbs() that
takes an array of doubles and returns a new array where each element is the absolute value of
the corresponding element in the argument array. The declaration of this method in C# syntax
thus looks like double[] ArrayAbs(double[] a). This is how you would call such a method
from Mathematica.
The above example is how you probably want the method to work: you pass a Mathematica list
and get back a list. Now assume you have another method named ArraySqrt() that acts like
ArrayAbs() except that it performs the Sqrt() function instead of Abs().
In[3]:= ArraySqrt@ArrayAbs@81., - 2., 3., 4.<DD
Out[3]= 81., 1.41421, 1.73205, 2.<
In this computation, the original list is sent over MathLink to .NET and a .NET array is created
with these values. That array is passed as an argument to ArrayAbs(), which itself creates and
returns another array. This array is then sent back to Mathematica via MathLink to create a list,
which is then promptly sent back to .NET as the argument for ArraySqrt(). You can see that it
was a waste of time to send the array data back to Mathematica~you had a perfectly good
array (the one returned by the ArrayAbs() method) living on the .NET side, ready to be
passed to ArraySqrt(), but instead you sent its contents back to Mathematica only to have it
immediately come back to .NET again as a new array with the same values! For this example,
the cost is negligible, but what if the array had 200,000 elements?
What is needed is a way to let the array data remain in .NET and return only a reference to the
array, not the actual data itself. This can be accomplished with the ReturnAsNETObject
function.
Earlier you saw ArraySqrt() being called with an argument that was a Mathematica list of
reals. Here it is being called with a reference to a .NET object that is a one-dimensional array of
doubles. All arguments can be called from Mathematica with either a Mathematica value or a
reference to a .NET object of the appropriate type.
In summary, the ReturnAsNETObject function causes methods and properties that return
objects that would normally be converted into Mathematica values to return references instead.
It is often used as an optimization to avoid unnecessarily passing large amounts of data
between Mathematica and .NET, and as such it will be useful primarily for very large arrays and
strings. Objects of most .NET types have no meaningful “by value” representation in Mathemat-
ica, and they are always returned "by reference." ReturnAsNETObject is redundant these cases.
NETObjectToExpression
In the previous section, you saw how the ReturnAsNETObject function can be used to cause
objects normally returned to Mathematica by value to be returned by reference. It is necessary
to have a function that does the reverse~takes a reference and converts it to its value represen-
tation. That function is NETObjectToExpression.
Keep in mind that almost always when you are dealing with a .NET object that has a meaningful
“value” representation in Mathematica, the object will be automatically converted to this value
when it is sent to Mathematica. There are some exceptions to this rule, and these are where
NETObjectToExpression becomes useful. You saw earlier that the ReturnAsNETObject function
can be used to force an object to be returned as a reference. Another way to get a reference is
to call NETNew or MakeNETObject, as these functions always return an object reference. Here
we create a String object explicitly.
In[2]:= NETObjectToExpression@%D
Out[2]= ABC
The section on "Overloaded Operators" introduces the MakeNETObject function, which is easier
than using NETNew to construct .NET objects out of Mathematica strings, numbers, and arrays.
34 .NET/Link User Guide
The section on "Overloaded Operators" introduces the MakeNETObject function, which is easier
than using NETNew to construct .NET objects out of Mathematica strings, numbers, and arrays.
NETObjectToExpression also converts into their value representations some object types that
are normally returned by reference: enumerations and collections (objects that implement the
ICollection interface). Enumeration types are discussed in the "Enums" section. Collections
can be usefully operated on in Mathematica as lists, but unlike arrays, collections might be
expensive to iterate through, so .NET/Link leaves them as references and does not automati-
cally convert them to lists. If you want a list, use NETObjectToExpression.
In[3]:= NETObjectToExpression@arrayListD
Out[3]= 81, 2, 3, 4, 5, 6, 7, 8, 9, 10<
Overloaded Operators
Some .NET languages allow you to define overloaded operators such as +, >, and so on for a
class. Support for overloading of operators is not required in a .NET language. C# and C++
allow it; Visual Basic .NET does not. An example of a class that defines a number of overloaded
operators is System.TimeSpan. For instance, it defines a + operator so that you can add two
TimeSpan objects just like they were numbers. Here is what it looks like in C# code.
// C# code
TimeSpan t1 = new TimeSpan(2, 45, 55); // 2 hrs, 45 mins, 55 secs.
TimeSpan t2 = new TimeSpan(3, 10, 25); // 3 hrs, 10 mins, 25 secs.
TimeSpan sum = t1 + t2;
Because .NET languages are not required to support overloaded operators, any class that
defines them should always provide some other means to accomplish the same operation,
generally via a method call. The TimeSpan class provides an Add() method that you can use in
languages like Visual Basic .NET that do not allow overloaded operators.
.NET/Link does not support overloaded operators in Mathematica syntax, so you should seek
out the method that performs the same operation. Here is the Add() method to add two TimeSÖ
.NET/Link User Guide 35
.NET/Link does not support overloaded operators in Mathematica syntax, so you should seek
out the method that performs the same operation. Here is the Add() method to add two TimeSÖ
pan objects.
In[63]:= t1 = NETNew@“System.TimeSpan“, 2, 4, 55D;
t2 = NETNew@“System.TimeSpan“, 3, 10, 25D;
sum = t1 ü Add@t2D;
sum ü ToString@D
Out[66]= 05:15:20
Even if the class author ignored the .NET guidelines and failed to provide an alternative method
for accomplishing the same operation as an overloaded operator, you could still invoke the
operation from Mathematica. This is because overloaded operators in C# and C++ are achieved
internally through special static methods with names like op_XXX where XXX is the name of the
operation. The class author does not write these methods directly~they are created by the
compiler. Nonetheless, they can be called directly from Mathematica like any other method.
Here are all these cryptically-named methods in the TimeSpan class.
In[60]:= NETTypeInfo[“System.TimeSpan“, “Methods“, “op_*“]
Even if there was no Add() method in the TimeSpan class, you could still add them together by
invoking the op_Addition() method. Note that as always when calling .NET names from
Mathematica, you map the underscore character to a U because underscore is not a legal charac-
ter in a Mathematica symbol.
Casting
Introduction
.NET programs often include casts, where an object of one type is converted to another type. A
typical example is where a programmer has a variable of type Object, probably obtained as the
result of a method call typed to return Object, and wants to cast it to a derived type so that
methods from that type can be called on it. This often occurs when dealing with collection
classes, as they can hold objects of any type and thus their methods are typed to return noth-
ing more specific than Object. Here is the signature of the IList.Item property, which
extracts from a list the object at a given index.
// C#
object this[int index] {get; set;}
In C# the Item property is the indexer for the class, so it can be written with the above unusual
syntax or as a property named Item, like in Visual Basic. If you are putting, say, strings into an
IList and later extract one using the Item property, you would have to cast it to a string to be
able to assign it to a string variable.
// C#
ArrayList aList = new ArrayList;
aList.Add(“abc“);
...
string s = (string) aList[0];
In Visual Basic .NET, a cast is performed using the CType HL function, and it is only necessary if
Option Strict is set.
This type of cast is called a downcast because you are casting down the inheritance hierarchy
(from a parent type to a derived type). Such downcasting is probably the most common form of
casting (aside from the casting used to convert numbers of one type to another, such as int to
.NET/Link User Guide 37
This type of cast is called a downcast because you are casting down the inheritance hierarchy
(from a parent type to a derived type). Such downcasting is probably the most common form of
casting (aside from the casting used to convert numbers of one type to another, such as int to
byte).
Although you will see downcasting scattered throughout the C# and Visual Basic .NET programs
that you might be trying to duplicate in .NET/Link, downcasting is virtually never relevant in
.NET/Link. This is because casting between reference types is primarily a compile-time opera-
tion. In the above sample code, the programmer is telling the compiler that they know the
object they just extracted from the ArrayList is a string, and they want the compiler to allow
them to treat it as one. But in .NET/Link objects are always returned to Mathematica as their
true runtime types, so when you call the Item property, you get back an object of type String.
It is completely irrelevant that the Item property is typed to return Object. In effect, downcast-
ing is irrelevant and even impossible in .NET/Link because every object has its true runtime
type~there is no type further down the inheritance hierarchy to cast an object to!
The point of this preamble is to make it clear that the vast majority of casts you see in .NET
programs are irrelevant in .NET/Link. They are either conversions between numeric types
(which are easily done in Mathematica by other means if they are even necessary at all), or
downcasts from some general type, like Object, to a more specific type (which are pointless
because they are done for the sake of the compiler and there is no compilation stage in
.NET/Link).
There are some places in .NET/Link, however, where casting is necessary. One case is when
working with COM objects. This is discussed in the "COM" section and will not be dealt with
here. All the other cases where casting is necessary in .NET/Link are upcasts, where you are
casting an object to a parent class or interface. The three situations where upcasting is neces-
sary are as follows.
Note that these are relatively rare circumstances, and many programmers will never encounter
them. Although these are nontrivial aspects of .NET programming, there is really no extra
complexity introduced by .NET/Link~these are precisely the cases where upcasting is required
in C#, Visual Basic .NET, and other .NET languages. These three cases will be discussed individu-
ally in the following sections.
The function that casts a .NET object reference is CastNETObject. You will see examples in the
following sections. CastNETObject does not create a new object reference, just an “alias” of an
existing object reference. This means that if you call ReleaseNETObject on an object, the
object and all casted references to it are freed. In other words, an object and its casted ver-
sions are really just different ways of viewing the same object, not separate references.
CastNETObject@obj,“type“D cast the object obj to the given type, specified as a string
CastNETObject@obj,NETTypeD cast the object obj to the given type, specified as a NET-
Type expression
// C# code
public class Parent {
public string Foo() { return “from parent“; }
}
If you had an instance of the Child class, but wanted to call the Parent implementation of
Foo HL, you could do this by casting the Child instance to the Parent class.
// C# code
Child c = new Child();
string s1 = c.Foo(); // s1 gets the value “from child“
string s2 = ((Parent) c).Foo(); // s2 gets the value “from parent“
The behavior is the same whether the Foo HL method is declared virtual or not in the Parent
.NET/Link User Guide 39
The behavior is the same whether the Foo HL method is declared virtual or not in the Parent
class. Note that the new keyword (Shadows in Visual Basic .NET) is not strictly required,
although the compiler will generate a warning if it is left out.
To call the Parent class implementation of Foo HL using .NET/Link, use CastNETObject to cast
the object to the Parent class, exactly as was done in the C# code.
// C# code
interface IEnglishDimensions {
double Length();
}
interface IMetricDimensions {
double Length();
}
double lengthInches;
Here is how you would call these methods. You must cast the Box object to either the
IMetricDimensions or IEnglishDimensions interface before you can call the LengthHL
method.
myBox = NETNew@“Box“D;
englishLength = CastNETObject@myBox, “IEnglishDimensions“D ü Length@D;
metricLength = CastNETObject@myBox, “IMetricDimensions“D ü Length@D;
Here is a real-world example. The Array class (which is the parent class for all arrays in .NET)
uses explicit interface implementation for methods from the IList interface. If a class uses
explicit interface implementation for some of its methods this should be mentioned clearly in
the documentation, and this is true for the Array class. One method from the IList interface is
Contains HL. You cannot call this directly on an array object, even though Array implements
.NET/Link User Guide 41
Here is a real-world example. The Array class (which is the parent class for all arrays in .NET)
uses explicit interface implementation for methods from the IList interface. If a class uses
explicit interface implementation for some of its methods this should be mentioned clearly in
the documentation, and this is true for the Array class. One method from the IList interface is
Contains HL. You cannot call this directly on an array object, even though Array implements
IList.
NET::nomethod : No public instance method named Contains exists for the .NET type System.Int32@D.
Out[9]= $Failed
This may sound confusing, so consider the following example. Assume an interface called IFoo
and an internal class that implements IFoo (internal classes are visible only to other types
within the same assembly).
interface IFoo {
int Foo();
}
Now assume there is some other class that has a method type to return IFoo that returns an
instance of the InternalIFooImpl class.
It doesn’t work to call the Foo HL method on the foo object because it is typed as a non-public
class.
NET::nomethod : No public instance method named Foo exists for the .NET type InternalIFooImpl.
Out[3]= $Failed
The error message isn’t very accurate above~there is a public method named Foo HL in the
InternalIFooImpl class, it just cannot be seen via reflection because the class itself is not
public. This sort of thing never shows up in C# or Visual Basic .NET because the variable that
holds the result of CreateIFoo HL will be typed as the public interface IFoo. The programmer
would never have any reason to see or even know about the InternalIFooImpl class. The code
looks like the following.
// C# code
IFoo foo = FooFactory`CreateIFoo();
int result = foo.Foo();
.NET/Link User Guide 43
In .NET/Link, however, objects are seen by default as their true runtime types, so we end up
with an instance of an object that is typed as a non-public class. The solution is to do what is
done in C# and Visual Basic .NET: upcast the object to the IFoo interface.
The “factory” design pattern in the above example is relatively common. A special object-
creation method returns objects typed only as some interface. This allows the designer of the
library to document an interface only, and hide the implementation details in private classes.
Clients of the library write only to the interface and are kept completely isolated from details
like the actual names of the implementation classes. This suggests that the need for upcasting
a non-public class to an interface type would not be rare for .NET/Link programmers. In prac-
tice, however, it is often the case that the non-public class inherits implementations of at least
some of its methods from a public parent class. If this is the case, these methods will be found
and can be invoked on the non-public child class without casting.
Indexers
Some .NET classes define a special member that permits instances of the class to be accessed
in the same way as arrays. This special member is called an indexer in C# terminology, and a
default parameterized property in Visual Basic .NET terminology. Here are skeleton definitions
of example members in C# and Visual Basic .NET.
// C# indexer
public int this(int i) {
get { ... }
set { ... }
}
Indexers allow a class to act as if it were an array even though it is not. Most of the .NET
collection classes (classes that implement the ICollection interface) support an indexer so
44 .NET/Link User Guide
Indexers allow a class to act as if it were an array even though it is not. Most of the .NET
collection classes (classes that implement the ICollection interface) support an indexer so
that elements can be set and retrieved using a simple array-like syntax. If a class had a
definition like one of the above, you could access the “ith element” using code like the following.
// C#
int firstElement = obj[0];
‘ VB
firstElement = obj(0)
If a class defines an indexer, you can call the indexer in Mathematica using function brackets.
H* Call indexer *L
firstElement = obj@0D;
Note that there is no method or property name in the above code~just an “argument” to the
object itself, as if it were a function. It could be argued that Part-based syntax (i.e., using
obj[[0]]) would be more suitable for calling indexers in .NET/Link, as it is the Mathematica
equivalent of array access, but that syntax was rejected for various philosophical and technical
reasons.
Here is another example of calling an indexer using the BitArray class, which is a collection of
true/false values that is stored in a very compact way. This class defines an indexer so that it
can be treated like an array.
This calls the indexer to get the second element (because it is a zero-based index).
In[2]:= bitArray@1D
Out[2]= False
.NET/Link User Guide 45
If you write a class in C# and give it an indexer, the compiler creates a public property named
Item for you. This is a parameterized property, meaning that it takes an argument like a
method call. The indexer syntax is just a shorthand for calling the Item property. If you are
writing in Visual Basic .NET, the convention is that your default parameterized property should
be named Item, but this is not a requirement. Whatever the default parameterized property is
named, you can skip the indexer-style syntax and call the property directly from Mathematica if
you wish.
Exceptions
In[26]:= LoadNETType@“System.Int32“D;
Int32`Parse@“1234.5“D
NET::netexcptn :
A .NET exception occurred: System.FormatException: Input string was not in a correct format.
at System.Number.ParseInt32HString s, NumberStyles style, NumberFormatInfo infoL
at System.Int32.ParseHString s, NumberStyles style, IFormatProvider providerL
at System.Int32.ParseHString sL.
Out[27]= $Failed
If the .NET code was compiled with debugging information included, the Mathematica message
you get as a result of an exception will show the full stack trace to the point where the excep-
tion occurred, with the exact line numbers in each file.
46 .NET/Link User Guide
GetNETException
You can use the function GetNETException to get the Exception object for the exception
thrown in the last call from Mathematica to .NET. It returns Null if no exception was thrown.
Most programmers will have no use for this function, but you could use it to implement a spe-
cial exception-handling feature in your programs. Below you see the exception thrown by the
previous call to Int32.Parse(). You can see that most exceptions that occur will come back
wrapped in a special CallNETException object that wraps the actual exception thrown using
the standard .NET design pattern for “inner exceptions”.
To get the actual exception thrown, you must examine the InnerException property.
In this example the .NET reflection system has wrapped the exception in another exception, so
you have to dig one level deeper to see the “real” one.
To implement custom handling for .NET exceptions in Mathematica, use the symbol
$NETExceptionHandler. The value of $NETExceptionHandler is treated as a function that will
be passed three arguments: the symbol associated with the message (this will usually be the
symbol NET), the message tag (this will typically be the string “netexcptn”), and the descriptive
string of text associated with the message.
You will usually set $NETExceptionHandler within a Block so that its effect will be limited to a
precisely defined segment of code, as in the following example that silences messages.
.NET/Link User Guide 47
You will usually set $NETExceptionHandler within a Block so that its effect will be limited to a
precisely defined segment of code, as in the following example that silences messages.
Block@8$NETExceptionHandler = Null &<,
obj ü Method@D
D
You can use GetNETException within your handler function to obtain the actual .NET exception
object that was thrown. Here is an example.
exceptionThrower = Throw[GetNETException[]]&;
Block[{$NETExceptionHandler = exceptionThrower},
... code that calls .NET ...
]
You should avoid setting $NETExceptionHandler outside of a Block, as you are almost sure to
inadvertently create situations where its value does not get cleared, leaving users scratching
their heads wondering why their exceptions are not being handled like they expect.
Nested Types
Some .NET types have declarations of other types nested within them. Here is an example in
C#.
namespace SomeNamespace {
In .NET, the + character is used in a type name to separate the name of an inner class from its
outer class. In the above example, the actual type name of the Inner class is SomeNamespaceÖ
.Outer+Inner. This is the name you must use in LoadNETType .
In[1]:= innerClass = LoadNETType@“SomeNamespace.Outer+Inner“D
Out[1]= [email protected]+Inner, 25D
You also use type names in NETNew. Here is how you construct an instance of the Inner class.
48 .NET/Link User Guide
You also use type names in NETNew. Here is how you construct an instance of the Inner class.
The + character only appears in type names. When referring to a nested type in code, use the
standard scope resolution operator (the period in C# and Visual Basic .NET) to separate the
inner class from the outer class.
// C# code
Outer.Inner obj = new Outer.Inner();
Although most .NET languages allow the above syntax for nested types, keep in mind that the
actual type names use the + character to separate the inner type from the outer one. In
.NET/Link, whenever you enter a type name as a string, you must use the + notation.
You call instance methods on objects of nested types in the usual way.
Here is how to call a static member. Notice that as in C# and Visual Basic .NET, the + character
disappears and is replaced by the scope resolution operator (` in Mathematica).
In[4]:= Outer`Inner`StaticInnerFoo@D
Out[4]= 42
Another point to note about the above line is that you cannot refer to a static member of a
nested class using simply the inner class name, as in Inner`StaticInnerFoo[]. This is to be
expected, since you cannot do this in other .NET languages either. You always need to prefix
the inner class name with the outer one.
Here is a real-world example. The System.Environment class has a nested enum called SpeÖ
cialFolder. This enum contains constants that designate special locations within the Windows
operating system (it has values that include ProgramFiles, Recent, System, StartMenu, and
so on). Here is how to determine the path to the user’s Favorites folder. You need to call static
members from the System.Environment class and the System.Environment.SpecialFolder
enum (members of an enum are static), so first you load these two types. Note the + in the
type name.
In[5]:= LoadNETType@“System.Environment“D;
LoadNETType@“System.Environment+SpecialFolder“D;
The GetFolderPath() method takes members of the SpecialFolder enumeration and gets
the appropriate path as a string. Note how we refer to the Favorites member of the SpecialÖ
Folder enum.
.NET/Link User Guide 49
The GetFolderPath() method takes members of the SpecialFolder enumeration and gets
the appropriate path as a string. Note how we refer to the Favorites member of the SpecialÖ
Folder enum.
In[7]:= Environment`GetFolderPath@Environment`SpecialFolder`FavoritesD
Out[7]= C:\Documents and Settings\tgayley\Favorites
In summary, the important point to remember about nested types is that when you need to
refer to the name of one in a string, you use the + character to separate the outer type from
the inner type. When you refer to a type in code, you go back to using the familiar ` to
separate the outer and inner names.
MakeNETObject
The most common way to create a .NET object is to call a constructor via NETNew. Sometimes,
however, you have a Mathematica expression that you want to convert into a .NET object but
the class does not have a convenient constructor. A common example is if you want to create
an array object out of a Mathematica list. You can call an array constructor via NETNew, but you
cannot initialize the array with values via the constructor. This example creates an array object
with NETNew and fills it manually.
MakeNETObject .
Keep in mind that you rarely have to call MakeNETObject. When you call a method that takes
an array, for example, you can just pass a Mathematica list and .NET/Link will create the .NET
array for you. There are times, however, when you want to explicitly create a .NET object that
must be populated with data from Mathematica and there is no convenient constructor. An
50 .NET/Link User Guide
Keep in mind that you rarely have to call MakeNETObject. When you call a method that takes
an array, for example, you can just pass a Mathematica list and .NET/Link will create the .NET
array for you. There are times, however, when you want to explicitly create a .NET object that
must be populated with data from Mathematica and there is no convenient constructor. An
example of a circumstance where MakeNETObject is useful is the following method, which
reverses a list passed in as an argument. Note that it does not return the reversed list, but
rather reverses it in place.
You could call this method with a Mathematica list, but there would be no way to get back the
reversed list. The way around this problem is to create an array object populated with the initial
list values, pass the object reference, let its internal data be reversed, and then convert the
object reference back to a Mathematica list.
In[7]:= MyClass`ReverseArray@intArray2D
In[8]:= NETObjectToExpression@intArray2D
Out[8]= 844, 43, 42<
Another case where is useful is if you need to give .NET/Link a little help in choosing the correct
signature of an overloaded method. Consider the following two overloads of a method.
If you called Foo() from Mathematica with an integer, the overload with the long parameter
would be called. This is because .NET/Link generally tries to call the method with the widest
possible type at each slot (but there is no formal guarantee, especially in complicated cases). If
you want to call the byte version, you can do this by creating a .NET object of the Byte type,
because .NET/Link always gives preference to a method signature that is an exact match for
the incoming argument types.
obj ü Foo@MakeNETObject@42, “System.Byte“DD
Remember that MakeNETObject is a rarely used function. You do not need to explicitly con-
struct .NET objects from Mathematica strings, arrays, and so on, just to pass them to .NET
methods~.NET/Link does this automatically for you. There are a few special circumstances
outlined above where it is useful.
Complex Numbers
.NET/Link User Guide 51
Complex Numbers
.NET number types (e.g., byte, int, double) are returned to Mathematica as integers and
reals, and integers and reals are converted to the appropriate types when sent as arguments to
.NET. What about complex numbers? It would be nice to have a .NET type representing com-
plex numbers that mapped directly to Mathematica’s Complex type, so that automatic conver-
sions would occur as they were passed back and forth between Mathematica and .NET. .NET
does not have a standard type for complex numbers, so .NET/Link lets you name the type that
you want to participate in this mapping.
You can use any class or struct you like as long as it has the following properties:
1. A public constructor that takes two doubles or two floats (the real and imaginary parts, in
that order)
2. Public methods, properties, or fields for the real and imaginary parts, having one of the
following signatures:
namespace MyCompany {
Assume that you compiled this class into the assembly MyCompany.Complex.dll. Here is an
example of using it.
In[1]:= LoadNETAssembly@“c:\\MyCompany.Complex.dll“D;
SetComplexType@“MyCompany.Complex“D;
In[3]:= c = NETNew@“MyCompany.Complex“, 2, 1D
Out[3]= «[email protected] »
Once you have used SetComplexType, NETObjectToExpression will convert object references
of that type to complex numbers in Mathematica (objects of type Complex will normally be
converted to complex numbers when returned to Mathematica, but a call to a constructor
always returns a NETObject).
In[4]:= NETObjectToExpression@cD
Out[4]= 46. + 2. Â
.NET/Link User Guide 53
Here are three examples of calling the Add() method. This method takes one argument of type
Complex. Note that you can pass a Complex object, a Mathematica complex number, or a real
number for this argument. .NET/Link handles any necessary conversions.
In[5]:= c ü Add@cD
Out[5]= 4. + 2. Â
In[6]:= c ü Add@42 + 15 ÂD
Out[6]= 44. + 16. Â
In[7]:= c ü Add@42D
Out[7]= 44. + 1. Â
The Complex class has an overloaded + operator, and overloaded operators would be expected
in any real implementation of a complex number class. As discussed in the "Overloaded Opera-
tors" section, you can call these operators from .NET/Link by using the special static method
equivalents that always exist in the class. For the + operator, the special method is called
op_Addition(). Here is how to call it (note the required _ to U conversion).
In[8]:= Complex`opUAddition@c, cD
Out[8]= 4. + 2. Â
Because some .NET languages (such as Visual Basic .NET) do not support overloaded operators,
class designers usually provide a documented alternative method, such as the Add() method in
the Complex class.
In[1]:= ShowNETConsole@D
Out[1]= «[email protected] »
Capturing of output only begins when you call ShowNETConsole. When the window first
appears, it will not have any content that might have been previously written to Console.Out
or Console.Error. Calling ShowNETConsole when the window is already open will cause it to
come to the foreground.
The next example writes some output from Mathematica. If you executed the
ShowNETConsole@D above, then you will see “Hello from .NET” printed in the window.
In[2]:= LoadNETType@“System.Console“D;
Console`Out ü WriteLine@“Hello from .NET“D
Although it is convenient to demonstrate writing to the window using Mathematica code like
this, this is typically done instead from .NET code that writes diagnostic information to the
console.
.NET/Link is designed to make it easy for application developers to distribute applications that
have parts of their implementation in .NET. If you structure your application directory properly,
your users will be able to install it simply by copying it into any standard location for Mathemat-
ica applications. In particular, .NET/Link will be able to find your .NET assemblies without users
having to perform any special operations or even restart the .NET runtime.
.NET/Link applications might include .NET assemblies or legacy Windows DLLs (which can be
called from .NET as described in the "Calling DLLs from Mathematica" section. If your Mathemat-
ica application uses .NET/Link and includes its own .NET assemblies, you should create an
assembly subdirectory in your application directory. You can place any assemblies that your
application needs into this assembly subdirectory. Legacy Windows DLLs (so-called
“unmanaged” DLLs) should be placed into into a Libraries\Windows subdirectory of your
application directory.
MyApp/
... other files and directories used by the application ...
assembly/
MyAssembly.dll
Libraries/
Windows/
MyLegacyDLL.dll
Remember that even if you use the above directory structure, your application code will still
have to load its assemblies explicitly. All assemblies, other than ones that make up the .NET
Framework itself, must be manually loaded before they can be used, as described in the
"Loading .NET Assemblies and Types" section. Having the assemblies in the proper location
merely means that they can be found by LoadNETAssembly when only a filename or assembly
name is supplied.
LoadNETAssembly@“MyAssembly.dll“D
H* or *L
LoadNETAssembly@“My.Assembly.Name“D
56 .NET/Link User Guide
Version Information
.NET/Link provides three symbols that supply version information. These symbols provide the
same type of information as their counterparts in Mathematica itself, except that they are in the
NETLink`Information` context, which is not on $ContextPath, so you must specify them by
their full names.
In[1]:= NETLink`Information`$Version
Out[1]= NETêLink Version 1.2.0 HSeptember, 2004L
In[2]:= NETLink`Information`$VersionNumber
Out[2]= 1.2
In[3]:= NETLink`Information`$ReleaseNumber
Out[3]= 0
The ShowNETConsole@D function, described in "The .NET Console Window" section, will display
the version number of the .NET/Link assembly file. This version should match the version of the
.NET/Link Mathematica-language component.
.NET/Link User Guide 57
Introduction
One application of .NET/Link is to write user interfaces for Mathematica programs. Examples of
such interfaces would be a progress bar monitoring the completion of a computation, a window
that displays an image or animation, a dialog box that prompts users for input or helps them
compose a proper call of an unfamiliar function, or a mini-application that leads users through
the steps of an analysis. These types of user interfaces are distinct from what you might write
for a .NET program that uses Mathematica in the background in that they “pop up” when the
user invokes some Mathematica code. These user interfaces do not replace the notebook front
end; they just augment it. In this way, they are like an extension of the palettes and other
specialty notebook elements that you can create in the front end.
Mathematica with .NET/Link is an extremely powerful and productive environment for creating
user interfaces. The complexity of user interface code is ideally suited to the interactive line-at-
a-time nature of .NET/Link development. You can build, modify, and experiment with your user
interface while it is running.
You can use either .NET/Link or J/Link to build user interfaces for Mathematica programs. J/Link
has the advantage of being cross-platform, so your interface will run on all Mathematica sys-
tems. .NET/Link integrates more tightly with Windows than J/Link does, so if you only need
your users interfaces to work on Windows machines, then .NET/Link is probably the best choice.
If you have used J/Link to build user interfaces in Mathematica, please note that there are
significant differences between .NET/Link and J/Link in this area. .NET/Link is generally simpler
than J/Link, not because of any superiority of .NET over Java, but because .NET/Link is a sec-
ond-generation design. The design simplifications in .NET/Link will eventually be brought to
J/Link.
Anyone considering writing user interfaces for Mathematica programs should also look at the
GUIKit add-on, which is bundled with Mathematica 5.1 and later, and available for download for
users with earlier versions of Mathematica. GUIKit is built on top of J/Link, and provides an
extremely high-level means of creating interfaces.
When the Mathematica kernel is being used from the front end, it spends most of its life waiting
for input to arrive on the MathLink that it uses to communicate with the front end. This
MathLink is given by $ParentLink , and it is therefore $ParentLink that has the kernel’s
attention. When input arrives on $ParentLink , it is evaluated, any results are sent back on the
link, and the kernel goes back to waiting for more input on $ParentLink . When .NET/Link is
being used, the kernel has another MathLink open~the one that connects to the .NET runtime.
When you execute some code that calls into .NET, the kernel sends something to .NET and then
blocks waiting for the return value from .NET. During this period when the kernel is waiting for
a return value from .NET, the .NET link has the kernel’s attention. It is only during this period of
time that the kernel is paying attention to the .NET link. A more general way of saying this is
that the kernel is only listening for input arriving from .NET when it has been specifically
instructed to do so. The rest of the time it is listening only to $ParentLink , which is typically
the notebook front end.
Consider what happens when the user clicks a button in your .NET window and that button tries
to execute some code that calls into Mathematica. The .NET side sends something to Mathemat-
ica and then waits for the result, but the kernel will never get the request because it is only
paying attention to the notebook front end link, not the .NET link. It is necessary to use some
means to tell the kernel to look for input arriving on the .NET link. .NET/Link provides two main
ways to manage the kernel’s attention to the .NET link and thereby control its readiness to
accept requests for evaluations initiated by the .NET side.
These two ways can be called “modal” and “modeless.” In modal interaction, characterized by
the use of the DoNETModal Mathematica function, the kernel is pointed at the .NET link until the
.NET side releases it. The kernel is a complete slave to the .NET side, and is unavailable for any
other computations. In modeless interaction, characterized by the use of the DoNETModeless
Mathematica function, the kernel is kept in a state where it is receptive to evaluation requests
arriving from either the notebook front end or .NET, evenly sharing its attention between these
two programs.
the use of the DoNETModal Mathematica function, the kernel is pointed at the .NET link until the
.NET side releases it. The kernel is a complete slave to the .NET side, and is .NET/Link
unavailable for any
User Guide 59
A common type of user interface element is analogous to a modal dialog: once it is displayed,
the Mathematica program hangs waiting for the user to dismiss the window. Typically, this is
because the window returns a result to Mathematica, so it is not meaningful for Mathematica to
continue until the window is closed. An example of such a window is a simple input window that
asks the user for some value, which it returns to Mathematica when the OK button is clicked.
It is important to understand the slightly generalized use of the term “modal” to describe these
windows. They may not be modal in the traditional sense that they must be dismissed before
anything else can be done in the user interface. Rather, they are modal with respect to the
Mathematica kernel~the kernel cannot do anything else until they are closed. A .NET window
that you create might not be modal with respect to other .NET windows on the screen, but it
ties up the kernel’s attention until it is dismissed.
Another type of user interface element is analogous to a modeless dialog: after it is displayed,
the Mathematica program that created it will finish, leaving the window visible and usable while
the user continues working in the notebook front end. An example would be a window that lets
users load packages into Mathematica by selecting them from a scrolling list. You write a
.NET/Link program that creates this window, displays it, and returns. The window is left open
and usable until the user clicks its close box. In the meantime, the user is free to continue
working in the front end, going back to use this .NET window whenever it is convenient.
Such a window is almost like another type of notebook or palette window in the front end. You
can have any number of front end or .NET modeless windows open and active at once, meaning
that they can be used to initiate computations in Mathematica. They are each their own little
interface onto the same kernel. What is different about the .NET window is that it is much more
general than a notebook window, and, importantly, it exists in a different application layer than
the front end. This last fact makes the .NET window, in effect, a second front end, rather than
an extension of the notebook front end. To accommodate such a second front end, the kernel
must be kept in a special state that allows it to handle requests for evaluations arriving from
either the notebook front end or .NET.
Before presenting examples of how to implement modal and modeless windows, it is necessary
to jump ahead a little bit and explain the mechanism by which .NET user interface elements
communicate events to Mathematica.
60 .NET/Link User Guide
Handling Events
User interface elements typically have active components such as buttons, scrollbars, menus,
and text fields, that need to trigger certain actions when they are used. In the .NET event
model, components fire events in response to user actions, and other components indicate their
interest in these events by supplying a delegate that connects an event with its handler. The
concept of a delegate is covered in detail in the .NET Framework documentation, but .NET/Link
users can generally ignore the details of delegates because you use a very simple syntax for
assigning a Mathematica function to be called when an event fires.
It is useful to compare the .NET/Link technique for assigning event handler functions with the
C# and Visual Basic .NET techniques. The following shows C# and Visual Basic .NET syntax for
adding an event handler to the KeyPress event in a TextBox.
// C#
myTextBox.KeyPress += new KeyEventHandler(MyKeyPressHandlerMethod);
After executing either of the above lines, the MyKeyPressHandlerMethod() method will be
called whenever a key is pressed while the myTextBox component has the focus. The C# syn-
tax is a little cryptic, as the += operator is overloaded for adding a delegate to an event.
The preceding code does not show the definition of MyKeyPressHandlerMethod(). The signa-
ture of this method must be the same as the delegate that corresponds to the KeyPress event.
As you can see in the C# code, the delegate type is KeyEventHandler, and here is the
declaration.
Because MyKeyPressHandlerMethod() must have the same signature, it would look some-
thing like this.
Note that it looks almost exactly like the Visual Basic .NET version. Once you have executed the
line above, whenever a key is pressed while myTextBox has the input focus, .NET will call back
to Mathematica and execute the myKeyPressHandler function. The Mathematica function will be
called with the same arguments as the KeyEventHandler delegate, and it should return the
same type of value (although most event handlers return void, so the return value is ignored).
Here is what it might look like.
myKeyPressHandler@sender_, keyEventArgs_D :=
Print@“The “ <> keyEventArgs ü KeyCode ü ToString@D <> “key was pressed“D
AddEventHandler@ set the Mathematica function that will be called when the
objüeventName, funcNameD object obj fires the eventName event
RemoveEventHandler@delegateD remove an event handler assigned by a previous call to
AddEventHandler
Assigning the Mathematica function that will be called in response to an event notification.
Wiring up your application’s event logic via calls to Mathematica functions is vastly more flexible
than writing a traditional application in .NET. When you write in a compiled .NET language, or
use a drag-and-drop GUI builder, you hard code the event logic. You have to decide at compile
time what every click, scroll, and keystroke will do. But when you use .NET/Link, you decide
how your program is wired together at run time. You can even change the behavior on the fly
simply by typing a few lines of code.
You can remove an event handler using the RemoveEventHandler function. When you call
AddEventHandler, it returns a NETObject. This object is the delegate created for you by the
internals of .NET/Link. You can save this object and later pass it into RemoveEventHandler to
remove the Mathematica callback that it represents. This is just about the only use you would
have for the return value of AddEventHandler.
dlg = AddEventHandler[myTextBox@KeyPress, myKeyPressHandler];
...
RemoveEventHandler[dlg];
Mathematica event handler functions called in response to events are automatically wrapped in
NETBlock. This means that the objects sent as arguments to the function, as well as any new
objects you create during the execution of the function, are released after the function returns.
You do not have to use NETBlock or ReleaseNETObject manually. If you want an object from
your handler function to persist in Mathematica after the function returns, you must use
KeepNETObject to allow it to escape the unseen NETBlock that wraps the function call. Here is
Mathematica
62 event
.NET/Link User Guidehandler functions called in response to events are automatically wrapped in
NETBlock. This means that the objects sent as arguments to the function, as well as any new
objects you create during the execution of the function, are released after the function returns.
You do not have to use NETBlock or ReleaseNETObject manually. If you want an object from
your handler function to persist in Mathematica after the function returns, you must use
KeepNETObject to allow it to escape the unseen NETBlock that wraps the function call. Here is
a modified version of myKeyPressHandler that stores the KeyCode objects in a list for later
inspection.
myKeyPressHandler2@sender_, keyEventArgs_D :=
Module@8keyCode< ,
keyCode = keyEventArgs ü KeyCode;
AppendTo@keysPressed, keyCodeD;
KeepNETObject@keyCodeD
D
AddEventHandler takes two options that control its behavior. SendDelegateArguments allows
you to specify which of the delegate arguments you want to send to your Mathematica handler
function and in which order. By default, .NET/Link sends all the delegate arguments, but as an
optimization, you might not want to send them all. Creation of a new NETObject expression in
Mathematica is comparatively expensive, and the arguments to most event delegates are
objects. In the case of the KeyPress event example above, the first argument is the TextBox
object, which probably already exists in Mathematica, so it is not a significant optimization to
avoid sending it. The KeyEventArgs object, however, is definitely new to Mathematica, so you
might want to avoid sending it if you do not need it. Here is an example of setting up an event
handler that sends only the first argument to the Mathematica callback function.
AddEventHandler@myTextBox ü KeyPress,
myKeyPressHandler3, SendDelegateArguments Ø 81<D
The values you can specify for the SendDelegateArguments option are All (the default), None,
or a list of integers giving the indices of the arguments you want to send.
Options to AddEventHandler .
The CallsUnshare option is for advanced programmers who are using the ShareKernel and
UnshareKernel functions to manually control kernel sharing, instead of using DoNETModeless.
The sharing functions are discussed in "Manually Sharing the Kernel and Front End with .NET".
.NET/Link User Guide 63
The CallsUnshare option is for advanced programmers who are using the ShareKernel and
UnshareKernel functions to manually control kernel sharing, instead of using DoNETModeless.
The sharing functions are discussed in "Manually Sharing the Kernel and Front End with .NET".
If your Mathematica callback function calls UnshareKernel, you must set CallsUnshare to True
in the call to AddEventHandler.
NETNewDelegate@type, funcNameD create a new instance of the specified delegate type whose
action is to call the specified Mathematica function
DefineNETDelegate@name, create a new delegate type, for when there is no existing
returnType,8argType,...<D .NET delegate of the appropriate signature
Now that you have seen how to specify Mathematica event handler callbacks, recall that the
kernel must be in a special state to be receptive to calls originating from user events in .NET.
The two main ways of doing this are the functions DoNETModal and DoNETModeless, discussed
in the next sections.
Modal Windows
The basic concepts of modal and modeless .NET/Link interfaces are discussed in the earlier
section "Modal versus Modeless Operation". Here is an example of a simple modal window. The
window is a simple Form object that changes its background color to a new random color each
time it is clicked.
64 .NET/Link User Guide
Note that simply creating a new Form object does not make it visible. Use the ShowNETWindow
function to make a window visible and to bring it in front of all other windows. The DoNETModal
function, used later, will make a form visible, but ShowNETWindow is useful while you are just
tinkering with an interface, before you want to actually run it modally.
In[2]:= ShowNETWindow@frmD;
At this point, you should see a small frame window centered on the screen. Drag it to the side
so that it is not hidden by Mathematica windows when you bring the current notebook window
to the foreground. A huge advantage of using .NET/Link for user interface development, com-
pared to a typical compiled .NET language, is that you can experiment with your interface while
it is running. Now change the color of the background.
In[3]:= LoadNETType@“System.Drawing.Color“D;
frm ü BackColor = Color`Red;
This is the definition of the onClick function. It sets the form’s BackColor property to a ran-
dom color. This function ignores the event arguments, but you can learn what they are from
the signature of the Click event.
In[6]:= onClick@args___D :=
frm ü BackColor =
Color`FromArgb@Random@Integer, 80, 255<D,
Random@Integer, 80, 255<D, Random@Integer, 80, 255<DD
At this point, if you click the form, you will get a beep and nothing will happen to the color.
When the Click event fires, .NET tries to call Mathematica to execute the onClick function,
but it is not safe to make this call because Mathematica is not listening for input on the .NET
link. The call to Mathematica would hang forever. .NET/Link knows the kernel is not ready, so it
refuses to make the call and issues a beep warning instead.
What you need is a way to put the kernel into a state where it is continuously reading from the
.NET link. This is what makes the window “modal”~the kernel cannot do anything else until the
window is closed. The function that implements this modal state is DoNETModal. The first argu-
ment to DoNETModal is a top-level window object (in the .NET Framework, this means a SysÖ
tem.Windows.Forms.Form or any class that inherits from it).
.NET/Link User Guide 65
DoNETModal@ formD put the kernel into a state where its attention is solely
directed at the .NET link until the specified form window is
closed
DoNETModal@ form, returnValueD run the form modally and return the result of the returnValue
computation (this is executed before the window is
destroyed)
Now that everything is ready, you can enter the modal state and use the window.
In[7]:= DoNETModal@formD
DoNETModal will not return until the .NET form window is closed. Click the window a few times
to see the color change, then click the close box in the title bar to destroy the form and cause
DoNETModal to return.
You often want to get some information from a modal dialog box when it is closed, such as the
value from a text box, or whether the form was closed by clicking an OK or Cancel button.
When DoNETModal returns, the form object has been destroyed, so it is too late to call methods
on it. If you need to get some information out of a form before it is destroyed, use the optional
second argument DoNETModal. This argument specifies a computation that will be executed just
before the form is destroyed (it is held unevaluated until this time). DoNETModal will return the
result of this computation. The PackageHelper.nb example file shows how to use the second
argument to DoNETModal to determine whether a form was closed by clicking the OK or Cancel
button.
Here is how the entire example looks when packaged into a single program.
In[8]:= SimpleModal@D :=
NETBlock@
Module@8frm, onClick<,
frm = NETNew@“System.Windows.Forms.Form“D;
LoadNETType@“System.Drawing.Color“D;
frm ü BackColor = Color`Red;
AddEventHandler@frm ü Click, onClickD;
onClick@args___D := frm ü BackColor = Color`FromArgb@Random@Integer, 80, 255<D,
Random@Integer, 80, 255<D, Random@Integer, 80, 255<DD;
DoNETModal@frmD
D
D
The .NET Framework documentation discusses how to implement modal windows using the
ShowDialog() method. There are some advantages and disadvantages to using this technique
instead of DoNETModal. One disadvantage is that a .NET window is not guaranteed to come in
front of notebook windows if you use ShowDialog(). However, this failure seems to happen
only for the very first window displayed in a session. Windows displayed with ShowDialog()
are truly modal in the sense that other .NET windows cannot be used until the modal one is
The
66 .NET Framework
.NET/Link User Guide documentation discusses how to implement modal windows using the
ShowDialog() method. There are some advantages and disadvantages to using this technique
instead of DoNETModal. One disadvantage is that a .NET window is not guaranteed to come in
front of notebook windows if you use ShowDialog(). However, this failure seems to happen
only for the very first window displayed in a session. Windows displayed with ShowDialog()
are truly modal in the sense that other .NET windows cannot be used until the modal one is
closed. The ShowDialog() method makes it easy to determine how the window was closed
(whether the OK or Cancel button was clicked), because it returns one of the DialogResult
enumeration values. You can get the same result by using the second argument to DoNETModal.
H* Returns the DialogResult value. *L
DoNETModal@someFormWindow, someFormWindow ü DialogResultD
The PackageHelper.nb example file demonstrates a classic modal dialog with OK and Cancel
buttons implemented with DoNETModal.
DoNETModal takes one option, FormStartPosition, that specifies the position in which the
window will appear on screen. The possible values are Center (the default), Automatic (the
form will have the Windows default location), and Manual (the form will appear at a location
specified elsewhere, for example, by setting the form’s Location property).
Modeless Windows
The previous section demonstrated how to use the DoNETModal function to display and run
modal windows, which cause the kernel to remain busy until the window is closed. Another type
of window, which could be called modeless, remains open and usable without completely tying
up the kernel. The basic concepts of modal and modeless .NET/Link interfaces are discussed in
more detail in the earlier section "Modal Versus Modeless Operation".
.NET/Link provides the DoNETModeless function to run a window modelessly. The first argument
to DoNETModeless is a top-level window (specifically, a Form or any class that inherits from it).
The window is made visible and brought in front of all notebook windows.
.NET/Link User Guide 67
DoNETModeless@ formD display the specified Form window and return immediately,
leaving the window active
Modeless windows.
Here is the SimpleModal example from the previous section implemented as a modeless
window.
In[1]:= SimpleModeless@D :=
NETBlock@
Module@8frm<,
frm = NETNew@“System.Windows.Forms.Form“D;
LoadNETType@“System.Drawing.Color“D;
frm ü BackColor = Color`Red;
AddEventHandler@frm ü Click, onClickD;
DoNETModeless@frmD
D
D
onClick@sender_, eventArgs_D :=
sender ü BackColor = Color`FromArgb@Random@Integer, 80, 255<D,
Random@Integer, 80, 255<D, Random@Integer, 80, 255<DD;
Executing SimpleModeless@D will make the window visible and then return immediately. You
can click the window to change its background color and also continue to use the kernel for
other computations via the notebook front end.
In[2]:= SimpleModeless@D
There are several important differences in the code of SimpleModeless and SimpleModal,
beyond the obvious call to DoNETModeless instead of DoNETModal. These differences revolve
around the fact that the form runs after the SimpleModeless function returns. The onClick
function must not be local to the Module, because the function’s definition would be cleared
when the Module ends. A NETBlock is used to automatically release all .NET objects created
when SimpleModeless runs, but that means that you cannot refer to frm by name in the code
for onClick, because the NETBlock has ended by the time onClick is executed (the symbol
frm is also local to the Module so its value is cleared anyway). The first argument to the
onClick function is the object that fired the event, which is the Form object, so you can use the
first argument to refer to it instead of the symbol frm.
DoNETModeless is very useful during development, even for a window that will be run modally
in its final form. Because DoNETModal does not return until the window is closed, you cannot
modify your event logic or anything else about your window while it is running. You can use
DoNETModeless to make your event callbacks “live” without tying up the kernel, so that you can
tinker with your window while it is being displayed. When you are satisfied that it works as
desired, you can package a complete program that runs with DoNETModal.
68 .NET/Link User Guide
DoNETModeless takes several options. FormStartPosition specifies the position in which the
window will appear on screen. The possible values are Center (the default), Automatic (the
form will be in the Windows default location), and Manual (the form will appear at a location
specified elsewhere, for example, by setting the form’s Location property). ActivateWindow
controls whether the window should be made visible and brought to the foreground. Set
ActivateWindow to False in the rare cases where you want to call DoNETModeless to enter the
modeless state, but only later make the window visible.
The final option, ShareFrontEnd, is used to allow .NET interfaces to interact with the notebook
front end. The functions ShareKernel and ShareFrontEnd are discussed in the next section,
and programmers using DoNETModeless are generally shielded from those low-level functions.
DoNETModeless is essentially a means of encapsulating calls to ShareKernel and
UnshareKernel, starting sharing when the window first appears and ending it when the window
is closed. If you want your modeless interface to cause actions in the notebook front end (such
as printing some text or making graphics appear), you need to force DoNETModeless to turn on
front end as well as kernel sharing. This can be done by setting the ShareFrontEnd option to
True.
One common circumstance where the ShareFrontEnd option is useful is when you want to
debug your program by inserting Print statements in event handler functions. In a modeless
interface, Print output and Mathematica warning messages triggered by event handler func-
tions are sent to the .NET side and therefore do not appear in the notebook. If you want to see
this information, setting ShareFrontEnd to True will cause it to appear in the frontmost note-
book window. If you use this option during development, but do not need it in the final version
of your program, be sure to remove it, as front end sharing is expensive to turn on and off, and
can delay the initial appearance of your window.
.NET/Link User Guide 69
The previous sections described the DoNETModal and DoNETModeless functions, which are ways
of putting the kernel into a state where it is receptive to calls from events originating in .NET.
Most programmers will only need to use those two functions to display and run .NET windows.
Recall that DoNETModeless makes the kernel receptive to input either from .NET or from the
notebook front end. In effect, the kernel is “shared” between the front end and .NET. In some
circumstances you might want to initiate kernel sharing, but find that DoNETModeless is not
appropriate for your needs. You can take direct control of kernel sharing by calling the
ShareKernel function.
ShareKernel was introduced with J/Link, and is defined in the JLink` context. Loading
NETLink` loads JLink`, so you do not have to worry about the different contexts unless you
are using ShareKernel or related functions in your own package. When you call BeginPackage,
Mathematica only makes available to the code in your package the contexts explicitly named in
the BeginPackage statement, not other contexts that are needed by those packages. This
means that for every symbol that you want to use within a package, you must always explicitly
include that symbol’s context in your BeginPackage statement. Here is an outline of a package
that uses .NET/Link and also calls ShareKernel directly.
EndPackage[]
The "J/Link User Guide" discusses ShareKernel and ShareFrontEnd in detail, and you should
refer to those sections for full information. One thing to remember about using ShareKernel or
ShareFrontEnd with .NET is that you must supply the link to .NET as the argument, otherwise
they will use the Java link by default.
tok = ShareKernel@NETLink@DD;
Always save the result from ShareKernel to later pass into UnshareKernel.
70 .NET/Link User Guide
Always save the result from ShareKernel to later pass into UnshareKernel.
UnshareKernel@tokD;
As mentioned earlier, DoNETModeless calls ShareKernel to initiate sharing, and arranges for
UnshareKernel to be called when the window is closed. In J/Link, programmers have to call
ShareKernel and UnshareKernel directly to create a modeless window. Having a special
function like DoNETModeless that turns sharing on and off automatically is much simpler.
One example of a program that needs to call ShareKernel directly is presented in "Handling
COM Events". That program sets up event handlers in Mathematica for COM events fired by the
Internet Explorer application. There is no top-level .NET Form window to pass into
DoNETModeless, so sharing has to be managed explicitly.
.NET/Link provides a Mathematica function, ShowNETWindow, that performs all the necessary
steps to make a .NET window visible and appear in front of all other windows. You do not need
to call ShowNETWindow if you are using DoNETModal or DoNETModeless, as it is called automati-
cally. Even when using DoNETModeless, however, ShowNETWindow can be useful to bring a
window back to the foreground if the user has brought other windows in front of it since it was
first displayed.
.NET/Link User Guide 71
ShowNETWindow@ formD make the specified .NET form window visible and bring it in
front of all other windows, including notebook windows
Example Files
The following GUI example programs are included with .NET/Link.
Circumcircle.nb
PackageHelper.nb
SimpleAnimationWindow.nb
RealTimeAlgebra.nb
AsteroidsGame.nb
Introduction
This documentation has shown you how to load and use existing .NET types. This gives Mathe-
matica programmers immediate access to the entire universe of .NET types. Sometimes,
though, existing types are not enough, and you need to write your own.
.NET/Link essentially obliterates the boundary between .NET and Mathematica, allowing you to
pass expressions of any type back and forth and use .NET objects in Mathematica in a meaning-
ful way. This means that when writing your own .NET types to call from Mathematica, you
usually do not need to do anything special. You write the code in exactly the same way you
would if you wanted to use the type only from .NET, and you can use any .NET language you
like.
.NET/Link essentially obliterates the boundary between .NET and Mathematica, allowing you to
pass
72 expressions of any type back and forth and use .NET objects in Mathematica in a meaning-
.NET/Link User Guide
ful way. This means that when writing your own .NET types to call from Mathematica, you
usually do not need to do anything special. You write the code in exactly the same way you
would if you wanted to use the type only from .NET, and you can use any .NET language you
like.
In some cases, you might want to exert more direct control over the interaction with Mathemat-
ica. For example, you might want a method to send a result to Mathematica that is different
from what the method actually returns. Or you might want the method to not only return some-
thing, but also trigger a side effect in Mathematica~for example, printing something or display-
ing a message under certain conditions. You can even have an extended “dialog” with Mathemat-
ica before your method returns, perhaps invoking multiple computations in Mathematica and
reading their results. You might also want to write code that calls into Mathematica as the
result of some event triggered in .NET.
If you do not want to do any of these things, then you can happily ignore this tutorial. The
whole point of .NET/Link is to make concern about the interaction with Mathematica through
MathLink unnecessary. Most programmers who want to write .NET types to be used from Mathe-
matica will just write .NET types, period, without thinking about Mathematica or .NET/Link. For
those programmers who want more control or want to know more about the possibilities avail-
able with .NET/Link, read on.
One point to remember when creating your own types to use with .NET/Link is that you must
use LoadNETAssembly to load the assembly that contains the types. Assemblies must always be
loaded before the types they contain can be used in .NET/Link, but it is easy to forget this
because .NET/Link automatically loads assemblies that are part of the .NET Framework as they
are needed.
Say you are writing a file-reading class that you want to call from Mathematica. Because you
want behavior that is almost identical to the standard class System.IO.StreamReader, your
class will be a subclass of it. The only changes you want to make are to provide some more
.NET/Link User Guide 73
Say you are writing a file-reading class that you want to call from Mathematica. Because you
want behavior that is almost identical to the standard class System.IO.StreamReader, your
class will be a subclass of it. The only changes you want to make are to provide some more
Mathematica-like behavior. One example is that you want the Read() method to return not -1
when it reaches the end of the file, but rather the symbol EndOfFile, which is what Mathe-
matica’s built-in file-reading functions return.
// C# code
using System.IO;
using Wolfram.NETLink;
int i = base.Read();
if (i == -1) {
IKernelLink link = StdLink.Link;
if (link != null) {
link.BeginManual();
link.PutSymbol(“EndOfFile“);
}
}
return i;
}
}
If the file has reached the end, i will be -1, and you want to manually return something to
Mathematica. The first thing you need to do is get an IKernelLink object that can be used to
communicate with Mathematica. This is obtained by calling the static property StdLink.Link.
If you have written installable MathLink programs in C, you will recognize the choice of names
here. A C program has a global variable named stdlink that holds the link back to Mathemat-
ica. .NET/Link has a StdLink class that has a few methods related to this link object.
74 .NET/Link User Guide
The next thing you do is check whether Link returns null. It will never be null if the method
is being called from Mathematica, so you can use this test to determine whether the method is
being called from Mathematica, or as part of a normal .NET program. In this way, you can have
a method that can be used from .NET in the usual way when a Mathematica kernel is nowhere
in sight.
Once you have verified that a link back to the kernel exists, the first thing you do is inform
.NET/Link that you will be sending the result back to Mathematica yourself, so it should not try
to automatically send the method’s return value. This is accomplished by calling the BeginManÖ
ual() method on the IKernelLink object.
You must call BeginManual() before you send any part of a result back to Mathematica. If you
fail to do this, the link will get out of sync and the next .NET/Link call you make from Mathemat-
ica will probably hang. It is safe to call BeginManual() more than once, so you do not have to
worry that your method might be called from another method that has already called
BeginManual().
Returning to the example program, the next thing after BeginManual() is to make the
required “put”-type calls to send the result back to Mathematica (in this case, just a single
PutSymbol()). The internal .NET/Link code that wraps all method calls will handle the cleanup
and recovery from any MathLink error that might have occurred calling PutSymbol(). You do
not need to do anything for MathLinkException exceptions that occur while you are putting a
result manually~the method call will return $Failed to Mathematica automatically.
In some sense, when you perform this type of interaction with Mathematica you are turning the
tables on Mathematica, reversing the “master” and “slave” roles for a moment. When Mathemat-
ica calls into .NET, the .NET code is acting as the slave, performing a computation and returning
control to Mathematica. In the middle of a .NET method, however, you can call back into Mathe-
.NET/Link User Guide 75
In some sense, when you perform this type of interaction with Mathematica you are turning the
tables on Mathematica, reversing the “master” and “slave” roles for a moment. When Mathemat-
ica calls into .NET, the .NET code is acting as the slave, performing a computation and returning
control to Mathematica. In the middle of a .NET method, however, you can call back into Mathe-
matica, temporarily turning it into a computational server for the .NET side. Thus you would
expect to encounter essentially all the same issues that are discussed in Calling Mathematica
from .NET, and you would need to understand the full .NET/Link API as seen by .NET
programmers.
The full treatment of the IMathLink and IKernelLink interfaces is presented in Calling Mathe-
matica from .NET. Here we will discuss a few special methods in IKernelLink interface that are
specifically intended for use by “installed” methods. You have already seen one, the BeginManÖ
ual() method. This section will present the Message(), Print(), and Evaluate() methods.
The tasks of issuing a Mathematica message from a .NET method or triggering some Print
output are so commonly done that the IKernelLink interface has special methods for these
operations. The method Message() performs all the steps of issuing a Mathematica message.
The Print() method performs all the steps necessary to invoke Mathematica’s Print function.
Here is an example method that uses both. Assume that the following messages are defined in
Mathematica.
Foo::arg = “The `1` argument to foo must be greater than or equal to 0.“
76 .NET/Link User Guide
Note that Print() and Message() send the required code to Mathematica and also read the
result from the link (it will always be the symbol Null).
LoadNETAssembly@“c:\\path\\to\\FooAssembly“D;
LoadNETType@“FooClass“D;
FooClass`[email protected], - 2.0D
inside foo
Foo::arg : The second argument to foo must be greater than or equal to 0.
Indeterminate
Note that you automatically get Indeterminate returned to Mathematica when a floating-point
result from .NET is NaN (“Not-a-Number”).
The methods Print() and Message() are convenience functions for two special cases of the
more general notion of sending intermediate evaluations to Mathematica before your method
returns a result. The general means of doing this is to wrap whatever you send to Mathematica
in EvaluatePacket, which is a signal to the kernel that this is not the final result, but rather
something that it should evaluate and send the result back to .NET. You can explicitly send the
EvaluatePacket head, or you can use one of the methods in IKernelLink that uses
EvaluatePacket for you. These methods are Evaluate(), EvaluateToInputForm(), EvaluÖ
ateToOutputForm(), EvaluateToImage(), and EvaluateToTypeset(). They are discussed in
detail in the .NET/Link API documentation.
.NET/Link User Guide 77
Throwing Exceptions
Any exceptions that your method throws will be handled gracefully by .NET/Link, resulting in
the printing of a message in Mathematica describing the exception. This is discussed in
"Exceptions". If you are sending computations to Mathematica, as described in the previous
section, you need to make sure that an exception does not interrupt your code unexpectedly. In
other words, if you start a transaction with Mathematica, make sure you complete it or you will
leave the link out of sync and future calls to .NET will probably hang.
78 .NET/Link User Guide
Here is an example method that performs a long computation, checking every 100 iterations
whether the user tried to abort it (using the Interrupt Evaluation or Abort Evaluation com-
mands in the Evaluation menu).
This method returns 0 if it detects an attempt by the user to abort, but this value will never be
seen by Mathematica. This is because .NET/Link causes a method, property, or constructor call
that is aborted to return Abort@D, whether or not you detect the abort in your code. Therefore,
if you detect an abort and want to honor the user’s request, just return some value right away.
When .NET/Link returns Abort@D, the user’s entire computation is aborted, just as if the
Abort@D was embedded in Mathematica code. This means that you do not have to be con-
cerned with any details of propagating the abort back to Mathematica~all you have to do is
return prematurely if you detect an abort request, and the rest is handled for you.
.NET/Link makes no distinction between an interrupt request and an abort request; they each
cause WasInterrupted to return true. Recall that Mathematica has separate commands for
interrupting and aborting computations. The “Abort” operation (‡-. on Windows) causes the
entire computation to end as soon as possible and return $Aborted. The “Interrupt” operation
(‡-, on Windows) brings up a dialog box with further choices. If this Interrupt dialog box is
triggered when a .NET method is executing, it has a different set of buttons than when normal
Mathematica code is executing. One of the options is Send Abort to Linked Program and
another is Send Interrupt to Linked Program. Both of these choices have the same effect for
.NET methods, which is to cause WasInterrupted to return true and the call to return
Abort@D when it completes. The third button is Kill Linked Program, which will cause the .NET
entire computation to end as soon as possible and return $Aborted. The “Interrupt” operation
(‡-, on Windows) brings up a dialog box with further choices. If this Interrupt
.NET/Linkdialog box 79
User Guide is
triggered when a .NET method is executing, it has a different set of buttons than when normal
Mathematica code is executing. One of the options is Send Abort to Linked Program and
another is Send Interrupt to Linked Program. Both of these choices have the same effect for
.NET methods, which is to cause WasInterrupted to return true and the call to return
Abort@D when it completes. The third button is Kill Linked Program, which will cause the .NET
runtime to quit. If you call a .NET method that is not interruptible, killing the .NET runtime in
this way is the only way to make the method call terminate. You can also kill the .NET runtime
using the Windows Task Manager.
Sometimes you might want a .NET method to detect an abort and do something other than
cause the entire Mathematica computation to abort. For example, you might want a loop to
stop and return its results up to that point. Note that this is not generally recommended. Users
expect a program to abort and return $Aborted when they issue an abort request. In some
cases, however, especially if the code is not intended for use by a large community, you might
find it useful to use an abort as a “message” to communicate some information to your .NET
code instead of just having the computation aborted. This idea is similar to Mathematica’s
CheckAbort function, which allows you to detect an abort and absorb it so that it does not
propagate further and abort the entire computation. To “absorb” the abort in your .NET code so
that .NET/Link does not return Abort@D, simply reset the WasInterrupted property to false.
Here is an example.
† Mathematica 5.1 or later is being used (in 5.1 and later the kernel is always shared with
.NET)
† Mathematica is executing DoNETModeless, and the kernel is not busy servicing a computa-
tion from the front end
† Kernel sharing has been turned on via ShareKernel or ShareFrontEnd, and the kernel is
not busy with another computation
† .NET is not being used from Mathematica (that is, the code is called in a standalone .NET
program that is using Mathematica for computations; InstallNET has not been called)
The fifth bullet point above warrants further discussion. Recall that whenever Mathematica has
called into .NET, it is reading from the .NET link and therefore is receptive to calls that arrive
from .NET. This means that callbacks to Mathematica from code that is itself called from Mathe-
matica do not need to call RequestTransaction() (although it is harmless to do so). Event
handlers, however, are typically called as the result of some user action on the .NET side, and
thus they originate in .NET.
The code below shows a prototypical event handler method written in C#.
.NET/Link User Guide 81
The code below shows a prototypical event handler method written in C#.
IKernelLink ml = StdLink.Link;
StdLink.RequestTransaction();
// Send a single computation to Mathematica to react to the KeyPress
event.
ml.PutFunction(“EvaluatePacket“, 1);
... code to put rest of expression to evaluate goes here ...
ml.EndPacket();
ml.WaitAndDiscardAnswer();
}
If you are using Visual Studio .NET and you want to debug a class library project that you are
using with .NET/Link, the exact steps depend on the language you are using. Select the project,
and choose Properties from the Project menu. In the Debugging panel of the Configuration
Properties section, set the startup application to be the InstallableNET.exe program. Set the
command-line arguments to something like -linkmode listen -linkname foo. Then start
the debugger. The InstallableNET program will launch and wait for Mathematica to connect.
In your Mathematica session, execute the following.
InstallNET[LinkConnect[“foo“]]
This works because InstallNET can take a LinkObject as its argument, in which case it will
not try to launch .NET itself. This allows you to manually establish the MathLink connection
between .NET and Mathematica, then feed that link to InstallNET and let it do the rest of the
work of preparing the Mathematica and .NET sides to interact with each other.
82 .NET/Link User Guide
Introduction
This section describes how you can use .NET/Link to call DLL functions from Mathematica.
These are traditional Windows DLLs, typically C-language libraries (although many languages
have the capability to create such DLLs). In .NET terminology, these types of DLLs are called
“unmanaged” because they do not execute within the .NET runtime. Although the task of calling
unmanaged functions does not appear to have anything to do with .NET, .NET/Link can lever-
age existing facilities in .NET for calling such functions. In other words, because .NET can call
DLLs, and Mathematica can call .NET, you can now easily call DLLs in Mathematica.
The capability to easily call external C functions from Mathematica means that Windows pro-
grammers have virtually no reason to ever write another so-called “template” MathLink pro-
gram that wraps an external function and directly handles MathLink communication. Other
tutorials have shown how .NET/Link eliminates the need for special programming to call .NET
code. In this tutorial we see how .NET/Link also eliminates those extra steps for calling legacy
DLLs.
Many programming languages allow you to call DLL functions by simply “declaring” them with a
line of code. Here are examples of such a declaration in several languages. The function is
GetTickCount(), which is part of the Windows API that is defined in kernel32.dll.
// Visual Basic 6
Declare Function GetTickCount Lib “kernel32“ () As Long
// C#
[DllImport(“kernel32.dll“)]
static extern int GetTickCount();
.NET/Link User Guide 83
Note that DefineDLLFunction returns a function. You should assign it to a symbol and then use
that symbol as the name of the function:
In[147]:= getTickCount@D
Out[147]= 789 292 652
There are four arguments to DefineDLLFunction. The first argument is the name of the func-
tion in the DLL. The second argument is the name of the DLL, and you can give either the full
pathname to the DLL or just its filename. ("How DLLs are Found" discusses in detail how DLLs
are found by .NET/Link.) The third argument is the return type, given as a string. The fourth
argument is a list of the types of the arguments. If the function takes zero arguments, like
GetTickCount(), you specify an empty list. The type specifications are strings, and .NET/Link
supports a number of ways to specify types. Type specifications are discussed in greater detail
in the section "Specifying Arguments and Return Values".
DefineDLLFunction supports several options. The first is CallingConvention, which you need
to use if the DLL function uses a calling convention different from the standard convention,
which is “stdcall” on versions of Windows other than Windows CE. In rare cases, functions use
the “cdecl” calling convention. The “thiscall” convention can be used when calling methods in
C++ classes. See the .NET Framework documentation for the
System.Runtime.InteropServices.CallingConvention enumeration for more information
on these values. For most uses, you leave the CallingConvention option at its default setting.
When you call DefineDLLFunction, no attempt is made to locate the DLL~that happens only
when the function is first called. This means that if .NET/Link cannot find the DLL or the named
function within it, you will see an error message only when the function is called, not when it is
defined.
Introduction
To specify the types of the return value and arguments you use strings such as “int”, “double”,
and “void”. You can use type names that conform to the syntax of whichever language you are
most comfortable with (C, C#, or Visual Basic .NET). You can also use many type names used
in the Windows API, such as “WORD”, “BOOL”, and “LPSTR”. In most cases, you will be working
from a function prototype in the C language, and it will be most convenient to use the names
directly from the prototype. For example, consider the following declaration for the floor()
function from the math.h header file in the Standard C library.
It is not likely that you would want to call this particular mathematical function from Mathemat-
ica, but it serves as a simple example from a DLL that everyone will have. On Windows, the C
runtime library is in the DLL msvcrt.dll. Here is one way to use DefineDLLFunction to create
a Mathematica function that calls the floor() function.
In[161]:= [email protected]
Out[161]= 4.
DefineDLLFunction allows you to use the C type names directly, which is handy when you are
looking at a C-language prototype from a header file. The following are equivalent ways of
making the same definition.
H* Using Visual Basic-style names. *L
DefineDLLFunction@“floor“, “msvcrt.dll“, “Double“, 8“Double“<D;
Using C# or Visual Basic .NET syntax for type names is convenient if you are copying an exter-
nal function declaration from some sample code in one of those languages. In fact, the easiest
way to use DefineDLLFunction is to find an existing declaration for the external function in
some C# or Visual Basic .NET sample code, and just copy the type names used in that declara-
tion. Here is what declarations for floor() would look like in those languages.
// C#
[DllImport(“msvcrt.dll“)]
static extern double floor(double);
You can also use a Visual Basic 6 Declare Function statement as a guide to the correct type
names, but keep in mind some important differences between VB 6 and VB .NET. First, in VB 6
parameters are ByRef by default (they are ByVal by default in VB .NET), so a type name like
Double in a VB 6 declaration should be translated to ByRef Double. Also, Integer in VB 6 is
equivalent to Short in VB .NET, and Long in VB 6 is equivalent to Integer in VB .NET. You
must use type names that are appropriate for VB .NET.
Primitive Types
The following table shows what type names are legal to use for primitive types (i.e., integers,
reals, booleans) and what types they map to in Mathematica.
.NET/Link User Guide 87
The use of the above type names should be straightforward. Note that “long” means a standard
Windows C long (4 bytes), not the C# long, which is 8 bytes. Also, the Windows API BOOL type
is mapped to an integer (0 and non-zero) rather than True and False. Pointers to, and arrays
of, primitive types are discussed in a later subsection.
88 .NET/Link User Guide
Strings
There are some subtleties you need to be aware of when calling DLL functions that take and
return strings. These center on how the DLL function expects strings to be represented: either
as ANSI-style, single-byte, null-terminated strings or as Unicode, double-byte, null-terminated
strings. The process of converting data from one representation to another as it moves across
system boundaries is called marshaling. The default behavior of .NET when calling unmanaged
code is to marshal strings as single-byte, null-terminated strings, because most DLL functions
are written to handle this common C string format. If you need different behavior than the
default, you can use the MarshalStringsAs option to DefineDLLFunction.
Here are examples of two DLL functions from the Windows C runtime library that operate on
different types of strings. Each converts a string to lowercase; the _strlwr() function takes an
ANSI string and the _wcslwr() function takes a wide-character string.
Here are calls to DefineDLLFunction for both of these functions. Because the _wcslwr()
function takes and returns a wide-character string, you need to override the default marshaling
of strings.
Both functions behave identically on a string with characters that fit into a single byte.
As expected, the strlwr function fails on a string with characters that require two bytes. Note
that the p character is truncated to a single byte (in this example the truncation occurs as the
string is passed from .NET into the DLL, but it would also happen on the way back out of the
DLL).
In[200]:= strlwr@“ApB“D
Out[200]= apb
.NET/Link User Guide 89
In[202]:= wcslwr@“ApB“D
Out[202]= apb
If you have more than one string as a parameter or return type and the strings must be mar-
shaled differently, then you cannot use the MarshalStringsAs option, as this applies to all
strings in the function. You can use the special “full declaration” form for DefineDLLFunction,
as discussed in "Declarations Requiring Special Attributes".
Legal type specifications for strings in DefineDLLFunction. These are all equivalent.
In DefineDLLFunction for _strlwr() and _wcslwr(), we used the type name “string,” which
is C# syntax, to indicate a string. As the table above shows, the following are completely equiva-
lent declarations.
H* C syntax: *L
DefineDLLFunction@“_strlwr“, “msvcrt.dll“, “char*“, 8“char*“<D;
H* CÒ syntax: *L
DefineDLLFunction@“_strlwr“, “msvcrt.dll“, “string“, 8“string“<D;
H* VB.NET syntax: *L
DefineDLLFunction@“_strlwr“, “msvcrt.dll“, “String“, 8“String“<D;
So far we have only discussed strings used as “[in]” parameters to functions~that is, where
character data is being sent into the function. Some functions that are typed to take char* use
the string as an “[out]” parameter, meaning that it is actually a buffer that is written into by
the function. Functions that use strings as [out] parameters typically require you to pass in an
extra argument that gives the length of the string buffer you have allocated, or they have a
documented maximum number of characters that they will write into your buffer. An example
So
90 far we have
.NET/Link only discussed strings used as “[in]” parameters to functions~that is, where
User Guide
character data is being sent into the function. Some functions that are typed to take char* use
the string as an “[out]” parameter, meaning that it is actually a buffer that is written into by
the function. Functions that use strings as [out] parameters typically require you to pass in an
extra argument that gives the length of the string buffer you have allocated, or they have a
documented maximum number of characters that they will write into your buffer. An example
of a function that writes data into a string is the familiar Standard C library function sprintf().
The buffer argument is a string into which the function writes. It is an [out] parameter, and
although you could pass a string of data into this function to be overwritten (provided it was
long enough so that the written data did not overrun the length of the string), you would have
no way of getting the modified string back out. The .NET runtime supports a special trick for
working with [out] string parameters, which is to use an instance of the System.Text.StringÖ
Builder class. A StringBuilder is marshaled to an unmanaged function as a character
buffer. After the function returns, the StringBuilder object will hold the data that was written
into the buffer. You can extract the data as a string using the StringBuffer.ToString()
method.
Let’s see how this is done with the sprintf() function. This function takes a variable argument
count, but DefineDLLFunction cannot handle that, so we will define a version specifically for
the case of one integer argument after the format string (three total arguments).
One small point to note in the above call to DefineDLLFunction is that you can specify a const
qualifier on any argument slot. It is ignored by .NET/Link because it is not relevant for
.NET/Link’s purposes, but you can use it if you think it makes your declarations more self-
documenting or if you are just blindly copying a C function prototype.
To call sprintf you first create a StringBuilder object that has a buffer large enough to hold
all the data that might be written into it. This example will use a small string, so 20 bytes is
more than enough.
The return value is the number of characters written into the buffer. To see the string, call
ToString().
In[225]:= sb ü ToString@D
Out[225]= xxx42xxx
† an array of integers that will be written into by the function (an [out] array), that possibly
also requires initial values in the array (an [in, out] array)
† the address of an integer variable that will have a value written into it by the function (an
[out] int), that possibly also requires an initial value (an [in, out] int)
This function breaks up the double d into an integer plus a fraction. The fraction is the return
value, and the integer value is stored in the double pointed to by pint. From this description
you can see that the double* parameter is not an array, but the address of a double that will
get written into (an [out] double). Try calling DefineDLLFunction using the type names
directly from the prototype and see what you get.
In[251]:= modf = DefineDLLFunction[“modf“, “msvcrt.dll“, “double“, {“double“, “double*“}];
When you use a pointer type like double* directly in DefineDLLFunction, as in the above
example, .NET/Link assumes that the parameter is an [in, out] double (the last item in the
bullet list above). In C# notation this type of parameter is called ref double, and in Visual
Basic .NET notation it is ByRef As Double. From “Out” and “Ref” Parameters, you know that
what you need to pass to a ref parameter slot is a symbol that has a value of the correct type
going in, and that this symbol will also be assigned a possibly modified value on the way out.
This means that to call modf and have it assign the second argument to a symbol called inteÖ
gerPart, we need to give integerPart a numerical value before the call or .NET/Link will
complain about bad arguments.
92 .NET/Link User Guide
In[253]:= integerPart = 0;
[email protected], integerPartD
Out[254]= 0.5
In[255]:= integerPart
Out[255]= 3.
This is not ideal because the second argument is conceptually an [out] double, not an [in, out]
double~its value going into the function is not used, so there is no point in having to give it
any value before the call. To improve the definition you can use “out double“ instead of
“double*“ as the type specification.
In[256]:= betterModf =
DefineDLLFunction@“modf“, “msvcrt.dll“, “double“, 8“double“, “out double“<D;
Clear@integerPartD;
[email protected], integerPartD
integerPart
Out[258]= 0.5
Out[259]= 3.
In summary, if you use a pointer type directly in DefineDLLFunction, .NET/Link will treat this
as a ref (C# notation) or ByRef (VB notation) parameter. If this does not correctly capture the
use of the parameter, you should use a different type specification. I prefer to use C# notation
for type names, so that an int* parameter that is treated as an address of an integer that will
be written into is specified as “out int“. If the value is both read and written by the function
it is a “ref int“. Visual Basic .NET does not have a syntax for a “pure” [out] parameter, so
using C# notation is the best choice for that case.
So far we have not considered the case of an array parameter. In a C function prototype, int*
could mean an array of ints, although this would often be written as int[]. If you need to
pass an array of data to a DLL function, the parameter type must be written with array brack-
ets, as in "int[]", not as "int*" (you have already seen how DefineDLLFunction treats types
declared explicitly as pointers). Consider the following two (fictitious) DLL function prototypes.
The SumArray() function takes an array of integers and the length of the array, and it returns
the sum. Here is how you would write DefineDLLFunction and the call to the function.
.NET/Link User Guide 93
Note that bracket notation is used to indicate an array passed into the function, and you call it
from Mathematica with a list of integers.
The ReverseArray() function is quite different. It reverses the array of data in place, so the
array is used as an [in, out] parameter. You can define it as follows:
ReverseArray =
DefineDLLFunction@“ReverseArray“, “SomeDLL.dll“, “void“, 8“int@D“, “int“<D;
This would succeed in the sense that the DLL function would receive an array of ints and
reverse it, but there is no way to propagate the modified array back out of the function. You
might guess that "ref int[]" would be the correct type to use, but that actually translates to
(int[])* because adding ref or out to a type is effectively adding a level of indirection. The
trick is to create a .NET array object and pass that object into the function. After the function
returns, you can get the array data as a Mathematica list. This works because anywhere in
.NET/Link if you have an argument slot typed to take an array you can call it from Mathematica
with either a list or a reference to a .NET object that is an array of the appropriate type. Here is
the proper way to call a DLL function that writes into an array:
H*This creates a.NET object of type Int32@D and fills it with
the data. If you didn‘t care about the initial values in the array,
you could use NETNew@“System.Int32@D“, 5D.*L
intArray = MakeNETObject@82, 4, 6, 8, 10<D;
ReverseArray@intArray, 5D;
The example files include more pointer-related techniques, including the use of the .NET Frame-
work IntPtr type to represent a generic pointer.
94 .NET/Link User Guide
Function Pointers
Some DLL functions take a callback function pointer as an argument. .NET maps function point-
ers to delegates, so you pass a delegate object of the appropriate type for a function pointer
argument. "Handling Events" introduces the NETNewDelegate function, and its main use is for
creating delegate objects for function pointers in DLL calls. It is often the case that there is no
existing .NET delegate type with the correct signature for the function pointer. You can use the
DefineNETDelegate function to create a .NET delegate type with the appropriate signature. The
EnumWindows.nb example file demonstrates using DefineNETDelegate and NETNewDelegate to
call a DLL function that takes a callback function pointer as an argument.
When faced with the need to specify attributes beyond what can be done with options to
DefineDLLFunction, you can use an alternative form where you specify a full declaration as a
string in C# syntax.
MoveFile =
DefineDLLFunction@“@DllImportH\“KERNEL32.DLL\“, EntryPoint=\“MoveFileW\“,
SetLastError=true, CharSet=CharSet.Unicode,
ExactSpelling=true,\nCallingConvention=CallingConvention.StdCallLD
public static extern bool MoveFileHString src, String dstL;“D;
In this version of .NET/Link, only C# syntax is supported not Visual Basic .NET.
Another example of a function that would need this type of full declaration would be one that
had two string arguments that needed separate marshaling conventions.
TwoStrings =
DefineDLLFunction@“@DllImportH\“SomeDLL.dll\“LD public static extern void
[email protected] string ansiString,
@MarshalAsHUnmanagedType.LPWStrLD string unicodeStringL;“D;
If your DLL declaration uses a type that is not in the System assembly, you need to use the
ReferencedAssemblies option to specify its assembly. This is analogous to adding a reference
to an assembly in a Visual Studio project. Here is an example of using this option. The RectanÖ
gle class is found in the System.Drawing assembly, so you will get an error unless you explic-
itly name it as a referenced assembly.
GetWindowRect = DefineDLLFunction@“GetWindowRect“,
“user32.dll“, “BOOL“, 8“HWND“, “ref System.Drawing.Rectangle“<,
ReferencedAssemblies Ø 8“System.Drawing.dll“<D;
Example Files
The following example programs, included with .NET/Link, demonstrate calling C-style DLLs
from Mathematica.
BZip2Compression.nb
WindowsAPI.nb
EnumWindows.nb
Introduction
The .NET runtime has many features that support interoperability with COM (the Component
Object Model, also referred to as ActiveX). Although the arrival of .NET makes COM/ActiveX
officially a "legacy" technology, there are still a huge number of COM objects and libraries in
use, and COM remains an important part of the Windows programming world. Because COM
objects are easily called from .NET, they are easily called from Mathematica via .NET/Link.
COM programming is a complex subject (one reason, no doubt, that Microsoft replaced it with
.NET), and readers are assumed to have some familiarity with the basics of COM. There is
considerable discussion of COM and .NET interoperability issues in the .NET SDK documentation.
The central element in .NET-to-COM interoperability is a special proxy object called a Runtime
Callable Wrapper. Whenever you create a COM object and want to import it into the .NET envi-
96 .NET/Link User Guide
The central element in .NET-to-COM interoperability is a special proxy object called a Runtime
Callable Wrapper. Whenever you create a COM object and want to import it into the .NET envi-
ronment, the .NET runtime creates an RCW object that represents the COM object in the .NET
environment. The RCW mediates calls from .NET into COM, marshaling arguments and return
values back and forth between the .NET and COM worlds. You will see examples of RCW objects
in the sections that follow.
.NET/Link provides two main ways of calling COM objects from Mathematica. The first technique
is to use so-called COM Automation (late binding). This is convenient because it requires no
preparation, but it is not ideal for various reasons discussed later. The second, preferred, tech-
nique is to create or obtain an interop assembly for the COM objects you want to call. An
interop assembly is a special .NET assembly that wraps a COM library and makes that library’s
types and interfaces look like native .NET types. These two methods for calling COM objects are
discussed in the next two sections.
Not all COM objects support Automation but many do, including all those that want to be usable
from the widest variety of programming languages and environments. Visual Basic 6 is capable
of using COM objects via either Automation or early binding (discussed later). Most scripting
languages, including VBScript, however, can only use Automation. .NET/Link can use either
Automation or early binding. Early binding is the preferred technique, and it is discussed in the
next section. Here, we focus on Automation. Using COM objects via Automation in .NET/Link is
almost exactly like using Automation in Visual Basic or VBScript. If you can find sample code in
either of those languages that uses the COM objects you are interested in, then you can gener-
ally translate that code verbatim into Mathematica.
As an example of a COM library, this section will use the Microsoft Speech API. Although
Microsoft will eventually move all its APIs to pure .NET implementations, many are still available
only as COM objects, and the Speech API is an example. (Note that Microsoft has a .NET-based
.NET/Link User Guide 97
As an example of a COM library, this section will use the Microsoft Speech API. Although
Microsoft will eventually move all its APIs to pure .NET implementations, many are still available
only as COM objects, and the Speech API is an example. (Note that Microsoft has a .NET-based
speech tool called the Speech Application SDK. This is targeted at ASP .NET developers creating
telephony applications and should not be confused with the older COM-based Speech API, which
will be used in the next examples.) You do not need to have the Speech API installed to under-
stand this section, as you can simply read the inputs and outputs, but if you want to reevaluate
the input or play around yourself, you can download the Speech API from
http://www.microsoft.com/speech/download/sdk51/. If the line that calls CreateCOMObject
fails, you do not have the Speech API installed.
The basic function for creating COM objects for control via Automation is CreateCOMObject.
This function is analogous to the CreateObject() function in Visual Basic. The argument to
CreateCOMObject is a string that provides either the ProgID or CLSID of a COM coclass. A
ProgID is a human-readable string, such as "Excel.Application", whereas the CLSID is a
sequence of hex digits, such as "{000208d5-0000-0000-c000-000000000046}". You can obtain
the CLSID or ProgID of a COM object from its documentation, or, even better, from some
sample code in Visual Basic that uses it.
The voice object is unlike any .NET object you have seen yet. This object is a Runtime Callable
Wrapper (RCW), a class of objects that was mentioned in the Introduction. You can think of it
as a proxy object that represents the COM object in the .NET world. For most .NET objects, the
string inside the brackets in the OutputForm representation of the object gives the name of the
object’s .NET type. The voice object is different~the string shows the name of the default COM
interface supported by the object (SpeechLib.ISpeechVoice). Here is the actual type name of
The
98 voice object
.NET/Link is unlike any .NET object you have seen yet. This object is a Runtime Callable
User Guide
Wrapper (RCW), a class of objects that was mentioned in the Introduction. You can think of it
as a proxy object that represents the COM object in the .NET world. For most .NET objects, the
string inside the brackets in the OutputForm representation of the object gives the name of the
object’s .NET type. The voice object is different~the string shows the name of the default COM
interface supported by the object (SpeechLib.ISpeechVoice). Here is the actual type name of
the object.
As you might have guessed, System.__ComObject is the name of the RCW class. Seeing a
.NET object represented in Mathematica as <<NETObject[System.__ComObject]>> would not
be very informative, as this could be any COM object and thus tells you nothing about the
object. When .NET/Link returns an RCW object to Mathematica, it tries to determine the name
of the default COM interface that the object supports. If this is successful, then .NET/Link
reports the object as <<NETObject[COMInterface[Default.COM.Interface]]>>. Remember
that this is the name of a COM interface and has no meaning whatsoever to .NET or .NET/Link.
It is displayed simply to help you know something about the COM object that this .NET object
represents. For .NET/Link to be able to determine the default COM interface name, the object
must provide sufficiently detailed type information via a COM type library. Most COM objects
provide this feature, so you will often see RCW objects formatted with a COM interface name.
In some cases, however, the search for a default interface name will fail, and you will see a
COM object formatted only as <<NETObject[System.__ComObject]>>.
One drawback to using COM objects via Automation is that you cannot get information about
COM methods and properties using NETTypeInfo .
In[3]:= NETTypeInfo@voiceD
NETTypeInfo::com : Type information is not currently available for "raw" COM objects.
Out[3]//TableForm=
Although you can call methods and properties on the COM object, you cannot see these meth-
ods directly from .NET. For information about methods and properties and their arguments, you
will need to turn to the documentation for the COM object. Often you can find sample code in
Visual Basic for using a COM object, and using it from Mathematica via .NET/Link will look
almost exactly the same.
.NET/Link User Guide 99
The Speak() method speaks a string of text. Here is the declaration for the Speak() method
from the IDL file for the SpeechLib type library.
Experienced COM programmers will recognize the elements of this declaration. The first argu-
ment is a BSTR, which is a string in the COM world. Such arguments are called with a string
from .NET, and thus with a string from Mathematica. The second argument is marked as
optional, with a default value of 0. This means that the Speak() method can be called without
the second argument.
In[5]:= voice ü Speak@“This is an example of using the SpVoice object via Automation“D;
The second argument is listed as being of the type SpeechVoiceSpeakFlags, which is a COM
enumeration containing constants that control how the text is spoken. One drawback to using
COM objects via Automation is that there is no way to access COM enumerations. To use the
second argument, you have to supply an integer value that corresponds to the correct value of
the enum. You can get this information from the documentation or from the type library itself
using a tool like OLE View, which is bundled with Microsoft Visual Studio. To speak the voice
asynchronously, meaning the Speak() method will return before the text finishes speaking, you
use the flag SVSFlagsAsync, which has the value 1.
In[6]:= voice ü
Speak@“This is an example of using the SpVoice object via Automation. This
text is spoken asynchronously“, 1D;
† You cannot use NETTypeInfo to get information about the methods and properties of an
object.
These drawbacks are the same as you would encounter using COM from a pure scripting lan-
guage like VBScript. The next section discusses a better way to use COM with .NET/Link.
100 .NET/Link User Guide
These drawbacks are the same as you would encounter using COM from a pure scripting lan-
guage like VBScript. The next section discusses a better way to use COM with .NET/Link.
Interop assemblies can be created with a tool called tlbimp.exe ("type library importer"),
which is included with the .NET Framework SDK, and also with Visual Studio .NET. You will find
ample documentation on how to run tlbimp, and you will see an example later. It is also
possible to create an interop assembly programmatically, and .NET/Link provides the
LoadCOMTypeLibrary function for this purpose. LoadCOMTypeLibrary takes a COM type library,
creates an interop assembly from it, and loads this assembly into .NET/Link. You can think of it
as analogous to LoadNETAssembly, except that it takes a path to a COM type library instead.
LoadCOMTypeLibrary@typeLibPathD create an interop assembly from the given type library and
load it
Earlier you used the COM-based Microsoft Speech API via Automation. The preferred method is
to load the type library to allow early binding.
Interop assemblies created by LoadCOMTypeLibrary are created with default rules for naming
of namespaces and types, and it is useful to use NETTypeInfo on the assembly to see what
types are available. For each coclass in the COM type library, a class will be created in the
interop assembly with the name of the coclass with the word "Class" appended. You saw earlier
that there was a coclass called SpVoice, so you expect to find a .NET class called SpVoiceÖ
Class in the interop assembly. There are a lot of types in this assembly; this shows just the
classes.
In[8]:= NETTypeInfo[speechAsm, “Classes“]
Assembly: interop.SpeechLib
Full Name: interop.SpeechLib, Version=5.0.0.0
Location:
Ê Classes
class SpeechLib. _ISpeechRecoContextEvents _SinkHelper
class SpeechLib. _ISpeechVoiceEvents _SinkHelper
class SpeechLib. SpAudioFormatClass
class SpeechLib. SpCompressedLexiconClass
class SpeechLib. SpCustomStreamClass
class SpeechLib. SpeechConstants
class SpeechLib. SpeechStringConstants
class SpeechLib. SpFileStreamClass
class SpeechLib. SpInProcRecoContextClass
class SpeechLib. SpInprocRecognizerClass
class SpeechLib. SpLexiconClass
class SpeechLib. SpMemoryStreamClass
class SpeechLib. SpMMAudioEnumClass
class SpeechLib. SpMMAudioInClass
class SpeechLib. SpMMAudioOutClass
class SpeechLib. SpNotifyTranslatorClass
class SpeechLib. SpNullPhoneConverterClass
class SpeechLib. SpObjectTokenCategoryClass
class SpeechLib. SpObjectTokenClass
class SpeechLib. SpPhoneConverterClass
class SpeechLib. SpPhraseInfoBuilderClass
class SpeechLib. SpRecPlayAudioClass
class SpeechLib. SpResourceManagerClass
class SpeechLib. SpSharedRecoContextClass
class SpeechLib. SpSharedRecognizerClass
class SpeechLib. SpStreamClass
class SpeechLib. SpStreamFormatConverterClass
class SpeechLib. SpTextSelectionInformationClass
class SpeechLib. SpUnCompressedLexiconClass
class SpeechLib. SpVoiceClass
class SpeechLib. SpWaveFormatExClass
You will find NETTypeInfo very useful when exploring an interop assembly. When creating a
COM object earlier using Automation, you used the CreateCOMObject function. Now that you
have .NET classes that represent the COM coclasses, you can call NETNew instead.
102 .NET/Link User Guide
You will find NETTypeInfo very useful when exploring an interop assembly. When creating a
COM object earlier using Automation, you used the CreateCOMObject function. Now that you
have .NET classes that represent the COM coclasses, you can call NETNew instead.
You use this object just like any other .NET object. Here is the Speak() method. For some
reason, the optional nature of the second argument is not preserved in the interop assembly, so
you have to call Speak() with two arguments.
When using Automation, you saw that the second argument is a COM enumeration called
SpeechVoiceSpeakFlags. When using Automation, however, there is no way to access an
enumeration, so you had to pass an integer value. But with an interop assembly there is a .NET
enumeration you can use to make your code more readable.
In[11]:= LoadNETType@“SpeechLib.SpeechVoiceSpeakFlags“D;
voice ü Speak@“Using COM objects is easier with an interop assembly“,
SpeechVoiceSpeakFlags`SVSFlagsAsyncD;
One great advantage of having an interop assembly is that you can use NETTypeInfo to get
information about the methods and properties supported by objects. This shows the properties
of the voice object.
Ê Properties
virtual SpeechLib.SpeechVoiceEvents AlertBoundary
virtual bool AllowAudioOutputFormatChangesOnNextSet
virtual SpeechLib.SpObjectToken AudioOutput
virtual SpeechLib.ISpeechBaseStream AudioOutputStream
virtual SpeechLib.SpeechVoiceEvents EventInterests
virtual SpeechLib.SpeechVoicePriority Priority
virtual int Rate
virtual SpeechLib.ISpeechVoiceStatus Status @read onlyD
virtual int SynchronousSpeakTimeout
virtual SpeechLib.SpObjectToken Voice
virtual int Volume
Note that once an interop assembly is loaded for a type library, if you call CreateCOMObject
with the name of a COM coclass, you get back a native .NET object of the class that corre-
sponds to the COM coclass, not a raw RCW as before. This means that CreateCOMObject and
NETNew become equivalent ways of creating an instance of a COM coclass.
.NET/Link User Guide 103
Note that once an interop assembly is loaded for a type library, if you call CreateCOMObject
with the name of a COM coclass, you get back a native .NET object of the class that corre-
sponds to the COM coclass, not a raw RCW as before. This means that CreateCOMObject and
NETNew become equivalent ways of creating an instance of a COM coclass.
Options to LoadCOMTypeLibrary .
LoadCOMTypeLibrary takes two options that control the assembly-creation process. The first is
SaveAssemblyAs, which allows you to specify a filename into which you want the created assem-
bly saved. LoadCOMTypeLibrary can take a while to execute, so it is useful to save the assem-
bly in a file and load it using LoadNETAssembly in the future. This makes LoadCOMTypeLibrary
the programmatic equivalent to running the tlbimp.exe tool, in that it can write out the gener-
ated assembly. The second option to LoadCOMTypeLibrary is SafeArrayAsArray, which speci-
fies whether to import all COM SAFEARRAY's as the System.Array class rather than a typed,
single dimensional managed array. The default is False. See the .NET Framework documenta-
tion for the System.Runtime.InteropServices.TypeLibImporterFlags enumeration for
more details on this advanced option. If you need more control over the generated assembly,
use the tlbimp.exe tool as described in the next section.
In the earlier discussion of using COM objects via Automation, the role of the RCW was
described. You saw that the class name of a "raw" RCW is System.__ComObject. It is impor-
tant to remember that all COM objects are represented in .NET as RCWs, even when using an
interop assembly. You can see below that the SpVoiceClass derives from __ComObject.
104 .NET/Link User Guide
Ê Type
class SpeechLib.SpVoiceClass
Inheritance:
System.Object
System.MarshalByRefObject
System.__ComObject
SpeechLib.SpVoiceClass
Interfaces Implemented: SpeechLib.ISpeechVoice, SpeechLib.SpVoice, SpeechLib._ISpeechVoiceEvents_Event
Assembly-Qualified Name: SpeechLib.SpVoiceClass, interop.SpeechLib, Version=5.0.0.0
Assembly Location: Dynamically generated
Once the assembly has been created, load it like any other assembly.
LoadNETAssembly@“c:\\interop.SpeechLib.dll“D;
.NET/Link User Guide 105
A good example of PIAs is the set created by Microsoft to accommodate the Office XP suite,
which exposes a rich object model for Automation. Anyone trying to control an Office XP
component like Word or Excel from Mathematica should obtain the Office PIAs from
http://msdn.microsoft.com/library/default.asp?url=/downloads/list/office.asp. These PIAs are
installed by default with Office 2003, but you can install them for use with Office XP and per-
haps earlier versions of Office as well.
The ExcelPieChart.nb example file shows how to call Excel from Mathematica using .NET/Link.
That example will work whether or not you have the Office PIAs installed, but if the PIAs are
present, you have the advantages of working with strongly typed .NET objects instead of raw
RCW objects. If the PIAs are installed on your machine, and CreateCOMObject is called to start
an instance of Excel, it automatically returns a .NET type from the Excel interop assembly, not
a raw RCW like <<NETObject[COMInterface[Excel._Application]]>>.
Every COM object in .NET is represented by a single unique RCW. If you acquire a reference to
the same COM object through two different means, you will get the same RCW each time. This
sole RCW keeps a reference count on the COM object. This reference count is internal to COM
and should not be confused with the reference count of a .NET object. Calling
ReleaseCOMObject does not actually force the immediate release of COM resources~it just
decrements this internal COM reference count. Often this count will be just one,
ReleaseCOMObject will cause it to go to zero, and then the resources will be freed.
ReleaseCOMObject returns the new reference count, so you can see if it has gone to zero yet.
Here is an example of acquiring multiple references to the same COM object. The following line
launches a new instance of Excel. It will not become visible, but you can see it in the Task
Manager listing of processes.
Now acquire two more references to that same instance of Excel. The GetActiveCOMObject
function is like CreateCOMObject except that instead of creating a new object, it acquires an
already-active one. It is analogous to the GetActiveObject() function in the COM API and
Visual Basic 6. The Pause is necessary here because COM apparently needs to catch its breath
a bit between calls to GetActiveObject().
.NET/Link User Guide 107
Now acquire two more references to that same instance of Excel. The GetActiveCOMObject
function is like CreateCOMObject except that instead of creating a new object, it acquires an
already-active one. It is analogous to the GetActiveObject() function in the COM API and
Visual Basic 6. The Pause is necessary here because COM apparently needs to catch its breath
a bit between calls to GetActiveObject().
If you called ReleaseCOMObject [excel1] now, you probably would not want Excel to quit,
because there are other outstanding references to Excel via the excel2 and excel3 objects.
Note how calling ReleaseCOMObject decrements the COM reference count on the instance of
Excel until it finally goes to zero. Only when it reaches zero will the Excel process quit.
You have now seen how to use ReleaseCOMObject to force the timely release of COM
resources. It is never strictly necessary to do this, as the .NET garbage collector will get around
to it eventually, but often it is not timely enough. An alternative to using ReleaseCOMObject is
simply to make sure that you use NETBlock or ReleaseNETObject to allow the .NET objects
you create to be released. Then you can manually force the .NET garbage collector to run. This
is especially convenient if you have code that creates a lot of COM objects. Rather than keeping
track of all of them and calling ReleaseCOMObject on each one, it is easier to use NETBlock to
ensure that the objects all have .NET reference counts of zero when you are done with them,
and then call the garbage collector. Here is an outline of what that looks like.
SomeFunction[args__] :=
Module[{result},
NETBlock[
... some code here that creates and manipulates COM objects
result = ...
];
LoadNETType[“System.GC“];
GC`Collect[];
result
]
108 .NET/Link User Guide
The ApplicationClass class has a property called ActiveSheet that will return the work-
sheet in the workbook you just created.
Notice that the result from ActiveSheet is a raw RCW object, not a strongly typed .NET object
(recall that raw RCW objects are of the class System.__ComObject, and .NET/Link tries to
format them with the name of the default COM interface that they support). There is a
Microsoft.Office.Interop.Excel.WorksheetClass class in the Excel interop assembly
that represents worksheets, so why was the result of ActiveSheet not an instance of that
class? To see the answer, look at the declaration of the ActiveSheet property.
Note that this property is typed to return only object, not WorksheetClass. That is because
the active sheet could be a chart or a worksheet, and these are different classes. In an interop
assembly, methods or properties that are typed to return object will return a raw RCW. This
reminds you that COM objects in .NET are different animals than normal .NET objects. When
any object is marshaled from COM into .NET, it always arrives as a raw RCW. With the help of
type information from an interop assembly, the .NET runtime can cast a raw RCW to a specific
managed type. For example, if a method is typed to return class X, and the method returns a
COM object (as an RCW), .NET casts the RCW to the type X before returning it from the
method. If a method is typed to return only object, like the ActiveSheet property, then there
assembly, methods or properties that are typed to return object will return a raw RCW. This
reminds you that COM objects in .NET are different animals than normal .NET/Link
.NET objects.
User Guide When
109
any object is marshaled from COM into .NET, it always arrives as a raw RCW. With the help of
type information from an interop assembly, the .NET runtime can cast a raw RCW to a specific
managed type. For example, if a method is typed to return class X, and the method returns a
COM object (as an RCW), .NET casts the RCW to the type X before returning it from the
method. If a method is typed to return only object, like the ActiveSheet property, then there
is no type information that .NET can use to cast the object, so you end up with a raw RCW.
You can use the object returned by ActiveSheet, but you will be calling it via late binding
because it has no type information. If you want to make a strongly typed object that you can
call via early binding, then you do exactly what you would do in C# or Visual Basic .NET~you
cast the object to the desired type. Once you have cast to the desired managed type, you once
again have all the advantages that come from using an interop assembly instead of using late
binding. In this example, you know that the active sheet is a worksheet, so you can cast it to
WorksheetClass.
In[26]:= activeSheet = CastNETObject@excel ü ActiveSheet,
“Microsoft.Office.Interop.Excel.WorksheetClass“D
Out[262]= «[email protected] »
If this sounds confusing, remember that this is exactly what is done in C# or Visual Basic .NET.
Here is what it would look like in C#.
If the COM object cannot be cast to the specified managed type, CastNETObject will issue a
message and return $Failed.
In "Casting", it was stated that there is never a need to downcast in .NET/Link, because objects
always have their true runtime type~there is never a type lower in the inheritance hierarchy to
downcast to. This rule does not apply for casting COM objects, because in some sense the
runtime type of all COM objects is just the raw RCW class __ComObject. In the presence of
type information, the .NET runtime can downcast automatically to more derived managed
types. When a property or method is typed to return only object, you can downcast the object
yourself, provided you know the correct type.
110 .NET/Link User Guide
The following example shows how to handle COM events fired by Internet Explorer. Internet
Explorer supports a rich object model for the content of an HTML window. This is called the
document object model, and it is exposed to clients via the mshtml COM library. Microsoft
bundles with the .NET Framework a primary interop assembly for mshtml, to make it easier to
use from .NET programs. Presumably, there will eventually be a native .NET version of Internet
Explorer and mshtml, but for now, as with many other COM-based Microsoft technologies, you
use them from .NET via an interop assembly. The example developed below will display a web
page in an Internet Explorer window, and as the user moves the mouse over elements in the
page, the elements will have their font size changed randomly.
The mshtml COM component and its associated primary interop assembly only manage the
content of an Internet Explorer window. The Internet Explorer application is a separate COM
object that must be created in the usual way for raw COM objects.
In[27]:= ie = CreateCOMObject@“InternetExplorer.Application“D
Out[27]= «NETObject@[email protected] »
The fact that this object is formatted with COMInterface[...] indicates that it is a raw RCW
and you can only interact with it via Automation. This is fine, as only a few simple properties
are needed. To get documentation for COM objects, look them up in the MSDN Library, either
online or in the Visual Studio help system.
In[28]:= ie ü navigate@“www.wolfram.comêsolutionsêmathlink“D
Now make the browser window visible and loop until the page has completely loaded.
You want to interact not with the Internet Explorer application but with the document object
that it contains, so acquire that object.
Note that this object is a strongly typed .NET object, not a raw RCW. Because there is a pri-
mary interop assembly for the document object model, whenever such a COM object is
imported into .NET it can be automatically wrapped in the .NET class that is mapped to the
document COM coclass. You are now in the cozy world of using strongly typed objects from an
interop assembly.
COM events fired by an object are mapped to .NET events in the interop assembly. You will see
a .NET event member for each method in every [source] COM interface that a .NET class
implements. You can use NETTypeInfo to see the events that are fired by the HTMLDocumentÖ
Class class. There are quite a few for this class, so this just shows the one you need.
In[32]:= NETTypeInfo@doc, “Events“, “*onmouseover*“D
There are two onmouseover events inherited from two different interfaces. You want to use the
one named HTMLDocumentEvents2_Event_onmouseover, which supplies an argument. There
is no separate documentation for the mshtml primary interop assembly, so you have to use the
documentation for the COM version and make the appropriate mental translations, which are
usually quite straightforward. You can find full documentation on the mshtml component at
http://msdn.microsoft.com/library/default.asp?url=/workshop/browser/mshtml/reference/
reference.asp.
"Handling Events" shows you how to use the AddEventHandler function to assign Mathematica
functions to be called when events are fired in .NET. You use the same function for COM events,
as they are made to look just like .NET events by the interop assembly. Note that as always
you must change _ characters to U when using .NET names as symbols.
Now define the onMouseOver function. The NETTypeInfo call above told you that the argument
to the event is of interface type mshtml.IHTMLEventObj. This is the managed equivalent of the
IHTMLEventObj COM interface, and from the documentation for that interface you can cook up
the following simple function that wraps every element in a <FONT> element that specifies a
random font size.
112 .NET/Link User Guide
Now define the onMouseOver function. The NETTypeInfo call above told you that the argument
to the event is of interface type mshtml.IHTMLEventObj. This is the managed equivalent of the
IHTMLEventObj COM interface, and from the documentation for that interface you can cook up
the following simple function that wraps every element in a <FONT> element that specifies a
random font size.
In[34]:= onMouseOver@evt_D :=
Module@8element<,
element = evt ü srcElement;
element ü innerHTML = “<FONT size=‘“ <>
ToString@Random@Integer, 81, 7<DD <> “‘>“ <> element ü innerHTML <> “<êFONT>“;
D
Before you actually try moving the mouse over the web page, there is one more detail that
must be handled. "Manually Sharing the Kernel and Front End with .NET" shows how to use the
ShareKernel function to put the kernel into a state where it was receptive to calls arriving from
.NET. ShareKernel is not often needed in .NET/Link, because you can usually enter and leave
the sharing state automatically using the DoNETModeless function. DoNETModeless requires a
top-level window as its argument, however. Here you have no such window, just an instance of
Internet Explorer. Therefore you have to use ShareKernel to manually enter the sharing state.
As always, you save the result from ShareKernel to pass into UnshareKernel later.
Now bring the Internet Explorer window to the foreground and move the mouse over it (without
pressing the mouse button). It might take a second or two for the first font effect to occur.
This is a frivolous example, but you can imagine many more useful and sophisticated ways to
interact with a browser window using Mathematica.
.NET/Link User Guide 113
There is full documentation for aximp in the .NET Framework SDK, but here is a simple exam-
ple. Say you want to use the Microsoft Calendar Control in a .NET window (you probably have
this control installed on your machine). Assume that the type library for this control is in the file
d:\OfficeXP\Office10\mscal.ocx on your machine. (One way to get information like this is
by looking up the control using the OLE View tool that is bundled with Visual Studio.) The
following command line runs aximp (of course, aximp.exe has to be on your PATH for this to
work as written).
The above invocation of aximp creates two assemblies in the current directory: MSACAL.dll
and AxMSACAL.dll (the "MSACAL" comes from the library MSACAL statement in the control’s
type library definition). The MSACAL.dll assembly contains managed types for the ICalendar
interface and CalendarClass class, along with a few others. This is the same interop assembly
that would be created by using the tlbimp tool. The second assembly, AxMSACAL.dll, contains
the special wrapper class that makes the Calendar control into a .NET control that can be
hosted in a .NET window. This wrapper class is called AxCalendar, named according to the
convention "Ax" followed by the name of the COM coclass (Calendar). The ildasm.exe tool
(intermediate language disassembler) is very useful for examining the created assemblies. The
ildasm.exe program is bundled with the .NET Framework SDK and resides in the same direc-
tory as aximp.exe and tlbimp.exe.
When you load the AxMSACAL.dll assembly, the MSACAL.dll assembly will be loaded as well,
because AxMSACAL.dll is dependent on it and it resides in the same directory.
114 .NET/Link User Guide
In[1]:= LoadNETAssembly@“c:\\AxMSACAL.dll“D
Out[1]= NETAssembly@AxMSACAL, 1D
Now create an instance of the AxCalendar wrapper class. This class has all the methods and
properties of the Calendar COM object, and it also inherits from the System.Windows.Forms.CoÖ
ntrol class, so it can be used like any other .NET control.
In[2]:= cal = NETNew@“AxMSACAL.AxCalendar“D
Out[2]= «[email protected] »
Now create a .NET form to host the control and display it. The DoNETModal function at the end
will display the form and return the calendar’s Value property when the form is closed. This
property will hold the date the user selected.
The .NET runtime has conveniently mapped the result of the Value property to a DateTime
object. This is easily manipulated to get the selected date as a string.
Now clean up by releasing the calendar object. Note that you do not call ReleaseCOMObject on
the AxCalendar object, because it is not a COM object~it is a pure .NET class that merely
holds a reference to a COM object. The actual COM object is of class MSACAL.CalendarClass,
but you never directly create an instance of that class, just the AxCalendar wrapper.
In[9]:= ReleaseNETObject@calD
Example Files
The following example program included with .NET/Link demonstrates calling COM components
from Mathematica.
ExcelPieChart.nb
.NET/Link User Guide 115
Introduction
"Calling .NET from Mathematica" describes using .NET/Link to allow you to call from Mathemat-
ica into .NET, thereby extending the Mathematica environment to include the functionality in all
existing and future .NET classes. This tutorial shows you how to use .NET/Link in the opposite
direction, as a means to write .NET programs that use the Mathematica kernel as a computa-
tional engine.
.NET/Link uses MathLink, Wolfram Research’s protocol for sending data and commands
between programs. Many of the concepts and techniques in .NET/Link programming are the
same as those for programming with the MathLink C-language API. The .NET/Link documenta-
tion is not intended to be an encyclopedic compendium of everything you need to know to write
.NET programs that use MathLink. Programmers may have to rely a little on the general docu-
mentation of MathLink programming. The Tutorial is divided into two major sections along the
same lines as this documentation. You will want to read the second part. Many of the functions
.NET/Link provides have C-language counterparts that are identical or nearly so.
You should at least skim the tutorial "Calling .NET from Mathematica" at some point. Your .NET
“front end” can use the same techniques for calling .NET methods from Mathematica code and
passing .NET objects as arguments that programmers use when running the kernel from the
notebook front end. This allows you to have a very high-level interface between .NET and
Mathematica. When you are writing MathLink programs in C, you have to think about passing
and returning simple things like strings and integers. With .NET/Link you can pass .NET objects
back and forth between .NET and Mathematica.
The sections below merely provide an overview of topics in .NET/Link programming. The main
class-by-class reference for .NET/Link is the API documentation. You should also look at the
example programs.
When you are reading this text, or programming in .NET or Mathematica, remember that the
entire source code for .NET/Link is provided. If you want to see how anything works (or why it
doesn’t), you can always consult the source code directly.
What Is MathLink?
116 .NET/Link User Guide
What Is MathLink?
MathLink is a platform-independent protocol for communicating between programs. In more
concrete terms, it is a means to send and receive Mathematica expressions. MathLink is the
means by which the notebook front end and kernel communicate with each other. It is also
used by a large number of commercial and freeware applications and utilities that link Mathemat-
ica and other programs or languages. It is implemented as a library of C-language functions.
.NET/Link brings the capabilities of MathLink into .NET in a way that is simpler to use and much
more powerful than the raw C-level API.
Introduction
The .NET/Link class library is written in an object-oriented style intended to maximize its extensi-
bility in the future without requiring users' code to change. This requires a clean separation
between interface and implementation. This is accomplished by exposing the main link function-
ality through interfaces, not classes. The names of the concrete classes that implement these
interfaces will hardly be mentioned because programmers do not need to know or care what
they are. Rather, you will use objects that belong to one of the interface types. You do not need
to know what the actual classes are because you will never create an instance directly; instead,
you use a "factory method" to create an instance of a link class. This will become clear further
on.
This section gives a brief overview of the main interfaces and classes. They will be discussed in
more detail later. In addition, there is full documentation for the class library in the .NET/Link
API documentation. Most of these classes and interfaces are in the Wolfram.NETLink name-
space; others are in Wolfram.NETLink.UI.
.NET/Link User Guide 117
The basic idea is that the IMathLink interface encompasses all the operations that can be
performed on a link without making any assumptions about what program is on the other side
of the link. IKernelLink adds the assumption that the other side is a Mathematica kernel.
IKernelLink is the most important interface, as most programmers will work exclusively with
IKernelLink . Of course, since IKernelLink extends IMathLink, many of the methods you will
use on your IKernelLink objects are declared and documented in the IMathLink interface.
The most important class that implements IMathLink is NativeLink, so named because it calls
directly into Wolfram Research’s MathLink library. In the future, other classes could be added
that do not rely on native methods~for example, one that uses .NET remoting to communicate
across a network. As discussed above, programmers do not need to be concerned about what
these classes are, because they will never type a link class name in their code.
MathLinkFactory
MathLinkFactory is the class that you use to create link objects. It contains the static methods
CreateMathLink(), CreateKernelLink(), and CreateLoopbackLink(), which take various
argument sequences. These are the equivalents of calling MLOpen in a C program.
MathLinkException
MathLinkException is the exception class that is thrown by many of the methods in IMathLink
and IKernelLink . The .NET/Link API uses exceptions to indicate errors, rather than function
return values like the MathLink C API. In C, you write code that checks the return values like
this:
118 .NET/Link User Guide
// C code
if (!MLPutInteger(link, 42)) {
// was error; print message and clean up.
}
In .NET/Link, you can wrap MathLink calls in a try block and catch MathLinkException.
Expr
The Expr class provides a direct representation of Mathematica expressions in .NET. Expr has a
number of methods that provide information about the structure of the expression and that let
you extract components. These methods have names and behaviors that will be familiar to
Mathematica programmers~for example, Length(), Part(), NumberQ(), VectorQ(), Take(),
Delete(), and so on. When reading from a link, instead of using the low-level IMathLink
interface methods for discovering the structure and properties of the incoming expression, you
can just read an entire expression from the link using GetExpr(), and then use Expr methods
to inspect it or decompose it. For writing to a link, Expr objects can be used as arguments to
some of the most important IKernelLink methods.
MathKernel
MathKernel is a non-visual component that provides a very high-level interface for interacting
with Mathematica. It is especially intended for use in visual programming environments, as it is
highly configurable via properties. For many types of .NET programs that use Mathematica for
computations, the IKernelLink interface provides ideal functionality. For some types of pro-
grams, however, programmers might find the MathKernel object even easier to use. This is
especially true for programs that want to capture not just the result of a computation, but also
messages, Print output, or graphics generated as side effects of the computation.
MathPictureBox
The MathPictureBox class provides an easy way to display Mathematica graphics and typeset
expressions. This class is often used from Mathematica code, but it is just as useful in .NET
programs.
Sample Program
.NET/Link User Guide 119
Sample Program
The .NET/Link distribution includes a SimpleLink sample program that demonstrates simple
techniques for launching Mathematica and performing computations. The code is available in
both C# and Visual Basic .NET.
A consequence of the fact that Wolfram.NETLink.dll is not strong-named is that you can
replace your application’s copy with an updated version, and the updated version will be used
without requiring the application to be recompiled. In contrast, strong-named assemblies in
.NET are strictly versioned, so that when a program is compiled against a specific version of the
assembly, the program can only run with that precise version. Of course, this strict versioning
is touted as a benefit of .NET, and it is advantageous in certain circumstances, but for various
technical reasons it is not desirable for Wolfram.NETLink.dll to be strong-named.
120 .NET/Link User Guide
The command-line compilers rely on several DOS environment variables being set correctly, so
the .NET Framework SDK comes with a batch file named sdkvars.bat that you can run in your
DOS session to set these variables. If you own Visual Studio .NET and want to use any com-
mand-line tools, use the Microsoft Visual Studio .NET/Visual Studio .NET Tools/ViÖ
sual Studio .NET Command Prompt item on the Windows Start menu to launch a DOS
session with all the required settings.
It is convenient to place a copy of Wolfram.NETLink.dll into your build directory before you
compile, as you would otherwise need to include the full path to this assembly on the compiler
command line, and you will need a copy of it to be present in the program’s directory anyway.
The examples below assume that you have copied (not moved!) the Wolfram.NETLink.dll file
from <Mathematica dir>\SystemFiles\Links\NETLink into the directory in which you are
performing the build. Here is a sample command for a C# program:
Either of the above commands will result in the creation of a MyProgram.exe file in the current
directory. This program will need to have a copy of Wolfram.NETLink.dll alongside it to run.
.NET/Link User Guide 121
When Visual Studio .NET builds your program it will automatically place a copy of WolframÖ
.NETLink.dll in the output directory, alongside your .exe file. Your program will require a
copy of Wolfram.NETLink.dll alongside it to run, so if you deploy your program to another
location or distribute it to other users, you must keep the Wolfram.NETLink.dll file with it.
Deploying Programs
If you build a .NET program that uses .NET/Link and want to distribute it to others, you will
need to include a copy of the Wolfram.NETLink.dll assembly alongside your application’s
.exe file. Alternatively, you can put Wolfram.NETLink.dll in a subdirectory of the applica-
tion’s directory, according to the standard rules for how .NET probes for assemblies that are not
strong-named.