title: When i try to get physical sector size via DeviceIoControl i receive Access is denied
body: <p>From my webserver app i need to check the physical sector size of the harddrive where the app is located. For this i use <code>DeviceIoControl</code> with <code>IOCTL_STORAGE_QUERY_PROPERTY</code> to query <code>StorageAccessAlignmentProperty</code>. The problem is that when i try to run these commands from the webserver i got "<strong>Access is denied</strong>" error. </p>
  
  <p>How can i retrieve the physical sector size of the harddrive where inetpub is located from the webserver app ??  </p>
  
  <p>I know from <a href="https://msdn.microsoft.com/windows/compatibility/advanced-format-disk-compatibility-update" rel="nofollow noreferrer">https://msdn.microsoft.com/windows/compatibility/advanced-format-disk-compatibility-update</a> that with Windows 8 Microsoft has introduced a new API that enables Calling from an unprivileged app. The API is in the form of a new info class <code>FileFsSectorSizeInformation</code> with associated structure <code>FILE_FS_SECTOR_SIZE_INFORMATION</code>, but i don't know how to make it working with Delphi</p>
  
  <p>This is my actual code that don't work (written in Delphi) : </p>
  
  <pre><code>{~~~~~~~~~~~~~~~~~~~~~~~~~}
  procedure _CheckSectorSize;
  
  type
    STORAGE_PROPERTY_ID  = (StorageDeviceProperty = 0,
                            StorageAdapterProperty,
                            StorageDeviceIdProperty,
                            StorageDeviceUniqueIdProperty,
                            StorageDeviceWriteCacheProperty,
                            StorageMiniportProperty,
                            StorageAccessAlignmentProperty,
                            StorageDeviceSeekPenaltyProperty,
                            StorageDeviceTrimProperty,
                            StorageDeviceWriteAggregationProperty,
                            StorageDeviceDeviceTelemetryProperty,
                            StorageDeviceLBProvisioningProperty,
                            StorageDevicePowerProperty,
                            StorageDeviceCopyOffloadProperty,
                            StorageDeviceResiliencyProperty,
                            StorageDeviceMediumProductType,
                            StorageAdapterCryptoProperty,
                            StorageDeviceIoCapabilityProperty = 48,
                            StorageAdapterProtocolSpecificProperty,
                            StorageDeviceProtocolSpecificProperty,
                            StorageAdapterTemperatureProperty,
                            StorageDeviceTemperatureProperty,
                            StorageAdapterPhysicalTopologyProperty,
                            StorageDevicePhysicalTopologyProperty,
                            StorageDeviceAttributesProperty);
    STORAGE_QUERY_TYPE  = (PropertyStandardQuery = 0,
                           PropertyExistsQuery = 1,
                           PropertyMaskQuery = 2,
                           PropertyQueryMaxDefined = 3);
    _STORAGE_PROPERTY_QUERY = packed record
      PropertyId: STORAGE_PROPERTY_ID;
      QueryType: STORAGE_QUERY_TYPE;
      AdditionalParameters: array[0..9] of Byte;
   end;
    _STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR = packed record
      Version: DWORD; // Contains the size of this structure, in bytes. The value of this member will change as members are added to the structure.
      Size: DWORD; // Specifies the total size of the data returned, in bytes. This may include data that follows this structure.
      BytesPerCacheLine: DWORD; // The number of bytes in a cache line of the device.
      BytesOffsetForCacheAlignment: DWORD; // The address offset necessary for proper cache access alignment, in bytes.
      BytesPerLogicalSector: DWORD; // The number of bytes in a logical sector of the device.
      BytesPerPhysicalSector: DWORD; // The number of bytes in a physical sector of the device.
      BytesOffsetForSectorAlignment: DWORD; // The logical sector offset within the first physical sector where the first logical sector is placed, in bytes.
   end;
  
  var
    aVolumePath: array[0..MAX_PATH] of AnsiChar;
    aVolumeName: array[0..MAX_PATH] of AnsiChar;
    hFile: THANDLE;
    inbuf: _STORAGE_PROPERTY_QUERY;
    outbuf: _STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR;
    dwLen: DWORD;
    i: integer;
  
  begin
  
    // Convert the directory to a Volume Name
    aVolumePath[0] := #$00;
    if not GetVolumePathNameA(pAnsiChar(DFRooter_HayStackDirectory),  // _In_  LPCTSTR lpszFileName,
                              aVolumePath,  // _Out_ LPTSTR  lpszVolumePathName,
                              length(aVolumePath)) then raiseLastOsError; // _In_ DWORD cchBufferLength
    aVolumeName[0] := #$00;
    if not GetVolumeNameForVolumeMountPointA(aVolumePath, // _In_  LPCTSTR lpszVolumeMountPoint,
                                             aVolumeName,  // _Out_ LPTSTR lpszVolumeName,
                                             length(aVolumeName)) then raiseLastOsError; // _In_  DWORD   cchBufferLength
  
    // Opening a physical device so no trailing '\'. Trailing '\' would open the ROOT DIR instead of the volume
    for i := 1 to High(aVolumeName) do
      if aVolumeName[i] = #0 then begin
        if aVolumeName[i-1] = '\' then aVolumeName[i-1] := #0;
        break;
      end;
  
    //create the file
    hFile := CreateFileA(PAnsiChar(@aVolumeName[0]), // _In_ LPCTSTR lpFileName,
                         GENERIC_READ, // _In_ DWORD dwDesiredAccess,
                         FILE_SHARE_READ or FILE_SHARE_WRITE, //_In_ DWORD dwShareMode,
                         0, // _In_opt_ LPSECURITY_ATTRIBUTES lpSecurityAttributes,
                         OPEN_EXISTING, // _In_ DWORD dwCreationDisposition,
                         FILE_ATTRIBUTE_NORMAL, // _In_ DWORD dwFlagsAndAttributes,
                         0); // _In_opt_ HANDLE hTemplateFile
    if (hFile = INVALID_HANDLE_VALUE) then raiseLastOsError;
    try
  
      ZeroMemory(@inbuf, SizeOf(inbuf));
      ZeroMemory(@outbuf, SizeOf(outbuf));
      inbuf.QueryType := PropertyStandardQuery;
      inbuf.PropertyId := StorageAccessAlignmentProperty;
      outbuf.Size := sizeOf(outbuf);
      if not DeviceIoControl(hFile, //  _In_ HANDLE hDevice,
                             IOCTL_STORAGE_QUERY_PROPERTY, // _In_ DWORD dwIoControlCode,
                             @inbuf, // _In_opt_ LPVOID lpInBuffer,
                             sizeof(inbuf), // _In_ DWORD nInBufferSize,
                             @outbuf, // _Out_opt_ LPVOID lpOutBuffer,
                             sizeof(outbuf), // _In_ DWORD nOutBufferSize,
                             dwLen, // _Out_opt_ LPDWORD lpBytesReturned,
                             nil) then raiseLastOsError; // _Inout_opt_ LPOVERLAPPED lpOverlapped
  
    finally
      CloseHandle(hFile);
    end;
  
  end;
  </code></pre>