Проекты

DeviceIoControl Plugin

While analyzing my old C++ projects, I have found source code for project Network Administrator. One of the goals of this application was to transfer S.M.A.R.T. data to client from many other server machines through WinSock. Original author of the wrapper is Andrew I. Reshin, who has written it at 2001 with the source code in C++. At that time API to receive SMART data was undocumented at MSDN and need to be called with message:

#define DFP_RECEIVE_DRIVE_DATA	0x0007c088

For sporting interest I manage to port original C++ code to .NET without unsafe code, because it's not very interesting. Resulting source code is available at GitHub.

DeviceIoControl UI

User interface is available at Tools→WinAPI→Device Info. On launch plugin will scan devices using WinAPI function GetLogicalDriveStrings. Automate callbacks on adding or removing devices not implemented, so it can be done manually with Refresh button. After device selected next information will be displayed:

  • General
    • Power
    • Capabilities
    • Channel
  • Geometry
    • Media type
    • Capacity
    • Cylinders
    • Tracks per cylinder
    • Sectors per track
    • Bytes per sector
  • SMART
    • Type
    • Serial Number
    • Firmware Version
    • Model Number
    • Capabilities
    • Total Addressable sectors
    • Cylinders
    • Number of heads
    • Current number of cylinders
    • Current number of heads
    • Current sectors per track
    • Current sector capacity
y

SystemFirmware UI

User interface is available at Tools → WinAPI → SMBIOS. By default will show motherboard information where application is started. Due to the fact that the function GetSystemFirmwareTable returns addess to read only memory array, I've implemented feature to save and load firmare data from file storage. That то я добавил возможность сохранять и загружать массив на файловую смстему, which makes it possible to transfer motherboard data from other computers.

Function EnumSystemFirmwareTables can return not only SMBIOS structures but also ACPI, FIRM and RSMB. But right now only SMBIOS structures supported. However, the source code of the application is available on GitHub, so if you know how to do this, then I will be glad for help.

DeviceInfo internals

Most interesting part of DeviceInfo assembly is calling method DeviceIoControl from kernel32.dll. For invoking control codes (IOCTRL) I was interesting universal method, witch will usable for all wrapping features. The method would be much simpler if it were not for the codes for checking the presence of code in a certain version of the OS. For this difference I've made wrapper with HRESULT as a return value. For other occasions it is enough to throw Win32ErrorException, if HRESULT returns 0.

[DllImport("kernel32.dll", EntryPoint = "DeviceIoControl", SetLastError = true)]
private static extern Boolean DeviceIoControl(
	IntPtr hDevice,
	UInt32 dwIoControlCode,
	IntPtr lpInBuffer,
	UInt32 nInBufferSize,
	IntPtr lpOutBuffer,
	UInt32 nOutBufferSize,
	ref UInt32 lpBytesReturned,
	[In] ref NativeOverlapped lpOverlapped);

public static Boolean DeviceIoControl(
	IntPtr hDevice,
	UInt32 dwIoControlCode,
	Object inParams,
	out UInt32 lpBytesReturned,
	out T outBuffer) where T : struct
{
	Int32 nInBufferSize = 0;
	IntPtr lpInBuffer = IntPtr.Zero;
	IntPtr lpOutBuffer = IntPtr.Zero;

	try
	{
		if(inParams != null)
		{
			nInBufferSize = Marshal.SizeOf(inParams);
			lpInBuffer = Marshal.AllocHGlobal(nInBufferSize);
			Marshal.StructureToPtr(inParams, lpInBuffer, true);
		}

		outBuffer = new T();
		UInt32 nOutBufferSize = Marshal.SizeOf(typeof(T));

		lpOutBuffer = Marshal.AllocHGlobal(nOutBufferSize);
		Marshal.StructureToPtr(outBuffer, lpOutBuffer, true);

		lpBytesReturned = 0;
		NativeOverlapped lpOverlapped = new NativeOverlapped();

		Boolean result = Methods.DeviceIoControl(
			hDevice,
			dwIoControlCode,
			lpInBuffer,
			(UInt32)nInBufferSize,
			lpOutBuffer,
			(UInt32)nOutBufferSize,
			ref lpBytesReturned,
			ref lpOverlapped);
		//if(result) In some cases, even with a negative value, it is necessary to read the outgoing buffer
		outBuffer = (T)Marshal.PtrToStructure(lpOutBuffer, typeof(T));

		return result;
	} finally
	{
		if(lpInBuffer != IntPtr.Zero)
			Marshal.FreeHGlobal(lpInBuffer);
		if(lpOutBuffer != IntPtr.Zero)
			Marshal.FreeHGlobal(lpOutBuffer);
	}
}

