INTERNAL: Callable IDL example using Micrsoft's C# .net
Anonym
Topic:
Microsoft Visual Studio version 7.0 encourages the use of the C# programming language. C# (C-sharp) is an object oriented programming language with syntax similar to C/C++. C# is NOT a direct extension of C/C++ and does NOT conform to the ANSI C standards.
The following is an example of calling into IDL from C# using the callable IDL interface.Discussion:
One important thing to note about C# is that it discourages the use of pointers. Instead of allocating a block of memory and using a pointer to access it as an array as it is done in plain C, C# encourages creating an instance of an object class to encapsulate the data.
Since IDL is written in C, there is a need to use pointers to efficiently access IDL arrays. In order to be able to use pointers directly in C# the scope must be declared as "unsafe".
The following example shows how to access an IDL array in C# and vice versa using the Callable IDL interface.
File->New->Project
Select Visual C# projects and Windows Application.
Select a name (for example: "callableIDL") and a location.
Select View->Toolbox
Add a button. Change the text on the button to for example "Callable IDL example".
Double-click on the button. This should bring up the code editor. and a stub should appear:
private void button1_Click(object sender, System.EventArgs e)
{
}
Add the word "unsafe" to the function declaration since pointers will be used:
unsafe private void button1_Click(object sender, System.EventArgs e)
{
}
Add the following code to the button click event:
/* Initialize IDL */
int Status = 0;
Status = Idl32.IDL_Win32Init(0, (void *) (this.Handle), null, null);
if (Status==0) MessageBox.Show("Failed to initialize IDL");
/* Create an array of 10 double precision floating point numbers */
double[] d=new double[10];
/* Initialize array */
for (int i=0;i<10;i++) d[i] = i;
/* Use IDL_ImportNamedArray to access a C# array inside IDL */
fixed (void *data=d)/* IDL needs a pointer to the data */
{
long[] dim = new long[8]; /* define dimensions array */
dim[0] = 10;
Idl32.IDL_ImportNamedArray("D", 1, dim, 5, data, null, null);
string command = "D[9]=12"; /* Change the last element of D */
Status = Idl32.IDL_ExecuteStr(command);
command = "void=dialog_message('D = '+strcompress(strjoin(D)),/info)";
Status = Idl32.IDL_ExecuteStr(command);
if (d[9] == 12) MessageBox.Show("C# Array successfully altered by IDL");
if (d[9] == 9) MessageBox.Show("IDL Failed to change original array");
/* Use IDL_GetVarAddr to access an IDL array in C# */
double *test; /* define a pointer to the array */
long n=0;
Idl32.IDL_ExecuteStr("A=dindgen(20)");
Idl32.IDL_VarGetData(Idl32.IDL_GetVarAddr("A"),
&n, (char **) &test, 0);
/* Calculate the total sum of "lindgen(20)", it should be 190 */
double total=0;
for (int i=0;i<20;i++) total+=test[i];
MessageBox.Show(total.ToString());
if (total == 190) MessageBox.Show("C# successfully calculated the total (190)");
else MessageBox.Show("C# Failed to calculate the correct total");
/* Change the elements of the array by adding 100 */
for (int i=0;i<20;i++) test[i]+=100.0;
/* Show that the IDL array was modified from C# */
command = "void=dialog_message('A = '+strcompress(strjoin(A)),/info)";
Idl32.IDL_ExecuteStr(command);
}
Status = Idl32.IDL_Cleanup(0);
Next, go to the beginning of the file where the following lines can be seen:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
Add the following line (after using System.Data) to allow calling idl32.dll from this project.
using System.Runtime.InteropServices;
The next lines in the file are:
namespace callableIDL
{
After these two lines declare a new class that will encapsulate idl32.dll.
In this example 5 functions are defined from idl32.dll. These are:
IDL_Win32Init, IDL_ExecuteStr, IDL_ImportNamedArray, IDL_GetVarAddr, and IDL_VarGetData.
/* Declare a class that encapsulates the idl32.dll */
/* The function definitions are adapted from idl_export.h */
/* The "unsafe" and "public" keywords are added for C# compatibility */
public class Idl32
{
[DllImport(@"C:\RSI\IDL60\bin\bin.x86\idl32.dll", CharSet=CharSet.Auto)]
unsafe public static extern int IDL_Win32Init(int iOpts, void *hinstExe,
void *hwndExe, void *hAccel);
[DllImport(@"C:\RSI\IDL60\bin\bin.x86\idl32.dll", CharSet=CharSet.Auto)]
unsafe public static extern int IDL_ExecuteStr(
[MarshalAs(UnmanagedType.LPStr)] string cmd);
[DllImport(@"C:\RSI\IDL60\bin\bin.x86\idl32.dll", CharSet=CharSet.Auto)]
public static extern int IDL_Cleanup(int just_cleanup);
[DllImport(@"C:\RSI\IDL60\bin\bin.x86\idl32.dll", CharSet=CharSet.Auto)]
unsafe public static extern void* IDL_ImportNamedArray(
[MarshalAs(UnmanagedType.LPStr)]string name,
int n_dim, long[] dim, int type, void* data, void* free_cb, void* s);
[DllImport(@"C:\RSI\IDL60\bin\bin.x86\idl32.dll", CharSet=CharSet.Auto)]
unsafe public static extern char* IDL_GetVarAddr(
[MarshalAs(UnmanagedType.LPStr)] string name);
[DllImport(@"C:\RSI\IDL60\bin\bin.x86\idl32.dll", CharSet=CharSet.Auto)]
unsafe public static extern void* IDL_VarGetData(void *var, long *n,
char **pd, int ensure_simple);
}
The next step is to change the build options to allow "unsafe" functions.
Select View->Solution Explorer.
Right-click on the project name (callableIDL in this example).
Select Properties from the pulldown menu.
Go to Configuration Properties->Build.
Change "Allow unsafe code blocks" from 'False" to "True".
Click "Apply" and "OK"
At this point the project can be run with Debug->Start or hit F5.
The complete listing of the form code (Form1.cs) is included below.Solution:
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.Runtime.InteropServices;
namespace callableIDL
{
/* Declare a class that encapsulates the idl32.dll */
/* The function definitions are adapted from idl_export.h */
/* The "unsafe" and "public" keywords are added for C# compatibility */
public class Idl32
{
[DllImport(@"C:\RSI\IDL60\bin\bin.x86\idl32.dll", CharSet=CharSet.Auto)]
unsafe public static extern int IDL_Win32Init(int iOpts, void *hinstExe,
void *hwndExe, void *hAccel);
[DllImport(@"C:\RSI\IDL60\bin\bin.x86\idl32.dll", CharSet=CharSet.Auto)]
unsafe public static extern int IDL_ExecuteStr(
[MarshalAs(UnmanagedType.LPStr)] string cmd);
[DllImport(@"C:\RSI\IDL60\bin\bin.x86\idl32.dll", CharSet=CharSet.Auto)]
public static extern int IDL_Cleanup(int just_cleanup);
[DllImport(@"C:\RSI\IDL60\bin\bin.x86\idl32.dll", CharSet=CharSet.Auto)]
unsafe public static extern void* IDL_ImportNamedArray(
[MarshalAs(UnmanagedType.LPStr)]string name,
int n_dim, long[] dim, int type, void* data, void* free_cb, void* s);
[DllImport(@"C:\RSI\IDL60\bin\bin.x86\idl32.dll", CharSet=CharSet.Auto)]
unsafe public static extern char* IDL_GetVarAddr(
[MarshalAs(UnmanagedType.LPStr)] string name);
[DllImport(@"C:\RSI\IDL60\bin\bin.x86\idl32.dll", CharSet=CharSet.Auto)]
unsafe public static extern void* IDL_VarGetData(void *var, long *n,
char **pd, int ensure_simple);
}
///
/// Summary description for Form1.
///
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
///
/// Required designer variable.
///
private System.ComponentModel.Container components = null;
public Form1()
{
//
// Required for Windows Form Designer support
//
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
///
/// Clean up any resources being used.
///
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Windows Form Designer generated code
///
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
///
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(96, 88);
this.button1.Name = "button1";
this.button1.TabIndex = 0;
this.button1.Text = "CallableIDL";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.AddRange(new System.Windows.Forms.Control[] {
this.button1});
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
}
#endregion
///
/// The main entry point for the application.
///
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
unsafe private void button1_Click(object sender, System.EventArgs e)
{
/* Initialize IDL */
int Status = 0;
Status = Idl32.IDL_Win32Init(0, (void *) (this.Handle), null, null);
if (Status==0) MessageBox.Show("Failed to initialize IDL");
/* Create an array of 10 double precision floating point numbers */
double[] d=new double[10];
/* Initialize array */
for (int i=0;i<10;i++) d[i] = i;
/* Use IDL_ImportNamedArray to access a C# array inside IDL */
fixed (void *data=d)/* IDL needs a pointer to the data */
{
long[] dim = new long[8]; /* define dimensions array */
dim[0] = 10;
Idl32.IDL_ImportNamedArray("D", 1, dim, 5, data, null, null);
string command = "D[9]=12"; /* Change the last element of D */
Status = Idl32.IDL_ExecuteStr(command);
command = "void=dialog_message('D = '+strcompress(strjoin(D)),/info)";
Status = Idl32.IDL_ExecuteStr(command);
if (d[9] == 12) MessageBox.Show("C# Array successfully altered by IDL");
if (d[9] == 9) MessageBox.Show("IDL Failed to change original array");
/* Use IDL_GetVarAddr to access an IDL array in C# */
double *test; /* define a pointer to the array */
long n=0;
Idl32.IDL_ExecuteStr("A=dindgen(20)");
Idl32.IDL_VarGetData(Idl32.IDL_GetVarAddr("A"),
&n, (char **) &test, 0);
/* Calculate the total sum of "lindgen(20)", it should be 190 */
double total=0;
for (int i=0;i<20;i++) total+=test[i];
MessageBox.Show(total.ToString());
if (total == 190) MessageBox.Show("C# successfully calculated the total (190)");
else MessageBox.Show("C# Failed to calculate the correct total");
/* Change the elements of the array by adding 100 */
for (int i=0;i<20;i++) test[i]+=100.0;
/* Show that the IDL array was modified from C# */
command = "void=dialog_message('A = '+strcompress(strjoin(A)),/info)";
Idl32.IDL_ExecuteStr(command);
}
Status = Idl32.IDL_Cleanup(0);
}
}
}