I am trying to call a Win32 DLL from some C#. The DLL function is declared as follows:
extern "C" __declspec(dllexport) UINT foo(TCHAR** list[], int& listSize, TCHAR* error);
In C#, I declare the external function like so:
[DllImport("foo.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Auto)]
static extern uint foo(StringBuilder[] list, ref int listSize, StringBuilder error);
My problem has to do with the list parameter, which is an array of StringBuilder classes.
Some test code where I call the DLL function is as follows:
(Note: I realise that there are boundary checks missing, etc. At this stage, I am just trying to get things working).
// allocate a buffer for a possible error message being returned
StringBuilder error = new StringBuilder(1000);
// allocate buffers for the list of strings returned
StringBuilder[] list = new StringBuilder[10];
for (int i = 0; i < 10; i++)
{
list[i] = new StringBuilder(1000);
}
int listSize = list.Length;
uint result = foo(list, ref listSize, error);
Passing the StringBuilder as a buffer for the error parameter, works fine. I can set its contents in the DLL as follows:
_tcscpy(error, _T("Something went wrong");
When the C# call to foo returns, the string error variable has the text we set it to in the DLL.
But, I cannot work out how to marshal the StringBuilder[] list parameter.
In the C++, I am able to set the contents of the list array:
_tcscpy((*list)[0], _T("First item"));
// and so on...
And, even though there is no crash that occurrs due to any possible problematic marshalling, the list in the C#, when the call to foo() returns, does not contain any of the strings we set in the C++.
I’m guessing that the problem is with the DllImport and how I’ve declared the list parameter should be marshalled.
By the way, the example DLL has a matching function which one would then call to deallocate the “TCHAR** list” returned by the example foo shown above.
OK, I have found a solution to my question. It looks like the answer lay in IntPtr. The C function created and returned an array of string in “TCHAR** list[]”.
First, I changed the declaration in C# to:
Then, when the call to the DLL returned, I needed to extract the strings from the array:
And that resulted in getting back the array of strings from the C DLL.