本文介绍了调用从C#的DeviceIoControl与IOCTL_DVD_ *控制代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从C#调用DeviceIoControl的为 IOCTL_DVD _ * 控制代码。看了很多资料,并尝试了一些例子我还没有取得很大进展。

I am trying to call DeviceIoControl from C# for IOCTL_DVD_* control codes. Having read a lot of information and trying a number of examples I have not made much progress.

我所想最终做的就是一个关于当前的DVD驱动器中的介质DVD_LAYER_DESCRIPTOR 结构。我能的CreateFile 成功调用DVD设备上,但是当我尝试调用的DeviceIoControl 通过控制码 IOCTL_DVD_START_SESSION 它返回一个成功代码,但我似乎并没有得到的SessionID值回成功,总是返回0(以及任何尝试然后我做了尝试获得层描述, IOCTL_DVD_READ_STRUCTURE 失败,即函数失败或返回成功,但给出了一个空白的输出结构。)

What I am trying to eventually do is get a DVD_LAYER_DESCRIPTOR structure about the media currently in the DVD drive. I can call CreateFile successfully on the DVD device, but when I try to call DeviceIoControl with the control code IOCTL_DVD_START_SESSION it returns a success code but I don't seem to get the sessionId value back successfully, always returns 0. (And any attempt I have then made to try getting the layer description with IOCTL_DVD_READ_STRUCTURE fails, i.e. function fails or returns success but gives a blank output structure.)

发现了一些C代码之后让类似的电话,我能够编译此代码(使用Visual C ++ 2008年速成版),并成功能够启动一个会话,阅读 DVD_LAYER_DESCRIPTOR ,并关闭会话,而不问题,所以我知道这个工作的。

After finding some C code which makes similar calls I was able to compile this code (using Visual C++ 2008 Express Edition) and it successfully is able to start a session, read the DVD_LAYER_DESCRIPTOR, and close the session without problem so I know this works.

C#的问题似乎涉及到外部函数是如何定义以及参数编组。以及如何传递和返回的各种结构的定义。

The C# issues appear to relate to how the external function is defined and the parameters marshalled. And how the various structures that are passed and returned are defined.

我已经看过www.pinvoke.net他们是如何定义它,并使用了一些给出的示例代码和定义,但仍然有正如上文所述相同的问题。问题的部分似乎是每个IOCTL控制代码参数都不同,主要是结构,但 IOCTL_DVD_START_SESSION 的产值是32位整数。如何在C#中的extern方法被定义为处理这些不同的情况?还有各种结构,用正确的大小成员类型定义,显示他们是C和C#代码之间不同的大小,但个别成员相同的大小???

I have looked at www.pinvoke.net for how they define it, and have used some of the example code and definitions given but still have the same issues as outlined above. Part of the problem seems to be that for each IOCTL control code the parameters are different, mostly structs, but for IOCTL_DVD_START_SESSION the output value is a 32 bit integer. How can an extern method in C# be defined to handle these different cases? Also various structs, defined with the right sized member types, show they are different sizes between the C and C# code, but the individual members are the same sizes???

如果我使用一个程序像 DeviceIOView 并观看 IOCTL_DVD_START_SESSION 的C由C代码和C#代码双方的呼吁版本返回3的SessionID和DeviceIOView显示了运行的C#代码当被发送的数据后面也是3所以似乎有某种返回的参数编组问题,因为我们只是在C#代码中看到的0

If I use a program like DeviceIOView and watch the calls made by both the C code and C# code for IOCTL_DVD_START_SESSION the C version returns a sessionid of 3 and DeviceIOView shows the data being sent back when running the C# code is also 3 so there seems to be some sort of Marshalling issue of the returned parameters as we only see 0 in the C# code

有没有人对如何从C#调用DeviceIoControl来访问DVD信息任何意见或工作示例代码? (说明如何将结构和功能应该被定义和使用。)有用的网站或其他建议的任何链接,将不胜感激。

Does anyone have any ideas or working example code on how to call DeviceIoControl from C# to access DVD information? (Showing how the structures and function should be defined and used.) Any links to useful websites or other advice would be much appreciated.

