#c# #c #string #pinvoke
#c# #c #строка #pinvoke
Вопрос:
Код на C :
__declspec(dllexport) const char* Get() {
return "hello word!";
}
C # код:
[DllImport("TestLink.dll")]
public static extern string Get();
Программа завершает работу сразу после вызова
Комментарии:
1. Но с использованием IntPtr проблем нет, я могу использовать следующий код для нормальной работы « [DllImport(«TestLink.dll «)] публичный статический extern IntPtr Get(); «
2. Я уже вижу отсутствие
__stdcall
в коде C … И есть, по крайней мере, еще одна проблема… C # попытается освободить память для строки C (которая должна быть выделена,Marshal.AllocCoTaskMem
а не обязательно буквальной строкой). И вы должны сказать C #, что строка будет ANSI, а не Unicode. В конце концов, вы идете в направлении, противоположном «правильному».3. внутренняя небезопасная статическая строка ConvertToManaged(IntPtr cstr) { if (IntPtr.Zero == cstr) { возвращает null; } возвращает новую строку((sbyte *)((void *)cstr)); } Я могу использовать приведенный выше код, я вижу. Net framework, похоже, является тем же преобразованием
4. «Классический» способ возврата строк из C — это использование
StringBuilder()
C #-стороны. В противном случае существуют различные решения
Ответ №1:
В любом случае, когда вы выделяете что-либо с C / C / родной стороны, вы должны использовать распределитель COM, который .NET понимает. Итак, есть много способов вернуть строку, например:
C :
extern "C" __declspec(dllexport) void* __stdcall GetBSTR() {
return SysAllocString(L"hello world"); // uses CoTaskMemAlloc underneath
}
extern "C" __declspec(dllexport) void* __stdcall GetLPSTR() {
const char* p = "hello world";
int size = lstrlenA(p) 1;
void* lp = CoTaskMemAlloc(size);
if (lp)
{
CopyMemory(lp, p, size);
}
return lp;
}
extern "C" __declspec(dllexport) void* __stdcall GetLPWSTR() {
const wchar_t* p = L"hello world";
int size = (lstrlenW(p) 1) * sizeof(wchar_t);
void* lp = CoTaskMemAlloc(size);
if (lp)
{
CopyMemory(lp, p, size);
}
return lp;
}
И C#
[DllImport("MyDll")]
[return: MarshalAs(UnmanagedType.BStr)]
public static extern string GetBSTR();
[DllImport("MyDll")]
[return: MarshalAs(UnmanagedType.LPWStr)]
public static extern string GetLPWSTR();
[DllImport("MyDll")]
[return: MarshalAs(UnmanagedType.LPStr)]
public static extern string GetLPSTR();
Комментарии:
1. Я думаю, вам следует указать соглашение о вызовах… Я думаю, что код, как есть, использует cdecl на стороне C и stdcall на стороне C #. На x64 это, вероятно, не является большой проблемой, потому что stdcall и cdecl одинаковы, но на x86 это так.
2. @xanatos — да.
3. Это перебор для строки const. Просто объявите возвращаемый тип as
IntPtr
и вызовитеMarshal.PtrToStringAnsi()
orMarshal.PtrToStringUTF8()
.4. Стоит отметить, что причина сбоя кода в Q заключается в том, что маршалер вызывает
CoTaskMemFree
возвращаемый указатель.