Ошибка при получении информации ATA диска на C#C#

Место общения программистов C#
Ответить
Anonymous
 Ошибка при получении информации ATA диска на C#

Сообщение Anonymous »

Я создавал консольное приложение 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 я могу получить эти данные или причину ошибки в моем коде?

Подробнее здесь: https://stackoverflow.com/questions/787 ... in-c-sharp
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»