Marshal C++ "char**" in C# - c#

I'm calling C# method from C++ and passing char** as argument. It has to be char** because I need to return value through parameter.
C# code:
[ExportDll("test", System.Runtime.InteropServices.CallingConvention.StdCall)]
public static int test([MarshalAs(UnmanagedType.AnsiBStr)] ref string p)
{
Console.WriteLine(p);
}
C++ code to invoke function:
typedef int (__stdcall *MYPROC)(char **);
VOID main(VOID)
{
HINSTANCE hinstLib;
MYPROC MyProc;
BOOL fFreeResult, fRunTimeLinkSuccess = FALSE;
hinstLib = LoadLibrary(TEXT("mydll.dll"));
if (hinstLib != NULL)
{
ProcAdd = (MYPROC) GetProcAddress(hinstLib, "test");
if (NULL != ProcAdd)
{
fRunTimeLinkSuccess = TRUE;
char s1[] = "test";
char *s2 = s1;
char **s3 = &s2;
(MyProc) (s3);
cout << s3;
}
fFreeResult = FreeLibrary(hinstLib);
}
}
It's simple to pass char* (remove ref in c#, and use char* in c++), but when trying to pass char** i get a runtime error on line where I call the function :(
in c#, Console.WriteLine prints out correct value, but after that, I get an error:
Windows has triggered a breakpoint in COMDynamicLoad.exe.
This may be due to a corruption of the heap, which indicates a bug in COMDynamicLoad.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while COMDynamicLoad.exe has focus.
The output window may have more diagnostic information.
How should I do this?

You declare ref UnmanagedType.AnsiBStr but you expect a char**. This cannot work, since a ref to a BSTR is not a char**. See Default Marshaling for Strings for examples of marshaling declarations. These are possible declarations for an input-output string:
PassStringRef2([in, out] BSTR *s);
PassStringRef3([in, out] LPStr *s);
PassStringRef4([in, out] LPWStr *s);
and the equivalent C# marshaling declarations are:
PassStringRef2([MarshalAs(UnmanagedType.BStr)]ref String s);
PassStringRef3([MarshalAs(UnmanagedType.LPStr)]ref String s);
PassStringRef4([MarshalAs(UnmanagedType.LPWStr)]ref String s);
Your char** declaration is the equivalent of LPStr *s, so the correct marshaling is [MarshalAs(UnmanagedType.LPStr)]ref String s. But a better option is to use BSTR because of the explicit length declaration, and manipulate it in C++ with the BSTR helpers.

This is likely because you took a char* pointing to a string literal- which is bad because modifying that memory is undefined behaviour.

Would this work?
public static int test([In, Out, MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr)] string[] p)

In many cases and as seems to be the situation here (see accepted answer by Remus Rusanu), using the proper marshaling attributes in the API declarations is all that is needed to have the interop "glue" on both ends of the interface start "playing nice with one another" and result in...
the proper data values being sent/delivered [good!]
Windows not triggering automatic breakpoint upon various suspected ... corruption of the heap ... [better! ;-)]
I am adding this answer, 5 months after the original post, because this question and its responses were very useful in fixing a recent interop bug of mine, but failed to mention directly information about the very plausible cause of many interop issues, namely:
Mismatch in the Memory Ownership conventions
(and/or in the memory allocation and freeing methods).
The January 2008 article on MSDN Magazine titled Marshaling between Managed and Unmanaged Code provided me with the info I needed in regards to memory ownership conventions. Indeed this article provides a complete overview of the marshaling process. It covers in specific details and examples the issues of
[InAttribute] and [OutAttribute] aka [In] and [Out]
Keywords Out and Ref and passing by reference
Return values
StringBuilder and marshaling
Copying and pinning
(Pinning = optiimization by CLR when it deems it safe to lock data area in the CLR heap and pass corresponding pointers to unmanaged code)
Memory Ownership:
No change allowed vs. In-place change vs. Reference change
Also, on the need of using CoTaskMemFree() and CoTaskMemAlloc() to free or allocate memory respectively received from or sent to the Managed code.
Reverse P/Invoke and delegate lifetime
P/Invoke Interop Assistant
This article is very useful because it gathers in a single document and in an accessible fashion information otherwise disseminated across dozen of technically authoritative but dry [and oft' confusing] reference documents (cf. the old but on-point joke about Microsoft's documentation at large).
In short, it makes it a good primer or refresher for casual implementers of interop solutions.

