为什么这个Explicit P / Invoke不起作用?

时间:2010-06-10 14:25:26

标签: c# c++ visual-studio-2008 visual-c++ pinvoke

以下.net到本机C代码不起作用,任何想法

extern "C" {
   TRADITIONALDLL_API int TestStrRef( __inout char* c)    {
   int rc = strlen(c);
   std::cout << "the input to TestStrRef is: >>" << c << "<<" ;
   c = "This is from the C code ";
   return rc;
   }
 }

 [DllImport("MyDll.dll", SetLastError = true)]
 static extern int TestStrRef([MarshalAs(UnmanagedType.LPStr)] ref string s);
 String abc = "InOut string";
 TestStrRef(ref abc);

此时Console.WriteLine(abc)应该打印“这是来自C代码”但是没有,任何关于什么错误的想法?

仅供参考 - 我有另一个不使用ref类型字符串的测试函数,它可以正常工作

2 个答案:

答案 0 :(得分:5)

你的代码也在C方面错了。 __inout注释只告诉编译器你可以改变“c”参数指向的缓冲区。但是指针本身位于堆栈中,如果修改了“c”参数,则不会返回调用者。 您的声明可能如下:

extern "C" {
   TRADITIONALDLL_API int TestStrRef( __inout char** c)    {
   int rc = strlen(*c);
   std::cout << "the input to TestStrRef is: >>" << *c << "<<" ;
   *c = "This is from the C code ";
   return rc;
   }
 }

和C#方:

[DllImport("MyDll.dll", SetLastError = true)]
static extern int TestStrRef(ref IntPtr c);

{
    String abc = "InOut string";
    IntPtr ptrOrig = Marshal.StringToHGlobalAnsi(abc)        
    IntPtr ptr = ptrOrig; // Because IntPtr is structure, ptr contains copy of ptrOrig
    int len = TestStrRef(ref ptr);
    Marshal.FreeHGlobal(ptrOrig); // You need to free memory located to abc' native copy
    string newAbc = Marshal.PtrToStringAnsi(ptr); 
    // You cannot free memory pointed by ptr, because it pointed to literal string located in dll code.
}

答案 1 :(得分:0)

这对你有用吗?基本上只需将CallingConvention = CallingConvention.Cdecl添加到DllImport语句中。您可能还想指定CharSet(例如:CharSet:= CharSet.Unicode)

 [DllImport("MyDll.dll", CallingConvention = CallingConvention.Cdecl, SetLastError = true)]
 static extern int TestStrRef([MarshalAs(UnmanagedType.LPStr)] ref string s);