Я пытаюсь связать С# (.NET Compact Framework 3.5) с потоковым драйвером Windows CE 6 R2, используя вызовы P/Invoked DeviceIoControl(). Для одного из кодов IOCTL драйверу требуется входной буфер DeviceIoControl, представляющий собой следующую неуправляемую структуру, содержащую встроенный указатель:
typedef struct {
DWORD address;
const void* pBuffer;
DWORD size; // buffer size
} IOCTL_TWL_WRITEREGS_IN;
Я определил структуру в С# как:
[StructLayout(LayoutKind.Sequential)]
public struct IoctlWriteRegsIn
{
public uint Address;
public byte[] Buffer;
public uint Size;
}
и моя подпись P/Invoke как:
[DllImport("coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern bool DeviceIoControl(IntPtr hDevice,
UInt32 dwIoControlCode,
ref IoctlWriteRegsIn lpInBuffer,
UInt32 nInBufferSize,
UInt32[] lpOutBuffer,
UInt32 nOutBufferSize,
ref UInt32 lpBytesReturned,
IntPtr lpOverlapped);
Однако всякий раз, когда я вызываю DeviceIoControl() в C#, он всегда возвращает false с последней ошибкой Win32 ERROR_INVALID_PARAMETER
. Вот фрагмент исходного кода оператора IOCTL switch в драйвере, который обрабатывает код IOCTL и выполняет проверку ошибок во входном буфере, где inSize — это параметр nInBufferSize:
case IOCTL_TWL_WRITEREGS:
if ((pInBuffer == NULL) ||
(inSize < sizeof(IOCTL_TWL_WRITEREGS_IN)))
{
SetLastError(ERROR_INVALID_PARAMETER);
break;
}
address = ((IOCTL_TWL_WRITEREGS_IN*)pInBuffer)->address;
pBuffer = ((IOCTL_TWL_WRITEREGS_IN*)pInBuffer)->pBuffer;
size = ((IOCTL_TWL_WRITEREGS_IN*)pInBuffer)->size;
if (inSize < (sizeof(IOCTL_TWL_WRITEREGS_IN) + size))
{
SetLastError(ERROR_INVALID_PARAMETER);
break;
}
rc = TWL_WriteRegs(context, address, pBuffer, size);
Я попробовал жесткие размеры кодирования, которые должны пройти проверку ошибок драйвера, но безуспешно, предполагая, что это проблема сортировки. Вероятно, я неправильно определил встроенный указатель в структуре C# или ошибся в подписи P/Invoke. Любые идеи?
Заранее спасибо, Бен
Для справки, я могу без проблем общаться с драйвером из C++:
IOCTL_TWL_WRITEREGS_IN reg;
reg.address = 0x004B0014;
unsigned char data = 0xBE;
reg.pBuffer = &data;
reg.size = sizeof(char);
BOOL writeSuccess = DeviceIoControl(driver, IOCTL_TWL_WRITEREGS, ®, sizeof(IOCTL_TWL_WRITEREGS_IN) + 1, NULL, 0, NULL, NULL);
Обновление: вот что сработало! Использовал предложение JaredPar IntPtr и очистил мою подпись P/Invoke по предложению SwDevMan81:
[StructLayout(LayoutKind.Sequential)]
public struct IoctlWriteRegsIn
{
public uint Address;
public IntPtr Buffer;
public uint Size;
}
// elided
byte regData = 0xFF;
GCHandle pin = GCHandle.Alloc(regData, GCHandleType.Pinned);
IoctlWriteRegsIn writeInBuffer = new IoctlWriteRegsIn{Address = twlBackupRegA, Buffer = pin.AddrOfPinnedObject(), Size = 1};
bool writeSuccess = DeviceIoControl(driverHandle, IoctlTwlWriteRegs, ref writeInBuffer, (uint) Marshal.SizeOf(writeInBuffer) + 1, IntPtr.Zero, 0, ref numBytesReturned, IntPtr.Zero);
// P/Invoke signature
[DllImport("coredll.dll", CharSet = CharSet.Unicode, SetLastError = true)]
static extern bool DeviceIoControl(IntPtr hDevice,
UInt32 dwIoControlCode,
ref IoctlWriteRegsIn lpInBuffer,
UInt32 nInBufferSize,
IntPtr lpOutBuffer,
UInt32 nOutBufferSize,
ref UInt32 lpBytesReturned,
IntPtr lpOverlapped);
GCHandle pin = GCHandle.Alloc(regData, GCHandleType.Pinned);
что именно она делает? - person FosterZ   schedule 25.03.2011