/// <summary>Проверка на существование свойства перед запросом</summary> /// <param name="propertyId">Идентификатор свойства перед запросом</param> /// <returns>Такое свойство существует</returns> private Boolean IsPropertyExists(StorageAPI.STORAGE_PROPERTY_QUERY.STORAGE_PROPERTY_ID propertyId) { StorageAPI.STORAGE_PROPERTY_QUERY query = new StorageAPI.STORAGE_PROPERTY_QUERY(); query.QueryType = StorageAPI.STORAGE_PROPERTY_QUERY.STORAGE_QUERY_TYPE.PropertyExistsQuery; query.PropertyId = propertyId; return(this.Info.IoControl(Constant.IOCTL_STORAGE.QUERY_PROPERTY, query)); }
static extern bool DeviceIoControl( SafeFileHandle hDevice, DWORD dwIoControlCode, ref StorageAPI.STORAGE_PROPERTY_QUERY lpInBuffer, DWORD nInBufferSize, out StorageAPI.STORAGE_DEVICE_ID_DESCRIPTOR lpOutBuffer, int nOutBufferSize, ref DWORD lpBytesReturned, LPOVERLAPPED lpOverlapped );
private T IoControl <T>() where T : struct { StorageAPI.STORAGE_PROPERTY_QUERY inParams = new StorageAPI.STORAGE_PROPERTY_QUERY(); inParams.QueryType = StorageAPI.STORAGE_PROPERTY_QUERY.STORAGE_QUERY_TYPE.PropertyStandardQuery; inParams.PropertyId = Properties.GetPropertyId(typeof(T)); T outParams; if (this.IsPropertyExists(inParams.PropertyId) && //Перед запросом проверяю поддержку этого свойства устройством this.Info.IoControl <T>(Constant.IOCTL_STORAGE.QUERY_PROPERTY, inParams, out outParams)) { return(outParams); } else { return(default(T)); } }
// deviceId is the physical disk number, e.g. from Get-PhysicalDisk. // Throws: System.ComponentModel.Win32Exception public static string Get_GcePdName(string deviceId) { string physicalDrive = PHYSICALDRIVE + deviceId; var hDevice = CreateFile(physicalDrive, ((uint)WinAPI.FILE_ACCESS_FLAGS.GENERIC_READ | (uint)WinAPI.FILE_ACCESS_FLAGS.GENERIC_WRITE), (uint)WinAPI.FILE_SHARE.READ, IntPtr.Zero, (uint)WinAPI.CreateDisposition.OPEN_EXISTING, 0, IntPtr.Zero ); if (hDevice.IsInvalid) { var e = new Win32Exception(Marshal.GetLastWin32Error(), String.Format("CreateFile({0}) failed. Is the drive number valid?", physicalDrive)); WriteDebugLine(String.Format("Error: {0}", e.ToString())); WriteDebugLine("Please use a valid physical drive number (e.g. " + "(Get-PhysicalDisk).DeviceId)"); throw e; } // https://stackoverflow.com/a/17354960/1230197 var query = new StorageAPI.STORAGE_PROPERTY_QUERY { PropertyId = StorageAPI.STORAGE_PROPERTY_QUERY.STORAGE_PROPERTY_ID.StorageDeviceIdProperty, // page 83 QueryType = StorageAPI.STORAGE_PROPERTY_QUERY.STORAGE_QUERY_TYPE.PropertyStandardQuery }; var qsize = (uint)Marshal.SizeOf(query); // https://stackoverflow.com/a/2069456/1230197 var result = default(StorageAPI.STORAGE_DEVICE_ID_DESCRIPTOR); var rsize = Marshal.SizeOf(result); uint written = 0; bool ok = DeviceIoControl(hDevice, IOCTL_STORAGE_QUERY_PROPERTY, ref query, qsize, out result, rsize, ref written, IntPtr.Zero); if (!ok) { var e = new Win32Exception(Marshal.GetLastWin32Error(), String.Format("DeviceIoControl({0}) failed", physicalDrive)); WriteDebugLine(String.Format("Error: {0}", e.ToString())); hDevice.Close(); throw e; } uint numIdentifiers = result.NumberOfIdentifiers; WriteDebugLine(String.Format("numIdentifiers: {0}", numIdentifiers)); int identifierBufferStart = 0; for (int i = 0; i < numIdentifiers; ++i) { // Example: // https://docs.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.marshal.copy?view=netframework-4.7.2#System_Runtime_InteropServices_Marshal_Copy_System_Byte___System_Int32_System_IntPtr_System_Int32_. // We don't know exactly how large this identifier is until we marshal // the struct below. "BUFFER_SIZE" is used by // STORAGE_DEVICE_ID_DESCRIPTOR for the combined size of all the // identifiers so it's an upper bound on the size of this one. IntPtr storageIdentifierBuffer = Marshal.AllocHGlobal(StorageAPI.BUFFER_SIZE); int identifiersBufferLeft = StorageAPI.BUFFER_SIZE - identifierBufferStart; WriteDebugLine( String.Format("getting storageIdentifier {0} from memory [{1}, {2})", i, identifierBufferStart, identifierBufferStart + identifiersBufferLeft)); Marshal.Copy(result.Identifiers, identifierBufferStart, storageIdentifierBuffer, identifiersBufferLeft); var storageIdentifier = Marshal.PtrToStructure <StorageAPI.STORAGE_IDENTIFIER>( storageIdentifierBuffer); WriteDebugLine(String.Format("storageIdentifier type: {0} ({1})", storageIdentifier.Type, (int)storageIdentifier.Type)); WriteDebugLine(String.Format("storageIdentifier association: {0} ({1})", storageIdentifier.Association, (int)storageIdentifier.Association)); WriteDebugLine(String.Format("storageIdentifier size: {0}", (int)storageIdentifier.IdentifierSize)); if (storageIdentifier.Type == StorageAPI.STORAGE_IDENTIFIER.STORAGE_IDENTIFIER_TYPE.StorageIdTypeVendorId && storageIdentifier.Association == StorageAPI.STORAGE_IDENTIFIER.STORAGE_ASSOCIATION_TYPE.StorageIdAssocDevice) { IntPtr identifierData = Marshal.AllocHGlobal(storageIdentifier.IdentifierSize + 1); Marshal.Copy(storageIdentifier.Identifier, 0, identifierData, storageIdentifier.IdentifierSize); // Make sure to close the file handle before returning, or subsequent // CreateFile calls for this disk or others may fail. hDevice.Close(); string fullName = System.Text.Encoding.ASCII.GetString( storageIdentifier.Identifier, 0, storageIdentifier.IdentifierSize); // TODO(pjh): make this more robust? Works well enough on two Windows // Server 2016 VMs at least. if (!fullName.StartsWith(GOOGLEPREFIX)) { Console.WriteLine("WARNING: unexpectedly got back disk name {0} " + "that doesn't contain Google prefix {1}", fullName, GOOGLEPREFIX); return(fullName); } return(fullName.Substring(GOOGLEPREFIX.Length)); } // To get the start of the next identifier we need to advance // by the length of the STORAGE_IDENTIFIER struct as well as // the size of its variable-length data array. We subtract // the size of the "byte[] Identifiers" member because it's // included in the size of the data array. // // TODO(pjh): figure out how to make this more robust. // Marshal.SizeOf(storageIdentifier) returns bonkers // values when we set the SizeConst MarshalAs attribute (which // we need to do in order to copy from the byte[] above). I // couldn't figure out how to correctly calculate this value // using Marshal.SizeOf, but it's 20 bytes - this value is // fixed (for this platform at least) by the definition of // STORAGE_IDENTIFIER in winioctl.h. int advanceBy = 20 - sizeof(byte) + storageIdentifier.IdentifierSize; WriteDebugLine( String.Format("advanceBy = {0} - {1} + {2} = {3}", 20, sizeof(byte), storageIdentifier.IdentifierSize, advanceBy)); identifierBufferStart += advanceBy; WriteDebugLine(String.Format("will read next identifier starting at {0}", identifierBufferStart)); WriteDebugLine(""); Marshal.FreeHGlobal(storageIdentifierBuffer); } hDevice.Close(); return(null); }