Slow response to drive state(DVD,SD) if no disk in drive

Please report only one bug per message!

Moderators: white, Hacker, petermad, Stefan2

User avatar
BORG52
Junior Member
Junior Member
Posts: 28
Joined: 2011-04-23, 16:16 UTC

Slow response to drive state(DVD,SD) if no disk in drive

Post by *BORG52 »

Hello,
If "no disk" in drive - after click to any removable drive icon(DVD,SD), TCMD has very slow response to drive state.(similar as link to network drive)
Windows explorer response is fast.

TCMD use history and trying link to latest(removed) medium inserted to removable drive. Restart TCMD solve problem with (no)linked medium, but this is not optimal solution - response to drive(no medium) state is always slow.
FDD drive(with no floppy) response is OK in TCMD.
TCMD912/XP32
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48012
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

I don't think there is anything I can do. TC uses functions like FindFirstFile or SetCurrentDirectory, and they sometimes have a long timeout. TC should show a wait dialog after about 1 second where you can cancel the operation.
Author of Total Commander
https://www.ghisler.com
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

I can confirm the problem.

My DVD drive is E: - when it is empty:

- when I call FindFirst('E:\*.*', ...) - it immediately returns ERROR_NOT_READY

- when I call SetCurrentDirectory('E:') - it immediately fails with ERROR_NOT_READY

- when I select E: in 32-bit or 64-bit TC, mouse cursor is changed to a waiting state and TC is thinking for about 3 seconds before displaying an error message.

Regards
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48012
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

I cannot reproduce your report: When FindFirstFile and/or SetCurrentDirectory is fast, TC is fast too. Tried with two different CD drives, one internal and one connected via USB.
Author of Total Commander
https://www.ghisler.com
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

I found the reason: TC assumes a default CDCloseDoor=1 configuration seting. After adding CDCloseDoor=0 to [Configuration] in wincmd.ini, the problem is solved.



For CDCloseDoor=1 setting (Totalcmd.exe, 9.20 Beta 5):

1) at 0x0041C20E, a call is executed: mciSendStringA('open e: type cdaudio alias ding', nil, 0, 0) - this call blocks execution for about 2 seconds

2) at 0x0041C20E, a call is executed: mciSendStringA('set ding door closed wait', nil, 0, 0) - this call blocks execution for about 0.5 second

3) at 0x0041C20E, a call is executed: mciSendStringA('close ding', nil, 0, 0)

4) at 0x0041C2EC, Sleep(500) is executed

5) at 0x0041C431, Sleep(1000) is executed



What is a purpose of these MCI calls?

Regards
User avatar
BORG52
Junior Member
Junior Member
Posts: 28
Joined: 2011-04-23, 16:16 UTC

Post by *BORG52 »

With CDCloseDoor=0 is response the same as windows explorer. This solve problem with "response to drive state"
MarcinW: thank

MCI call: I also noticed it's. I am not programmer, but when testing TCMD in Dependency Walker i found MCI call, when make door closed/open .TCMD sounds are not associated with eject/close-here is no relation.
Here is relation with CD audio. TCMD tests if audioCD inserted and load/unload anytime mcicda.dll. Probably therefore is slow response(?). I mean, that TCMD first check for audioCD,no for data.This should be optimized.
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48012
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

TC calls these to close an open CD drawer, so you can just open the drawer, put the CD/DVD in, and then switch to it in TC without closing the CD drawer manually.
Author of Total Commander
https://www.ghisler.com
User avatar
BORG52
Junior Member
Junior Member
Posts: 28
Joined: 2011-04-23, 16:16 UTC

Post by *BORG52 »

OK, thank for ifo about MCI function in this case.
For me is this function here unnecessary, but in some cases this may be usefull.
Therefore any switch for CDCloseDoor in TCMD config bar is need.

When I have to strain my hand to the DVD mechanic to insert or remove the media, it will make it easier for me to press the button on the mechanics before somewhere to catch something with the mouse. :D
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

It seems that the current TC behavior can be made much faster, without any compatibility loss. I'll investigate this and let you know here.

Regards
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48012
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

You can disable it:
wincmd.ini
[Configuration]
CdCloseDoor=0
Author of Total Commander
https://www.ghisler.com
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

I found some info here: https://ws0.org/windows-how-to-get-the-tray-status-of-the-optical-drive/

By using DeviceIoControl API with IOCTL_STORAGE_CHECK_VERIFY2 and IOCTL_SCSI_PASS_THROUGH_DIRECT control codes, we can check if:
- tray is ejected,
- tray is closed with some media inside,
- tray is closed with no media inside.

In opposite to MCI calls, IOCTL calls return immediately.


I created a piece of test code by using a sample code from the article mentioned above (I made some corrections though). Curently TC code looks like:

Code: Select all

if CDCloseDoor <> 0 then
  call MCI functions to close the CD tray
This could be improved in the following way:

Code: Select all

if CDCloseDoor <> 0 then
if IsCDTrayEjected(DriveNum) then
  call MCI functions to close the CD tray

Thanks to this change, TC could respond immediately, even for CDCloseDoor=1. The IsCDTrayEjected() function always returns True in case of any errors, so it will not break compatibility. It may even work on Win 9x systems, if the CD driver supports needed IOCTL codes (in other cases just True is returned). The code below has been sucessfully tested on two physical machines with DVD drives, where TC hangs for few seconds when accessing the drive - on Win 98, Win 2000 and Win 7 64-bit (both as 32-bit and 64-bit code).

Code: Select all

program CDTest;

uses
  Windows;

