2

.NET コンパクト フレームワークは初めてです。DeviceIoControl 関数を呼び出し、構造体を入出力パラメーターとして IOControl 関数に渡す必要があります。

PInvoke/DeviceIoControlで、関数自体にアクセスする方法を見つけました。しかし、どうすればポインタを構造体InBufOutBufパラメータとして渡すことができますか?

DeviceIoControl は 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);

問題の構造のレイアウトは次のとおりです。

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);   
}

編集:このコードをコンパイルしようとすると、エラーが発生します:

cannot convert from 'ref MyNamespace.Response' to 'byte[]'

構造体参照の代わりにバイトへのポインターを期待する DeviceIoControl 関数に構造体のアドレスを渡すにはどうすればよいですか?

4

1 に答える 1

2

問題は、P/Invoke 宣言が呼び出しと一致しないことです。DeviceIoControl は、in/out パラメーターのポインターを受け取ります。

BOOL DeviceIoControl(
  HANDLE hDevice, 
  DWORD dwIoControlCode, 
  LPVOID lpInBuffer, 
  DWORD nInBufferSize, 
  LPVOID lpOutBuffer, 
  DWORD nOutBufferSize, 
  LPDWORD lpBytesReturned, 
  LPOVERLAPPED lpOverlapped
);

したがって、多くの方法で宣言を「調整」できます。あなたが提供するリンクのものは、byte[]おそらく彼らがそれを使用していた便宜上を使用しています。あなたの場合、単純な構造体 (つまり、他のデータへの内部ポインターがない) を渡しているため、最も簡単な「修正」は、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);    

そして、あなたのコードはうまくいくはずです。最初の 2 つのパラメーターの型も変更して、キャストなしで呼び出しコードをより明確にすることに注意してください。

編集2

別の署名が必要な場合は、単純に P/Invoke をオーバーロードします。たとえば、スマート デバイス フレームワークコードには、DeviceIoControl の少なくとも 11 のオーバーロードがあります。以下にその一部を示します。

    [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);
于 2012-05-18T13:05:46.223 に答える