我把完整的代码放在这篇文章的后面。
我最近回答了一个问题,详细的解释张贴在
顺便回答另一个
我想知道,如果有人认为有任何问题或改进的代码。
代码:
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);
}
}
}发布于 2013-03-06 09:43:54
正如评论中的大多数人所建议的那样,它缺少了一些在所有C#开发人员中普遍接受的约定。这将主要着眼于风格点,因为在实现方面并没有什么问题。
在关闭代码块({)时,大多数与括号/空格相关的点都由Visual强制执行。
PascalCase中PascalCase中dwDesiredAccess)是劝阻性的,除了在WebForms和WinForms中命名控件时。和camelCase一起去。ALL_CAPS-style命名在C#中不使用,有时用于常量,但一般不使用。通常,注释是在类定义上面的行中进行的,如果您真的想要将文件的不同部分分开,您可能会更好地将它放入一个IoCtrl.Methods.cs文件或其他什么地方。我通常远离partial,除非文件长得离谱,不能被考虑在内。
// methods
public static partial class IoCtl {虽然我并不特别喜欢它,但是您在顶部的“定义”是有意义的,因为它们的应用程序和kernal32.dll程序集的文献资料。
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 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);使用IntPtr.Zero而不是别名(NULL)可以更容易地理解以后的值。
var result = DeviceIoControl(hDevice, dwIoControlCode, IntPtr.Zero, 0,
lpOutBuffer, nOutBufferSize, ref lpBytesReturned, IntPtr.Zero);总是喜欢var == <number>而不是<number> == var,这种条件被亲切地称为“尤达条件”。
if (result == 0)
throw new Win32Exception(Marshal.GetLastWin32Error());
x = (T)Marshal.PtrToStructure(lpOutBuffer, typeof(T));
Marshal.FreeHGlobal(lpOutBuffer);
}
}对所有类型使用pascal大小写。
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
}始终指定访问修饰符。
// 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;
// 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; }
}
}不要连接变量声明,一行,一个变量。
// 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);
}将属性放在方法之前(可选),使用单行表示自动属性.
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)之前的方法。
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变量,因为我找不到定义了一些变量的位置。
https://codereview.stackexchange.com/questions/23264
复制相似问题