Using .NET in IDEAScript
Using .NET in IDEAScript
CaseWare IDEA Inc. is a privately held software development and marketing company,
with offices in Toronto and Ottawa, Canada, related companies in The Netherlands and
China, and CaseWare IDEA Partners serving over 90 countries. CaseWare IDEA Inc. is a
subsidiary of CaseWare International Inc., the world leader in business-intelligence
software for auditors, accountants, and systems and financial professionals.
Overview 6
Creating the .NET Project 6
Creating the Class 7
Accessing the Library from IDEAScript 9
Working with Strings 10
Registering the Library 12
Pitfalls 13
Conclusion 13
Using .NET in IDEAScript
Overview
The purpose of this guide is to demonstrate how to communicate with .NET objects in
IDEAScript. This can be helpful in extending the capabilities of IDEAScript and perform
processing that is not supported in IDEAScript.
To start you will want to create a new Visual C#/VB.NET Class library. First, you will need to
start Visual Studio by right clicking its icon and selecting Run as Administrator. Visual Studio
needs to register the DLL each time the project is built.
This new library will contain the .NET code that you want IDEAScript to access. Create a new
project by clicking File -> New -> Project. Give your project the name IDEAdotNETInterop.
After the project is created right click the Class1.cs and select Delete.
The first problem that needs to be addressed is that .NET is managed code and IDEAScript is
unmanaged code. In order for the two to work together IDEAScript must be able to find the
managed code. You do that by exposing your project to COM. To do that from the Project
menu select the properties for the project. On the Application tab click the Assembly
Information… button. On the dialog that comes up select the Make assembly COM-Visible
check box and click OK.
Now when the project is compiled certain portions of the assembly will be visible to COM, and
thus IDEAScript. This will allow the use of the CreateObject function in IDEAScript to create
an instance of a .NET class in that assembly and access its properties, methods, and so forth
which are visible to COM.
In order for IDEAScript to be able to find the assembly it must be registered. Otherwise
Windows will not be able to find the assembly. For development purposes you can setup the
project so that Visual Studio will register the assembly. Do so by selecting the Build tab of the
Properties window and checking the Register for COM interop check box. In order to use this
assembly on a machine other than the development machine the assembly will need to be
registered manually. That will be covered in a later section.
Page 6 of 15
Using .NET in IDEAScript
Add a new class to the project by right clicking the project in the Solution Explorer, selecting
Add and then New Class. Name this new class Calculator. Update the code for the class as
follows:
The next step is to make these two methods so that they are visible to COM and in turn
IDEAScript. In order to do so, first create an interface with all of the public members and
then create an interface for them. This is done by selecting all of those members, right
clicking the selection, selecting Refactor and then Extract Interface. Use the default options
when extracting the interface. This interface defines what members of the class COM will be
able to interact with. Open the interface and add the following attribute to it as follows:
[System.Runtime.InteropServices.ComVisible(true)]
interface ICalculator
{
int Add(int a, int b);
int Multiply(int a, int b);
}
This makes the members in this interface COM visible so IDEAScript can interact with them.
Similar attributes need to be added to the Calculator class and to its public members that you
want to access in IDEAScript. To save a bit of typing add a using statement for the
System.Runtime.InteropServices namespace. The new code for the Calculator class is next.
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
namespace IDEAdotNETInterop
{
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
Page 7 of 15
Using .NET in IDEAScript
[ComVisible(true)]
public int Multiply([MarshalAs(UnmanagedType.I4)]int a, [MarshalAs
(UnmanagedType.I4)]int b)
{
return a * b;
}
}
}
The class is now visible to COM and in turn the two public methods. The parameters for the
methods have been marshalled using the MarshalAs attribute with the type
UnmanagedType.I4. This makes it clear what the types are for the parameters for the
methods, to others using the class. The value UnmanagedType.I4 represents a 4 byte integer
and is equivalent to the Long variable type in IDEAScript. The last step is to build the project
by pressing F6 or selecting Build -> Build Solution.
Page 8 of 15
Using .NET in IDEAScript
Sub Main
Dim calc As Object
calc = CreateObject("IDEAdotNETInterop.Calculator")
MsgBox(calc.Add(10, 10))
MsgBox(calc.Multiply(10, 10))
calc = Nothing
End Sub
Saving and running the macro will create two message boxes. The first message box will
display 20, which is the sum of 10 and 10. The second will display 100, which is the product of
10 and 10.
Page 9 of 15
Using .NET in IDEAScript
using System;
namespace IDEAdotNETInterop
{
[System.Runtime.InteropServices.ComVisible(true)]
interface ICalculator
{
int Add(int a, int b);
int Multiply(int a, int b);
int StrLen(string value);
string Replace(string value, string toBeReplaced, string replaceWith);
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace IDEAdotNETInterop
{
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
public class Calculator : IDEAdotNETInterop.ICalculator
{
[ComVisible(true)]
public int Add(
[MarshalAs(UnmanagedType.I4)]int a,
[MarshalAs(UnmanagedType.I4)]int b)
{
return a + b;
}
[ComVisible(true)]
public int Multiply(
[MarshalAs(UnmanagedType.I4)]int a,
[MarshalAs(UnmanagedType.I4)]int b)
{
return a * b;
}
[ComVisible(true)]
public int StrLen([MarshalAs(UnmanagedType.LPStr)]string value)
{
return value.Length;
}
[ComVisible(true)]
Page 10 of 15
Using .NET in IDEAScript
[return: MarshalAs(UnmanagedType.LPStr)]
public string Replace(
[MarshalAs(UnmanagedType.LPStr)]string value,
[MarshalAs(UnmanagedType.LPStr)]string toBeReplaced,
[MarshalAs(UnmanagedType.LPStr)]string replaceWith)
{
return value.Replace(toBeReplaced, replaceWith);
}
}
}
The following is an updated IDEAScript macro that calls the two new functions added:
Sub Main()
Dim calc As Object
Dim replaced As String
calc = CreateObject("IDEAdotNETInterop.Calculator")
MsgBox(calc.Add(10, 10))
MsgBox(calc.Multiply(10, 10))
MsgBox(calc.StrLen("What is the length of this string."))
calc = Nothing
End Sub
As can be seen working with strings is relatively straightforward as well. The trick is that the
types need to be marshalled correctly.
Page 11 of 15
Using .NET in IDEAScript
The simplest deployment strategy is to place all of the required files in one folder, including a
batch file, and then run the batch file for either an elevated command prompt or by right
clicking and selecting Run as Administrator.
This is a sample batch script that will copy the required files used in this guide to a folder and
then register the library. Note that I used the .NET version that IDEA uses in registering. In
theory any version of .NET could be targeted. However, it is best if you stick with the version
that IDEA uses as there is no guarantee that a different version will be available on another
computer.
"%systemroot%\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe"
IDEAdotNETInterop.dll
/tlb:IDEAdotNETInterop.tlb
Page 12 of 15
Using .NET in IDEAScript
Pitfalls
There are a few pitfalls to keep in mind. The first is related to memory management. It is
important that
.NET objects are disposed of correctly and set to null or nothing, depending on the language
used. Therefore it is a good idea to include a Dispose method in the class and exposed it so
that when the user is done and any objects that need to be disposed can be and then can be
set to null or nothing to remove the references.
As with simple data types, it is possible to work with objects as well. However, there are
several major issues here and it is recommended to avoid using objects directly. The main
issue is that in most cases the object will not be disposed correctly and will remain in
memory after the IDEAScript has completed. If you must use a class, it is best to create a
wrapper which can be used to call members and set members rather than returning the
object itself.
When you are testing the .NET object in IDEAScript you must close out of IDEA completely in
order to rebuild the application. IDEA will be holding a reference to the object and any
attempts to register the new version will fail because there is still an open reference.
Conclusion
It is possible to use .NET code in an IDEAScript using this guide as a reference but only what
you expose to COM. It is best that you use primitive data types where ever possible and do
not return objects directly but create wrappers around them.
Page 13 of 15
1400 St. Laurent Blvd., Suite 500
Ottawa, ON K1K 4H4
CaseWare IDEA Inc. idea.caseware.com
Canada
1-800-265-4332