/*
** Command & Conquer Generals Zero Hour(tm)
** Copyright 2025 Electronic Arts Inc.
**
** 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 3 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, see .
*/
/***********************************************************************************************
*** C O N F I D E N T I A L --- W E S T W O O D S T U D I O S ***
***********************************************************************************************
* *
* Project Name : Command & Conquer *
* *
* $Archive:: /Renegade Setup/Autorun/CDCNTRL.CPP $*
* *
* $Author:: Maria_l $*
* *
* $Modtime:: 10/18/01 5:33p $*
* *
* $Revision:: 5 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* *
* CDControlClass::Auto_Eject_Volume -- Eject the removable media *
* CDControlClass::Auto_Eject_Volume_95 -- Eject the specified CD drive *
* CDControlClass::CDControlClass -- Class constructor *
* CDControlClass::Close_Removable_Volume -- Close the handle to a removable volume *
* CDControlClass::Close_VWin32 -- Closes the handle opened by Open_VWin32. *
* CDControlClass::Dismount_Volume -- Dismount the given volume *
* CDControlClass::Eject_CD -- Force the CD drive to eject *
* CDControlClass::Eject_CD_Win95 -- Eject the cd in the given drive *
* CDControlClass::Force_CD_Eject -- Ppen the CD tray on the given drive *
* CDControlClass::Lock_CD_Drive -- Lock the CD tray and prevent ejection *
* CDControlClass::Lock_CD_Drive_95 -- Prevent the user from ejecting the cd in the given driv*
* CDControlClass::Lock_CD_Tray -- Prevent CD ejection on the specified drive *
* CDControlClass::Lock_Logical_Volume -- Take a lock on a logical volume *
* CDControlClass::Lock_Volume -- Prevent access by other threads to a given volume *
* CDControlClass::Lock_Volume_95 -- Locks removable media so that it can't be ejected *
* CDControlClass::Open_Removable_Volume -- Fetch a handle to a removable drive *
* CDControlClass::Open_VWin32 -- Opens a handle to VWIN32 to issue low-level disk I/O *
* CDControlClass::Prevent_Removal_Of_Volume -- Disable the eject button on the given drive *
* CDControlClass::Unlock_CD_Drive -- Unlock the CD tray and allow ejection *
* CDControlClass::Unlock_CD_Drive_95 -- Allow the user to eject the cd in the given drive *
* CDControlClass::Unlock_CD_Tray -- Allow CD ejection on the specified drive *
* CDControlClass::Unlock_Logical_Volume -- Unlocks a logical volume *
* CDControlClass::Unlock_Volume -- Allow access by other threads to a given volume *
* CDControlClass::Unlock_Volume_95 -- Unlocks removable media so that it can be ejected *
* CDControlClass::~CDControlClass -- Class destructor *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "assert.h"
#include "cdcntrl.h"
#include "winfix.h"
#include "wnd_file.h"
#pragma warning(disable : 4201)
#include
#include
#include
CDControlClass CDControl;
void Last_Error_Text ( LPTSTR szPrefix, HRESULT hr );
/***********************************************************************************************
* CDControlClass::CDControlClass -- Class constructor *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/17/99 2:03AM ST : Created *
*=============================================================================================*/
CDControlClass::CDControlClass(void)
{
}
/***********************************************************************************************
* CDControlClass::~CDControlClass -- Class destructor *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/17/99 2:03AM ST : Created *
*=============================================================================================*/
CDControlClass::~CDControlClass(void)
{
}
/***********************************************************************************************
* CDControlClass::Force_CD_Eject -- Ppen the CD tray on the given drive *
* *
* INPUT: Drive number (0=a, 1=b etc) *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/17/99 1:17AM ST : Created *
*=============================================================================================*/
void CDControlClass::Force_CD_Eject(int drive)
{
if ( WinVersion.Is_Win9x() ) {
Eject_CD_Win95(drive);
}else{
Eject_CD(drive);
}
}
/***********************************************************************************************
* CDControlClass::Lock_CD_Tray -- Prevent CD ejection on the specified drive *
* *
* INPUT: drive number (0=a: etc) *
* *
* OUTPUT: true if locked *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/17/99 1:56AM ST : Created *
*=============================================================================================*/
bool CDControlClass::Lock_CD_Tray (int drive)
{
if ( WinVersion.Is_Win9x() ) {
return (Lock_CD_Drive_95(drive));
}else{
return (Lock_CD_Drive(drive));
}
}
/***********************************************************************************************
* CDControlClass::Unlock_CD_Tray -- Allow CD ejection on the specified drive *
* *
* INPUT: drive number (0=a: etc) *
* *
* OUTPUT: true if unlocked OK *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/17/99 1:57AM ST : Created *
*=============================================================================================*/
bool CDControlClass::Unlock_CD_Tray (int drive)
{
if ( WinVersion.Is_Win9x() ) {
return (Unlock_CD_Drive_95(drive));
}else{
return (Unlock_CD_Drive(drive));
}
}
/***********************************************************************************************
* CDControlClass::Open_Removable_Volume -- Fetch a handle to a removable drive *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/16/99 11:25PM ST : Created *
*=============================================================================================*/
HANDLE CDControlClass::Open_Removable_Volume( char drive )
{
assert (WinVersion.Is_WinNT());
HANDLE volume;
unsigned drivetype;
char volume_name[8];
char rootname[5];
unsigned long access_flags;
/*----------------------------------------------------------------------------------------
** Get the drive type to ensure that this is a removable volume.
*/
_stprintf (rootname, _TEXT( "%c:\\" ), drive + 'A');
drivetype = GetDriveType( rootname );
switch( drivetype ) {
case DRIVE_REMOVABLE:
access_flags = GENERIC_READ | GENERIC_WRITE;
break;
case DRIVE_CDROM:
access_flags = GENERIC_READ;
break;
default:
// DebugString ("Attempt to open non-removable volume for locking or ejection\n");
Msg( __LINE__, TEXT(__FILE__), TEXT("Attempt to open non-removable volume for locking or ejection" ));
return( INVALID_HANDLE_VALUE );
}
/*----------------------------------------------------------------------------------------
** Get a handle to the volume.
*/
_stprintf( volume_name, _TEXT( "\\\\.\\%c:" ), drive + 'A' );
volume = CreateFile( volume_name, access_flags, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
// assert (volume != INVALID_HANDLE_VALUE);
if ( volume == INVALID_HANDLE_VALUE ) {
// DebugString ("Unable to open drive %c: for ejection\n", drive + 'A');
Msg( __LINE__, TEXT(__FILE__), TEXT("Unable to open drive %c: for ejection"), drive + 'A' - 1 );
}
return( volume );
}
/***********************************************************************************************
* CDControlClass::Close_Removable_Volume -- Close the handle to a removable volume *
* *
* INPUT: HANDLE of volume to close *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/16/99 11:27PM ST : Created *
*=============================================================================================*/
bool CDControlClass::Close_Removable_Volume(HANDLE volume)
{
assert (WinVersion.Is_WinNT());
return ((CloseHandle(volume)) ? true : false);
}
/***********************************************************************************************
* CDControlClass::Lock_Volume -- Prevent access by other threads to a given volume *
* *
* INPUT: HANDLE to volume *
* *
* OUTPUT: true if locked *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/16/99 11:29PM ST : Created *
*=============================================================================================*/
bool CDControlClass::Lock_Volume( HANDLE volume )
{
assert( WinVersion.Is_WinNT( ));
unsigned long bytes_returned = 0;
unsigned long sleep_amount = LOCK_TIMEOUT / LOCK_RETRIES;
/*
** Do this in a loop until a timeout period has expired
*/
for ( int trycount = 0; trycount < LOCK_RETRIES; trycount++ ) {
if ( DeviceIoControl( volume, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &bytes_returned, NULL )) {
return( true );
}
// Msg( __LINE__, TEXT(__FILE__), TEXT("DeviceIoControl failed to lock volume. Error %d - %s"), GetLastError(), Last_Error_Text());
Last_Error_Text( _TEXT( "DeviceIoControl failed to lock volume." ), GetLastError());
// Sleep( sleep_amount );
Sleep( LOCK_TIMEOUT );
}
return( false );
}
/***********************************************************************************************
* CDControlClass::Unlock_Volume -- Allow access by other threads to a given volume *
* *
* INPUT: HANDLE to volume *
* *
* OUTPUT: true if unlocked *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/16/99 11:29PM ST : Created *
*=============================================================================================*/
bool CDControlClass::Unlock_Volume(HANDLE volume)
{
assert( WinVersion.Is_WinNT());
unsigned long bytes_returned;
unsigned long sleep_amount = LOCK_TIMEOUT / LOCK_RETRIES;
/*
** Do this in a loop until a timeout period has expired
*/
for ( int trycount = 0; trycount < LOCK_RETRIES; trycount++ ) {
if ( DeviceIoControl( volume, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &bytes_returned, NULL )) return( true );
// DebugString ("DeviceIoControl failed to unlock volume. Error %d - %s\n", GetLastError(), Last_Error_Text());
// Msg( __LINE__, __FILE__, "DeviceIoControl failed to unlock volume. Error %d - %s", GetLastError(), Last_Error_Text());
Last_Error_Text( _TEXT( "DeviceIoControl failed to unlock volume." ), GetLastError());
// Sleep( sleep_amount );
Sleep( LOCK_TIMEOUT );
}
return( false );
}
/***********************************************************************************************
* CDControlClass::Dismount_Volume -- Dismount the given volume *
* *
* INPUT: HANDLE of volume to dismount *
* *
* OUTPUT: true if volume dismounted OK *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/16/99 11:31PM ST : Created *
*=============================================================================================*/
bool CDControlClass::Dismount_Volume(HANDLE volume)
{
assert( WinVersion.Is_WinNT());
unsigned long bytes_returned;
bool result = ((DeviceIoControl( volume, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &bytes_returned, NULL)) ? true : false );
if (result == false) {
// DebugString ("DeviceIoControl failed to dismount volume. Error %d - %s\n", GetLastError(), Last_Error_Text());
// Msg( __LINE__, __FILE__, "DeviceIoControl failed to dismount volume. Error %d - %s", GetLastError(), Last_Error_Text());
Last_Error_Text( _TEXT( "DeviceIoControl failed to dismount volume." ), GetLastError());
}
return( result );
}
/***********************************************************************************************
* CDControlClass::Prevent_Removal_Of_Volume -- Disable the eject button on the given drive *
* *
* INPUT: HANDLE of volume to enable/disable *
* true to prevent removal. false to allow it. *
* *
* OUTPUT: true if status changed OK *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/16/99 11:32PM ST : Created *
*=============================================================================================*/
bool CDControlClass::Prevent_Removal_Of_Volume( HANDLE volume, bool prevent )
{
assert( WinVersion.Is_WinNT());
unsigned long bytes_returned;
PREVENT_MEDIA_REMOVAL pmrbuffer;
pmrbuffer.PreventMediaRemoval = prevent;
bool result = ((DeviceIoControl( volume, IOCTL_STORAGE_MEDIA_REMOVAL, &pmrbuffer, sizeof(PREVENT_MEDIA_REMOVAL), NULL, 0, &bytes_returned, NULL)) ? true : false);
if (result == false) {
// DebugString ("DeviceIoControl failed to prevent media removal. Error %d - %s\n", GetLastError(), Last_Error_Text());
// Msg( __LINE__, __FILE__, "DeviceIoControl failed to prevent media removal. Error %d - %s", GetLastError(), Last_Error_Text());
Last_Error_Text( _TEXT( "DeviceIoControl failed to prevent media removal." ), GetLastError());
}
return( result );
}
/***********************************************************************************************
* CDControlClass::Auto_Eject_Volume -- Eject the removable media *
* *
* INPUT: HANDLE of volume to eject *
* *
* OUTPUT: true if ejection occured *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/16/99 11:34PM ST : Created *
*=============================================================================================*/
bool CDControlClass::Auto_Eject_Volume(HANDLE volume)
{
assert (WinVersion.Is_WinNT());
unsigned long bytes_returned;
bool result = ((DeviceIoControl( volume, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &bytes_returned, NULL)) ? true : false);
if (result == false) {
// DebugString ("DeviceIoControl failed to eject media. Error %d - %s\n", GetLastError(), Last_Error_Text());
// Msg( __LINE__, __FILE__, "DeviceIoControl failed to eject media. Error %d - %s", GetLastError(), Last_Error_Text());
Last_Error_Text( TEXT("DeviceIoControl failed to eject media."), GetLastError());
}
return (result);
}
/***********************************************************************************************
* CDControlClass::Eject_CD -- Force the CD drive to eject *
* *
* INPUT: drive number *
* *
* OUTPUT: true if ejected *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/16/99 11:35PM ST : Created *
*=============================================================================================*/
bool CDControlClass::Eject_CD(char drive)
{
assert (WinVersion.Is_WinNT());
HANDLE volume;
bool ejected = false;
volume = Open_Removable_Volume(drive);
if (volume == INVALID_HANDLE_VALUE) return (false);
/*
** Lock and dismount the volume.
*/
if (Lock_Volume(volume) && Dismount_Volume(volume)) {
/*
** Set prevent removal to false and eject the volume.
*/
if (Prevent_Removal_Of_Volume(volume, false) && Auto_Eject_Volume(volume)) {
ejected = true;
}
}
/*
** Close the volume so other processes can use the drive.
*/
Close_Removable_Volume(volume);
return (ejected);
}
/***********************************************************************************************
* CDControlClass::Lock_CD_Drive -- Lock the CD tray and prevent ejection *
* *
* INPUT: drive number *
* *
* OUTPUT: true if locked *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/17/99 0:11AM ST : Created *
*=============================================================================================*/
bool CDControlClass::Lock_CD_Drive(char drive)
{
assert (WinVersion.Is_WinNT());
HANDLE volume;
bool retval = false;
volume = Open_Removable_Volume(drive);
if (volume == INVALID_HANDLE_VALUE) return (false);
/*
** Lock the volume.
*/
if (Lock_Volume(volume)) {
/*
** Set prevent removal to false
*/
if (Prevent_Removal_Of_Volume(volume, true)) {
retval = true;
}
}
/*
** Close the volume so other processes can use the drive.
*/
Unlock_Volume(volume);
Close_Removable_Volume(volume);
return (true);
}
/***********************************************************************************************
* CDControlClass::Unlock_CD_Drive -- Unlock the CD tray and allow ejection *
* *
* INPUT: drive number *
* *
* OUTPUT: true if unlocked *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/17/99 0:11AM ST : Created *
*=============================================================================================*/
bool CDControlClass::Unlock_CD_Drive(char drive)
{
assert (WinVersion.Is_WinNT());
HANDLE volume;
bool retval = false;
volume = Open_Removable_Volume(drive);
if (volume == INVALID_HANDLE_VALUE) return (false);
/*
** Lock the volume.
*/
if (Lock_Volume(volume)) {
/*
** Set prevent removal to false
*/
if (Prevent_Removal_Of_Volume(volume, false)) {
retval = true;
}
}
/*
** Close the volume so other processes can use the drive.
*/
Unlock_Volume(volume);
Close_Removable_Volume(volume);
return (true);
}
/***********************************************************************************************
* CDControlClass::Eject_CD_Win95 -- Eject the cd in the given drive *
* *
* INPUT: drive. 0=a etc. *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/17/99 1:04AM ST : Created *
*=============================================================================================*/
void CDControlClass::Eject_CD_Win95 (char drive)
{
assert (WinVersion.Is_Win9x());
HANDLE vwin32 = INVALID_HANDLE_VALUE;
drive++;
vwin32 = Open_VWin32 ();
assert (vwin32 != INVALID_HANDLE_VALUE);
/*
** Make sure no other applications are using the drive.
*/
bool drive_locked = Lock_Logical_Volume (vwin32, drive, 0, 0);
// assert (drive_locked);
if (!drive_locked) {
// DebugString("Unable to lock volume %c:\n", 'A' + drive - 1);
Msg( __LINE__, TEXT(__FILE__), TEXT("Unable to lock volume %c: "), 'A' + drive - 1 );
return;
}
/*
** Make sure there is no software lock keeping the media in the drive.
*/
if (!Unlock_Volume_95 (vwin32, drive)) {
// DebugString("Could not unlock media from drive %c:\n", 'A' + drive - 1);
Msg( __LINE__, TEXT(__FILE__), TEXT("Could not unlock media from drive %c: "), 'A' + drive - 1 );
Unlock_Logical_Volume (vwin32, drive);
return;
}
/*
** Eject!
*/
if (!Auto_Eject_Volume_95 (vwin32, drive)) {
// DebugString("Could not eject media from drive %c:\n", 'A' + drive - 1);
Msg( __LINE__, TEXT(__FILE__), TEXT("Could not eject media from drive %c: "), 'A' + drive - 1 );
}
Unlock_Logical_Volume (vwin32, drive);
Close_VWin32 (vwin32);
}
/***********************************************************************************************
* CDControlClass::Lock_CD_Drive_95 -- Prevent the user from ejecting the cd in the given drive*
* *
* INPUT: drive. 0=a etc. *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/17/99 1:04AM ST : Created *
*=============================================================================================*/
bool CDControlClass::Lock_CD_Drive_95 (char drive)
{
// DebugString ("CDControlClass::Lock_CD_Drive_95\n");
Msg( __LINE__, TEXT(__FILE__), TEXT("CDControlClass::Lock_CD_Drive_95." ));
bool retval = true;
assert (WinVersion.Is_Win9x());
HANDLE vwin32 = INVALID_HANDLE_VALUE;
// DebugString ("Preventing ejection on CD drive %c\n", drive + 'A');
Msg( __LINE__, TEXT(__FILE__), TEXT("Preventing ejection on CD drive %c: "), 'A' + drive -1 );
drive++;
vwin32 = Open_VWin32();
assert (vwin32 != INVALID_HANDLE_VALUE);
/*
** Make sure no other applications are using the drive.
*/
// DebugString ("About to lock logical volume to enable exclusive access\n");
Msg( __LINE__, TEXT(__FILE__), TEXT("About to lock logical volume to enable exclusive access." ));
bool drive_locked = Lock_Logical_Volume (vwin32, drive, 0, 0);
// assert (drive_locked);
if (!drive_locked) {
// DebugString("Unable to lock volume %c:\n", 'A' + drive - 1);
Msg( __LINE__, TEXT(__FILE__), TEXT("Unable to lock volume %c:"), 'A' + drive - 1 );
return(false);
}
// DebugString ("Volume locked OK\n");
Msg( __LINE__, TEXT(__FILE__), TEXT("Volume locked OK." ));
/*
** Lock the tray in the closed position.
*/
// DebugString ("About to prevent CD tray ejection\n");
Msg( __LINE__, TEXT(__FILE__), TEXT("About to prevent CD tray ejection." ));
if (!Lock_Volume_95 (vwin32, drive)) {
// DebugString("Could not lock CD tray in drive %c:\n", 'A' + drive - 1);
Msg( __LINE__, TEXT(__FILE__), TEXT("Could not lock CD tray in drive %c:"), 'A' + drive - 1 );
retval = false;
}else{
// DebugString ("CD tray ejection disabled OK\n");
Msg( __LINE__, TEXT(__FILE__), TEXT("CD tray ejection disabled OK." ));
}
Unlock_Logical_Volume (vwin32, drive);
Close_VWin32 (vwin32);
// DebugString ("CDControlClass::Lock_CD_Drive_95 returning %s\n", retval ? "true" : "false");
Msg( __LINE__, TEXT(__FILE__), TEXT("CDControlClass::Lock_CD_Drive_95 returning %s."), retval ? "true" : "false" );
return (retval);
}
/***********************************************************************************************
* CDControlClass::Unlock_CD_Drive_95 -- Allow the user to eject the cd in the given drive *
* *
* INPUT: drive. 0=a etc. *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/17/99 1:04AM ST : Created *
*=============================================================================================*/
bool CDControlClass::Unlock_CD_Drive_95 (char drive)
{
// DebugString ("CDControlClass::Unlock_CD_Drive_95\n");
Msg( __LINE__, TEXT(__FILE__), TEXT("CDControlClass::Unlock_CD_Drive_95 returning %s." ));
bool retval = true;
assert (WinVersion.Is_Win9x());
HANDLE vwin32 = INVALID_HANDLE_VALUE;
// DebugString ("Allowing ejection on CD drive %c\n", drive + 'A');
Msg( __LINE__, TEXT(__FILE__), TEXT("Allowing ejection on CD drive %c."), drive + 'A' - 1 );
drive++;
vwin32 = Open_VWin32();
assert (vwin32 != INVALID_HANDLE_VALUE);
/*
** Make sure no other applications are using the drive.
*/
// DebugString ("About to lock logical volume to enable exclusive access\n");
Msg( __LINE__, TEXT(__FILE__), TEXT("About to lock logical volume to enable exclusive access." ));
bool drive_locked = Lock_Logical_Volume (vwin32, drive, 0, 0);
// assert (drive_locked);
if (!drive_locked) {
// DebugString("Unable to lock volume %c:\n", 'A' + drive - 1);
Msg( __LINE__, TEXT(__FILE__), TEXT("Unable to lock volume %c:."), 'A' + drive - 1 );
return(false);
}
// DebugString ("Volume locked OK\n");
Msg( __LINE__, TEXT(__FILE__), TEXT("Volume locked OK." ));
/*
** Unlock the tray to allow ejection.
*/
// DebugString ("About to allow CD tray ejection\n");
Msg( __LINE__, TEXT(__FILE__), TEXT("About to allow CD tray ejection." ));
if (!Unlock_Volume_95 (vwin32, drive)) {
// DebugString("Could not unlock CD tray in drive %c:\n", 'A' + drive - 1);
Msg( __LINE__, TEXT(__FILE__), TEXT("Could not unlock CD tray in drive %c:"), 'A' + drive - 1 );
retval = false;
}else{
// DebugString ("CD tray ejection enabled OK\n");
Msg( __LINE__, TEXT(__FILE__), TEXT("CD tray ejection enabled OK." ));
}
Unlock_Logical_Volume (vwin32, drive);
Close_VWin32 (vwin32);
// DebugString ("CDControlClass::Unlock_CD_Drive_95 returning %s\n", retval ? "true" : "false");
Msg( __LINE__, TEXT(__FILE__), TEXT("CDControlClass::Unlock_CD_Drive_95 returning %s."), retval ? "true" : "false" );
return (retval);
}
/***********************************************************************************************
* CDControlClass::Unlock_Volume_95 -- Unlocks removable media so that it can be ejected *
* *
* INPUT: Handle to VWIN32 *
* drive to unlock (DOS format) *
* *
* OUTPUT: true if unlocked *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/17/99 0:19AM ST : Created *
*=============================================================================================*/
bool CDControlClass::Unlock_Volume_95 (HANDLE vwin32, char drive)
{
assert (WinVersion.Is_Win9x());
DIOC_REGISTERS regs = {0};
PARAMBLOCK unlock_params = {0};
bool result;
unsigned long cb;
/*
** First, check the lock status. This way, we'll know the number of pending locks we must unlock.
*/
unlock_params.bOperation = 2; // return lock/unlock status
regs.reg_EAX = 0x440D;
regs.reg_EBX = drive;
regs.reg_ECX = MAKEWORD(0x48, 0x08);
regs.reg_EDX = (unsigned long)&unlock_params;
result = (DeviceIoControl (vwin32, VWIN32_DIOC_DOS_IOCTL, ®s, sizeof(regs), ®s, sizeof(regs), &cb, 0)) ? true : false;
if (result) {
/*
** DeviceIoControl succeeded. Now see if the unlock succeeded. It
** succeeded if the carry flag is not set, or if the carry flag is
** set but EAX is 0x01 or 0xB0.
**
** It failed if the carry flag is set and EAX is not 0x01 or 0xB0.
**
** If the carry flag is clear, then unlock succeeded. However, you
** don't need to set fResult because it is already TRUE when you get
** in here.
*/
if (regs.reg_Flags & CARRY_FLAG) {
result = (regs.reg_EAX == 0xB0) || (regs.reg_EAX == 0x01);
}
} else {
// DebugString ("DeviceIoControl failed to perform DOS IO control function. Error %d - %s\n", GetLastError(), Last_Error_Text());
// Msg( __LINE__, __FILE__, "DeviceIoControl failed to perform DOS IO control function. Error %d - %s.", GetLastError(), Last_Error_Text() );
Last_Error_Text( TEXT("DeviceIoControl failed to perform DOS IO control function.."), GetLastError());
}
if (!result) return (false);
/*
** Now we have to unlock the media for every time it was locked. This gets us a lock count of
** 0 and totally unlocked media.
*/
for (int i = 0; i < unlock_params.bNumLocks; ++i) {
unlock_params.bOperation = 1; // unlock the media
regs.reg_EAX = 0x440D;
regs.reg_EBX = drive;
regs.reg_ECX = MAKEWORD(0x48, 0x08); // LOCK/UNLOCK
regs.reg_EDX = (unsigned long)&unlock_params;
result = (DeviceIoControl (vwin32, VWIN32_DIOC_DOS_IOCTL, ®s, sizeof(regs), ®s, sizeof(regs), &cb, 0)) ? true : false;
if (result == false) {
// DebugString ("DeviceIoControl failed to perform DOS IO control function. Error %d - %s\n", GetLastError(), Last_Error_Text());
// Msg( __LINE__, __FILE__, "DeviceIoControl failed to perform DOS IO control function. Error %d - %s.", GetLastError(), Last_Error_Text() );
Last_Error_Text( TEXT("DeviceIoControl failed to perform DOS IO control function.."), GetLastError());
}
/*
** See if DeviceIoControl and the lock succeeded
*/
result = result && !(regs.reg_Flags & CARRY_FLAG);
if (!result) break;
}
return (result);
}
/***********************************************************************************************
* CDControlClass::Lock_Volume_95 -- Locks removable media so that it can't be ejected *
* *
* INPUT: Handle to VWIN32 *
* drive to lock (DOS format) *
* *
* OUTPUT: true if unlocked *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/17/99 0:19AM ST : Created *
*=============================================================================================*/
bool CDControlClass::Lock_Volume_95 (HANDLE vwin32, char drive)
{
assert (WinVersion.Is_Win9x());
DIOC_REGISTERS regs = {0};
PARAMBLOCK unlock_params = {0};
bool result;
unsigned long cb;
/*
** Bring the lock count down to 0.
*/
Unlock_Volume_95(vwin32, drive);
/*
** Increment the lock count.
*/
unlock_params.bOperation = 0; // lock the media
regs.reg_EAX = 0x440D;
regs.reg_EBX = drive;
regs.reg_ECX = MAKEWORD(0x48, 0x08); // LOCK/UNLOCK
regs.reg_EDX = (unsigned long)&unlock_params;
result = (DeviceIoControl (vwin32, VWIN32_DIOC_DOS_IOCTL, ®s, sizeof(regs), ®s, sizeof(regs), &cb, 0)) ? true : false;
if (result == false) {
// DebugString ("DeviceIoControl failed to perform DOS IO control function. Error %d - %s\n", GetLastError(), Last_Error_Text());
// Msg( __LINE__, __FILE__, "DeviceIoControl failed to perform DOS IO control function. Error %d - %s.", GetLastError(), Last_Error_Text() );
Last_Error_Text( TEXT("DeviceIoControl failed to perform DOS IO control function."), GetLastError());
}
/*
** See if DeviceIoControl and the lock succeeded
*/
result = result && !(regs.reg_Flags & CARRY_FLAG);
return (result);
}
/***********************************************************************************************
* CDControlClass::Auto_Eject_Volume_95 -- Eject the specified CD drive *
* *
* INPUT: Handle to VWIN32 *
* Drive number (DOS format) *
* *
* OUTPUT: True if ejected *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/17/99 0:24AM ST : Created *
*=============================================================================================*/
bool CDControlClass::Auto_Eject_Volume_95 (HANDLE vwin32, char drive)
{
assert (WinVersion.Is_Win9x());
DIOC_REGISTERS regs = {0};
bool result;
unsigned long cb;
regs.reg_EAX = 0x440D;
regs.reg_EBX = drive;
regs.reg_ECX = MAKEWORD(0x49, 0x08); //EJECT
result = (DeviceIoControl (vwin32, VWIN32_DIOC_DOS_IOCTL, ®s, sizeof(regs), ®s, sizeof(regs), &cb, 0)) ? true : false;
if (result == false) {
// DebugString ("DeviceIoControl failed to perform DOS IO control function. Error %d - %s\n", GetLastError(), Last_Error_Text());
// Msg( __LINE__, __FILE__, "DeviceIoControl failed to perform DOS IO control function. Error %d - %s.", GetLastError(), Last_Error_Text() );
Last_Error_Text( TEXT("DeviceIoControl failed to perform DOS IO control function."), GetLastError());
}
/*
** See if we ejected OK
*/
result = result && !(regs.reg_Flags & CARRY_FLAG);
return (result);
}
/***********************************************************************************************
* CDControlClass::Open_VWin32 -- Opens a handle to VWIN32 to issue low-level disk I/O *
* *
* INPUT: Nothing *
* *
* OUTPUT: HANDLE to VWin32 *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/17/99 0:26AM ST : Created *
*=============================================================================================*/
HANDLE WINAPI CDControlClass::Open_VWin32 (void)
{
assert (WinVersion.Is_Win9x());
HANDLE result = CreateFile ( TEXT("\\\\.\\vwin32"), 0, 0, NULL, 0, FILE_FLAG_DELETE_ON_CLOSE, NULL);
assert (result != INVALID_HANDLE_VALUE);
return (result);
}
/***********************************************************************************************
* CDControlClass::Close_VWin32 -- Closes the handle opened by Open_VWin32. *
* *
* INPUT: Handle to VWin32 *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/17/99 0:26AM ST : Created *
*=============================================================================================*/
bool WINAPI CDControlClass::Close_VWin32 (HANDLE vwin32)
{
assert (WinVersion.Is_Win9x());
return ((CloseHandle (vwin32)) ? true : false);
}
/***********************************************************************************************
* CDControlClass::Lock_Logical_Volume -- Take a lock on a logical volume *
* *
* INPUT: Handle to VWin32 *
* drive number (DOS format) *
* lock level *
* permissions *
* *
* OUTPUT: true if locked *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 2/17/99 0:33AM ST : Created *
*=============================================================================================*/
bool WINAPI CDControlClass::Lock_Logical_Volume (HANDLE vwin32, char drive, char lock_level, short permissions)
{
assert (WinVersion.Is_Win9x());
bool result;
DIOC_REGISTERS regs = {0};
char device_cat; // can be either 0x48 or 0x08
unsigned long cb;
/*
** lock_level
** Can be 0, 1, 2, or 3. Level 0 is an exclusive lock that can only
** be taken when there are no open files on the specified drive.
** Levels 1 through 3 form a hierarchy where 1 must be taken before
** 2, which must be taken before 3.
**
** permissions
** Specifies how the lock will affect file operations when lock levels
** 1 through 3 are taken. Also specifies whether a formatting lock
** should be taken after a level 0 lock.
*/
/*
** Try first with device category 0x48 for FAT32 volumes. If it
** doesn't work, try again with device category 0x08. If that
** doesn't work, then the lock failed.
*/
device_cat = 0;
do {
if (device_cat == 0) {
device_cat = 0x48;
}else{
device_cat = 0x08;
}
/*
** Set up the parameters for the call.
*/
regs.reg_EAX = 0x440D;
regs.reg_EBX = MAKEWORD(drive, lock_level);
regs.reg_ECX = MAKEWORD(0x4A, device_cat);
regs.reg_EDX = permissions;
result = (DeviceIoControl (vwin32, VWIN32_DIOC_DOS_IOCTL, ®s, sizeof(regs), ®s, sizeof(regs), &cb, 0)) ? true : false;
if (result == false) {
// DebugString ("DeviceIoControl failed to perform DOS IO control function. Error %d - %s\n", GetLastError(), Last_Error_Text());
// Msg( __LINE__, __FILE__, "DeviceIoControl failed to perform DOS IO control function. Error %d - %s.", GetLastError(), Last_Error_Text() );
Last_Error_Text( TEXT("DeviceIoControl failed to perform DOS IO control function."), GetLastError());
}
result = result && !(regs.reg_Flags & CARRY_FLAG);
} while (result == false && device_cat != 0x08);
return (result);
}
/***********************************************************************************************
* CDControlClass::Unlock_Logical_Volume -- Unlocks a logical volume *
* *
* INPUT: Handle to VWin32 *
* drive number (DOS format) *
* *
* OUTPUT: true if unlocked *
* *
* WARNINGS: None *
* *
* Must be called the same number of times as LockLogicalVolume() to *
* completely unlock a volume. *
* *
* Only the lock owner can unlock a volume. *
* *
* HISTORY: *
* 2/17/99 0:39AM ST : Created *
*=============================================================================================*/
bool WINAPI CDControlClass::Unlock_Logical_Volume (HANDLE vwin32, char drive)
{
assert (WinVersion.Is_Win9x());
bool result;
DIOC_REGISTERS regs = {0};
char device_cat; // can be either 0x48 or 0x08
unsigned long cb;
/*
** Try first with device category 0x48 for FAT32 volumes. If it
** doesn't work, try again with device category 0x08. If that
** doesn't work, then the unlock failed.
*/
device_cat = 0;
do {
if (device_cat == 0) {
device_cat = 0x48;
}else{
device_cat = 0x08;
}
/*
** Set up the parameters for the call.
*/
regs.reg_EAX = 0x440D;
regs.reg_EBX = drive;
regs.reg_ECX = MAKEWORD(0x6A, device_cat);
result = (DeviceIoControl (vwin32, VWIN32_DIOC_DOS_IOCTL, ®s, sizeof(regs), ®s, sizeof(regs), &cb, 0)) ? true : false;
if (result == false) {
// DebugString ("DeviceIoControl failed to perform DOS IO control function. Error %d - %s\n", GetLastError(), Last_Error_Text());
// Msg( __LINE__, __FILE__, "DeviceIoControl failed to perform DOS IO control function. Error %d - %s.", GetLastError(), Last_Error_Text());
Last_Error_Text( TEXT("DeviceIoControl failed to perform DOS IO control function."), GetLastError());
}
result = result && !(regs.reg_Flags & CARRY_FLAG);
} while (result == false && device_cat != 0x08);
return (result);
}
/************************************************************************************************
* Last_Error_Text -- Display error messages based on FormatMessage() and GetLastError(). *
* *
* INPUT: LPSTR - title. *
* HRESULT - last error message. *
* *
* OUTPUT: None *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 6/24/99 4:44PM MML : Created *
*==============================================================================================*/
void Last_Error_Text ( LPTSTR szPrefix, HRESULT hr )
{
LPVOID szMessage;
char szDisplay[1000];
if ( hr == S_OK ) {
_stprintf( szDisplay, TEXT("%s"), szPrefix );
// MessageBox( NULL, szDisplay, TEXT("Msg"),0 );
return;
}
if ( HRESULT_FACILITY( hr ) == FACILITY_WIN32 ) {
hr = HRESULT_CODE( hr );
}
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
NULL,
hr,
MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
(LPTSTR)&szMessage,
0,
NULL );
_stprintf( szDisplay, TEXT( "%s: %s(%lx)" ), szPrefix, szMessage, hr );
Msg( __LINE__, TEXT(__FILE__), TEXT("GetLastError: %s"), szDisplay );
// MessageBox( NULL, szDisplay, TEXT( "GetLastError" ), MB_OK );
LocalFree( szMessage );
}