NETCF ¿Cómo paso una estructura por referencia a DeviceIoControl?
-
11-12-2019 - |
Pregunta
Soy nuevo en el marco compacto .NET.Necesito llamar a una función DeviceIoControl y pasar estructuras como parámetros de entrada y salida a la función IOControl.
En PInvocar/DeviceIoControl Encontré cómo acceder a la función en sí.Pero, ¿cómo puedo pasar un puntero a la estructura como? InBuf
y OutBuf
¿parámetro?
DeviceIoControl se define 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);
Las estructuras en cuestión tienen este diseño:
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:Cuando intento compilar este código me sale el error:
cannot convert from 'ref MyNamespace.Response' to 'byte[]'
¿Cómo puedo pasar la dirección de la estructura a la función DeviceIoControl que espera un puntero a byte en lugar de referencia de estructura?
Solución
El problema es que su declaración P/Invoke no coincide con su llamada.DeviceIoControl toma punteros para los parámetros de entrada/salida:
BOOL DeviceIoControl(
HANDLE hDevice,
DWORD dwIoControlCode,
LPVOID lpInBuffer,
DWORD nInBufferSize,
LPVOID lpOutBuffer,
DWORD nOutBufferSize,
LPDWORD lpBytesReturned,
LPOVERLAPPED lpOverlapped
);
Así que puedes "ajustar" tu declaración de muchas maneras.El que está en el enlace que proporcionas utiliza un byte[]
probablemente por conveniencia donde lo estaban usando.En su caso, dado que está pasando estructuras simples (es decir,no hay punteros internos a otros datos), entonces la "solución" más fácil es simplemente cambiar su declaración 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);
Y tu código debería funcionar.Tenga en cuenta que también cambié los tipos de los dos primeros parámetros para permitir que su código de llamada sea más claro sin conversiones.
EDITAR 2
Si descubre que necesita firmas diferentes, simplemente sobrecargue P/Invoke.Por ejemplo, el Marco de dispositivos inteligentes El código tiene al menos 11 sobrecargas para DeviceIoControl.Éstos son sólo algunos de ellos para darle una idea:
[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);