Это просто любопытство. Возможно, в этом мире есть человек, который делал такие вещи:
Я должен экспортировать функцию C и загрузить ее из кода C # через DllImport
const wchar_t * SysGetLibInfo() {
return dllmanager.SysGetLibInfo();
}
Лучший способ сделать это, и это широко рекомендуется, — объявить IntPtr, а затем преобразовать его в строку, используя некоторую функцию. Другими словами, как-то так
[DllImport(dll, CallingConvention = CallingConvention.Cdecl)]
private static extern IntPtr SysGetLibInfo();
// ...
Marshal.PtrToStringUni(SysGetLibInfo());
Этот подход работает. Но есть ли способ сделать это автоматически? Чтобы SysGetLibInfo возвращал строку? Я нашел несколько предложений, как это:
[DllImport(dll, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.LPWStr)]
private static extern string SysGetLibInfo();
Но это не работает, и, согласно множеству примеров и скудных отчетов, это не должно работать.
Есть ли способ написать свой собственный атрибут, например MarshalAs, который будет конвертировать IntPtr в строку? Что-то похожее на это:
[DllImport(dll, CallingConvention = CallingConvention.Cdecl)]
[return: MyOwnMarshalPtrToStringUni]
private static extern string SysGetLibInfo();
Заранее спасибо за любую информацию или полезные ссылки, примеры, книги. Опять же, это просто любопытство.
Постскриптум Предложение обернуть SysGetLibInfo отдельной функцией, которая преобразует результат в строку, используя PtrToStringUni, не вариант;)
Вы не можете переопределить MarshalAs, но вместо этого вы можете использовать собственный маршаллинг
http://msdn.microsoft.com/en-us/library/w22x2hw6.aspx
[DllImport(dll, CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(MyMarshaller))]
private static extern string SysGetLibInfo();
Я думаю, что проблема с PLWStr
:
вы не можете использовать значение LPWStr с неуправляемой строкой если только
строка была создана с помощью неуправляемой функции CoTaskMemAlloc
Это отлично работает. Родной код:
// header
extern "C" __declspec(dllexport) wchar_t* SysGetLibInfo(void);
// implementation
extern "C" __declspec(dllexport) wchar_t* SysGetLibInfo(void)
{
return TEXT("Hello from unmanaged world!");
}
Управляемый код:
[DllImport("NativeLibrary.dll", CallingConvention = CallingConvention.Cdecl)]
[return: MarshalAs(UnmanagedType.LPTStr)]
static extern string SysGetLibInfo();
Если вы измените нативную функцию следующим образом:
extern "C" __declspec(dllexport) wchar_t* SysGetLibInfo(void)
{
wchar_t* pStr = (wchar_t*)CoTaskMemAlloc(100);
ZeroMemory(pStr, 100);
wcscpy(pStr, TEXT("Hello from unmanaged world!"));
return pStr;
}
затем [return: MarshalAs(UnmanagedType.LPWStr)]
тоже будет работать