#c# #interop #pinvoke
#c# #взаимодействие #pinvoke
Вопрос:
У меня есть следующий собственный функциональный интерфейс на C :
int func1(void* param, int sizeOfParam).
В документации приведен следующий пример вызова:
typedef struct
{
int x;
int y;
int width;
int height;
} Rect;
Rect rect;
int func1((void*)amp;rect, sizeof(rect));
Мне нужно вызвать эту функцию из кода C #.
У меня есть следующий заголовок в C # от разработчиков собственной библиотеки:
[DllImport(NATIVE_DLL_NAME,
CallingConvention = CallingConvention.Cdecl,
EntryPoint = "func1")]
private static extern int func1(IntPtr param, int sizeOfParam);
У меня также есть следующая структура C # Rect
:
public struct Rect
{
int x;
int y;
int width;
int height;
};
Мне нужно вызвать func1
код C # и передать Rect
:
Я делаю следующее:
Rect rect = new Rect();
int rectSize = System.Runtime.InteropServices.Marshal.SizeOf(rect);
func1(???, rectSize);
Что поместить в положение ???
, в котором rect
должно быть передано (но это невозможно из-за несовместимых типов)?
Кажется, это IntPtr
должно быть передано, а затем преобразовано в struct rect
. Как этого добиться?
( rect
здесь является выходным параметром)
Обновить:
Желательно не изменять подписи кода C и оболочек C # — это третья часть кода.
Более того, не всегда переменная of Rect
передается как первый параметр func1
Ответ №1:
Вы изменили правила игры, чтобы запретить внесение изменений в код C #. И поэтому P / invoke должен иметь такую форму:
private static extern int func1(IntPtr param, int sizeOfParam);
В этом случае вам нужно выполнить сортировку вручную:
int size = Marshal.SizeOf(typeof(Rect));
IntPtr param1 = Marshal.AllocHGlobal(size);
try
{
func1(param1, size);
Rect rect = (Rect)Marshal.PtrToStructure(param1, typeof(Rect));
}
finally
{
Marshal.FreeHGlobal(param1);
}
Комментарии:
1. Спасибо! Извините за путаницу. Просто небольшой вопрос. Может ли отсутствие
[StructLayout(LayoutKind.Sequential)]
in Rect потенциально вызвать проблемы?2. Вам нужно использовать
[StructLayout(LayoutKind.Sequential)]
. И какие проблемы вы видите?3. На данный момент проблем нет. Спасибо. Я только что прочитал на msdn.microsoft.com/en-us/library/0t2cwe11(v=vs.71).aspx определение StructLayout и боялся, что компилятор может переставлять члены struct по своему усмотрению. И если сейчас это не проблема, это не значит, что в будущем она не появится.
Ответ №2:
Я бы, вероятно, немного упростил себе жизнь, используя out
параметр типа Rect
, а не IntPtr
. Вот так:
[StructLayout(LayoutKind.Sequential)]
public struct Rect
{
int x;
int y;
int width;
int height;
};
[DllImport(NATIVE_DLL_NAME, CallingConvention = CallingConvention.Cdecl, EntryPoint = "func1")]
private static extern int func1(out Rect param, int sizeOfParam);
Затем для вызова функции вы можете написать это:
Rect param;
int res = func1(out param, Marshal.SizeOf(typeof(Rect)));
Комментарии:
1. Да, вы действительно упростили жизнь 🙂 Странно, что это не всегда
Rect
передается как первый параметр…2. Вы можете создавать
func1Rect
иfunc1SomeOtherType
т. Д. чтобы справиться с этим.3. нет, не могу. Я обновил вопрос, чтобы прояснить ситуацию: код C и обертки C # являются сторонними, и я бы не хотел их изменять. Конечно, если других решений не существует, я действительно должен их обновить.
Ответ №3:
Попробуйте вместо этого передать ref Rect .
[DllImport(NATIVE_DLL_NAME, CallingConvention = CallingConvention.Cdecl, EntryPoint = "func1")]
private static extern int func1(ref Rect param, int sizeOfParam);
Комментарии:
1. Это не совсем то, о чем я спрашиваю. Я прояснил вопрос.