J'essaie d'interfacer C# (.NET Compact Framework 3.5) avec un pilote de flux Windows CE 6 R2 à l'aide d'appels DeviceIoControl() P/Invoqués. Pour l'un des codes IOCTL, le pilote a besoin d'un tampon d'entrée DeviceIoControl qui est le struct non géré suivant qui contient un pointeur intégré:Structure de regroupement avec pointeur intégré de C# vers un pilote non géré
typedef struct {
DWORD address;
const void* pBuffer;
DWORD size; // buffer size
} IOCTL_TWL_WRITEREGS_IN;
je définissais la struct en C# comme:
[StructLayout(LayoutKind.Sequential)]
public struct IoctlWriteRegsIn
{
public uint Address;
public byte[] Buffer;
public uint Size;
}
et mon signature P/Invoke comme:
[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);
Cependant, chaque fois que j'appelle DeviceIoControl() en C#, il retourne toujours faux, avec une dernière erreur Win32 de ERROR_INVALID_PARAMETER
. Voici un extrait de code source de l'instruction switch IOCTL du pilote qui gère le code IOCTL et fait la vérification des erreurs sur la mémoire tampon d'entrée, où inSize est le paramètre 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);
J'ai essayé dur de codage des tailles qui doivent passer la erreur de vérification du pilote sans succès, ce qui suggère que c'est un problème de triage. Je n'ai probablement pas correctement défini le pointeur intégré dans la structure C# ou ma signature P/Invoke est incorrecte. Des idées?
Merci à l'avance, Ben
Pour référence, je peux parler au conducteur de C++ sans problème comme celui-ci:
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);
Mise à jour: voici ce qui a fonctionné! occasion suggestion IntPtr de JaredPar et nettoyé ma signature P/Invoke par la suggestion de 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);
Vous mettez l'IntPtr à une valeur aléatoire e en mémoire. Vous devez réellement allouer le pointeur à la mémoire réelle – JaredPar
Oups, bonne prise. Ça fonctionne maintenant! Merci beaucoup, j'apprécie vraiment votre aide. –
pouvez-vous s'il vous plaît m'expliquer cette ligne 'GCHandle pin = GCHandle.Alloc (regData, GCHandleType.Pinned);' que fait-il exactement? – FosterZ