我正在开发一个需要与Video4Linux抽象交互的应用程序。该应用程序是使用单一框架在C#中开发的。P /调用ioctl系统调用
我面临的问题是我无法P/Invoke ioctl
系统调用。或者,更确切地说,我可以P /调用它,但它崩溃严重。
的extern声明如下:
[DllImport("libc", EntryPoint = "ioctl", SetLastError = true)]
private extern static int KernelIoCtrl(int fd, int request, IntPtr data);
到目前为止好。
使用该KernelIoCtrl
实际的日常如下:
protected virtual int Control(IoSpecification request, object data)
{
GCHandle dataHandle;
IntPtr dataPointer = IntPtr.Zero;
try {
// Pin I/O control data
if (data != null) {
dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
dataPointer = dataHandle.AddrOfPinnedObject();
}
// Perform I/O control
int result = KernelIoCtrl(mFileDescriptor, request.RequestCode, dataPointer);
int errno = Marshal.GetLastWin32Error();
// Throw exception on errors
if (errno != (int)ErrNumber.NoError)
throw new System.ComponentModel.Win32Exception(errno);
return (result);
} finally {
if (dataPointer != IntPtr.Zero)
dataHandle.Free();
}
}
所有上面的代码似乎不错。类IoSpecification
用于计算所述I/O请求的代码的报头规范以下(基本上它遵循在/usr/include/linux/asm/ioctl.h
宣布_IOC
宏
的data
参数是一个结构,声明如下:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct Capability
{
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)]
public string Driver;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string Device;
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
public string BusInfo;
public UInt32 Version;
public CapabilityFlags Capabilities;
[MarshalAs(UnmanagedType.ByValArray, SizeConst=4)]
public UInt32[] Reserved;
}
这应该模仿结构如下(在/usr/include/linux/videodev2.h
声明):
struct v4l2_capability {
__u8 driver[16]; /* i.e. "bttv" */
__u8 card[32]; /* i.e. "Hauppauge WinTV" */
__u8 bus_info[32]; /* "PCI:" + pci_name(pci_dev) */
__u32 version; /* should use KERNEL_VERSION() */
__u32 capabilities; /* Device capabilities */
__u32 reserved[4];
};
具有崩溃之前,有一个问题IOCTL请求代码计算和KernelIoCtrl
按预期工作(返回errno
等于EINVAL)。当我纠正错误(并确实有正确的IOCTRL请求代码)时,调用已开始导致崩溃。
总之,看来结构编组存在问题,但我看不出它出错了。
我担心的问题是可变的参数列表,因为IOCTL例行声明如下(从人获得):
int ioctl(int d, int request, ...);
但是我看到很多代码,宣布根据上述程序为int ioctl(int d, int request, void*);
,并且我可以确保特定的IOCTRL请求只接受一个参数。
我没有类似的东西而回,并结束了每次使用的ioctl不同的方法声明。尝试:'私人extern静态int KernelIoCtrl(int fd,诠释请求,参考能力);'这应该让你摆脱钉住的东西。如果它仍然崩溃,那么你的结构声明是错误的。 – dtb
@dtb哇...它的工作!有没有一种通用的方式来处理多个IOCTL请求,而无需声明一堆extern?必须有办法做到这一点! – Luca
也许有一些方法可以使它工作,但是我猜想宣布一堆extern更容易,更可靠。 – dtb