Related

can native C **char be safely passed to managed C# delegate with paramter type "out string"?

In C:
extern "C" __declspec(dllexport) int CfgGetVariableString(const char *Name, char **Value)
{
char StrValue[STR_MAX];
int RetValue = GetVariableToStrValue(Name, StrValue, STR_MAX);
if (RetValue == 0)
*Value = StrValue;
return RetValue;
}
C#
[DllImport(DllName, CallingConvention = DllCallingConvention)]
private static extern int CfgGetVariableString([MarshalAs(UnmanagedType.LPStr)]string name, [MarshalAs(UnmanagedType.LPStr)]out string value);
This does not work. I can make it work by calling CoTaskMemAlloc, but then I guess I should free it with separate managed to native call?
So what is the cleanest way to do it?
I can make it work by calling CoTaskMemAlloc.
That is the only way that it can work. Because the marshaller will call CoTaskMemFree to deallocate the memory returned from the native function.
I guess I should free it with separate managed to native call?
As mentioned above, that's not necessary because the framework already does so.
What is the cleanest way to do it?
In my opinion the cleanest approach here, since you are already using a string length determined at compile time, is to have the caller allocate the memory. Change the type from char** to char*. Add an extra argument containing the length of the allocated string. Use StringBuilder on the C# side. There are countless examples of this pattern available here and indeed in other places so I don't feel any need to add to the canon.

C# Interop - Releasing memory allocated in unmanaged code

I'm calling the following VC++ method
__declspec(dllexport) unsigned char* Get_Version_String()
from C# as follows:
internal static class NativeMethods
{
[DllImport("my.dll"),
CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true,
CallingConvention = CallingConvention.Cdecl)]
internal static extern string Get_Version_String();
}
The above code is in a library which targets .NET 3.5. When I call this from a 3.5 assembly, it works fine; when calling it from a 4.5 assembly, however, it results in
0xC0000374: A heap has been corrupted
After reading this question, I changed my method calls as follows:
[DllImport("my.dll",
EntryPoint = "Get_Version_String",
CharSet = CharSet.Ansi, BestFitMapping = false, ThrowOnUnmappableChar = true,
CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr Get_Version_String_PInvoke();
internal static string Get_Version_String()
{
IntPtr ptr = Get_Version_String_PInvoke();
string versionString = Marshal.PtrToStringAnsi(ptr);
return versionString;
}
This works as expected, but the answer from Hans Passant comes with a warning:
The workaround you found is the correct one, the marshaller isn't going to try to release the memory for an IntPtr. Do note that this will only actually come to a good end if the C code returns a const char* that doesn't need to be released. You have a permanent memory leak if that's not the case.
Since the C++ method does not return const, I'm going on the assumption that the workaround for my specific function will result in a memory leak.
I cannot change the original method so I found this other question which discusses how to free memory from manged code. However, calling either Marshal.FreeHGlobal(ptr) or Marshal.FreeCoTaskMem(ptr) also throw 0xC0000374: A heap has been corrupted.
Can anyone
a) confirm that such a method will indeed suffer from a memory leak, and
b) if so, suggest how to free the memory from the pointer in managed code?
The C++ method body is, simplified, as follows:
unsigned char versionString[50];
__declspec(dllexport) unsigned char* Get_Version_String()
{
strcpy((char *) versionString, "Key1:[xx],Key2:[xx],Key3:[xx],Key4:[xx]");
// string manipulation
return versionString;
}
Thanks in advance, and sorry if this is trivial; I'm neither a C++ nor an Interop expert.
Can anyone confirm that such a method will indeed suffer from a memory leak
Only you can do that, the missing const keyword is not a guarantee that the native code does not in fact return a literal. Pervasive mistake in C code btw. Write a little test program that calls the function a hundred million times. If you don't see the memory usage explode with Task Manager then you don't have a problem.
if so, suggest how to free the memory from the pointer in managed code?
You just can't, it must be the native code itself that calls free(). So that it uses the correct heap, the one that was created by the C runtime library used by that code. Underlying winapi call is HeapCreate(), you don't have the heap handle. Technically it is discoverable with GetProcessHeaps() but you just don't know which one is the "right" one. Starting with VS2012, the CRT uses GetProcessHeap() instead of HeapCreate(), now Marshal.FreeHGlobal() can work. But you know that this code doesn't, you'll have to ask the author or vendor for an update. As long as you do that, ask him for a more usable flavor of this function, it should take a char* as an argument instead.
A more constructive approach is to just take the memory leak in stride. Simply call the function once, the version number is not going to change while your program is running. So store it in a static variable. Losing ~80 bytes of address space is not a problem you can ever notice, the OS automatically cleans up when your program terminates.

Managing unmanaged string across C++ / C# boundary with P/Invoke

I have the following struct declared (C++):
struct NativeOperationResult {
const INTEROP_BOOL Success; // INTEROP_BOOL = char
const char16_t* const ErrorMessage;
NativeOperationResult(const NativeOperationResult& c);
/* various constructors, omitted for brevity */
};
Now, I have an exported function definition elsewhere:
extern "C" __declspec(dllexport) NativeOperationResult ReturnFailureWithMessage() {
return { INTEROP_BOOL_FALSE, "Test" };
}
My expectation is to be calling ReturnFailureWithMessage (a test method in case you were wondering) from C# via P/Invoke. In the NativeOperationResult constructor, it takes a copy of "Test" and puts it in ErrorMessage.
The NativeOperationResult has ownership of the char16_t* so I need to delete it when the struct is destroyed. That's no problem, but I don't want to delete the memory before the .NET CLR has a chance to copy the string in to the managed heap.
Frankly I'm a bit fuzzy on where to delete that memory. What I think is that the C++ compiler will make a copy of my struct (or just move it) and then the CLR will use that copy... Which means I should delete the native memory from .NET with Marshal.FreeHGlobal.
Is that correct?
No, that is not correct. You need to differentiate between two cases:
1) You didn't do any allocations on C++ side. This is the case you are talking about right now.
2) You did do allocations on C++ side, you need to take care of deallocation.
Thus to answer your question: no, your example does not need any "deletion" of memory, since no-one has allocated the memory explictly.
Second case is a bit trickier. If you do memory allocations on C++ side with new char16_t[blah], you need to release the memory with delete[] nativeOperationResult.ErrorMessage. This is not possible to do on C# side. The memory can be allocated using different allocators(such as; malloc, new) and C# does not know how to deal with these pointers.
You need to add a new flag to NativeOperationResult, such as DeletionRequired, and export new function from unmanaged side: FreeNativeOperationResultIfNeeded(..). There is longer discussion here.
You can avoid all this non-sense with C++ strings. They work magically, and no deletion is required.
struct NativeOperationResult {
const INTEROP_BOOL Success; // INTEROP_BOOL = char
const string const ErrorMessage;
NativeOperationResult(const NativeOperationResult& c);
/* various constructors, omitted for brevity */
};
Instead of returning NativeOperationResult, you can make it an out parameter and expect the calling method to pass it the right amount of memory. That way the .Net can allocate memory and then clean it up after the pinvoke is done. But you will have to figure out a way to inform .Net the amount of memory it is expected to allocate.
extern "C" __declspec(dllexport) void ReturnFailureWithMessage(NativeOperationResult* result)

