我有一个生成值的c ++ plus方法。我从c#应用程序中调用此方法 C ++方法是这样的:
extern "C" REGISTRATION_API char * generate(char dIn[],char dOut[])
generate
方法返回一个字符数组(sOut[]=returnvalue; return sOut;
)
现在我从我的c#app调用此方法:
[DllImport("mydll.dll")]
static extern string generate(string sIn, string sOut);
如您所见,c#中的返回类型为string
。发生的事情是c#中返回的值不正确并且已损坏。 (generate
方法中的值是正确的,但每当我从c#调用它来提取它时,我都会得到一些错误的值。)
C#中的方法是否有string
返回值,而在c ++中它是char*
吗?
请分享您的意见,这很紧急,谢谢。
答案 0 :(得分:3)
不幸的是,char*
可能有些含糊不清。 (从字面上看,它是一个指向单个字符的指针,你可能会或者可能无法通过像数组一样取消引用指针来获取其他字符。)但是,通常,它是指向以空字符结尾的单字节字符串的指针。 ANSI编码(Microsoft称之为LPStr
)。默认情况下,P / Invoke将System.String
的实例封送为BStr
类型,类似于Unicode Pascal字符串(开头的长度)。您需要使用MarshalAs
attribute明确指定在托管代码和非托管代码之间编组字符串的方式。
最有可能的是,你要宣布它是这样的:
[DllImport("mydll.dll")]
[return: MarshalAs(UnmanagedType.LPStr)]
static extern string generate(
[MarshalAs(UnmanagedType.LPStr)] string sIn,
[MarshalAs(UnmanagedType.LPStr)] out string sOut);
但是,您的函数签名令人困惑:是返回字符串,还是设置输出变量?您可能需要调整P / Invoke声明以满足您的需求。
答案 1 :(得分:2)
我在C#中的方法是否可以 字符串返回值,而在c ++中它是 一个char *?
这完全取决于。
如果C ++方法为字符串分配内存并期望调用者释放它,那么你就会遇到问题......大问题。您可以尝试在其上调用Marshal.FreeHGlobal
,但是没有保证C ++方法实际上在全局堆上分配了内存。大多数API都会将指针反馈到其中一个方法中以释放内存。
char *
也可能指向不需要释放的内存。在这种情况下,使用string
应该没问题。
您可以让C#声明返回IntPtr
,然后调用其中一个Marhsal.PtrToStringXXX
方法。
答案 2 :(得分:1)
也无法从本机C ++应用程序安全地调用此方法。它返回指向堆栈帧上的数组的指针。对另一个函数的任何调用都将覆盖该堆栈帧并破坏该数组。
这可能在C ++程序中偶然发生,因为在获得此函数的返回值后没有函数调用。当P / Invoke marshaller介于两者之间时,这种运气不再可用。
您必须重新设计C ++功能。你应该给它一些参数,允许调用者传递自己的缓冲区来填充结果。例如:
extern "C" void __stdcall generate(const char* input, char* output, int outputSize)
通过为输出参数传递StringBuilder,在C#代码中调用它,并使用足够的容量正确初始化以接收字符串。 outputSize参数确保C ++函数可以避免写入缓冲区的末尾并破坏垃圾收集堆。不要忽视它。