首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >期待DeviceIoControl工作样本的评审

期待DeviceIoControl工作样本的评审
EN

Code Review用户
提问于 2013-02-28 11:53:21
回答 1查看 8.3K关注 0票数 6

我把完整的代码放在这篇文章的后面。

我最近回答了一个问题,详细的解释张贴在

顺便回答另一个

我想知道,如果有人认为有任何问题或改进的代码。

代码:

代码语言:javascript
复制
using System.Runtime.InteropServices;
using System.ComponentModel;
using System;

namespace DiskManagement {
    using Microsoft.Win32.SafeHandles;

    using LPSECURITY_ATTRIBUTES=IntPtr;
    using LPOVERLAPPED=IntPtr;
    using LPVOID=IntPtr;
    using HANDLE=IntPtr;

    using LARGE_INTEGER=Int64;
    using DWORD=UInt32;
    using LPCTSTR=String;

    public static partial class IoCtl /* methods */ {
        [DllImport("kernel32.dll", SetLastError=true)]
        static extern SafeFileHandle CreateFile(
            LPCTSTR lpFileName,
            DWORD dwDesiredAccess,
            DWORD dwShareMode,
            LPSECURITY_ATTRIBUTES lpSecurityAttributes,
            DWORD dwCreationDisposition,
            DWORD dwFlagsAndAttributes,
            HANDLE hTemplateFile
            );

        [DllImport("kernel32.dll", SetLastError=true)]
        static extern DWORD DeviceIoControl(
            SafeFileHandle hDevice,
            DWORD dwIoControlCode,
            LPVOID lpInBuffer,
            DWORD nInBufferSize,
            LPVOID lpOutBuffer,
            int nOutBufferSize,
            ref DWORD lpBytesReturned,
            LPOVERLAPPED lpOverlapped
            );

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

        public static void Execute<T>(
            ref T x,
            DWORD dwIoControlCode,
            LPCTSTR lpFileName,
            DWORD dwDesiredAccess=GENERIC_READ,
            DWORD dwShareMode=FILE_SHARE_WRITE|FILE_SHARE_READ,
            LPSECURITY_ATTRIBUTES lpSecurityAttributes=default(LPSECURITY_ATTRIBUTES),
            DWORD dwCreationDisposition=OPEN_EXISTING,
            DWORD dwFlagsAndAttributes=0,
            HANDLE hTemplateFile=default(IntPtr)
            ) {
            using(
                var hDevice=
                    CreateFile(
                        lpFileName,
                        dwDesiredAccess, dwShareMode,
                        lpSecurityAttributes,
                        dwCreationDisposition, dwFlagsAndAttributes,
                        hTemplateFile
                        )
                ) {
                if(null==hDevice||hDevice.IsInvalid)
                    throw new Win32Exception(Marshal.GetLastWin32Error());

                var nOutBufferSize=Marshal.SizeOf(typeof(T));
                var lpOutBuffer=Marshal.AllocHGlobal(nOutBufferSize);
                var lpBytesReturned=default(DWORD);
                var NULL=IntPtr.Zero;

                var result=
                    DeviceIoControl(
                        hDevice, dwIoControlCode,
                        NULL, 0,
                        lpOutBuffer, nOutBufferSize,
                        ref lpBytesReturned, NULL
                        );

                if(0==result)
                    throw new Win32Exception(Marshal.GetLastWin32Error());

                x=(T)Marshal.PtrToStructure(lpOutBuffer, typeof(T));
                Marshal.FreeHGlobal(lpOutBuffer);
            }
        }
    }

