Вам не нужно использовать corflags application.exe / 32bit + .Все, что вам нужно сделать, это установить целевую платформу на x86 в project / properties / build.
Это сработает (хорошо, что это работает с использованием собственного метода тестирования, который я создал с той же сигнатурой, что и приведенная выше).Этот первый метод не требует ключевого слова unsafe или требует, чтобы проект был построен с установленным в true значением «Разрешить небезопасный код».
internal static class NativeMethods
{
[DllImport("Reader2.dll")]
public static extern short GetIDBuffer(
IntPtr hCom, ref byte dataFlag, ref byte count,
byte [] value, ref byte stationNum);
}
static int TestGetIDBuffer()
{
const int arraySize = 255;
byte[] bytes = new byte[arraySize + 1];
byte dataFlag = 0;
byte count = arraySize;
byte status = 0;
int retval = NativeMethods.GetIdBuffer(IntPtr.Zero, ref dataFlag, ref count, bytes, ref status);
Debug.WriteLine(Encoding.ASCII.GetString(bytes));
Debug.WriteLine(dataFlag);
Debug.WriteLine(status);
Debug.WriteLine(count);
Debug.WriteLine(retval);
return retval;
}
Вот альтернативный вариант с использованием исправлено массив байтов.Для этого второго метода требуется ключевое слово unsafe , а также проект, в котором для «Разрешить небезопасный код» установлено значение true.
internal static class NativeMethods
{
[DllImport("Reader2.dll")]
public static extern unsafe short GetIDBuffer(
IntPtr hCom, ref byte dataFlag, ref byte count,
byte* value, ref byte stationNum);
}
static unsafe int TestGetIDBuffer()
{
const int arraySize = 255;
byte[] bytes = new byte[arraySize + 1];
byte dataFlag = 0;
byte count = arraySize;
byte status = 0;
int retval;
fixed (byte* buffer = bytes)
retval = NativeMethods.GetIdBuffer(
IntPtr.Zero, ref dataFlag, ref count, buffer, ref status);
Debug.WriteLine(Encoding.ASCII.GetString(bytes));
Debug.WriteLine(dataFlag);
Debug.WriteLine(status);
Debug.WriteLine(count);
Debug.WriteLine(retval);
return retval;
}
Кажется, что все dataFlag, count и stationNumзначения байтов in / out.
Заполняемый буфер данных представляет собой массив байтов.Этот буфер необходимо исправить, чтобы GC не перемещал его, пока вы вызываете нативный метод.Это делается неявно в первом примере и явно во втором.
Я предполагаю, что доступный размер буфера должен быть передан в метод в параметре count, и это значение при выходе будет равным суммебуфера используется.Я позволил дополнительный байт, чтобы обеспечить нулевой завершающий символ, если массив байтов необходимо преобразовать в строку.
На самом деле есть две формы оператора fixed .Одна из упомянутых в этой статье MSDN позволяет создавать массив фиксированного размера, как в общедоступных байтах с фиксированным байтом [ArraySize];Другой в этой статье MSDN позволяет закрепить местоположение переменной, чтобы получить ее адрес.
Вот мой тестовый код C ++:
extern "C" __declspec(dllexport) unsigned short __stdcall GetIDBuffer(
HANDLE hCom, unsigned char * dataFlag, unsigned char * count,
unsigned char* buffer, unsigned char * status )
{
memset(buffer, 0x1E, *count);
*dataFlag = 0xa1;
*count = 0x13;
*status = 0xfe;
return 0x7531;
}
единственное различие между приведенным выше кодом C # и моим тестовым кодом заключается в том, что точку входа нужно указывать по-разному, поскольку я использовал компилятор C ++, например
[DllImport("PInvokeTestLib.dll", EntryPoint = "_GetIDBuffer@20")]
public static extern unsafe short GetIdBuffer(...
. Можно смело указывать параметры, передаваемые методу (не включая параметр массива значений) в качестве примитивных типов, отличных от байта, таких как int, long и т. д. Это связано с тем, что 1) значения передаются в виде ссылки и 2) x86 использует порядок байтов с прямым порядком байтов.Это приводит к тому, что отдельный байт записывается в младший байт из четырех байтов, переданных в int.
Рекомендуется использовать совпадающие типы, в данном случае - байт.