Я создавал консольное приложение C++ для получения информации ATA диска, но получал код ошибки 1 в DeviceIoControl, поэтому попробовал его на C#.ATAFeaturesForm.cs
using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApp1
{
public partial class ATAFeaturesForm : Form
{
const uint FILE_READ_ACCESS = 0x80000000;
const uint FILE_WRITE_ACCESS = 0x40000000;
const uint FILE_SHARE_READ = 0x1;
const uint FILE_SHARE_WRITE = 0x2;
const uint OPEN_EXISTING = 3;
const uint IOCTL_ATA_PASS_THROUGH = 0x4D02C;
const ushort ATA_FLAGS_DATA_IN = 0x02;
[StructLayout(LayoutKind.Sequential)]
struct ATA_PASS_THROUGH_EX
{
public ushort Length;
public ushort AtaFlags;
public byte PathId;
public byte TargetId;
public byte Lun;
public byte ReservedAsUchar;
public uint DataTransferLength;
public uint TimeOutValue;
public IntPtr DataBuffer;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] PreviousTaskFile;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)]
public byte[] CurrentTaskFile;
}
[StructLayout(LayoutKind.Sequential)]
struct ATAIdentifyDeviceData
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 512)]
public byte[] Data;
}
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr CreateFile(
string lpFileName,
uint dwDesiredAccess,
uint dwShareMode,
IntPtr lpSecurityAttributes,
uint dwCreationDisposition,
uint dwFlagsAndAttributes,
IntPtr hTemplateFile
);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool DeviceIoControl(
IntPtr hDevice,
uint dwIoControlCode,
ref ATA_PASS_THROUGH_EX lpInBuffer,
uint nInBufferSize,
IntPtr lpOutBuffer,
uint nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped
);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr hObject);
public ATAFeaturesForm()
{
InitializeComponent();
FetchATADetails();
}
private void FetchATADetails()
{
try
{
string drivePath = @"\\.\PhysicalDrive0";
IntPtr hDevice = CreateFile(
drivePath,
FILE_READ_ACCESS | FILE_WRITE_ACCESS,
FILE_SHARE_READ | FILE_SHARE_WRITE,
IntPtr.Zero,
OPEN_EXISTING,
0,
IntPtr.Zero
);
if (hDevice == IntPtr.Zero || hDevice.ToInt32() == -1)
{
int error = Marshal.GetLastWin32Error();
throw new IOException($"Failed to open the device. Error code: {error}");
}
ATA_PASS_THROUGH_EX ataPassThrough = new ATA_PASS_THROUGH_EX
{
Length = (ushort)Marshal.SizeOf(typeof(ATA_PASS_THROUGH_EX)),
AtaFlags = ATA_FLAGS_DATA_IN,
PathId = 0,
TargetId = 0,
Lun = 0,
ReservedAsUchar = 0,
DataTransferLength = 512,
TimeOutValue = 10,
DataBuffer = Marshal.AllocHGlobal(512),
PreviousTaskFile = new byte[8],
CurrentTaskFile = new byte[8]
};
ataPassThrough.CurrentTaskFile[6] = 0xEC; // ATA IDENTIFY command
uint bytesReturned;
IntPtr ataIdentifyDeviceData = Marshal.AllocHGlobal(512);
//Problematic Part
//I think the problem is here, some wrong parameters maybe
if (!DeviceIoControl(
hDevice,
IOCTL_ATA_PASS_THROUGH,
ref ataPassThrough,
(uint)Marshal.SizeOf(ataPassThrough),
ataIdentifyDeviceData,
512,
out bytesReturned,
IntPtr.Zero))
{
int error = Marshal.GetLastWin32Error();
Marshal.FreeHGlobal(ataIdentifyDeviceData);
Marshal.FreeHGlobal(ataPassThrough.DataBuffer);
throw new IOException($"Failed to retrieve ATA information. Error code: {error}");
}
byte[] data = new byte[512];
Marshal.Copy(ataIdentifyDeviceData, data, 0, 512);
DisplayATADetails(data);
Marshal.FreeHGlobal(ataIdentifyDeviceData);
Marshal.FreeHGlobal(ataPassThrough.DataBuffer);
if (!CloseHandle(hDevice))
{
int error = Marshal.GetLastWin32Error();
throw new IOException($"Failed to close the device handle. Error code: {error}");
}
}
catch (Exception ex)
{
MessageBox.Show($"Error retrieving ATA details: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
private void DisplayATADetails(byte[] data)
{
var ataRevision = Encoding.ASCII.GetString(data, 54, 8).Trim();
var transportVersion = Encoding.ASCII.GetString(data, 76, 8).Trim();
var cylinders = BitConverter.ToUInt16(data, 2);
var heads = BitConverter.ToUInt16(data, 6);
var sectors = BitConverter.ToUInt16(data, 12);
var totalSectors = BitConverter.ToUInt32(data, 120);
var bytesPerSector = 512; // Typically 512 bytes
var multipleSectors = BitConverter.ToUInt16(data, 94);
var maxPIO = (data[102] >> 0) & 0xFF;
var maxDMA = (data[63] >> 0) & 0xFF;
var unformattedCapacity = (long)bytesPerSector * totalSectors / (1024 * 1024); // MB
string message = $"ATA Revision: {ataRevision}\r\n" +
$"Transport Version: {transportVersion}\r\n" +
$"Hard Disk Cylinders: {cylinders}\r\n" +
$"Hard Disk Heads: {heads}\r\n" +
$"Hard Disk Sectors: {sectors}\r\n" +
$"Total Sectors: {totalSectors}\r\n" +
$"Bytes Per Sector: {bytesPerSector}\r\n" +
$"Multiple Sectors: {multipleSectors}\r\n" +
$"Maximum PIO Mode: {maxPIO}\r\n" +
$"Maximum DMA Mode: {maxDMA}\r\n" +
$"Unformatted Capacity: {unformattedCapacity} MB";
MessageBox.Show(message, "ATA Details", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
Я получил код ошибки 87, связанный с неверным параметром, я потратил на это около 2 недель, я оставил комментарии над DeviceIoControl. Вот в чем проблема, может кто-нибудь мне помочь!
Кто-нибудь знает, с помощью какого IOCTL я могу получить эти данные или причину ошибки в моем коде?
Я создавал консольное приложение [b]C++[/b] для получения информации ATA диска, но получал код ошибки 1 в DeviceIoControl, поэтому попробовал его на [b]C#[/b].ATAFeaturesForm.cs [code]using System; using System.IO; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms;
[StructLayout(LayoutKind.Sequential)] struct ATA_PASS_THROUGH_EX { public ushort Length; public ushort AtaFlags; public byte PathId; public byte TargetId; public byte Lun; public byte ReservedAsUchar; public uint DataTransferLength; public uint TimeOutValue; public IntPtr DataBuffer; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] PreviousTaskFile; [MarshalAs(UnmanagedType.ByValArray, SizeConst = 8)] public byte[] CurrentTaskFile; }
if (hDevice == IntPtr.Zero || hDevice.ToInt32() == -1) { int error = Marshal.GetLastWin32Error(); throw new IOException($"Failed to open the device. Error code: {error}"); }
//Problematic Part //I think the problem is here, some wrong parameters maybe if (!DeviceIoControl( hDevice, IOCTL_ATA_PASS_THROUGH, ref ataPassThrough, (uint)Marshal.SizeOf(ataPassThrough), ataIdentifyDeviceData, 512, out bytesReturned, IntPtr.Zero)) { int error = Marshal.GetLastWin32Error(); Marshal.FreeHGlobal(ataIdentifyDeviceData); Marshal.FreeHGlobal(ataPassThrough.DataBuffer); throw new IOException($"Failed to retrieve ATA information. Error code: {error}"); }
byte[] data = new byte[512]; Marshal.Copy(ataIdentifyDeviceData, data, 0, 512);
if (!CloseHandle(hDevice)) { int error = Marshal.GetLastWin32Error(); throw new IOException($"Failed to close the device handle. Error code: {error}"); } } catch (Exception ex) { MessageBox.Show($"Error retrieving ATA details: {ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); } }
private void DisplayATADetails(byte[] data) { var ataRevision = Encoding.ASCII.GetString(data, 54, 8).Trim(); var transportVersion = Encoding.ASCII.GetString(data, 76, 8).Trim(); var cylinders = BitConverter.ToUInt16(data, 2); var heads = BitConverter.ToUInt16(data, 6); var sectors = BitConverter.ToUInt16(data, 12); var totalSectors = BitConverter.ToUInt32(data, 120); var bytesPerSector = 512; // Typically 512 bytes var multipleSectors = BitConverter.ToUInt16(data, 94); var maxPIO = (data[102] >> 0) & 0xFF; var maxDMA = (data[63] >> 0) & 0xFF; var unformattedCapacity = (long)bytesPerSector * totalSectors / (1024 * 1024); // MB
MessageBox.Show(message, "ATA Details", MessageBoxButtons.OK, MessageBoxIcon.Information); } } } [/code] Я получил код ошибки 87, связанный с неверным параметром, я потратил на это около 2 недель, я оставил комментарии над DeviceIoControl. Вот в чем проблема, может кто-нибудь мне помочь! Кто-нибудь знает, с помощью какого IOCTL я могу получить эти данные или причину ошибки в моем коде?