Я работаю над драйвером для сканера. Получил dll и заголовочные файлы от провайдера, кроме руководства в PDF, написанного на родном C ++ (не имеет исходного кода). Нужно использовать его в проекте C #, но у меня проблемы со структурами (пытаюсь их прочитать или отправить).
Я получил методы dll, используя командную строку, разбирая их на веб-сайте (так как он имеет +100). Конечно, я не буду использовать их все, только те, которые мне нужны. Не было проблем с теми, кто использовал примитивные типы данных, фактически заставлял сканер включать / выключать, сканировать и тому подобное.
Моя основная проблема заключается в следующем: мне нужно установить некоторые параметры, потому что с параметрами по умолчанию я не получаю нужную информацию (и это САМАЯ важная вещь, которая мне нужна, на самом деле). Единственный способ сделать это с помощью метода, который включает 2 параметра: идентификатор (просто int) и параметр (структура). Внутри этой структуры есть не один, а 2 разных экземпляра структур (и один из них представляет собой массив в структуре другого типа в качестве одного из параметров). Другими словами, нужно будет работать с 4 различными структурами.
Я объявил все свои структуры, следуя шаблону, предоставленному в файле .h, и ввел метод. Когда я пытаюсь сделать тест, он постоянно выдает мне ошибку. Я считаю, что проблема заключается в массиве структур. Я попытался с обычной передачей, Marshaling, используя пин-код для массива, изменив тип данных, добавив «MarshalAs» со всеми переменными bool ... похоже, ничего не работает.
Я пытался решить эту проблему уже несколько дней. Не знаю, что я делаю неправильно (потому что это мой первый раз методы импорта). Я читал о C ++ / Cli, но никогда не работал с этим.
См. Код ниже (я немного изменил из-за конфиденциальности информации)
Так определено в файле .h (C ++)
// The structs (won't add all parameters, but are basically the same type)
typedef struct _ImParam
{
UINT Format;
UINT Resolution;
UINT ColorDepth;
} IM_PARAM;
typedef struct _sValues
{
UINT Xpos;
UINT Ypos;
UINT Width;
UINT Height;
BOOL Milli;
} S_VALUES;
typedef struct _sProperties
{
BOOL Enable;
S_VALUES Properties;
} S_PROPERTIES;
typedef struct _DevParam
{
BOOL Enable;
UINT Font;
char Symbol;
IM_PARAM Image1;
IM_PARAM Image2;
S_PROPERTIES Properties[10];
UINT FeedMode;
} DevParam;
// more code, comments, etc. etc.
// This is how is defined
BOOL SetParameters( DWORD ID, DevParams DParam )
Вот как я строю структуры в C #
[StructLayout(LayoutKind.Sequential)]
public struct ImParam
{
public uint Format;
public uint Resolution;
public uint ColorDepth;
public ImParam(uint n)
{
Format = n;
Resolution = 300;
ColorDepth = 256;
}
};
[StructLayout(LayoutKind.Sequential)]
public struct sValues
{
public uint Xpos;
public uint Ypos;
public uint Width;
public uint Height;
public bool Milli;
public sValues(uint n)
{
Xpos = n;
Ypos = n;
Width = n;
Height = n;
Milli = false;
}
};
[StructLayout(LayoutKind.Sequential)]
public struct sProperties
{
public bool Enable;
public sValues Properties;
public sProperties(int n)
{
Enable = false;
Front = false;
Properties = new sValues(n);
}
};
// Commented code is from another attemp
[StructLayout(LayoutKind.Sequential)]
public struct DevParam
{
public bool Enable;
public uint Font;
public char Symbol;
public ImParam Image1;
public ImParam Image2;
public IntPtr Properties;
//public sProperties[] Properties;
public uint FeedMode;
public DeviceParameters(IntPtr SnP) //(int n)
{
Enable = true;
Font = 0;
Symbol = '?';
Image1 = new ImParam(3);
Image2 = new ImParam(3);
Properties = SnP;
/*Properties = new sProperties[n];
*for(int i = 0; i < n; i++)
* Properties[i] = new sProperties(0);*/
FeedMode = 1;
}
};
// .dll file path definition, some methods imported, etc. etc.
[DllImport(path, EntryPoint = "?SetParameters@@YGHKU_DevParam@@@Z")]
public static extern bool SetParameters(int ID, DevParam dParam);
И вот когда я это называю (добавил закомментированный код, чтобы показать вам мои попытки)
static void Main(string[] args)
{
bool res = false;
int ID;
sProperties[] SnP = new sProperties[10];
for (int i = 0; i < 10; i++)
SnP[i] = new sProperties(0);
try
{
// Some code to turn on scanner, get ID value and such
/* Attemp1: Passing the struct normaly.
* Result: ArgumentException [HRESULT: 0x80070057 (E_INVALIDARG))]
* try
* {
* DevParam dParam = new DevParam(10);
* res = Class1.SetParameters(ID, dParam);
* Console.WriteLine(res);
* }
* catch (Exception e) { Console.WriteLine(e); }*/
/* Attemp2: Marshaling each element of the array.
* Result: The managed PInvoke signature doesnt mach the destination one
* int S = Marshal.SizeOf(typeof(sProperties));
* DevParam dParam = new DevParam(Marshal.AllocHGlobal(SnP.Length*S));
* IntPtr ptr = dParam.Properties;
* for (int i = 0; i < SnP.Length; i++)
* {
* Marshal.StructureToPtr(SnP[i], ptr, false);
* ptr += S;
* }
* try
* {
* res = Class1.SetDevParam(ID, dParam);
* Console.WriteLine(res);
* }
* finally { Marshal.FreeHGlobal(dParam.sProperties); }*/
/* Attemp3: Adding a Pin Pointer to struct
* Result: Exception (Object has no primitive data and it can't
* be transfered into bits blocks) */
GCHandle SpHandle = GCHandle.Alloc(SnP, GCHandleType.Pinned);
try
{
DevParam dParam = new DevParam(SpHandle.AddrOfPinnedObject());
res = Class1.SetParameters(ID, dParam);
Console.WriteLine(res);
}
catch (Exception e) { Console.WriteLine(e); }
finally { SpHandle.Free(); }
// More code for testing other methods and blahblahblah
}
catch (Exception e) { Console.WriteLine(e); }
Console.WriteLine("Finished");
Console.ReadKey();
}
Чего мне ожидать? Получение только логического результата, чтобы увидеть, успешно ли выполнен метод (и, конечно, если true, сканер должен был определить новые параметры)
Что я получу? Куча исключений.
Пожалуйста, любая помощь будет отличной. Заранее спасибо.
PD: Простите за этот длинный пост.
PD2: Я довольно сумасшедший, поэтому, пожалуйста, попробуйте объяснить это "для чайников"