我的任務是實施一個可靠的解決方案來檢索硬盤的序列號。不幸的是the WMI method根本不可靠。所以我正在尋找另一個解決方案。如何通過C#.net中的DeviceIoControl使用IOCTL_SCSI_MINIPORT?
我發現這個小piece的software,這正是我想要在C#.net中實現的。幸運的是,源代碼也是available。
基本上我想從C#中的diskid32實現函數ReadIdeDriveAsScsiDriveInNT
。
如何與設備進行通信:
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern bool DeviceIoControl(
SafeFileHandle device,
int inputOutputControlCode,
[In] ref sbyte[] inputBuffer,
int inputBufferSize,
[In] [Out] ref sbyte[] outputBuffer,
int outputBufferSize,
ref uint bytesCount,
int overlapped);
public static string GetSerialNumberUsingMiniportDriver(int deviceNumber)
{
using (var device = OpenScsi(2))
{
var bytesReturned = default(uint);
var sio = new ScsiRequestBlockInputOutputControl();
var sop = new SendCommandOutParameters();
var sip = new SendCommandInParameters();
var buffer = new byte[Marshal.SizeOf(sio) + Marshal.SizeOf(sop) + IdentifyBufferSize];
sio.HeaderLength = Marshal.SizeOf(sio);
sio.Timeout = 10000;
sio.Length = Marshal.SizeOf(sop) + IdentifyBufferSize;
sio.ControlCode = InputOutputControlSCSIMiniportIdentify;
sio.Signature = Encoding.ASCII.GetBytes("SCSIDISK".ToCharArray());
var ptr = Marshal.AllocHGlobal(Marshal.SizeOf(sio));
Marshal.StructureToPtr(sio, ptr, true);
Marshal.Copy(ptr, buffer, 0, Marshal.SizeOf(sio));
sip.DriveRegister.CommandRegister = IDEATAIdentify;
sip.DriveNumber = 0;
ptr = Marshal.AllocHGlobal(Marshal.SizeOf(sip));
Marshal.StructureToPtr(sip, ptr, true);
Marshal.Copy(ptr, buffer, Marshal.SizeOf(sio), Marshal.SizeOf(sip));
var signedBuffer = new sbyte[buffer.Length];
Buffer.BlockCopy(buffer, 0, signedBuffer, 0, buffer.Length);
if (
!DeviceIoControl(
device,
InputOutputControlSCSIMiniport,
ref signedBuffer,
Marshal.SizeOf(sio) + Marshal.SizeOf(sip) - 1,
ref signedBuffer,
Marshal.SizeOf(sio) + Marshal.SizeOf(sop) + IdentifyBufferSize,
ref bytesReturned,
0))
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
var result = new StringBuilder();
result.Append(buffer);
return result.ToString();
}
}
我如何創建句柄:
[DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Auto)]
private static extern SafeFileHandle CreateFile(
string fileName,
int desiredAccess,
FileShare shareMode,
IntPtr securityAttributes,
FileMode creationDisposition,
FileAttributes flagsAndAttributes,
IntPtr templateFile);
private static SafeFileHandle OpenScsi(int scsiNumber)
{
var device = CreateFile(string.Format(@"\\.\Scsi{0}:", scsiNumber), 0, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, 0, IntPtr.Zero);
if (device.IsInvalid)
{
throw new Win32Exception(Marshal.GetLastWin32Error());
}
return device;
}
的signedBuffer
包含完全相同的字節作爲diskid32例如緩衝區! Diskid32返回那個句柄\\.\Scsi2:
和DriveNumber = 0
的結果,所以我使用相同的參數。
創建手柄時存在差異。我也試過在diskid32中做了什麼。沒有任何成功。
當我在C#中調用DeviceIoControl
時,我總是會得到一個Win32Exception
,這就是Access denied
。有人有個想法嗎?
您也可以找到我的圖書館幫助。 http://scsi.codeplex.com/ – Mehrdad
看起來不錯@Mehrdad。我會看看。謝謝! :-) – Robin
不客氣! – Mehrdad