Pinvoke for C Function That Returns Char *

PInvoke for C function that returns char *

You must return this as an IntPtr. Returning a System.String type from a PInvoke function requires great care. The CLR must transfer the memory from the native representation into the managed one. This is an easy and predictable operation.

The problem though comes with what to do with the native memory that was returned from foo(). The CLR assumes the following two items about a PInvoke function which directly returns the string type

  1. The native memory needs to be freed
  2. The native memory was allocated with CoTaskMemAlloc

Therefore it will marshal the string and then call CoTaskMemFree(...) on the native memory blob. Unless you actually allocated this memory with CoTaskMemAlloc this will at best cause a crash in your application.

In order to get the correct semantics here you must return an IntPtr directly. Then use Marshal.PtrToString* in order to get to a managed String value. You may still need to free the native memory but that will dependent upon the implementation of foo.

C# pinvoke of C function returning char*

You cannot return a pointer to a local variable since those are allocated on the stack (and the stack may get destroyed when the function returns).

You'd need to allocate memory on the heap (preferably using CoTaskMemAlloc so the CLR can free up the memory later) on your C function and return a pointer to that memory.

As a side note, you can directly return a string when marshalling (assuming it's a c null-terminated unicode string), no need to return IntPtr.

More info here: http://limbioliong.wordpress.com/2011/06/16/returning-strings-from-a-c-api/

What type to PInvoke for a char**

The function returns a brand new C-string. The pinvoke marshaller always makes sure that the memory required to store a string that's returned by native code is released again. This will not come to a good end, surely the caller of this function is not supposed to release it. The const keyword is a strong hint that the native code will return a pointer to a string literal that's not allocated on the heap. Trying to release such a pointer will crash your program on later Windows versions, the kind that have a strict heap implementation (after XP).

You have to help to stop the marshaller from doing this. This requires you to declare the argument as a raw pointer, not a string:

  [DllImport(DllPath, CallingConvention = CallingConvention.Cdecl)]
public static extern int get_lib_version(out IntPtr version);

And you have to make the extra step to convert the pointer to a string:

  public string GetLibraryVersion() {
IntPtr strptr;
get_lib_version(out strptr);
return Marshal.PtrToStringAnsi(strptr);
}

Write a little test program to verify this assumption. Call GetLibraryVersion() a billion times. If the memory usage doesn't explode then you're good.

C# PInvoke - Function returning char* and with reference char* parameter

This is writing to unallocated memory.

sprintf(TotalMb,"%f",freeMemFloat);

You can either allocate memory using new in the routine and free it in the caller, or you can have a fixed buffer in the routine (not thread-safe).

Why can't I return a char* string from C++ to C# in a Release build?

Or maybe try to use

[DllImport("SimpleDll")]
public static extern IntPtr ReturnString();

and in your calling code, use the Marshal Class

string ret = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(PInvoke.ReturnString());

c# PInvoke w_char_t**

The function would be p/invoked like this:

[DllImport(@"mylib.dll")]
static extern int TEST(out IntPtr xml);

I removed the size paramter since it is not needed since you can use a null-terminated string.

Call the function like this:

IntPtr xmlptr;
int retval = TEST(out xmlptr);
string xml = Marshal.PtrToStringUni(xmlptr);
// deallocate xmlptr somehow

The tricky bit is to deallocate the memory allocated on the native side. Either use a shared allocator, e.g. the COM allocator. Or export a deallocator from the native code.

Personally I'd re-design the interface to use COM BSTR. I'd have the C++ return a BSTR and on the managed side use [MarshalAs(UnmanagedType.BStr)]. Then the framework handles all the deallocation and marshalling for you.

Returning a string from PInvoke?

First of all, as others have pointed out, your C++ is broken even before trying interop. You are returning a pointer to stri's buffer. But because stri is destroyed as soon as the function returns, the return value is not valid.

What's more, even if you fixed this, you need to do more. It won't work allocating memory in your C++ code which you would need the C# code to deallocate.

There are a few options to do it right.

Your C# code can ask the C++ code how long the string is. Then a C# StringBuilder is created and allocated to the appropriate size. Next the StringBuilder object is passed to the C++ code and its default marshalling is as a LPWSTR. In this approach the C# code allocates the string and your C++ code receives a C string to which it must copy the buffer.

Alternatively you can return a BSTR from the C++ which allows allocation in the native C++ code and deallocation in the C# code.

The BSTR approach is probably how I would do it. It looks like this:

C++

#include <comutil.h>
BSTR GetSomeText()
{
return ::SysAllocString(L"Greetings from the native world!");
}

C#

[DllImport(@"test.dll", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.BStr)]
private static extern string GetSomeText();

Update

Hans Passant added a couple of useful observations in the comments. First of all, most P/Invoke interop is done against an existing interface which cannot be changed and you do not have the luxury of picking your preferred interop interfacing approach. It would appear that is not the case here, so which approach should be chosen?

Option 1 is to allocate the buffer in the managed code, after having first asked the native code how much space is needed. Perhaps it is enough to use a fixed size buffer that both parties agree on.

Where option 1 falls down is when assembling the string is expensive and you don't want to do it twice (e.g. once to return its length, and once again for the contents). This is where option 2, the BSTR comes into play.

Hans pointed out one drawback of the BSTR, namely that it carries a UTF-16 payload but your source data may well char*, which is a "bit of a hassle".

To overcome the hassle you can wrap up the conversion from char* to BSTR like this:

BSTR ANSItoBSTR(char* input)
{
BSTR result = NULL;
int lenA = lstrlenA(input);
int lenW = ::MultiByteToWideChar(CP_ACP, 0, input, lenA, NULL, 0);
if (lenW > 0)
{
result = ::SysAllocStringLen(0, lenW);
::MultiByteToWideChar(CP_ACP, 0, input, lenA, result, lenW);
}
return result;
}

That's the hardest one out of the way, and now it's easy to add other wrappers to convert to BSTR from LPWSTR, std::string, std::wrstring etc.

C# PInvoke of C++ function that returns struct by value crashes if the struct is left uninitialized

The problem was that the code was compiled debug-mode and runtime checks for (lack of) variable initialization were setting a breakpoint. Since this was P-invoked and I was attached to the calling C#, I couldn't see what was going on in the C++ and it was simply exiting with error code 0x80000003, as @HansPassant points out. Once I enabled native code debugging in Visual Studio, the exception became clear and the process no longer terminated abruptly.

Also, release-mode compilation takes out the runtime checks (/RTC compile flag) and this wouldn't be an issue in release mode. So return of an uninitialized struct actually does work in practice.



Related Topics



Leave a reply



Submit