📄 main.cpp
字号:
/*
CD-ROM Tool - Allows you to set the read speed and spindown time
time of a CD-ROM drive.
Copyright (C) 1999-2000 Jesse Carroll
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
//---------------------------------------------------------------------------
#include <vcl.h>
#include "registry.hpp"
#include "main.h"
#include "aboutcode.h"
#include "splashcode.h"
#include <stdio.h>
#pragma hdrstop
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
//-----defines for SCSI commands------------------
#define SCSI_SETSPEED 0xBB
#define SCSI_INQUIRY 0x12
#define SCSI_MODESENSE 0x5A
#define SCSI_MODESELECT 0x55
//-----SCSI device type define------------------
#define DTYPE_CDROM 0x05
#define STATUS_CHKCOND 0x02
//according to the ASPI docs, a host adapter can support up to 16 targets
#define MAX_SCSI_TARGETS 16
//transfer rate in kilobytes of the 1x CD-ROM read speed
#define X1 176
//Causes debug info to be written to c:\\cdromtool.txt if set to true
//In the Main Window's OnCreate event, this is set to true if the
// command line was "-debug" or shift is held when the program is run.
// It is otherwise set to false.
bool LOG;
//the handle for the ASPI32 DLL
HMODULE ASPIDLL;
//used to store the proc addresses of the ASPI DLL functions
DWORD (*gpfnGetASPI32SupportInfo)( VOID );
DWORD (*gpfnSendASPI32Command)( LPSRB );
//variable to make the command line globally available
extern AnsiString CommandLineGlobal;
TMainWindow *MainWindow;
//---------------------------------------------------------------------------
__fastcall TMainWindow::TMainWindow(TComponent* Owner)
: TForm(Owner)
{
}
//-------------------------------------------------------
//simple function that checks to see if a key is pressed
//-------------------------------------------------------
inline bool isKeyDown( int keycode )
{
if( (GetAsyncKeyState(keycode) & 0x8000) == 0x8000 )
return TRUE;
else
return FALSE;
}
//----------------------------------------------------
//simple function that appends text to a log file
//----------------------------------------------------
inline void log(char *string)
{
if( LOG )
{
FILE *fp=fopen("c:\\cdromtool.txt", "a+");
fprintf( fp, "%s\n", string);
fclose( fp );
}
}
//----------------------------------------------------------------------------
//Used for debugging, this dumps the entire mode pages 2A & 0D to the log file
//----------------------------------------------------------------------------
void __fastcall TMainWindow::ModeSenseDump()
{
if( LOG )
{
SRB_ExecSCSICmd s;
unsigned char b[256];
memset( &s, 0, sizeof( s ) );
memset( b, 0xFF, 256 );
s.SRB_Cmd = SC_EXEC_SCSI_CMD;
s.SRB_HaId = gbyCurrentHostAdapter;
s.SRB_Target = gbyCurrentTarget;
s.SRB_Lun = 0;
s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
s.SRB_BufLen = 256;
s.SRB_BufPointer = b;
s.SRB_CDBLen = 12;
s.CDBByte[0] = SCSI_MODESENSE;
s.CDBByte[2] = 0x2A;
s.CDBByte[7] = 0x01;
s.CDBByte[8] = 0x00;
ExecSCSICommand(&s);
log( "Mode Page 2A Dump" );
FILE *fp=fopen("c:\\cdromtool.txt", "a+");
for( int i = 0; i < 256; i++ )
fprintf( fp, "%c", b[i]);
fclose( fp );
memset( &s, 0, sizeof( s ) );
memset( b, 0xFF, 256 );
s.SRB_Cmd = SC_EXEC_SCSI_CMD;
s.SRB_HaId = gbyCurrentHostAdapter;
s.SRB_Target = gbyCurrentTarget;
s.SRB_Lun = 0;
s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
s.SRB_BufLen = 256;
s.SRB_BufPointer = b;
s.SRB_CDBLen = 12;
s.CDBByte[0] = SCSI_MODESENSE;
s.CDBByte[2] = 0x0D;
s.CDBByte[7] = 0x01;
s.CDBByte[8] = 0x00;
ExecSCSICommand(&s);
log( "Mode Page 0D Dump" );
fp=fopen("c:\\cdromtool.txt", "a+");
for( int i = 0; i < 256; i++ )
fprintf( fp, "%c", b[i]);
fclose( fp );
}
}
//---------------------------------------------------------------------------
//Executes SCSI Command specified in the structure "s"
//Returns the final SRB (SCSI request block) status
//---------------------------------------------------------------------------
BYTE __fastcall TMainWindow::ExecSCSICommand( SRB_ExecSCSICmd* s )
{
//use the event method for determining completion
HANDLE heventSRB = CreateEvent( NULL, TRUE, FALSE, NULL );
ResetEvent( heventSRB );
s->SRB_PostProc = (LPVOID)heventSRB;
//issue the command
DWORD dwStatus = gpfnSendASPI32Command( s );
//sendASPI32Command is asynchronous, so if the operation
// is still pending, wait for it to return
if ( dwStatus == SS_PENDING )
WaitForSingleObject( heventSRB, INFINITE );
CloseHandle( heventSRB );
//return the final SRB status
return s->SRB_Status;
}
//---------------------------------------------------------
//Gets the name of the drive
//Returns the final SRB (SCSI request block) status
//---------------------------------------------------------
BYTE __fastcall TMainWindow::getDriveName( BYTE hostadapter, BYTE target, char* stringbuffer )
{
SRB_ExecSCSICmd s;
BYTE buf[100];
memset( &s, 0, sizeof( s ) );
memset( buf, 0, 100 );
s.SRB_Cmd = SC_EXEC_SCSI_CMD;
s.SRB_HaId = hostadapter;
s.SRB_Target = target;
s.SRB_Lun = 0;
s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
s.SRB_BufLen = 100;
s.SRB_BufPointer = buf;
s.SRB_SenseLen = SENSE_LEN;
s.SRB_CDBLen = 6;
s.CDBByte[0] = SCSI_INQUIRY;
s.CDBByte[4] = 100;
BYTE byStatus = ExecSCSICommand(&s);
if( byStatus != SS_COMP )
log( ((AnsiString)"getDriveName returned status " +
LookupASPIStatus(byStatus) +
(AnsiString)" with HaStat " +
(AnsiString)s.SRB_HaStat +
(AnsiString)" TargStat " +
(AnsiString)s.SRB_TargStat).c_str() );
if( byStatus == SS_ERR && s.SRB_TargStat == STATUS_CHKCOND )
{
BYTE SenseKey = s.SenseArea[2] & (BYTE)15;
BYTE ASC = s.SenseArea[12];
BYTE ASCQ = s.SenseArea[13];
log( ((AnsiString)" Check Condition: Sense Key " +
(AnsiString)SenseKey +
(AnsiString)" ASC " +
(AnsiString)ASC +
(AnsiString)" ASCQ " +
(AnsiString)ASCQ).c_str() );
}
//if the command was successful
if( byStatus == SS_COMP )
{
//extract the whole string identifying the drive
for( int i = 8; i < 36; i++ )
stringbuffer[i-8] = buf[i];
//the part I wish to extract is 28 characters long
stringbuffer[28] = NULL;
}
return byStatus;
}
//---------------------------------------------------------------------------
//CD Speed Commands
//---------------------------------------------------------------------------
BYTE __fastcall TMainWindow::setCDSpeed( DWORD speed )
{
//if the requested speed is less than 1x speed (176 kb/s),
// this command *will* return an error (it's part of the
// ATAPI specs). Therefore, stop this function here if
// speed < 1x (176)
if( speed < X1 ) return 0;
SRB_ExecSCSICmd s;
memset( &s, 0, sizeof( s ) );
s.SRB_Cmd = SC_EXEC_SCSI_CMD;
s.SRB_HaId = gbyCurrentHostAdapter;
s.SRB_Target = gbyCurrentTarget;
s.SRB_Lun = 0;
s.SRB_Flags = SRB_DIR_OUT | SRB_EVENT_NOTIFY;
s.SRB_SenseLen = SENSE_LEN;
s.SRB_CDBLen = 12;
s.CDBByte[0] = SCSI_SETSPEED;
//bytes 2 & 3 represent the desired read speed
s.CDBByte[2] = (BYTE)(speed >> 8);
s.CDBByte[3] = (BYTE)speed;
//bytes 4 & 5 represent the desired write speed
//THIS CAUSED ME A LOT OF GRIEF - it seems that with
// some drives, YOU MUST set the write speed to a
// non-zero value, or this call will return with
// an error. This applies even if you don't want to
// change the write speed! For instance, I could get
// away with not setting these bytes when sending
// this command to my old 4x drive, but I *had* to
// put *something* in here when sending the command
// to my Creative CDRW
s.CDBByte[4] = (BYTE)(706 >> 8);
s.CDBByte[5] = (BYTE)706;
BYTE byStatus = ExecSCSICommand(&s);
if( byStatus != SS_COMP )
log( ((AnsiString)"setCDSpeed returned status " +
LookupASPIStatus(byStatus) +
(AnsiString)" with HaStat " +
(AnsiString)s.SRB_HaStat +
(AnsiString)" TargStat " +
(AnsiString)s.SRB_TargStat +
(AnsiString)" attempting " +
(AnsiString)(unsigned int)speed +
(AnsiString)" kb/s").c_str() );
if( byStatus == SS_ERR && s.SRB_TargStat == STATUS_CHKCOND )
{
BYTE SenseKey = s.SenseArea[2] & (BYTE)15;
BYTE ASC = s.SenseArea[12];
BYTE ASCQ = s.SenseArea[13];
log( ((AnsiString)" Check Condition: Sense Key " +
(AnsiString)SenseKey +
(AnsiString)" ASC " +
(AnsiString)ASC +
(AnsiString)" ASCQ " +
(AnsiString)ASCQ).c_str() );
}
return byStatus;
}
int __fastcall TMainWindow::getCDSpeed()
{
SRB_ExecSCSICmd s;
unsigned char b[256];
memset( &s, 0, sizeof( s ) );
memset( b, 0xFF, 256 );
s.SRB_Cmd = SC_EXEC_SCSI_CMD;
s.SRB_HaId = gbyCurrentHostAdapter;
s.SRB_Target = gbyCurrentTarget;
s.SRB_Lun = 0;
s.SRB_Flags = SRB_DIR_IN | SRB_EVENT_NOTIFY;
s.SRB_BufLen = 256;
s.SRB_BufPointer = b;
s.SRB_CDBLen = 12;
s.CDBByte[0] = SCSI_MODESENSE;
s.CDBByte[2] = 0x2A; //mode page 0x2A contains the speed
s.CDBByte[7] = 0x01;
s.CDBByte[8] = 0x00;
BYTE byStatus = ExecSCSICommand(&s);
if( byStatus != SS_COMP )
log( ((AnsiString)"getCDSpeed returned status " +
LookupASPIStatus(byStatus) +
(AnsiString)" with HaStat " +
(AnsiString)s.SRB_HaStat +
(AnsiString)" TargStat " +
(AnsiString)s.SRB_TargStat).c_str() );
if( byStatus == SS_ERR && s.SRB_TargStat == STATUS_CHKCOND )
{
BYTE SenseKey = s.SenseArea[2] & (BYTE)15;
BYTE ASC = s.SenseArea[12];
BYTE ASCQ = s.SenseArea[13];
log( ((AnsiString)" Check Condition: Sense Key " +
(AnsiString)SenseKey +
(AnsiString)" ASC " +
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -