Video4Linux 抽象化と対話する必要があるアプリケーションを開発しています。このアプリケーションは、mono フレームワークを使用して C# で開発されています。
私が直面している問題は、ioctl
システム コールを P/Invoke できないことです。または、より正確には、P/Invoke はできますが、ひどくクラッシュします。
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 要求コードを計算するために使用されます (基本的には_IOC
、/usr/include/linux/asm/ioctl.h
.
パラメータは構造体で、次の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 要求コードの計算に問題があり、期待どおりに動作していました ( EINVALに等しい値をKernelIoCtrl
返します)。バグを修正したとき (そして実際に正しい IOCTRL 要求コードを持っていたとき)、呼び出しがクラッシュを引き起こし始めました。errno
結論として、構造のマーシャリングに問題があるようですが、何が問題なのかわかりません。
ioctlルーチンが次のように宣言されているため (man から取得) 、問題は可変引数リストにあるのではないかと心配しています。
int ioctl(int d, int request, ...);
しかし、上記のルーチンを として宣言するコードをたくさん見たのでint ioctl(int d, int request, void*);
、特定の IOCTRL リクエストが引数を 1 つだけ取るようにすることができます。