sara
sara

Reputation: 3934

Array change in C++ function is not preserved in C#

I have a C# code calling a C++ function.

The C++ function should fill a buffer passed with a pointer. However, the array returns empty.

The import declaration is:

[DllImport("ProjectLogicInterface", EntryPoint = "FillArr", CallingConvention = CallingConvention.Cdecl)]
public static extern UInt32 FillArr(char[] arr);

The code, after simplifications and entering some hard coded values looks like that:

The code in C#:

char[] arr= new char[10];
ret = LogicInterface.FillArr(arr);

The C++ code:

bool FillArr(char* arr)
{
       int length=10;
       for(int i = 0; i < length; i++) 
       {
              arr[i] = 3; //replaced with some hard coded value
       }
       return true;
}

However, the array remains empty.

Any suggestions?

Upvotes: 2

Views: 473

Answers (3)

sara
sara

Reputation: 3934

Found this link highly usefull:

C#: calling C++ DLL with char** argument

The final code looks like:

    [DllImport("ProjectLogicInterface", EntryPoint = "FillArr", CallingConvention = CallingConvention.Cdecl)]
    static extern bool FillArr([MarshalAs(UnmanagedType.LPStr, ArraySubType = UnmanagedType.LPStr)] StringBuilder args);

        static void Main(string[] args)
        {
            StringBuilder arr = new StringBuilder(9);
            bool res = FillArr(arr);
        }

Upvotes: -1

Pedro
Pedro

Reputation: 1124

You don't need to pin the array as long as the code in C++ doesn't cache it before returning.

In your case, you need to pass the array by reference so it can be considered as an out argument.

[DllImport("ProjectLogicInterface", EntryPoint = "FillArr", CallingConvention = CallingConvention.Cdecl)]
public static extern UInt32 FillArr(ref char[] arr);`

Upvotes: 1

Nick
Nick

Reputation: 25799

I believe that you would have to pin the array before passing it to your native code. This prevents the GC from moving the managed array around in memory while you're accessing it in C++.

So you could use:

[DllImport("ProjectLogicInterface", EntryPoint = "FillArr", CallingConvention = CallingConvention.Cdecl)]
public static extern UInt32 FillArr( char* arr );

And then:

char[] arr = new char[ 10 ];

fixed (char* pinned = arr )
{
    ret = LogicInterface.FillArr( pinned );
}

Note that I haven't actually compiled and run this but it should give you some ideas on how to proceed.

Upvotes: 1

Related Questions