type
  SCSI_PASS_THROUGH_DIRECT = record
    Length : Word;
    ScsiStatus : Byte;
    PathId : Byte;
    TargetId : Byte;
    Lun : Byte;
    CdbLength : Byte;
    SenseInfoLength : Byte;
    DataIn : Byte;
    DataTransferLength : Cardinal;
    TimeOutValue : Cardinal;
    DataBuffer : Pointer;
    SenseInfoOffset : Cardinal;
    Cdb : array[0..15] of Byte;
  end;

const
  IOCTL_STORAGE_CHECK_VERIFY2 = $002D0800;
  IOCTL_SCSI_PASS_THROUGH_DIRECT = $0004D014;

const
  SCSI_IOCTL_DATA_IN = 1;

const
  FILE_SHARE_DELETE = 4;

// DriveNum: 0=A:, 1=B:, 2=C:, ...
function IsCDTrayEjected(DriveNum : Byte) : Boolean;
var
  DeviceName : array[0..6] of WideChar;
  HDevice : THandle;
  BytesReturned : DWORD;
  SCSIBuffer : record
    SPTD : SCSI_PASS_THROUGH_DIRECT;
    SenseBuffer : array[0..17] of Byte;
  end;
  DataBuffer : array[0..7] of Byte;
begin
  Result:=True; // Return True in case of any errors

  DeviceName[0]:='\';
  DeviceName[1]:='\';
  DeviceName[2]:='.';
  DeviceName[3]:='\';
  DeviceName[4]:=WideChar(Ord('A')+DriveNum);
  DeviceName[5]:=':';
  DeviceName[6]:=#0;

  HDevice:=CreateFileW(DeviceName,0,FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
  if HDevice = INVALID_HANDLE_VALUE then
    Exit;
  try
    Result:=not DeviceIoControl(HDevice,IOCTL_STORAGE_CHECK_VERIFY2,nil,0,nil,0,BytesReturned,nil);
  finally
    CloseHandle(hDevice);
  end;

  if not Result then // Tray closed, media present
    Exit;

  HDevice:=CreateFileW(DeviceName,GENERIC_READ or GENERIC_WRITE,FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,nil,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
  if HDevice = INVALID_HANDLE_VALUE then
    Exit;
  try
    FillChar(SCSIBuffer,SizeOf(SCSIBuffer),0);
    with SCSIBuffer do
    begin
      SPTD.Length:=SizeOf(SPTD);
      SPTD.CdbLength:=10;
      SPTD.SenseInfoLength:=SizeOf(SenseBuffer);
      SPTD.DataIn:=SCSI_IOCTL_DATA_IN;
      SPTD.DataTransferLength:=SizeOf(DataBuffer);
      SPTD.TimeOutValue:=1;
      SPTD.DataBuffer:=@DataBuffer;
      SPTD.SenseInfoOffset:=HINST(@SenseBuffer)-HINST(@SCSIBuffer);
      SPTD.Cdb[0]:=$4A;
      SPTD.Cdb[1]:=$01;
      SPTD.Cdb[4]:=$10;
      SPTD.Cdb[8]:=$08;
    end;
    FillChar(DataBuffer,SizeOf(DataBuffer),0);

    BytesReturned:=0;
    Result:=DeviceIoControl(HDevice,IOCTL_SCSI_PASS_THROUGH_DIRECT,@SCSIBuffer,SizeOf(SCSIBuffer),@SCSIBuffer,SizeOf(SCSIBuffer),BytesReturned,nil);
  finally
    CloseHandle(hDevice);
  end;

  if (not Result) or (BytesReturned < SizeOf(SCSIBuffer.SPTD)) then // Error
  begin
    Result:=True;
    Exit;
  end;

  case DataBuffer[5] of
    0  : Result:=False; // Tray closed, no media
    1  : Result:=True;  // Tray ejected
    else Result:=False; // Tray closed, media present
  end;
end;

var
  DriveNum : Byte; // 0=A:, 1=B:, 2=C:, ...
begin
  DriveNum:=0;
  while True do
  begin
    if GetDriveType(PChar(string(Char(Ord('A')+DriveNum))+':')) = DRIVE_CDROM then
      Break;
    if DriveNum = 26 then
    begin
      MessageBox(0,'No CD drive found','Error',MB_ICONSTOP);
      Exit;
    end;
    Inc(DriveNum);
  end;

  if IsCDTrayEjected(DriveNum) then
    MessageBox(0,'Tray ejected (or error occured)',PChar('Drive '+Char(Ord('A')+DriveNum)+':'),MB_ICONINFORMATION)
  else
    MessageBox(0,'Tray closed',PChar('Drive '+Char(Ord('A')+DriveNum)+':'),MB_ICONINFORMATION);
end.
Regards
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48012
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

Unfortunately I have had mixed results with ioctl calls, it really depends on the driver and hardware. I'm using some calls to check whether a medium is in the drive or not when using HideRemovableNoMedia options. But I had to disable this because some users had complete lockups or long delays when this was enabled. The functions I use with CDCloseDoor have worked for many years. I prefer not to change them. The user can just set CdCloseDoor=0 if he doesn't need this function.
Author of Total Commander
https://www.ghisler.com
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

Ok, thanks for your explanation.

Maybe it would be good to move this thread to the English forum?

Regards
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48012
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

Or to suggestions?
Author of Total Commander
https://www.ghisler.com
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

Well, both places are good, but I suppose that most of the users read just English forum, not the Suggestions forum - so English forum might be a better place to find a solution for a slow CD/DVD response.
Post Reply