    public enum MEDIA_TYPE: int {
        Unknown=0,
        F5_1Pt2_512=1,
        F3_1Pt44_512=2,
        F3_2Pt88_512=3,
        F3_20Pt8_512=4,
        F3_720_512=5,
        F5_360_512=6,
        F5_320_512=7,
        F5_320_1024=8,
        F5_180_512=9,
        F5_160_512=10,
        RemovableMedia=11,
        FixedMedia=12,
        F3_120M_512=13,
        F3_640_512=14,
        F5_640_512=15,
        F5_720_512=16,
        F3_1Pt2_512=17,
        F3_1Pt23_1024=18,
        F5_1Pt23_1024=19,
        F3_128Mb_512=20,
        F3_230Mb_512=21,
        F8_256_128=22,
        F3_200Mb_512=23,
        F3_240M_512=24,
        F3_32M_512=25
    }

    partial class DiskGeometry /* structures */ {
        [StructLayout(LayoutKind.Sequential)]
        struct DISK_GEOMETRY {
            internal LARGE_INTEGER Cylinders;
            internal MEDIA_TYPE MediaType;
            internal DWORD TracksPerCylinder;
            internal DWORD SectorsPerTrack;
            internal DWORD BytesPerSector;
        }

        [StructLayout(LayoutKind.Sequential)]
        struct DISK_GEOMETRY_EX {
            internal DISK_GEOMETRY Geometry;
            internal LARGE_INTEGER DiskSize;

            [MarshalAs(UnmanagedType.ByValArray, SizeConst=1)]
            internal byte[] Data;
        }
    }

    partial class DiskGeometry /* properties and fields */ {
        public MEDIA_TYPE MediaType {
            get {
                return m_Geometry.MediaType;
            }
        }

        public String MediaTypeName {
            get {
                return Enum.GetName(typeof(MEDIA_TYPE), this.MediaType);
            }
        }

        public override long Cylinder {
            get {
                return m_Geometry.Cylinders;
            }
        }

        public override uint Head {
            get {
                return m_Geometry.TracksPerCylinder;
            }
        }

        public override uint Sector {
            get {
                return m_Geometry.SectorsPerTrack;
            }
        }

        public DWORD BytesPerSector {
            get {
                return m_Geometry.BytesPerSector;
            }
        }

        public long DiskSize {
            get {
                return m_DiskSize;
            }
        }

        public long MaximumLinearAddress {
            get {
                return m_MaximumLinearAddress;
            }
        }

        public CubicAddress MaximumCubicAddress {
            get {
                return m_MaximumCubicAddress;
            }
        }

        public DWORD BytesPerCylinder {
            get {
                return m_BytesPerCylinder;
            }
        }

        CubicAddress m_MaximumCubicAddress;
        long m_MaximumLinearAddress;
        DWORD m_BytesPerCylinder;
        LARGE_INTEGER m_DiskSize;
        DISK_GEOMETRY m_Geometry;
    }
}

namespace DiskManagement {
    using Microsoft.Win32.SafeHandles;

    using LPSECURITY_ATTRIBUTES=IntPtr;
    using LPOVERLAPPED=IntPtr;
    using LPVOID=IntPtr;
    using HANDLE=IntPtr;

    using LARGE_INTEGER=Int64;
    using DWORD=UInt32;
    using LPCTSTR=String;

    partial class IoCtl /* constants */ {
        public const DWORD
            DISK_BASE=0x00000007,
            METHOD_BUFFERED=0,
            FILE_ANY_ACCESS=0;

        public const DWORD
            GENERIC_READ=0x80000000,
            FILE_SHARE_WRITE=0x2,
            FILE_SHARE_READ=0x1,
            OPEN_EXISTING=0x3;

        public static readonly DWORD DISK_GET_DRIVE_GEOMETRY_EX=
            IoCtl.CTL_CODE(DISK_BASE, 0x0028, METHOD_BUFFERED, FILE_ANY_ACCESS);

        public static readonly DWORD DISK_GET_DRIVE_GEOMETRY=
            IoCtl.CTL_CODE(DISK_BASE, 0, METHOD_BUFFERED, FILE_ANY_ACCESS);
    }

