Praveen Katiyar' Blog

Learning along the way . . . .

Modifying array of numeric types (default Marshaling)

Define some functions in native dll (let say it “Win32Native.dll”)  as shown below. These 2 functions receives integer buffer, and double buffer respectively.

extern "C" __declspec(dllexport) int ModifyIntegerArrayValues ( int nSize, int* pArray)

extern "C" __declspec(dllexport) double ModifyDoubleArrayValues ( int nSize, double* pArray)

Implementing Functions

extern "C" __declspec(dllexport) int ModifyIntegerArrayValues ( int nSize, int* pArray)
{
    int nResult = 0 ;
    for ( int i = 0; i < nSize; i++ )
    {
        nResult += pArray[ i ];
        pArray[i] += 100;
    }
    return nResult;
}

extern "C" __declspec(dllexport) double ModifyDoubleArrayValues ( int nSize, double* pArray)
{
    double dblResult = 0 ;
    for ( int i = 0; i < nSize; i++ )
    {
        dblResult += pArray[ i ];
        pArray[i] += 200 ;
    }
    return dblResult ;
}

Point of Interest

  • CoTaskMemAlloc is used to allocated the memory required.
  • CoTaskMemFree is used to free any previously allocated buffer, if null is passed then, CoTaskMemFree is not called.

If you want to use a heap that is shared between native and managed, it is more common to use the COM heap.

Writing the client code (the managed part)

one can simple create a console base application which can use this dll. let’s name it MarshallingTest.

see the code snippet below.

using System;
using System.Runtime.InteropServices;
using System.Text;

namespace MarshallingTest
{
    class Program
    {
         [DllImport("Win32Native.dll")]
        public static extern void ModifyIntegerArrayValues(int nCount, [In, Out] int[] arrStr);

         [DllImport("Win32Native.dll")]
         public static extern int ModifyDoubleArrayValues(int nSize, [In, Out] double[] nArr);
    
        static void Main(string[] args)
        {
            int nSize = 5 ;
            int[] arrInt = new int[nSize];
            for (int nI = 0; nI < nSize; nI++) arrInt[nI] = (nI + 1) * 10;

            Console.WriteLine("\nValues of Integer array, before calling function");
            for (int i = 0; i < nSize; i++)
            {
                Console.WriteLine(string.Format("Array[{0:D2}] : {1:D3}", i, arrInt[i]));
            }

            ModifyIntegerArrayValues(nSize, arrInt);

            Console.WriteLine("\nValues of Integer array, after calling function");
            for (int i = 0; i < nSize; i++)
            {
                Console.WriteLine(string.Format("Array[{0:D2}] : {1:D3}", i, arrInt[i]));
            }

            double [] arrDbl= new double [nSize];
            for (int nI = 0; nI < nSize; nI++) arrDbl[nI] = (nI + 1) * 5.0 ;

            Console.WriteLine("\nValues of Double array, before calling function");
            for (int i = 0; i < nSize; i++)
            {
                Console.WriteLine(string.Format("Array[{0:D2}] : {1:F2}", i, arrDbl[i]));
            }

            ModifyDoubleArrayValues(nSize, arrDbl);

            Console.WriteLine("\nValues of double array, after calling function");
            for (int i = 0; i < nSize; i++)
            {
                Console.WriteLine(string.Format("Array[{0:D2}] : {1:F2}", i, arrDbl[i]));
            }
        }
    }
}

Point of Interest
  • namespace System.Runtime.InteropServices;  defines the declarations necessary for Interop operations, like DllImport,
  • DllImport defines the DLL entry point.
  • Marshal.Copy function used to copy buffer from managed buffer to unmanaged buffer and vice versa.
  • Marshal.FreeCoTaskMem frees the memory allocated by native DLL.

compile and execute you will get following output.

image

August 5, 2013 - Posted by | .NET, CodeProject, Interoperability, Marshaling, Win32 | , , ,

No comments yet.

Leave a comment