P/Invoke with arrays of double - marshalling data between C# and C++

I've read the various MSDN pages on C++ Interop with P/Invoke here and here but I am still confused.
I have some large arrays of doubles that I need to get into native code, and some resulting arrays that need to get back. I do not know the sizes of the output arrays in advance. For simplicity, I will use only a single array in the example. The platform is x64; I read that marshalling internals are quite different between 32- and 64-bit environments so this might be important.
C#
[DllImport("NativeLib.dll")]
public static extern void ComputeSomething(double[] inputs, int inlen,
[Out] out IntPtr outputs, [Out] out int outlen);
[DllImport("NativeLib.dll")]
public static extern void FreeArray(IntPtr outputs);
public void Compute(double[] inputs, out double[] outputs)
{
IntPtr output_ptr;
int outlen;
ComputeSomething(inputs, inputs.Length, out output_ptr, out outlen);
outputs = new double[outlen];
Marshal.Copy(output_ptr, outputs, 0, outlen);
FreeArray(output_ptr);
}
C++
extern "C"
{
void ComputeSomething(double* inputs, int input_length,
double** outputs, int* output_length)
{
//...
*output_length = ...;
*outputs = new double[output_length];
//...
}
void FreeArray(double* outputs)
{
delete[] outputs;
}
}
It works, that is, I can read out the doubles I wrote into the array on the C++ side. However, I wonder:
Is this really the right way to use P/Invoke?
Aren't my signatures needlessly complicated?
Can P/Invoke be used more efficiently to solve this problem?
I believe I read that marshalling for single dimensional arrays of built-in types can be avoided. Is there a way around Marshal.Copy?
Note that we have a working C++/Cli version, but there are some problems related to local statics in third-party library code that lead to crashes. Microsoft marked this issue as WONTFIX, which is why I am looking for alternatives.
It is okayish. The complete lack of a way to return an error code is pretty bad, that's going to hurt when the arrays are large and the program runs out of memory. The hard crash you get is pretty undiagnosable.
The need to copy the arrays and to explicitly release them doesn't win any prizes of course. You solve that by letting the caller pass a pointer to its own array and you just write the elements. You however need a protocol to let the caller figure out how large the array needs to be, that is going to require calling the method twice. The first call returns the required size, the second call gets the job done.
A boilerplate example would be:
[DllImport("foo.dll")]
private static int ReturnData(double[] data, ref int dataLength);
And a sample usage:
int len = 0;
double[] data = null;
int err = ReturnData(data, ref len);
if (err == ERROR_MORE_DATA) { // NOTE: expected
data = new double[len];
err = ReturnData(data, len);
}
No need to copy, no need to release memory, good thing. The native code can corrupt the GC heap if it doesn't pay attention to the passed len, not such a good thing. But of course easy to avoid.
If it were practical to separate the code that determines the output length from the code that populates the output then you could:
Export a function that returned the output length.
Call that from the C# code and then allocate the output buffer.
Call the unmanaged code again, this time asking it to populate the output buffer.
But I'm assuming that you have rejected this option because it is impractical. In which case your code is a perfectly reasonable way to solve your problem. In fact I would say that you've done a very good job.
The code will work just the same in x86 once you fix the calling convention mismatch. On the C++ side the calling convention is cdecl, but on the C# side it is stdcall. That doesn't matter on x64 since there is only one calling convention. But it would be a problem under x86.
Some comments:
You don't need to use [Out] as well as out. The latter implies the former.
You can avoid exporting the deallocator by allocating off a shared heap. For instance CoTaskMemAlloc on the C++ side, and then deallocate with Mashal.FreeCoTaskMem on the C# side.
If you knew the array size beforehand, you could write a C++/CLI DLL that takes the managed array as parameter, pins it, and calls the native C++ DLL on the pinned pointer it obtains.
But if it's output-only, I don't see any version without a copy. You can use a SAFEARRAY so P/Invoke does the copying instead of you, but that's all.

.Net Compact Framework - Calling ActiveX Object that uses [out] SAFEARRAY(float) *

In the Compact Framework 3.5, I am attempting to call an ActiveX object that has an IDL function signature:
HRESULT MyFunc([out] SAFEARRAY(float) *var)
The Interop generation creates the msil
[out] class [mscorlib]System.Array& marshal( safearray float32)
Which seems reasonable enough, but I keep getting a "NotSupportedException". According to an article entitled "Interop: Common issues and debugging techniques" (I can't post more than one hyperlink, it's the first google result for that phrase), in the first bullet point under the "Marshaling" heading, the compact framework doesn't properly marshal SAFEARRAYs.
I have attempted to get around this problem, by manipulating the answer described in this MSDN forum post (Last entry describes his method): http://social.msdn.microsoft.com/forums/en-US/clr/thread/6641abfc-3a9c-4976-a523-43890b2b79a2/
So, I have created the following definition:
[StructLayout(LayoutKind.Sequential)]
struct SafeArray
{
public ushort dimensions; // Count of dimensions in the SAFEARRAY
public ushort features; // Flags to describe SAFEARRAY usage
public uint elementSize; // Size of an array element
public uint locks; // Number of times locked without unlocking
public IntPtr dataPtr; // Pointer to the array data
public uint elementCount; // Element count for first (only) dimension
public int lowerBound; // Lower bound for first (only) dimension
}
And redefined the IDL for the function signature to:
HRESULT MyFunc([out] long *var)
And then issuing the following code:
IntPtr safeArrayPtr = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(SafeArray)));
SafeArray safeArray;
safeArray.dimensions = 1;
safeArray.features = 0;
safeArray.elementSize = (uint)(Marshal.SizeOf(typeof(float)));
safeArray.locks = 0;
safeArray.elementCount = 6;
safeArray.lowerBound = 0;
safeArray.dataPtr = Marshal.AllocCoTaskMem((int)(safeArray.elementCount * safeArray.elementSize));
Marshal.StructureToPtr(safeArray, safeArrayPtr, false);
int iTmp = safeArrayPtr.ToInt32();
MyFunc(out iTmp)
While the code appears to succeed, when I try to read back the data values, using the Marshal.Copy(dataPtr, myFloatArr, false) function, I am getting all 0's for the data, which tells me that the pointer that the ActiveX DLL is getting is probably totally bogus and it's off writing into oblivion.
Any suggestions as to what I may have messed up in these definitions, or suggestions for other ways of approaching this problem?
Thanks In Advance...
Well, I've solved this one.
Hopefully, my answer will help others who encounter the same problem. The problem that I was running into was that the [out] tag in a COM tlb declaration means that whatever I pass in will be overwritten with the object created inside the COM library. A rather complicated version of the classic (and very elementary problem) "Pass By Reference vs Pass By Value"
So, the correct marshaling is to use the definition of SafeArray that I posted above.
Don't touch the IDL signature itself - that's not a very clean way of doing it. Instead, use ildasm on the generated Interop library to modify the il from:
[out] class [mscorlib]System.Array& marshal( safearray float32)
to
[out] native int&
and then reassemble with ilasm which will produce a C# function signature
void MyFunc(out IntPtr var)
The calling code then becomes:
IntPtr ip;
SafeArray safeArray;
float []arrFloats;
MyFunc(out ip);
//Marshal the structure itself
Marshal.StructureToPtr(safeArray, ip, false);
//Marshal the data over to .NET
float []arrFloats = new float[safeArray.elementCount];
Marshal.Copy(safeArray.dataPtr, arrFloats, 0, (int)safeArray.elementCount);
Finally, we need to free the memory (remember, we changed the function signature so we're not giving .NET enough information to actually free the memory on its own.
//Don't forget to free both the structure and the object
Marshal.FreeCoTaskMem(safeArray.dataPtr);
Marshal.FreeCoTaskMem(ip);

Categories

Resources