English 中文(简体)
How do I properly return a char * from an Unmanaged DLL to C#?
原标题:

Function signature:

char * errMessage(int err);

My code:

[DllImport("api.dll")]       
internal static extern char[] errMessage(int err);
...
char[] message = errMessage(err);

This returns an error:

Cannot marshal  return value : Invalid managed/unmanaged type combination.

What am I doing wrong? Thanks for any help.

最佳回答

try this:

[DllImport("api.dll")]
[return : MarshalAs(UnmanagedType.LPStr)]
internal static extern string errMessage(int err);
...
string message = errMessage(err);

I believe C# is smart enough to handle the pointer and return you a string.

Edit: Added the MarshalAs attribute

问题回答

A simple and robust way is to allocate a buffer in C# in the form if a StringBuilder, pass it to the unmanaged code and fill it there.

Example:

C

#include <string.h>

int foo(char *buf, int n) {
   strncpy(buf, "Hello World", n);
   return 0;
}

C#

[DllImport("libfoo", EntryPoint = "foo")]
static extern int Foo(StringBuilder buffer, int capacity);

static void Main()
{
    StringBuilder sb = new StringBuilder(100);
    Foo(sb, sb.Capacity);
    Console.WriteLine(sb.ToString());
}

Test:

Hello World

See this question. To summary, the function should return an IntPtr and you have to use Marshal.PtrToString* to convert it to a managed String object.

It is a horrible function signature, there s no way to guess how the string was allocated. Nor can you deallocate the memory for the string. If you declare the return type as "string" in the declaration then the P/Invoke marshaller will call CoTaskMemFree() on the pointer. That is very unlikely to be appropriate. It will silently fail in XP but crash your program in Vista and Win7.

You can t even reliably call the function in an unmanaged program. The odds that you d use the correct version of free() are pretty slim. All you can do is declare it as IntPtr and marshal the return value yourself with Marshal.PtrToStringAnsi(). Be sure to write a test program that does so a million times while you observe it in Taskmgr.exe. If the VM size for the program grows without bound, you have a memory leak you cannot plug.

Try using String in the managed side. you might as well set the CharSet to Ansi





相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签