Click here to Skip to main content
Click here to Skip to main content

Tagged as

.NET Interop Revisited

, 19 Jan 2011
Rate this:
Please Sign up or sign in to vote.
.NET Interop Revisited
There is plenty of unmanaged code out there and they expose a list of static entry points (functions that can be directly called from other applications) through DLLs. These functions are not organized in objects or interfaces but as simple list of methods. CLR enables interaction of managed boundary with unmanaged boundary (such as COM components, COM++ services, Win32 APIs and other types of unmanaged code)in a seamless way through PInvoke (or Platform Invoke Services). Interoperation can be achieved through the use of custom attributes- DllImportAttribute in the System.Runtime.InteropServices namespace.
 
Using Pinvoke in C#.NET (with Unmanaged C++ DLLs)
 
1. To consume services from unmanaged DLLs, the functions in unmanaged C/C++ must be preceded with "extern "C" __declspec(dllexport)". (This allows the compiler to export data, functions, classes, or class member functions from a DLL. This adds the export directive to the object file so you do not need to use the .def file.)
2. To begin interoperation, the declaration in C#.NET (for example) can be in the following format:
class Wrapper
{
    [DllImport(@"<PhysicalDllname>.dll",
        ExactSpelling = true, // ---- Optional
        CharSet = CharSet.Ansi, // ---- Optional
        CallingConvention = CallingConvention.Cdecl) // ---- Optional
        ]
    //This signature must tally the C/C++ signature
      public static extern <returnType> <functionName>(<Parameters>);
      ...
      ...
      ...
}
 
Handling Unmanaged Data Types in Managed Code

As Data types, error-handling mechanisms, creation and destruction rules, and design guidelines vary between managed and unmanaged object models. To simplify this interoperation and to ease migration,the CLR interoperability layer conceals the differences in these object models
from both clients and servers.
 
Examples:

Example 1:
Getting Array of Strings from an Unmanaged memory area as shown by the following code snippet:
 
//    Unmanaged data
extern "C"  __declspec(dllexport) char** getSystemInformation()
{
    //Do something and return;
}
//GetSystemInformation output in Managed Code (Declaration)
class MyWrapper
{
    [DllImport(@"<some>.dll",
           ExactSpelling = true,
           CharSet = CharSet.Ansi,
           CallingConvention = CallingConvention.Cdecl)
        ]
        public static extern IntPtr getSystemInformation();
}
 
Note that the char ** is a double pointer and in managed code System.IntPtr is a platform-specific type that is used to represent a pointer(any pointer) or Handle (more on IntPtr can be found on MSDN). The following code can be used to read the characters from the unmanaged area.
 
//Using getSystemInformation() in your C# code
    try
    {
        IntPtr    ptrSI = MyWrapper.getSystemInformation();
        for(int i=0; i<NUM_LINES ; i++)
        {
            Console.WriteLine(
                Marshal.PtrToStringAnsi(
                    Marshal.ReadIntPtr(
                        ptrSI,
                         i*Marshal.SizeOf(   //Since the array is double
                                             //array, so we need
                                             //to get offset/pointer
                                             //this array.
                            typeof(IntPtr)
                            )
                        )
                    )
                );
        }
    }
    catch(Exception ex){ //display/Handle/Log Exception }
 
Example 2: Reading the Structure elements. (useful when reading/writing Multi Dimensional Matrices)
 
Reading/writing Structure is not as simple as reading/writing character
strings, but it's a little tricky.
 
Let's consider the following example:
//C Code
    //Structure representing a Matrix
    typedef struct
    {
        int width;
        int height;
        double *data;
    }MATRIX;
    extern "C"  __declspec(dllexport) MATRIX getMatrixMultiplication
(MATRIX A , MATRIX B)
    {
        //Matrix Multiplication Logic
    }
 
In C# (or any managed code), the structure is represented using a Dummy Structure that resembles the C Structure.
In this case:
[StructLayoutAttribute(LayoutKind.Sequential)]
public struct Matrix
{
        public int row;
        public int col;
        public IntPtr data;
}
 
Explanation for [StructLayoutAttribute(LayoutKind.Sequential)]:
When declaring a type, the CLR at runtime automatically rearranges the
order of members for performance, to allow faster access to these members and to optimize memory allocations. But you can force control CLR to follow the sequence you defined, and this helps especially in the interoperability with some C/C++ APIs that accepts structs.
 
Steps to follow:
 
1. First allocate a memory in unmanaged area to copy the matrix from managed code, using Marshal.AllocHGlobal()
2. Copy the matrix using Marshal.Copy() as shown
3. Do Matrix Multiplication process (Exposed Function of DLL)
4. Copy back the Matrix to Managed Matrix Array
 
Finally to use it in your C# code:
double[] matA = new double[MAXDATA];
            double[] matB = new double[MAXDATA];
 
            //populate matrices

        int sizeA = Marshal.SizeOf(matA[0])*matA.Length;
            int sizeB = Marshal.SizeOf(matB[0])*matB.Length;
   
        //Allocate Memory
            IntPtr pA = Marshal.AllocHGlobal(sizeA);
            IntPtr pB = Marshal.AllocHGlobal(sizeB);
       
        //Do matrix Multiplication
            Matrix AD = Wrapper.MatrixMultiplication(pA, pB);
       
            double[] managedArray2 = new double[MAXDATA];
 
        //Copy Back matrix result data to managed array.
            Marshal.Copy(AD.data, managedArray2, 0, MAXDATA);
 

"Attempted to Read/Write protected memory. This is often an indication
that other memory is corrupt".

If you encounter the above exception in your program, then it could mean the following:
a. Parameters passed may be wrong
b. Number of parameters may not be matching
c. DLL may not be present/deleted
d. DLL's architecture may not be matching (x64/x32)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

GPUToaster™
Other
India India
http://gputoaster.wordpress.com/about
Follow on   Twitter

Comments and Discussions

 
GeneralInteresting! If you are interested in advanced technologies of interop. PinmemberShawn-USA5-Aug-13 15:33 
If you are interested in advanced technologies of P/Invoke technology. Please take a look at xInterop NGen++. I wrote a lot of posts discussing how P/Invoke can be used to call C++ class. In the near future, a free express version with limited features may be released to public.

GeneralReason for my vote of 3 good article on Interop, vary few ar... Pinmemberkalpesh241-Jul-10 8:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web04 | 2.8.140827.1 | Last Updated 19 Jan 2011
Article Copyright 2010 by GPUToaster™
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid