Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Modifying an array of structures (default marshaling)

0.00/5 (No votes)
14 Aug 2013 1  
Modifying an array of structures.

Let’s assume you have a user defined structure EMPLOYEE in a Win32 DLL (let's call it Win32Native.dll) as shown below.

typedef struct _EMPLOYEE 
{ 
    int Age ; 
    int Sex; 
    double Salary ; 
    char* FirstName ; 
    char* LastName ; 
} EMPLOYEE;

Define some functions in the native DLL (let call it Win32Native.dll) as shown below.

extern "C" __declspec(dllexport) void ModifyArrayOfEmployeeStruct(int nSize, EMPLOYEE* pArray);

Implementing functions

extern "C" __declspec(dllexport) void ModifyArrayOfEmployeeStruct( int nSize, EMPLOYEE* pArray) 
{ 
    int result = 0; 
    EMPLOYEE* pCur = pArray; 
    STRSAFE_LPSTR temp1, temp2 ;     for ( int i = 0; i < nSize; i++ ) 
    { 
        size_t nLen1 = 0; 
        size_t nLen2 = 0; 
        StringCchLengthA( pCur->FirstName, STRSAFE_MAX_CCH, &nLen1 ); 
        StringCchLengthA( pCur->LastName, STRSAFE_MAX_CCH, &nLen2 ); 
        
        nLen1 = sizeof(char) * ( nLen1 + 11 );    //    To accomodate "<modified>" 
        nLen2 = sizeof(char) * ( nLen2 + 11 );    //    To accomodate "<modified>" 
        temp1 = (STRSAFE_LPSTR)CoTaskMemAlloc( nLen1 ); 
        temp2 = (STRSAFE_LPSTR)CoTaskMemAlloc( nLen2 );
        StringCchCopyA( temp1, nLen1, (STRSAFE_LPCSTR)"<modified>" ); 
        StringCbCatA( temp1, nLen1, (STRSAFE_LPCSTR)pCur->FirstName);
        StringCchCopyA( temp2, nLen2, (STRSAFE_LPCSTR)"<modified>" ); 
        StringCbCatA( temp2, nLen2, (STRSAFE_LPCSTR)pCur->LastName); 
                
        // CoTaskMemFree must be used instead of delete to free memory. 
        CoTaskMemFree( pCur->FirstName  ); 
        CoTaskMemFree( pCur->LastName  );
        pCur->FirstName = (char *)temp1; 
        pCur->LastName = (char *)temp2;
        pCur->Age += 1 ; 
        pCur->Salary  += 1000.0 ; 
        pCur++; 
   } 
}</modified></modified></modified></modified>

Points 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.
  • StringCchCopyA copies an ANSI string to a string buffer.
  • StringCbCatA Appends an ANSI string to a string buffer.

If you want to use a heap that is shared between native and managed, it is more common to use the COM heap. On the native side use CoTaskMemAlloc() and CoTaskMemFree().

Writing the client code (the managed part)

We can simply create a console based 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 
{
    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] 
    public struct Employee 
    { 
        public int Age; 
        public int Sex; 
        public double Salary; 
        public String FirstName; 
        public String LastName; 
    } 
    class Program 
    { 
        [DllImport("Win32Native.dll")]
        public static extern int ModifyArrayOfEmployeeStruct(
                                                    int nSize,
                                                    [In, Out] Employee[] empArr); 
        static void Main(string[] args) 
        { 
            int nCnt = 5; // Number of Items in Structure Array 
            Employee[] emp = new Employee[nCnt]; 
            emp[0].FirstName = "Ramesh"; emp[0].LastName = "Sharma"; 
              emp[0].Age = 42; emp[0].Salary = 40000; emp[0].Sex = 0; 
            emp[1].FirstName = "Shalini"; emp[1].LastName = "Verma"; 
              emp[1].Age = 30; emp[1].Salary = 25000; emp[1].Sex = 1; 
            emp[2].FirstName = "Ramesh"; emp[2].LastName = "Sharma"; 
              emp[2].Age = 51; emp[2].Salary = 35000; emp[2].Sex = 0; 
            emp[3].FirstName = "Aarushi"; emp[3].LastName = "Shukla"; 
              emp[3].Age = 25; emp[3].Salary = 20000; emp[3].Sex = 0; 
            emp[4].FirstName = "Malini"; emp[4].LastName = "Kapoor"; 
              emp[4].Age = 33; emp[4].Salary = 30000; emp[4].Sex = 1;
            Console.WriteLine("\nEmployee Array Before Call");
            for (int nI = 0; nI < nCnt; nI++) 
            { 
                StringBuilder sb = new StringBuilder( "First Name=[" ); 
                sb.Append(emp[nI].FirstName); 
                sb.Append("]  Last Name=["); 
                sb.Append(emp[nI].LastName ); 
                sb.Append("]  Age=["); 
                sb.Append(emp[nI].Age .ToString ()); 
                sb.Append("]  Salary=["); 
                sb.Append(emp[nI].Salary.ToString ("F2")); 
                sb.Append("]  Sex=["); 
                sb.Append(((emp[nI].Sex == 0) ? "Male" : "Female")); 
                sb.Append("]"); 
                Console.WriteLine(sb.ToString ()); 
            }
            // Call the Function.
            ModifyArrayOfEmployeeStruct(emp.Length, emp); 
            Console.WriteLine("\nEmployee Array After Call"); 
            for (int nI = 0; nI < nCnt; nI++) 
            { 
                StringBuilder sb = new StringBuilder("First Name=["); 
                sb.Append(emp[nI].FirstName); 
                sb.Append("]  Last Name=["); 
                sb.Append(emp[nI].LastName); 
                sb.Append("]  Age=["); 
                sb.Append(emp[nI].Age.ToString()); 
                sb.Append("]  Salary=["); 
                sb.Append(emp[nI].Salary.ToString("F2")); 
                sb.Append("]  Sex=["); 
                sb.Append(((emp[nI].Sex == 0) ? "Male" : "Female")); 
                sb.Append("]"); 
                Console.WriteLine(sb.ToString()); 
            }
        } 
    } 
}

Points of Interest

  • namespace System.Runtime.InteropServices; defines the declarations necessary for Interop operations, like DllImport.
  • DllImport defines the DLL entry point.

Compile and execute you will get following output.

image

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here