    public partial class CubicAddress {
        public static CubicAddress Transform(long linearAddress, CubicAddress geometry) {
            var cubicAddress=new CubicAddress();
            var sectorsPerCylinder=geometry.Sector*geometry.Head;
            long remainder;
            cubicAddress.Cylinder=Math.DivRem(linearAddress, sectorsPerCylinder, out remainder);
            cubicAddress.Head=(uint)Math.DivRem(remainder, geometry.Sector, out remainder);
            cubicAddress.Sector=1+(uint)remainder;
            return cubicAddress;
        }

        public virtual long Cylinder {
            get;
            set;
        }

        public virtual uint Head {
            get;
            set;
        }

        public virtual uint Sector {
            get;
            set;
        }
    }

    public partial class DiskGeometry: CubicAddress {
        internal static void ThrowIfDiskSizeOutOfIntegrity(long remainder) {
            if(0!=remainder) {
                var message="DiskSize is not an integral multiple of a sector size";
                throw new ArithmeticException(message);
            }
        }

        public static DiskGeometry FromDevice(String deviceName) {
            return new DiskGeometry(deviceName);
        }

        DiskGeometry(String deviceName) {
            var x=new DISK_GEOMETRY_EX();
            IoCtl.Execute(ref x, IoCtl.DISK_GET_DRIVE_GEOMETRY_EX, deviceName);
            m_DiskSize=x.DiskSize;
            m_Geometry=x.Geometry;

            long remainder;
            m_MaximumLinearAddress=Math.DivRem(DiskSize, BytesPerSector, out remainder)-1;
            ThrowIfDiskSizeOutOfIntegrity(remainder);

            m_BytesPerCylinder=BytesPerSector*Sector*Head;
            m_MaximumCubicAddress=DiskGeometry.Transform(m_MaximumLinearAddress, this);
        }
    }
}
EN

回答 1

Code Review用户

回答已采纳

发布于 2013-03-06 09:43:54

正如评论中的大多数人所建议的那样,它缺少了一些在所有C#开发人员中普遍接受的约定。这将主要着眼于风格点,因为在实现方面并没有什么问题。

通用备注

