The .NET framework was designed to be the “lingua franca” for Windows development, with the expectation that it will set a new standard for building integrated software for Windows. However, it is inevitable that there is a time lag before .NET is fully adopted and existing applications are recoded. In particular, there is a large body of legacy code that will likely never be rewritten in .NET. To address this situation, Microsoft provides attributes, assembly, and marshaling. At the Numerical Algorithms Group (where I work), our particular interest in using these techniques is to utilize numerical software developed in C from within the .NET environment. Because C# is the premier .NET language, the examples I present here are in C#. While I use an example of data types that are current in the NAG C Library, the techniques I present are general enough for calling unmanaged code written in C from C# directly.

The NAG C Library uses the following data types as parameters:
• Scalars of type double, int, and Complex. These are passed either by value or by reference (as pointers to the particular type).
• enum types.
• Arrays of type double, int, and Complex.
• A large number of structures, generally passed as pointers.
• A few instance of arrays which are allocated within NAG routines and have to be freed by users (these have type double**).
• Function parameters (also know as “callbacks”). These are pointers to functions with particular signatures.

For instance, take the example of a C function that takes two parameters of the type double and double*; that is, the first parameter is input (pass by value) and the second is output (pass by reference in non-C parlance). The corresponding C# signature for the C function is then double, ref double. Listing One presents the definition of the C function and its call from C#. In C#, you have to provide the DLL import attribute (line 5), specifying how the C signature maps to C#. Also the qualifier ref has to be used twice, in the declaration of the C function and in its call. Finally, note the use of the assembly directive, System.Runtime.InteropServices (line 3), which is important because it is the classes defined within the InteropServices that provide the mapping between managed code and unmanaged code.

Download pdf Calling C Library DLLs from C#