예제 #1
0
        /// <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));
        }
예제 #2
0
 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
     );
예제 #3
0
        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));
            }
        }
예제 #4
0
        // 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);
        }