在关闭代码块({)时,大多数与括号/空格相关的点都由Visual强制执行。

  • 类型应该在PascalCase
  • 公共成员名称应在PascalCase
  • 匈牙利表示法(dwDesiredAccess)是劝阻性的,除了在WebForms和WinForms中命名控件时。和camelCase一起去。
  • 你的间距有点过了,所有的大括号都应该放在单独的线上。方法一般应该如下所示: public void方法(Type){ // Implementation }
  • 通常,每个文件应该有一个(部分)类,这可能不适用,但需要提及。
  • 在大多数符号之间放置一个空格是鼓励的。
  • 按以下方式订购您类型的成员:
    1. 变量(pref. )const/static )
    2. 构造函数/属性(任意一种)
    3. 方法

  • 通常,ALL_CAPS-style命名在C#中不使用,有时用于常量,但一般不使用。

Line-by-line

通常,注释是在类定义上面的行中进行的,如果您真的想要将文件的不同部分分开,您可能会更好地将它放入一个IoCtrl.Methods.cs文件或其他什么地方。我通常远离partial,除非文件长得离谱,不能被考虑在内。

代码语言:javascript
复制
// methods
public static partial class IoCtl {

虽然我并不特别喜欢它,但是您在顶部的“定义”是有意义的,因为它们的应用程序和kernal32.dll程序集的文献资料

代码语言:javascript
复制
using LPSECURITY_ATTRIBUTES = IntPtr;
using LPOVERLAPPED = IntPtr;
using LPVOID = IntPtr;
using HANDLE = IntPtr;

using LARGE_INTEGER = Int64;
using DWORD = UInt32;
using LPCTSTR = String;

用这样的结构构造你的牙套:

代码语言:javascript
复制
public static void Execute<T>(
    ref T x,
    DWORD dwIoControlCode,
    LPCTSTR lpFileName,
    DWORD dwDesiredAccess = GENERIC_READ,
    DWORD dwShareMode = FILE_SHARE_WRITE | FILE_SHARE_READ,
    LPSECURITY_ATTRIBUTES lpSecurityAttributes = default(LPSECURITY_ATTRIBUTES),
    DWORD dwCreationDisposition = OPEN_EXISTING,
    DWORD dwFlagsAndAttributes = 0,
    HANDLE hTemplateFile = default(IntPtr)) 
{

调用函数时尽量不要跨越太多行。

代码语言:javascript
复制
    using (var hDevice = CreateFile(lpFileName, dwDesiredAccess, dwShareMode,
        lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes,
        hTemplateFile)) 
    {

        if (null == hDevice || hDevice.IsInvalid)
            throw new Win32Exception(Marshal.GetLastWin32Error());

        var nOutBufferSize = Marshal.SizeOf(typeof(T));
        var lpOutBuffer = Marshal.AllocHGlobal(nOutBufferSize);
        var lpBytesReturned = default(DWORD);

使用IntPtr.Zero而不是别名(NULL)可以更容易地理解以后的值。

代码语言:javascript
复制
        var result = DeviceIoControl(hDevice, dwIoControlCode, IntPtr.Zero, 0,
        lpOutBuffer, nOutBufferSize, ref lpBytesReturned, IntPtr.Zero);

总是喜欢var == <number>而不是<number> == var,这种条件被亲切地称为“尤达条件”。

代码语言:javascript
复制
        if (result == 0)
            throw new Win32Exception(Marshal.GetLastWin32Error());

        x = (T)Marshal.PtrToStructure(lpOutBuffer, typeof(T));
        Marshal.FreeHGlobal(lpOutBuffer);
    }
}

对所有类型使用pascal大小写。

代码语言:javascript
复制
public enum MediaType : int
{
    Unknown = 0,
    F5_1Pt2_512 = 1,
    F3_1Pt44_512 = 2,
    F3_2Pt88_512 = 3,
    F3_20Pt8_512 = 4,
    F3_720_512 = 5,
    F5_360_512 = 6,
    F5_320_512 = 7,
    F5_320_1024 = 8,
    F5_180_512 = 9,
    F5_160_512 = 10,
    RemovableMedia = 11,
    FixedMedia = 12,
    F3_120M_512 = 13,
    F3_640_512 = 14,
    F5_640_512 = 15,
    F5_720_512 = 16,
    F3_1Pt2_512 = 17,
    F3_1Pt23_1024 = 18,
    F5_1Pt23_1024 = 19,
    F3_128Mb_512 = 20,
    F3_230Mb_512 = 21,
    F8_256_128 = 22,
    F3_200Mb_512 = 23,
    F3_240M_512 = 24,
    F3_32M_512 = 25
}

始终指定访问修饰符。

代码语言:javascript
复制
// Structures
internal partial class DiskGeometry
{
    [StructLayout(LayoutKind.Sequential)]
    internal struct DISK_GEOMETRY 
    {
        internal LARGE_INTEGER Cylinders;
        internal MEDIA_TYPE MediaType;
        internal DWORD TracksPerCylinder;
        internal DWORD SectorsPerTrack;
        internal DWORD BytesPerSector;
    }

    [StructLayout(LayoutKind.Sequential)]
    internal struct DISK_GEOMETRY_EX 
    {
        internal DISK_GEOMETRY Geometry;
        internal LARGE_INTEGER DiskSize;

        [MarshalAs(UnmanagedType.ByValArray, SizeConst=1)]
        internal byte[] Data;
    }
}

这方面没有真正的标准,但我更喜欢将简单的getter保持在一行上。还将变量保存在文件的顶部,并使用pascalCase

代码语言:javascript
复制
// properties and fields
partial class DiskGeometry 
{
    private CubicAddress maximumCubicAddress;
    private long maximumLinearAddress;
    private DWORD bytesPerCylinder;
    private LARGE_INTEGER diskSize;
    private DISK_GEOMETRY geometry;

    public MEDIA_TYPE MediaType
    {
        get { return geometry.MediaType; }
    }

    public String MediaTypeName
    {
        get { return Enum.GetName(typeof(MEDIA_TYPE), this.MediaType); }
    }

    public override long Cylinder
    {
        get { return geometry.Cylinders; }
    }

    public override uint Head
    {
        get { return geometry.TracksPerCylinder; }
    }

    public override uint Sector
    {
        get { return geometry.SectorsPerTrack; }
    }

    public DWORD BytesPerSector
    {
        get { return geometry.BytesPerSector; }
    }

    public long DiskSize
    {
        get { return diskSize; }
    }

    public long MaximumLinearAddress
    {
        get { return maximumLinearAddress; }
    }

    public CubicAddress MaximumCubicAddress
    {
        get { return maximumCubicAddress; }
    }

    public DWORD BytesPerCylinder
    {
        get { return bytesPerCylinder; }
    }
}

不要连接变量声明,一行,一个变量。

代码语言:javascript
复制
// constants
partial class IoCtl
{
    public const DWORD DISK_BASE = 0x00000007;
    public const DWORD METHOD_BUFFERED = 0;
    public const DWORD FILE_ANY_ACCESS = 0;

    public const DWORD GENERIC_READ = 0x80000000;
    public const DWORD FILE_SHARE_WRITE = 0x2;
    public const DWORD FILE_SHARE_READ = 0x1;
    public const DWORD OPEN_EXISTING = 0x3;

    public static readonly DWORD DISK_GET_DRIVE_GEOMETRY_EX =
        IoCtl.CTL_CODE(DISK_BASE, 0x0028, METHOD_BUFFERED, FILE_ANY_ACCESS);

    public static readonly DWORD DISK_GET_DRIVE_GEOMETRY =
        IoCtl.CTL_CODE(DISK_BASE, 0, METHOD_BUFFERED, FILE_ANY_ACCESS);
}

将属性放在方法之前(可选),使用单行表示自动属性.

代码语言:javascript
复制
public partial class CubicAddress
{
    public virtual long Cylinder { get; set; }
    public virtual uint Head { get; set; }
    public virtual uint Sector { get; set; }

    public static CubicAddress Transform(long linearAddress, CubicAddress geometry) 
    {
        var cubicAddress = new CubicAddress();
        var sectorsPerCylinder = geometry.Sector * geometry.Head;
        long remainder;
        cubicAddress.Cylinder = Math.DivRem(linearAddress, sectorsPerCylinder, out remainder);
        cubicAddress.Head = (uint)Math.DivRem(remainder, geometry.Sector, out remainder);
        cubicAddress.Sector = 1 + (uint)remainder;
        return cubicAddress;
    }
}

构造函数(S)之前的方法。

代码语言:javascript
复制
public partial class DiskGeometry: CubicAddress 
{
    DiskGeometry(String deviceName)
    {
        var x = new DISK_GEOMETRY_EX();
        IoCtl.Execute(ref x, IoCtl.DISK_GET_DRIVE_GEOMETRY_EX, deviceName);
        diskSize = x.DiskSize;
        geometry = x.Geometry;

        long remainder;
        m_MaximumLinearAddress = Math.DivRem(DiskSize, BytesPerSector, out remainder) - 1;
        ThrowIfDiskSizeOutOfIntegrity(remainder);

        mytesPerCylinder = BytesPerSector * Sector * Head;
        maximumCubicAddress = DiskGeometry.Transform(maximumLinearAddress, this);
    }

    internal static void ThrowIfDiskSizeOutOfIntegrity(long remainder) 
    {
        if (remainder != 0)
        {
            var message = "DiskSize is not an integral multiple of a sector size";
            throw new ArithmeticException(message);
        }
    }

    public static DiskGeometry FromDevice(String deviceName)
    {
        return new DiskGeometry(deviceName);
    }
}

嘿嘿。大的。

我没有更改匈牙利的符号,因为我肯定我会错过一些,而且不一致也没有用:)我也没有更改ALL_CAPS变量,因为我找不到定义了一些变量的位置。

票数 4
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/23264

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档