From: SilverPaladin <SilverPaladin@Neo.rr.com> - 2005-02-21 01:22:07
|
You seem to be the right group of people to ask....perhaps you can help me. My mission is simple (Don't they all start that way?): I want to map the drive letters in Windows XP Pro to the Drive numbers recognized by bios. I have tried many different solotions to this to no avail. I can query drive structures by controller and port. I can query drive structures by Drive letter. However, since my most common situation involves multiple of the same drive, I cannot corrolate that info. If I could return the DRIVE serial number by specifying a Windows Drive letter, even that would give me what I need. I was led to you because someone earlier in your list posted a reference to SMART_GET_VERSION returning an invalid bIDEDeviceMAP. MS has purged the entire Internet of all traces of the article detailing this bug in an effort to deliberately thwart my project. Perhaps you can help???????? Please??? My target device is Win XP Pro (SP1&SP2) on the Dell GX280 (and newer eventually) with 1 or more SATA drives and/or 1 or more PATA/standard IDE port drives. I am getting inconsisten results back from bIDEDeviceMap especially when I connect more drives. Connecting another drive should not affect how the first is reported!!! Here are the results: IDEPrimary0 - Drive Letters E, J - Windows says Disk0 - Bios Disk 1 - bIDEDeviceMap returns 3 for all these drives IDEPrimary1 - Drive Letters C, F, H - Windows says Disk1 - Bios Disk 2 - bIDEDeviceMap returns 3 for all these drives SATA0 - Drive Letters D, G, I - Windows says Disk 3 - bIDEDeviceMap returns 4 for all these drives If I remove the IDE slave, I get totally different results from bIDEDevicemap. Right now the order of BIOS and Windows match however I'm told that is not reliable. Can any of you confirm/deny this? Here is my current code base (please excuse my Delphi). It is a little inconsistent in it's approaches as it's had two days of debugging done to it (for instance I am currently using bitwise ANDs for bIDEDeviceMap as I wanted to make sure the set logic was done correctly). Thanks in advance and I do apologize for this somewhat off-topic post. I'm was amazed to find a group of people with expertise on the subject and am getting somewhat desperate. I am at about 500% of the time I allocated to figuring this out. unit UDrvProject2; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, ExtCtrls, StdCtrls; type TForm1 = class(TForm) ComboBox1: TComboBox; Button1: TButton; Button2: TButton; Button3: TButton; Memo1: TMemo; procedure FormCreate(Sender: TObject); procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button3Click(Sender: TObject); private { Private declarations } public { Public declarations } end; // Bitmask Flags Meaning // CAP_ATA_ID_CMD The device supports the ATA ID command. // CAP_ATAPI_ID_CMD The device supports the ATAPI ID command. // CAP_SMART_CMD The device supports SMART commands. TCapability = (CAP_ATA_ID_CMD, CAP_ATAPI_ID_CMD, CAP_SMART_CMD, cpReserved03, cpReserved04, cpReserved05, cpReserved06, cpReserved07, cpReserved08, cpReserved09, cpReserved10, cpReserved11, cpReserved12, cpReserved13, cpReserved14, cpReserved15, cpReserved16, cpReserved17, cpReserved18, cpReserved19, cpReserved20, cpReserved21, cpReserved22, cpReserved23, cpReserved24, cpReserved25, cpReserved26, cpReserved27, cpReserved28, cpReserved29, cpReserved30, cpReserved31); TCapabilities = set of TCapability; PGetVersionOutParams = ^TGetVersionOutParams; TGetVersionOutParams = packed record bVersion: Byte; bRevision: Byte; bReserved: Byte; bIDEDeviceMap: Byte; fCapabilities: TCapabilities; dwReserved: array[0..3] of DWord end; const // SMART Command constants SMART_GET_VERSION = $00074080; SMART_SEND_DRIVE_COMMAND = $00074084; SMART_RCV_DRIVE_DATA = $00074088; DM_IDE_PRIMARY_0 = 1; DM_IDE_PRIMARY_1 = 2; DM_IDE_SECONDARY_0 = 4; DM_IDE_SECONDARY_1 = 8; DM_ATAPI_PRIMARY_0 = 16; DM_ATAPI_PRIMARY_1 = 32; DM_ATAPI_SECONDARY_0 = 64; DM_ATAPI_SECONDARY_1 = 128; var Form1: TForm1; implementation {$R *.DFM} {*********************************************************************** ******* GetDriveMapping ************************************************************************ ******} function GetDriveMapping(DriveName: String): Byte; var BytesReturned: DWord; hDevice: THandle; VersionInfo: TGetVersionOutParams; begin Result := 0; hDevice := CreateFile(PAnsiChar(DriveName), GENERIC_READ, FILE_SHARE_READ + FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0); if hDevice = INVALID_HANDLE_VALUE then Exit; try FillChar(VersionInfo, SizeOf(VersionInfo), 0); BytesReturned := 0; if not DeviceIoControl(hDevice, SMART_GET_VERSION, nil, 0, @VersionInfo, SizeOf(VersionInfo), BytesReturned, nil) then Exit; Result := VersionInfo.bIDEDeviceMap; except end; CloseHandle(hDevice); end; {*********************************************************************** ******* FormCreate ************************************************************************ ******} procedure TForm1.FormCreate(Sender: TObject); var Drive : Char; begin // FormCreate // check for removable drive for Drive := 'a' to 'z' do begin case GetDriveType(PChar(Drive + ':\')) of DRIVE_FIXED: ComboBox1.Items.Add(UpCase(Drive)); end; end; if (ComboBox1.Items.Count > 0) then ComboBox1.ItemIndex := 0 else begin MessageDlg('This computer does not have any hard drives... That''s a bummer. I''m sorry dude...',mtError, [mbOk], 0); Application.Terminate; end; end; // FormCreate {*********************************************************************** ******* Button1Click ************************************************************************ ******} procedure TForm1.Button1Click(Sender: TObject); var Connector: Byte; begin // Button1Click // GetDeviceParamBlock(ComboBox1.Text[1], aParamBlock); Connector := GetDriveMapping('\\.\' + ComboBox1.Text[1] + ':'); if ((DM_IDE_PRIMARY_0 and Connector) <> 0) then Showmessage('dmIDEPRIMARY_0'); if ((DM_IDE_PRIMARY_1 and Connector) <> 0) then Showmessage('dmIDEPRIMARY_1'); if ((DM_IDE_SECONDARY_0 and Connector) <> 0) then Showmessage('dmIDESECONDARY_0'); if ((DM_IDE_SECONDARY_1 and Connector) <> 0) then Showmessage('dmIDESECONDARY_1'); if ((DM_ATAPI_PRIMARY_0 and Connector) <> 0) then Showmessage('dmATAPIPRIMARY_0'); if ((DM_ATAPI_PRIMARY_1 and Connector) <> 0) then Showmessage('dmATAPIPRIMARY_1'); if ((DM_ATAPI_SECONDARY_0 and Connector) <> 0) then Showmessage('dmATAPISECONDARY_0'); if ((DM_ATAPI_SECONDARY_1 and Connector) <> 0) then Showmessage('dmATAPISECONDARY_1'); end; // Button1Click {*********************************************************************** ******* Button2Click ************************************************************************ ******} procedure TForm1.Button2Click(Sender: TObject); var Connector: Byte; Loop: Integer; begin // Button2Click for Loop := 0 to ComboBox1.Items.Count - 1 // Iterate do begin Connector := GetDriveMapping('\\.\' + ComboBox1.Items[Loop][1] + ':'); Memo1.Lines.add('Drive ' + ComboBox1.Items[Loop][1] + ': ' + IntToStr(Connector)); end; // for Loop end; // Button2Click {*********************************************************************** ******* Button3Click ************************************************************************ ******} procedure TForm1.Button3Click(Sender: TObject); var Loop, Loop1: Integer; Connector: Byte; tmpConnector: Byte; begin // Button3Click Memo1.Clear; Loop := 0; while (Loop < ComboBox1.Items.Count) do begin Connector := GetDriveMapping('\\.\' + ComboBox1.Items[Loop][1] + ':'); for Loop1 := ComboBox1.Items.Count - 1 downto 0 // Iterate do begin if (Loop = Loop1) then Continue; tmpConnector := GetDriveMapping('\\.\' + ComboBox1.Items[Loop1][1] + ':'); if (Connector = tmpConnector) then ComboBox1.Items.Delete(Loop1); end; Inc(Loop); end; // while for Loop := ComboBox1.Items.Count - 1 downto 0 // Iterate do begin Connector := GetDriveMapping('\\.\' + ComboBox1.Items[Loop][1] + ':'); if ((DM_ATAPI_PRIMARY_0 and Connector) <> 0) then begin Memo1.Lines.add(IntToStr(Memo1.Lines.Count + 1) + ': ' + 'Drive ' + ComboBox1.Items[Loop][1] + ':.'); ComboBox1.Items.Delete(Loop); end; end; // for Loop for Loop := ComboBox1.Items.Count - 1 downto 0 // Iterate do begin Connector := GetDriveMapping('\\.\' + ComboBox1.Items[Loop][1] + ':'); if ((DM_ATAPI_PRIMARY_1 and Connector) <> 0) then begin Memo1.Lines.add(IntToStr(Memo1.Lines.Count + 1) + ': ' + 'Drive ' + ComboBox1.Items[Loop][1] + ':.'); ComboBox1.Items.Delete(Loop); end; end; // for Loop for Loop := ComboBox1.Items.Count - 1 downto 0 // Iterate do begin Connector := GetDriveMapping('\\.\' + ComboBox1.Items[Loop][1] + ':'); if ((DM_ATAPI_SECONDARY_0 and Connector) <> 0) then begin Memo1.Lines.add(IntToStr(Memo1.Lines.Count + 1) + ': ' + 'Drive ' + ComboBox1.Items[Loop][1] + ':.'); ComboBox1.Items.Delete(Loop); end; end; // for Loop for Loop := ComboBox1.Items.Count - 1 downto 0 // Iterate do begin Connector := GetDriveMapping('\\.\' + ComboBox1.Items[Loop][1] + ':'); if ((DM_ATAPI_SECONDARY_1 and Connector) <> 0) then begin Memo1.Lines.add(IntToStr(Memo1.Lines.Count + 1) + ': ' + 'Drive ' + ComboBox1.Items[Loop][1] + ':.'); ComboBox1.Items.Delete(Loop); end; end; // for Loop for Loop := ComboBox1.Items.Count - 1 downto 0 // Iterate do begin Connector := GetDriveMapping('\\.\' + ComboBox1.Items[Loop][1] + ':'); if ((DM_IDE_PRIMARY_0 and Connector) <> 0) then begin Memo1.Lines.add(IntToStr(Memo1.Lines.Count + 1) + ': ' + 'Drive ' + ComboBox1.Items[Loop][1] + ':.'); ComboBox1.Items.Delete(Loop); end; end; // for Loop for Loop := ComboBox1.Items.Count - 1 downto 0 // Iterate do begin Connector := GetDriveMapping('\\.\' + ComboBox1.Items[Loop][1] + ':'); if ((DM_IDE_PRIMARY_1 and Connector) <> 0) then begin Memo1.Lines.add(IntToStr(Memo1.Lines.Count + 1) + ': ' + 'Drive ' + ComboBox1.Items[Loop][1] + ':.'); ComboBox1.Items.Delete(Loop); end; end; // for Loop for Loop := ComboBox1.Items.Count - 1 downto 0 // Iterate do begin Connector := GetDriveMapping('\\.\' + ComboBox1.Items[Loop][1] + ':'); if ((DM_IDE_SECONDARY_0 and Connector) <> 0) then begin Memo1.Lines.add(IntToStr(Memo1.Lines.Count + 1) + ': ' + 'Drive ' + ComboBox1.Items[Loop][1] + ':.'); ComboBox1.Items.Delete(Loop); end; end; // for Loop for Loop := ComboBox1.Items.Count - 1 downto 0 // Iterate do begin Connector := GetDriveMapping('\\.\' + ComboBox1.Items[Loop][1] + ':'); if ((DM_IDE_SECONDARY_0 and Connector) <> 0) then begin Memo1.Lines.add(IntToStr(Memo1.Lines.Count + 1) + ': ' + 'Drive ' + ComboBox1.Items[Loop][1] + ':.'); ComboBox1.Items.Delete(Loop); end; end; // for Loop FormCreate(NIL); end; // Button3Click end. |
From: SilverPaladin <SilverPaladin@Neo.rr.com> - 2005-02-21 01:35:58
|
ACK... My apologies for the triple post. Outlook reported an "unknown error" on two consecutive sends before it successfully cleared the message from my outbox. I actually did some editing while it was sitting in the outbox. This may have contributed to the triple posting. In anycase, the third, and most recent, version has some additional comments in the method headers. Brian. |
From: Christian F. <Chr...@t-...> - 2005-02-21 20:04:34
|
Hi, you wrote: >I was led to you because someone earlier in your list posted a reference >to SMART_GET_VERSION returning an invalid bIDEDeviceMAP. > This issue was 9x/ME related, not 2000/XP. On 9x/ME, one device ("\\.\smartvsd.vxd") is used to access SMART data of all (and only) 4 legacy IDE interfaces. The bIDEDeviceMAP was intended for drive existence and type check. On 2000/XP, the drive selection is done by different device names ("\\.\PhysicalDrive[0123...]"). CreateFile() returns an error if drive does not exist, SMART_GET_VERSION returns an error if a drive(r) does not support SMART. Therefore, bIDEDeviceMAP is not necessary and may or may not contain an useful value on 2000/XP. Both smartctl and smartd do not rely on it. See ata_open() and ata_scan() in http://cvs.sourceforge.net/viewcvs.py/smartmontools/sm5/os_win32.c?view=markup >MS has purged >the entire Internet of all traces of the article detailing this bug in >an effort to deliberately thwart my project. > Unfortunately MS removed many 9x/ME related entries - from their Knowledge Base, not from the entire internet ;-) But this specific article won't help for XP. >... >My target device is Win XP Pro (SP1&SP2) on the Dell GX280 (and newer >eventually) with 1 or more SATA drives and/or 1 or more PATA/standard >IDE port drives. > >I am getting inconsisten results back from bIDEDeviceMap especially when >I connect more drives. Connecting another drive should not affect how >the first is reported!!! >... >Right now the order of BIOS and Windows match however I'm told that is >not reliable. Can any of you confirm/deny this? > > The drive assignment depends on registry entries below HKEY_LOCAL_MACHINE\Hardware\Devicemap. It possibly defaults to BIOS mapping after Windows installation and can be displayed/changed using Disk Management console. See http://support.microsoft.com/kb/159865/ for more info. >Here is my current code base (please excuse my Delphi).... > > Try IOCTL_DISK_CONTROLLER_NUMBER instead, see: http://msdn.microsoft.com/library/en-us/storage/hh/storage/k307_227ab511-78ff-4aba-be29-3429329d05e5.xml.asp I never tested this but it should work for your purpose if your IDE driver supports it. Hope this helps. Christian |