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?

Foi útil?

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);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top