使用IOCTL_DVD_*控制代码从C#调用DeviceIoControl我正在尝试从C#调用DeviceIoControl以获得IOCTL_DVD_*控制代码。在阅读了大量资料并尝试了一些示例之后,我并没有取得太大进展。我最终做的是获取DVD_LAYER_DESCRIPTOR结构,了解DVD驱动器中当前的介质。我可以在DVD设备上成功调用CreateFile,但是当我尝试用控制码IOCTL_DVD_START_SESSION调用DeviceIoControl时,它返回一个成功代码,但我似乎没有成功恢复sessionId值,总是返回0。(和然后我尝试使用IOCTL_DVD_READ_STRUCTURE进行任何尝试层描述失败,即函数失败或返回成功但给出空白输出结构。)找到一些进行类似调用的C代码后,我能够编译此代码(使用VisualC++2008ExpressEdition),并且它能够成功地启动会话,读取DVD_LAYER_DESCRIPTOR,并毫无问题地关闭会话,所以我知道这是可行的。C#问题似乎与外部函数的定义方式和参数编组有关。以及如何定义传递和返回的各种结构。我查看了www.pinvoke.net他们是如何定义它的,并使用了一些示例代码和给出的定义,但仍然存在与上述相同的问题。部分问题似乎是每个IOCTL控制代码的参数不同,主要是结构,但对于IOCTL_DVD_START_SESSION,输出值是一个32位整数。如何在C#中定义外部方法来处理这些不同的情况?此外,使用正确大小的成员类型定义的各种结构表明它们在C和C#代码之间具有不同的大小,但各个成员的大小相同???如果我使用DeviceIOView之类的程序并观察IOCTL_DVD_START_SESSION的C代码和IOCTL_DVD_START_SESSION的C#代码,则C版本返回3的sessionid,并且在运行C#代码时,DeviceIOView显示发回的数据也是3,因此看起来是返回参数的某种编组问题,因为我们只在C#代码中看到0有没有人有任何想法或工作示例代码如何从C#调用DeviceIoControl来访问DVD信息?(显示应该如何定义和使用结构和函数。)非常感谢任何指向有用站点或其他建议的链接。(在VisualC#2008ExpressEdition、.NET3.5中开发。)NJohns示范代码(已添加)usingSystem;使用System.Collections.Generic;使用System.Linq;使用系统文本;使用Microsoft.Win32.SafeHandles;使用System.Runtime.InteropServices;使用System.IO;使用系统线程;命名空间示例{类程序{staticvoidMain(string[]args){stringdriveLetter=args[0].Substring(0,1).ToUpper()+":";SafeFileHandle_hdev=CreateFileR(driveLetter);if(_hdev.IsClosed|_hdev.IsInvalid){Console.WriteLine("打开设备时出错");返回;}Console.WriteLine("DeviceIoControl-版本一");Console.WriteLine("IOCTL_DVD_START_SESSION");布尔结果=假;intbytesReturned=0;intsessionId=0;结果=DeviceIoControl(_hdev,CTL_CODE(0x00000033,0x0400,0,1),IntPtr.Zero,0,(IntPtr)sessionId,Marshal.SizeOf(sessionId),outbytesReturned,IntPtr.Zero);if(result==false){interror_code=Marshal.GetLastWin32Error();Console.WriteLine("结果:"+结果);Console.WriteLine("错误码:"+error_code);}else{Console.WriteLine("Result:"+result);Console.WriteLine("BytesReturned:"+bytesReturned);Console.WriteLine("SessionId:"+sessionId);Console.WriteLine("sizeof(SessionId):"+Marshal.SizeOf(sessionId));}Console.WriteLine("IOCTL_DVD_READ_STRUCTURE");Console.WriteLine("跳过...");Console.WriteLine("IOCTL_DVD_END_SESSION");bytesReturned=0;结果=DeviceIoControl(_hdev,CTL_CODE(0x00000033,0x0403,0,1),newIntPtr(sessionId),Marshal.SizeOf(sessionId),IntPtr.Zero,0,outbytesReturned,IntPtr.Zero);if(result==false){interror_code=Marshal.GetLastWin32Error();Console.WriteLine("错误代码:"+error_code);Console.WriteLine("Result:"+result);}else{Console.WriteLine("Result:"+result);Console.WriteLine("BytesReturned:"+bytesReturned);}Console.WriteLine("nDeviceIoControl-版本二");Console.WriteLine("IOCTL_DVD_START_SESSION");result=false;uintbytesReturned2=0;sessionId=-10;NativeOverlappednativeOverlapped=newNativeOverlapped();结果=DeviceIoControlAlt(_hdev,EIOControlCode.DvdStartSession,0,0,sessionId,(uint)Marshal.SizeOf(sessionId),refbytesReturned2,refnativeOverlapped);if(result==false){interror_code=Marshal.GetLastWin32Error();Console.WriteLine("结果:"+结果);Console.WriteLine("错误代码:"+error_code);}else{Console.WriteLine("结果:"+result);Console.WriteLine("BytesReturned:"+bytesReturned2);Console.WriteLine("SessionId:"+sessionId);Console.WriteLine("sizeof(SessionId):"+Marshal.SizeOf(sessionId));}Console.WriteLine("IOCTL_DVD_READ_STRUCTURE");Console.WriteLine("正在跳过...");Console.WriteLine("IOCTL_DVD_END_SESSION");bytesReturned2=0;结果=DeviceIoControlAlt(_hdev,EIOControlCode.DvdEndSession,sessionId,(uint)Marshal.SizeOf(sessionId),0,0,refbytesReturned2,refnativeOverlapped);如果(结果==false){interror_code=Marshal。GetLastWin32Error();Console.WriteLine("结果:"+结果);Console.WriteLine("错误代码:"+error_code);}else{Console.WriteLine("结果:"+result);Console.WriteLine("BytesReturned:"+bytesReturned2);}_hdev.Close();}publicstaticintCTL_CODE(intDeviceType,intFunction,intMethod,intAccess){return(((DeviceType)<<16)|((Access)<<14)|((Function)<<2)|(Method));}[DllImport("kernel32.dll",CharSet=CharSet.Auto,SetLastError=true)]privatestaticexternIntPtrCreateFile(stringlpFileName,uintdwDesiredAccess,uintdwShareMode,IntPtrlpSecurityAttributes,uintdwCreationDisposition,uintdwFlagsAndAttributes,IntPtrhTemplateFile);publicstaticSafeFileHandleCreateFileR(stringdevice){stringstr=device.EndsWith(@"")?device.Substring(0,device.Length-1):设备;返回新的SafeFileHandle(CreateFile(@"\."+str,WinntConst.GENERIC_READ,WinntConst.FILE_SHARE_READ,IntPtr.Zero,WinntConst.OPEN_EXISTING,WinntConst.FILE_ATTRIBUTE_NORMAL,IntPtr.Zero),true);}[返回:MarshalAs(UnmanagedType.Bool)][DllImport("kernel32.dll",CharSet=CharSet.Auto,SetLastError=true)]publicstaticexternboolDeviceIoControl([In]SafeFileHandlehDevice,[In]intdwIoControlCode,[In]IntPtrlpInBuffer,[In]intnInBufferSize,[Out]IntPtrlpOutBuffer,[In]intnOutBufferSize,outintlpBytesReturned,[In]IntPtrlpOverlapped);internalclassWinntConst{//字段internalstaticuintFILE_ATTRIBUTE_NORMAL=0x80;内部静态uintFILE_SHARE_READ=1;内部静态uintGENERIC_READ=0x80000000;内部静态uintOPEN_EXISTING=3;}//来自pinvoke.net[Flags]的DeviceIoControl的其他代码publicenumEIOControlCode:uint{//DVDDvdReadStructure=(EFileDevice.Dvd<<16)|(0x0450<<2)|EMethod.缓冲|(FileAccess.Read<<14),DvdStartSession=(EFileDevice.Dvd&<16)|(0x0400<<2)|EMethod.缓冲|(FileAccess.Read<<14),DvdEndSession=(EFileDevice.Dvd<<16)|(0x0403<<2)|EMethod.缓冲|(文件访问.Read<<14)};[标志]publicenumEFileDevice:uint{Dvd=0x00000033,}[标志]publicenumEMethod:uint{Buffered=0,InDirect=1,OutDirect=2,Neither=3}[DllImport("Kernel32.dll",EntryPoint=“DeviceIoControl”,SetLastError=true,CharSet=CharSet.Auto)]publicstaticexternboolDeviceIoControlAlt(Microsoft.Win32.SafeHandles.SafeFileHandlehDevice,EIOControlCodeIoControlCode,[MarshalAs(UnmanagedType.AsAny)][In]objectInBuffer,uintnInBufferSize,[MarshalAs(UnmanagedType.AsAny)][Out]对象OutBuffer,uintnOutBufferSize,refuintpBytesReturned,[In]refSystem.Threading.NativeOverlappedOverlapped);}}要运行这段代码,需要在命令行指定光驱的盘符产量DeviceIoControl-第一版IOCTL_DVD_START_SESSION结果:假错误代码:122IOCTL_DVD_READ_STRUCTURE跳过...IOCTL_DVD_END_SESSION错误代码:87结果:假DeviceIoControl-第二版IOCTL_DVD_START_SESSION结果:真BytesReturned:4SessionId:-10sizeofDVD_END_SESSION..IOCTL_DVD_END_SESSION结果:TrueBytesReturned:0两次调用均失败,并给出错误代码第一个版本:122-ERROR_INSUFFICIENT_BUFFER87-ERROR_INVALID_PARAMETER第二个版本似乎成功了,但SessionId的值为-10,这是初始值。(来自MSDN,这个值应该在-1到3之间?)结束会话也成功。[注意:启动会话的第二个版本似乎只对所有其他调用成功,不知道为什么,但这似乎也是我的C代码中的一个问题,因为它的错误处理正在重试。]问题是:result=DeviceIoControl(_hdev,CTL_CODE(0x00000033,0x0400,0,1),IntPtr.Zero,0,(IntPtr)sessionId,Marshal.SizeOf(sessionId),outbytesReturned,IntPtr.Zero);驱动程序需要指向lpOutBuffer中的缓冲区的指针,但您提供的是sessionId本身(为零)。当然这是行不通的。这里你需要做的是:IntPtrbuffer=Marshal.AllocHGlobal(sizeof(int));结果=DeviceIoControl(_hdev,CTL_CODE(0x00000033,0x0400,0,1),IntPtr.Zero,0,buffer,sizeof(int),outbytesReturned,IntPtr.Zero);intsessionId=Marshal.ReadInt32(buffer);元帅.FreeHGlobal(缓冲区);顺便说一句,这同样适用于所有后续DeviceIoControl调用,当您需要提供指向该值的指针时,您再次提供该值。您还需要检查CTL_CODE函数是否构建了有效的io代码。同样,DeviceIoControl需要指向入口和出口结构的缓冲区指针。以上就是C#学习教程:使用IOCTL_DVD_*控制代码从C#调用DeviceIoControl,分享全部内容。如果对大家有用,需要进一步了解C#学习教程,希望大家多多关注。本文收集自网络,不代表立场,如涉及侵权,请点击右边联系管理员删除。如需转载请注明出处:
