Я впервые пытаюсь использовать неуправляемую DLL C++ ("res_lib") в приложении C#. Я использовал cppsharp для генерации кода PInvoke: например, одну из функций/методов, которые я м, пытающийся позвонить, это get_system_snapshot
. Из файла .h
это определяется как
SYS_INT SYS_ERR get_system_snapshot(SNAPSHOT_PARMS* snapshotp);
SYS_INT
и SYS_ERR
равны int32_t
. SNAPSHOT_PARMS
это
typedef struct SNAPSHOT_PARMS
{
SYS_ULONG size;
SYS_UINT count;
SYS_CHAR serial_no[600];
} SYS_PACK_DIRECTIVE SYS_SNAPSHOT_PARMS;
cppsharp превратил это в следующие фрагменты кода:
Импорт библиотеки
[SuppressUnmanagedCodeSecurity]
[DllImport("res_lib", CallingConvention = CallingConvention.StdCall,
EntryPoint="get_system_snapshot")]
internal static extern int GetSystemSnapshot(IntPtr snapshotp);
Объект
public unsafe partial class SNAPSHOT_PARMS : IDisposable
{
[StructLayout(LayoutKind.Explicit, Size = 608)]
public partial struct __Internal
{
[FieldOffset(0)]
internal uint size;
[FieldOffset(4)]
internal uint count;
[FieldOffset(8)]
internal fixed sbyte serial_no[600];
[SuppressUnmanagedCodeSecurity]
[DllImport("res_lib", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.ThisCall,
EntryPoint="??0SNAPSHOT_PARMS@@QAE@ABU0@@Z")]
internal static extern global::System.IntPtr cctor(global::System.IntPtr instance, global::System.IntPtr _0);
}
}
public SNAPSHOT_PARMS()
{
__Instance = Marshal.AllocHGlobal(sizeof(global::res_lib.SNAPSHOT_PARMS.__Internal));
__ownsNativeInstance = true;
NativeToManagedMap[__Instance] = this;
}
Основной код
static void Main(string[] args)
{
SNAPSHOT_PARMS p = new SNAPSHOT_PARMS();
var result = res_lib.res_lib.GetSystemSnapshot(p);
}
public static unsafe int GetSystemSnapshot(global::res_lib.SNAPSHOT_PARMS snapshotp)
{
var __arg0 = ReferenceEquals(snapshotp, null) ? global::System.IntPtr.Zero : snapshotp.__Instance;
var __ret = __Internal.GetSystemSnapshot(out __arg0);
return __ret;
}
При вызове функции получаю печально известное:
Попытка чтения или записи защищенной памяти. Это часто указывает на то, что другая память повреждена.
Я пытался изменить CallingConvention
с StdCall
на Cdecl
, ввести [In]
и [Out]
в DllImport
и т. д., но все безрезультатно. Может ли кто-нибудь увидеть что-то явно не так с кодом - как может быть очевидно, все это ново для меня, и, возможно, я прошу слишком много, чтобы cppsharp сгенерировал код, который не нужно будет настраивать.
EDIT В оригинальной документации C++ есть пример, где структура инициализируется
#define INIT_STRUCT(struct_p) { memset(struct_p, 0, sizeof(*(struct_p))); (struct_p)->size = sizeof(*(struct_p)); }
и используется
SNAPSHOT_PARMS snapshot_parms;
SYS_ERR result;
INIT_STRUCT(&snapshot_parms);
result = get_system_snapshot(&snapshot_parms);
size
инициализируется установкой этого члена в размер структуры, видимый вызывающей стороне — это распространенный метод поддержки версионных структур. Просто увидев аргумент какSNAPSHOT_PARMS*
, вы не можете сказать, ожидает ли вызывающая сторона инициализацию каких-либо данных перед вызовом. - person Jeroen Mostert   schedule 17.08.2018size
и 2) хочет, чтобы функция поместила свои данные в эту структуру. Код C# не выполняет 1 и не может работать с 2, поскольку структура всегда передается только по значению в качестве входного параметра. ПараметрGetSystemSnapshot
должен быть неIntPtr
, аref SNAPSHOT_PARMS
, и он должен быть инициализированnew SNAPSHOT_PARMS { size = Marshal.SizeOf<SNAPSHOT_PARMS>() }
. - person Jeroen Mostert   schedule 17.08.2018cppsharp
в данном случае больше мешает, чем помогает — я вижу, что он пытается сделать, но его обертки на самом деле не упрощают задачу, и он импортирует некоторые вещи, которые не должен был импортировать (например, конструктор копирования вSNAPSHOT_PARMS
). Структура__Internal
, которую он поместил в класс, действительно все, что вам нужно, в сочетании с импортомGetSystemSnapshot
. - person Jeroen Mostert   schedule 17.08.2018