/* ** 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 ); }