Почему этот явный P / Invoke не работает? - PullRequest
1 голос
/ 10 июня 2010

Следующий код от .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 ]

5 голосов
/ 10 июня 2010

Ваш код неправильный на стороне C также. __в аннотации просто скажите компилятору, что вы можете изменить буфер, на который указывает аргумент "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.
}
0 голосов
/ 10 июня 2010

Это работает для вас? В основном просто добавьте 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);
...