NETCF como faço para passar uma estrutura por ref para DeviceIoControl
-
11-12-2019 - |
Pergunta
Sou novo no framework compacto .NET.Preciso chamar uma função DeviceIoControl e passar estruturas como parâmetros de entrada e saída para a função IOControl.
Em PInvoke/DeviceIoControl Descobri como obter acesso à função em si.Mas como posso passar um ponteiro para a estrutura como InBuf
e OutBuf
parâmetro?
O DeviceIoControl é definido como P/Invoke:
[DllImport("coredll", EntryPoint = "DeviceIoControl", SetLastError = true)]
internal static extern int DeviceIoControlCE(
int hDevice, int dwIoControlCode,
byte[] lpInBuffer, int nInBufferSize,
byte[] lpOutBuffer, int nOutBufferSize,
ref int lpBytesReturned, IntPtr lpOverlapped);
As estruturas em questão possuem este layout:
struct Query
{
int a;
int b;
char x[8];
}
struct Response
{
int result;
uint32 success;
}
void DoIoControl ()
{
Query q = new Query();
Response r = new Response();
int inSize = System.Runtime.InteropServices.Marshal.SizeOf(q);
int outSize = System.Runtime.InteropServices.Marshal.SizeOf(r);
NativeMethods.DeviceIoControlCE((int)handle, (int)IOCTL_MY.CODE,
ref q, inSize, ref r, outSize, ref bytesReturned, IntPtr.Zero);
}
Editar:Quando tento compilar esse código recebo o erro:
cannot convert from 'ref MyNamespace.Response' to 'byte[]'
Como posso passar o endereço da estrutura para a função DeviceIoControl que espera que um ponteiro seja bytado em vez de struct ref?
Solução
O problema é que sua declaração P/Invoke não corresponde à sua chamada.DeviceIoControl recebe ponteiros para os parâmetros de entrada/saída:
BOOL DeviceIoControl(
HANDLE hDevice,
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped
);
Portanto, você pode “ajustar” sua declaração de várias maneiras.Aquele no link que você fornece usa um byte[]
provavelmente por conveniência onde eles o estavam usando.No seu caso, já que você está passando estruturas simples (ou seja,sem ponteiros internos para outros dados), então a "correção" mais fácil é apenas alterar sua declaração P/Invoke:
[DllImport("coredll", SetLastError = true)]
internal static extern int DeviceIoControl(
IntPtr hDevice,
IOCTL.MY dwIoControlCode,
ref Query lpInBuffer,
int nInBufferSize,
ref Response lpOutBuffer,
int nOutBufferSize,
ref int lpBytesReturned,
IntPtr lpOverlapped);
E seu código deve funcionar.Observe que também alterei os tipos dos dois primeiros parâmetros para permitir tornar seu código de chamada mais claro sem conversões.
EDITAR 2
Se você achar que precisa de assinaturas diferentes, simplesmente sobrecarregue o P/Invoke.Por exemplo, o Estrutura de dispositivos inteligentes o código tem pelo menos 11 sobrecargas para DeviceIoControl.Aqui estão apenas alguns deles para lhe dar um gostinho:
[DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
internal static extern int DeviceIoControl<TInput, TOutput>(
IntPtr hDevice,
uint dwIoControlCode,
ref TInput lpInBuffer,
int nInBufferSize,
ref TOutput lpOutBuffer,
int nOutBufferSize,
out int lpBytesReturned,
IntPtr lpOverlapped)
where TInput : struct
where TOutput : struct;
[DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
internal unsafe static extern int DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
void* lpInBuffer,
int nInBufferSize,
void* lpOutBuffer,
int nOutBufferSize,
out int lpBytesReturned,
IntPtr lpOverlapped);
[DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
internal static extern int DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
IntPtr lpInBuffer,
uint nInBufferSize,
IntPtr lpOutBuffer,
uint nOutBufferSize,
out int lpBytesReturned,
IntPtr lpOverlapped);
[DllImport("coredll.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
internal static extern int DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
byte[] lpInBuffer,
int nInBufferSize,
IntPtr lpOutBuffer,
int nOutBufferSize,
out int lpBytesReturned,
IntPtr lpOverlapped);