(在Visual C#2008 Express的正在开发版,.NET 3.5。)

(Being developed in Visual C# 2008 Express Edition, .NET 3.5.)

约翰ñ

示例代码(新增)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Win32.SafeHandles;
using System.Runtime.InteropServices;
using System.IO;
using System.Threading;

namespace Example
{
    class Program
    {
        static void Main(string[] args)
        {
            string driveLetter = args[0].Substring(0, 1).ToUpper() + ":";

            SafeFileHandle _hdev = CreateFileR(driveLetter);
            if (_hdev.IsClosed | _hdev.IsInvalid)
            {
                Console.WriteLine("Error opening device");
                return;
            }

            Console.WriteLine("DeviceIoControl - Version One");

            Console.WriteLine("IOCTL_DVD_START_SESSION");

            bool result = false;
            int bytesReturned = 0;
            int sessionId = 0;

            result = DeviceIoControl(_hdev, CTL_CODE(0x00000033, 0x0400, 0, 1), IntPtr.Zero, 0, (IntPtr)sessionId, Marshal.SizeOf(sessionId), out bytesReturned, IntPtr.Zero);

            if (result == false)
            {
                int error_code = Marshal.GetLastWin32Error();
                Console.WriteLine("Result: " + result);
                Console.WriteLine("error code: " + 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("Skipping...");

            Console.WriteLine("IOCTL_DVD_END_SESSION");
            bytesReturned = 0;

            result = DeviceIoControl(_hdev, CTL_CODE(0x00000033, 0x0403, 0, 1), new IntPtr(sessionId), Marshal.SizeOf(sessionId), IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero);

            if (result == false)
            {
                int error_code = Marshal.GetLastWin32Error();
                Console.WriteLine("error code: " + error_code);
                Console.WriteLine("Result: " + result);
            }
            else
            {
                Console.WriteLine("Result: " + result);
                Console.WriteLine("BytesReturned: " + bytesReturned);
            }

            Console.WriteLine("\nDeviceIoControl - Version Two");

            Console.WriteLine("IOCTL_DVD_START_SESSION");

            result = false;
            uint bytesReturned2 = 0;
            sessionId = -10;

            NativeOverlapped nativeOverlapped = new NativeOverlapped();

            result = DeviceIoControlAlt(_hdev, EIOControlCode.DvdStartSession, 0, 0, sessionId, (uint)Marshal.SizeOf(sessionId), ref bytesReturned2, ref nativeOverlapped);

            if (result == false)
            {
                int error_code = Marshal.GetLastWin32Error();
                Console.WriteLine("Result: " + result);
                Console.WriteLine("error code: " + error_code);
            }
            else
            {
                Console.WriteLine("Result: " + result);
                Console.WriteLine("BytesReturned: " + bytesReturned2);
                Console.WriteLine("SessionId: " + sessionId);
                Console.WriteLine("sizeof(SessionId): " + Marshal.SizeOf(sessionId));
            }

            Console.WriteLine("IOCTL_DVD_READ_STRUCTURE");
            Console.WriteLine("Skipping...");

            Console.WriteLine("IOCTL_DVD_END_SESSION");
            bytesReturned2 = 0;

            result = DeviceIoControlAlt(_hdev, EIOControlCode.DvdEndSession, sessionId, (uint)Marshal.SizeOf(sessionId), 0, 0, ref bytesReturned2, ref nativeOverlapped);

            if (result == false)
            {
                int error_code = Marshal.GetLastWin32Error();
                Console.WriteLine("Result: " + result);
                Console.WriteLine("error code: " + error_code);
            }
            else
            {
                Console.WriteLine("Result: " + result);
                Console.WriteLine("BytesReturned: " + bytesReturned2);
            }

            _hdev.Close();
        }

        public static int CTL_CODE(int DeviceType, int Function, int Method, int Access)
        {
            return (((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2)
              | (Method));
        } 

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CreateFile(string lpFileName, uint dwDesiredAccess, uint dwShareMode, IntPtr lpSecurityAttributes, uint dwCreationDisposition, uint dwFlagsAndAttributes, IntPtr hTemplateFile);
        public static SafeFileHandle CreateFileR(string device)
        {
            string str = device.EndsWith(@"\") ? device.Substring(0, device.Length - 1) : device;
            return new SafeFileHandle(CreateFile(@"\\.\" + str, WinntConst.GENERIC_READ, WinntConst.FILE_SHARE_READ, IntPtr.Zero, WinntConst.OPEN_EXISTING, WinntConst.FILE_ATTRIBUTE_NORMAL, IntPtr.Zero), true);
        }

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        public static extern bool DeviceIoControl([In] SafeFileHandle hDevice,
            [In] int dwIoControlCode, [In] IntPtr lpInBuffer,
            [In] int nInBufferSize, [Out] IntPtr lpOutBuffer,
            [In] int nOutBufferSize, out int lpBytesReturned,
            [In] IntPtr lpOverlapped);

        internal class WinntConst
        {
            // Fields
            internal static uint FILE_ATTRIBUTE_NORMAL = 0x80;
            internal static uint FILE_SHARE_READ = 1;
            internal static uint GENERIC_READ = 0x80000000;
            internal static uint OPEN_EXISTING = 3;
        }

        // Other code for DeviceIoControl from pinvoke.net
        [Flags]
        public enum EIOControlCode : uint
        {
            // DVD
            DvdReadStructure = (EFileDevice.Dvd << 16) | (0x0450 << 2) | EMethod.Buffered | (FileAccess.Read << 14),
            DvdStartSession = (EFileDevice.Dvd << 16) | (0x0400 << 2) | EMethod.Buffered | (FileAccess.Read << 14),
            DvdEndSession = (EFileDevice.Dvd << 16) | (0x0403 << 2) | EMethod.Buffered | (FileAccess.Read << 14)
        };

        [Flags]
        public enum EFileDevice : uint
        {
            Dvd = 0x00000033,
        }

        [Flags]
        public enum EMethod : uint
        {
            Buffered = 0,
            InDirect = 1,
            OutDirect = 2,
            Neither = 3
        }

        [DllImport("Kernel32.dll", EntryPoint="DeviceIoControl", SetLastError = true, CharSet = CharSet.Auto)]
        public static extern bool DeviceIoControlAlt(
            Microsoft.Win32.SafeHandles.SafeFileHandle hDevice,
            EIOControlCode IoControlCode,
            [MarshalAs(UnmanagedType.AsAny)][In] object InBuffer,
            uint nInBufferSize,
            [MarshalAs(UnmanagedType.AsAny)][Out] object OutBuffer,
            uint nOutBufferSize,
            ref uint pBytesReturned,
            [In] ref System.Threading.NativeOverlapped Overlapped
        );
    }
}

要运行此代码,你需要指定驱动器号命令行上的DVD驱动器。

To run this code you need to specify the drive letter of a DVD drive on the command line.

输出

DeviceIoControl - Version One
IOCTL_DVD_START_SESSION
Result: False
error code: 122
IOCTL_DVD_READ_STRUCTURE
Skipping...
IOCTL_DVD_END_SESSION
error code: 87
Result: False

DeviceIoControl - Version Two
IOCTL_DVD_START_SESSION
Result: True
BytesReturned: 4
SessionId: -10
sizeof(SessionId): 4
IOCTL_DVD_READ_STRUCTURE
Skipping...
IOCTL_DVD_END_SESSION
Result: True
BytesReturned: 0 

第一个版本在给定的错误代码都调用失败:

The first version fails on both calls with the given error codes:

122 - ERROR_INSUFFICIENT_BUFFER

87 - ERROR_INVALID_PARAMETER

第二个版本似乎成功,但SESSIONID的值是-10,则初始化值。 (?从MSDN此值应为-1和3之间)结束会议还成功

The second version seems to succeed but the value of SessionId is -10, the initialised value. (From MSDN this value should be between -1 and 3?) The end session also succeeds.

[注:第二个版本开始会议只似乎每隔成功调用,不知道为什么,但是这也似乎是在C代码的问题我有,因为它是错误处理是重试。 ]

[ Note: the second version start session only seems to succeed on every other invocation, not sure why but this also appears to be an issue in the C code I have as it's error handling is to retry again. ]

推荐答案

问题就出在这里:

result = DeviceIoControl(_hdev, CTL_CODE(0x00000033, 0x0400, 0, 1),
   IntPtr.Zero, 0, (IntPtr)sessionId, Marshal.SizeOf(sessionId),
   out bytesReturned, IntPtr.Zero);



驱动程序预计指针在lpOutBuffer缓冲区,但你反而提供的sessionId本身(这是零)。当然这是不行的。

Driver expects pointer to buffer in lpOutBuffer, but you instead provide sessionId itself (which is zero). Of course this will not work.

在这里,您需要做什么:

Here what you need to do:

IntPtr buffer = Marshal.AllocHGlobal(sizeof(int));
result = DeviceIoControl(_hdev, CTL_CODE(0x00000033, 0x0400, 0, 1),
    IntPtr.Zero, 0, buffer, sizeof(int), out bytesReturned, IntPtr.Zero);
int sessionId = Marshal.ReadInt32(buffer);
Marshal.FreeHGlobal(buffer);



BTW,同样适用于所有以下DeviceIoControl的调用,您再次提供价值,当你需要提供指针价值。而且你还需要检查你的CTL_CODE功能构建有效的IO代码。

BTW, the same applies to all following DeviceIoControl calls, you again provide value, when you need provide pointer to value. And you also need to check if your CTL_CODE function builds valid io code.

再次DeviceIoControl的希望指向缓冲区和移出结构。

Again, DeviceIoControl expects pointers to buffers for in and out structures.

这篇关于调用从C#的DeviceIoControl与IOCTL_DVD_ *控制代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-30 05:22