2

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?

3 Answers 3

1

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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);`

1 Comment

Would the marshaller then pin the memory under the hood?
-1

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);
        }

2 Comments

Ah, you're marshalling strings... not just Arrays of char as described in the original question.
@Nick I would prefer using char array, but it didn't work. Nor did your answer and the other one. This way I can parse it back to string, and use it as char array.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.