internal static T DeviceIoControl(
	IntPtr hDevice,
	UInt32 dwIoControlCode,
	Object inParams,
	out UInt32 lpBytesReturned) where T : struct
{
	T result;
	if(Methods.DeviceIoControl(
		hDevice,
		dwIoControlCode,
		inParams,
		out lpBytesReturned,
		out result))
		return result;
	else
		throw new Win32Exception();
}

And not to hardcode all control codes, here is a sample of the CTL_CODE macros. In C++ it's unfolds in the compile time, but in .NET there is not such feature, thats why it's used as static method.

private static UInt32 CTL_CODE(UInt16 deviceType, UInt16 function, WinAPI.FILE_ACCESS access)
{
	return CTL_CODE(deviceType, function, WinAPI.METHOD.BUFFERED, access);
}

private static UInt32 CTL_CODE(UInt16 deviceType, UInt16 function, WinAPI.METHOD method, WinAPI.FILE_ACCESS access)
{
	return (UInt32)((deviceType << 16) | ((UInt16)access << 14) | (function << 2) | (Byte)method);
}

Right now next IO codes are supported:

  • IOCTL_VOLUME — Volume control
    • GET_VOLUME_DISK_EXTENTS — Retrieves the physical location of a specified volume on one or more disks.
    • IS_CLUSTERED — Determines whether the specified volume is clustered.
  • IOCTL_DISC — Disc control
    • PERFORMANCE — Increments a reference counter that enables the collection of disk performance statistics, such as the numbers of bytes read and written since the driver last processed this request, for a corresponding disk monitoring application.
    • IS_WRITABLE — Determines whether the specified disk is writable.
    • PERFORMANCE_OFF — Disables the counters that were enabled by previous calls to IOCTL_DISK_PERFORMANCE. This request is available in Windows XP and later operating systems. Caller must be running at IRQL = PASSIVE_LEVEL.
    • SMART_GET_VERSION — Returns version information, a capabilities mask, and a bitmask for the device.
    • SMART_SEND_DRIVE_COMMAND — Sends one of the following Self-Monitoring Analysis and Reporting Technology (SMART) commands to the device.
    • SMART_RCV_DRIVE_DATA — Returns the ATA-2 identify data, the Self-Monitoring Analysis and Reporting Technology (SMART) thresholds, or the SMART attributes for the device.
    • GET_DRIVE_GEOMETRY_EX — Returns information about the physical disk's geometry (media type, number of cylinders, tracks per cylinder, sectors per track, and bytes per sector).
  • IOCTL_STORAGE — Storage control
    • CHECK_VERIFY — Determines whether the media has changed on a removable-media device that the caller has opened for read or write access.
    • CHECK_VERIFY2 — Determines whether the media has changed on a removable-media device - the caller has opened with FILE_READ_ATTRIBUTES.
    • MEDIA_REMOVAL — Enables or disables the mechanism that ejects media, for those devices possessing that locking capability.
    • EJECT_MEDIA — Causes the device to eject the media if the device supports ejection capabilities.
    • GET_MEDIA_TYPES_EX — Retrieves information about the types of media supported by a device.
    • GET_MEDIA_SERIAL_NUMBER — Retrieves the serial number of a USB device.
    • GET_HOTPLUG_INFO — Retrieves the hotplug configuration of the specified device.
    • GET_DEVICE_NUMBER — Retrieves the device type, device number, and, for a partitionable device, the partition number of a device.
    • PREDICT_FAILURE — Polls for a prediction of device failure.
    • QUERY_PROPERTY — Returns properties of a storage device or adapter. The request indicates the kind of information to retrieve, such as inquiry data for a device or capabilities and limitations of an adapter.
  • FSCTL — File System control
    • LOCK_VOLUME — Locks a volume if it is not in use.
    • UNLOCK_VOLUME — Unlocks a volume.
    • DISMOUNT_VOLUME — Dismounts a volume regardless of whether or not the volume is currently in use.
    • IS_VOLUME_MOUNTED — Determines whether the specified volume is mounted, or if the specified file or directory is on a mounted volume.
    • FILESYSTEM_GET_STATISTICS — Retrieves the information from various file system performance counters.
    • GET_NTFS_VOLUME_DATA — Retrieves information about the specified NTFS file system volume.
    • GET_VOLUME_BITMAP — Retrieves a bitmap of occupied and available clusters on a volume.
Теги:

Скачать

Original
  • 6 апреля 2013 г.
    Автор оригинального кода на C++ является Andrew I. Reshin он был адаптирован под MFC и STL и использован в приложении Network Administrator, а затем в DeviceInfo приложении.

Ссылки

Родительские файлы