2

I have some of unmanaged C++ dynamic library and C# GUI application, using it. I need to pass array of strings with known size to C++ library, which populates it. Also there is maximum string length value:

// C++ part
#define MAX_SOME_STRING_LEN 250;

MYDLL_API uint8_t __stdcall  getSomeStrings(wchar_t** strings, uint64_t count) {
    /// populate strings, not more characters then MAX_SOME_STRING_LEN for each string
    return 0;
}

// C# part
[DllImport("biosec_lib.dll", CallingConvention = CallingConvention.StdCall)]
    static extern Byte getSomeStrings(string[] providers, UInt64 size);

I want to avoid array memory management on C++ library side. I get desirable string array size by other library API call. Then allocate suitable array on C# side and call this API method, passing suitable array.

  1. Is it good approach at all? Is there any better approach? Can I reserve MAX_SOME_STRING_LEN size for every string in my array before passing it to API method?
3
  • 1
    The problem is not the array, the C# code already allocated it. The problem is the array elements. How did you create them? Do they need to be released? If you want to use memory allocated by the C# program then using StringBuilder[] is required, initialized with StringBuilder objects that have a sufficient Capacity. It is risky, too low a Capacity causes heap corruption when your wcscpy() call overflows the buffer. Commented Jul 18, 2014 at 12:22
  • @HansPassant YEs, I want allocate them and release later on C# side. I know about problem with overflow, you mentioned. I should be careful with it, and buffer size is provided for that. Commented Jul 18, 2014 at 12:41
  • No. The count argument says how long the strings array is. There is no way for the caller to specify how long each string buffer is. The only truly safe way to write this code is for the C++ code to allocate the strings. Which does require you to deal with memory management, the caller has to release the strings again. The pinvoke marshaller will assume you used CoTaskMemAlloc(), kaboom if you didn't. Commented Jul 18, 2014 at 13:27

2 Answers 2

1

It's a different approach. You should allocate a kind of "unmanaged" buffer, pass to the DLL and then convert the result and free the buffer. It's exactly the same way in C, but calling from a managed environment.

The signature of your DLL will be something like:

[DllImport("biosec_lib.dll", CallingConvention = CallingConvention.StdCall)]
static extern Byte getSomeStrings(IntPtr buffer, UInt64 size);

To call it from C#, you should do:

        IntPtr unmanagedBuffer = Marshal.AllocHGlobal(100);
        // Your Unmanaged Call
        getSomeStrings(unmanagedBbuffer, 100);
        string yourString = Marshal.PtrToStringUni(unmanagedBuffer);
        Marshal.FreeHGlobal(unmanagedBuffer);

Don't forget to call FreeHGlobal if you don't want a memory leak in your app. It's interesting to protect this in "try/finally" clauses.

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

3 Comments

Is it possible to use in that case some RAII-kind wrapper for memory management? Does this approach suites passing array of buffers for each string, not single buffer?
In C/C++ null terminated strings are arrays of chars. It's how strings are handled (there are different ways, but this is popular). Since when use DLL's you need to be sure how the DLL expects the memory to be, the safest way is sending buffers.
This is like a "rule" when using unmanaged DLL's. Even the windows API works like this. If the DLL need to return you something, you need to pre-allocate the buffer to receive this something. Even structs works like this.
0

If you want to use IntPtr on Managed side, you can use like that:

[DllImport("biosec_lib.dll", CallingConvention = CallingConvention.StdCall)]
static extern Byte getSomeStrings([In][Out] [MarshalAs(UnmanagedType.LPArray, SizeConst = 1)] String[] providers, UInt64 count);

5 Comments

Does SizeConst = 1 means I know array size on compile time? I get this size in runtime calling API method, as I mentioned in my question. The known size on compile time - maximum strng length. Not array of strings size.
yes you are right, you have to know array size on compile time if you use SizeConst parameter. The best way is that using IntPtr i guess.
Unfortunately I know array size on runtime only. Library call says me how big array it needs.
i worked on Marshalling on my work, we can maybe make a live meeting. [email protected] and we can fix it.
Thank you, I hope we not need. It seems that StringBuilder array using is suitable for my issue. I will update question or write my answer if no one else do, when finish with it.

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.