CDCNTRL.CPP 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** 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 ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Command & Conquer *
  23. * *
  24. * $Archive:: /Renegade Setup/Autorun/CDCNTRL.CPP $*
  25. * *
  26. * $Author:: Maria_l $*
  27. * *
  28. * $Modtime:: 10/18/01 5:33p $*
  29. * *
  30. * $Revision:: 5 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * *
  35. * CDControlClass::Auto_Eject_Volume -- Eject the removable media *
  36. * CDControlClass::Auto_Eject_Volume_95 -- Eject the specified CD drive *
  37. * CDControlClass::CDControlClass -- Class constructor *
  38. * CDControlClass::Close_Removable_Volume -- Close the handle to a removable volume *
  39. * CDControlClass::Close_VWin32 -- Closes the handle opened by Open_VWin32. *
  40. * CDControlClass::Dismount_Volume -- Dismount the given volume *
  41. * CDControlClass::Eject_CD -- Force the CD drive to eject *
  42. * CDControlClass::Eject_CD_Win95 -- Eject the cd in the given drive *
  43. * CDControlClass::Force_CD_Eject -- Ppen the CD tray on the given drive *
  44. * CDControlClass::Lock_CD_Drive -- Lock the CD tray and prevent ejection *
  45. * CDControlClass::Lock_CD_Drive_95 -- Prevent the user from ejecting the cd in the given driv*
  46. * CDControlClass::Lock_CD_Tray -- Prevent CD ejection on the specified drive *
  47. * CDControlClass::Lock_Logical_Volume -- Take a lock on a logical volume *
  48. * CDControlClass::Lock_Volume -- Prevent access by other threads to a given volume *
  49. * CDControlClass::Lock_Volume_95 -- Locks removable media so that it can't be ejected *
  50. * CDControlClass::Open_Removable_Volume -- Fetch a handle to a removable drive *
  51. * CDControlClass::Open_VWin32 -- Opens a handle to VWIN32 to issue low-level disk I/O *
  52. * CDControlClass::Prevent_Removal_Of_Volume -- Disable the eject button on the given drive *
  53. * CDControlClass::Unlock_CD_Drive -- Unlock the CD tray and allow ejection *
  54. * CDControlClass::Unlock_CD_Drive_95 -- Allow the user to eject the cd in the given drive *
  55. * CDControlClass::Unlock_CD_Tray -- Allow CD ejection on the specified drive *
  56. * CDControlClass::Unlock_Logical_Volume -- Unlocks a logical volume *
  57. * CDControlClass::Unlock_Volume -- Allow access by other threads to a given volume *
  58. * CDControlClass::Unlock_Volume_95 -- Unlocks removable media so that it can be ejected *
  59. * CDControlClass::~CDControlClass -- Class destructor *
  60. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  61. #include "assert.h"
  62. #include "cdcntrl.h"
  63. #include "winfix.h"
  64. #include "wnd_file.h"
  65. #pragma warning(disable : 4201)
  66. #include <winioctl.h>
  67. #include <tchar.h>
  68. #include <stdio.h>
  69. CDControlClass CDControl;
  70. void Last_Error_Text ( LPTSTR szPrefix, HRESULT hr );
  71. /***********************************************************************************************
  72. * CDControlClass::CDControlClass -- Class constructor *
  73. * *
  74. * INPUT: Nothing *
  75. * *
  76. * OUTPUT: Nothing *
  77. * *
  78. * WARNINGS: None *
  79. * *
  80. * HISTORY: *
  81. * 2/17/99 2:03AM ST : Created *
  82. *=============================================================================================*/
  83. CDControlClass::CDControlClass(void)
  84. {
  85. }
  86. /***********************************************************************************************
  87. * CDControlClass::~CDControlClass -- Class destructor *
  88. * *
  89. * INPUT: Nothing *
  90. * *
  91. * OUTPUT: Nothing *
  92. * *
  93. * WARNINGS: None *
  94. * *
  95. * HISTORY: *
  96. * 2/17/99 2:03AM ST : Created *
  97. *=============================================================================================*/
  98. CDControlClass::~CDControlClass(void)
  99. {
  100. }
  101. /***********************************************************************************************
  102. * CDControlClass::Force_CD_Eject -- Ppen the CD tray on the given drive *
  103. * *
  104. * INPUT: Drive number (0=a, 1=b etc) *
  105. * *
  106. * OUTPUT: Nothing *
  107. * *
  108. * WARNINGS: None *
  109. * *
  110. * HISTORY: *
  111. * 2/17/99 1:17AM ST : Created *
  112. *=============================================================================================*/
  113. void CDControlClass::Force_CD_Eject(int drive)
  114. {
  115. if ( WinVersion.Is_Win9x() ) {
  116. Eject_CD_Win95(drive);
  117. }else{
  118. Eject_CD(drive);
  119. }
  120. }
  121. /***********************************************************************************************
  122. * CDControlClass::Lock_CD_Tray -- Prevent CD ejection on the specified drive *
  123. * *
  124. * INPUT: drive number (0=a: etc) *
  125. * *
  126. * OUTPUT: true if locked *
  127. * *
  128. * WARNINGS: None *
  129. * *
  130. * HISTORY: *
  131. * 2/17/99 1:56AM ST : Created *
  132. *=============================================================================================*/
  133. bool CDControlClass::Lock_CD_Tray (int drive)
  134. {
  135. if ( WinVersion.Is_Win9x() ) {
  136. return (Lock_CD_Drive_95(drive));
  137. }else{
  138. return (Lock_CD_Drive(drive));
  139. }
  140. }
  141. /***********************************************************************************************
  142. * CDControlClass::Unlock_CD_Tray -- Allow CD ejection on the specified drive *
  143. * *
  144. * INPUT: drive number (0=a: etc) *
  145. * *
  146. * OUTPUT: true if unlocked OK *
  147. * *
  148. * WARNINGS: None *
  149. * *
  150. * HISTORY: *
  151. * 2/17/99 1:57AM ST : Created *
  152. *=============================================================================================*/
  153. bool CDControlClass::Unlock_CD_Tray (int drive)
  154. {
  155. if ( WinVersion.Is_Win9x() ) {
  156. return (Unlock_CD_Drive_95(drive));
  157. }else{
  158. return (Unlock_CD_Drive(drive));
  159. }
  160. }
  161. /***********************************************************************************************
  162. * CDControlClass::Open_Removable_Volume -- Fetch a handle to a removable drive *
  163. * *
  164. * INPUT: Nothing *
  165. * *
  166. * OUTPUT: Nothing *
  167. * *
  168. * WARNINGS: None *
  169. * *
  170. * HISTORY: *
  171. * 2/16/99 11:25PM ST : Created *
  172. *=============================================================================================*/
  173. HANDLE CDControlClass::Open_Removable_Volume( char drive )
  174. {
  175. assert (WinVersion.Is_WinNT());
  176. HANDLE volume;
  177. unsigned drivetype;
  178. char volume_name[8];
  179. char rootname[5];
  180. unsigned long access_flags;
  181. /*----------------------------------------------------------------------------------------
  182. ** Get the drive type to ensure that this is a removable volume.
  183. */
  184. _stprintf (rootname, _TEXT( "%c:\\" ), drive + 'A');
  185. drivetype = GetDriveType( rootname );
  186. switch( drivetype ) {
  187. case DRIVE_REMOVABLE:
  188. access_flags = GENERIC_READ | GENERIC_WRITE;
  189. break;
  190. case DRIVE_CDROM:
  191. access_flags = GENERIC_READ;
  192. break;
  193. default:
  194. // DebugString ("Attempt to open non-removable volume for locking or ejection\n");
  195. Msg( __LINE__, TEXT(__FILE__), TEXT("Attempt to open non-removable volume for locking or ejection" ));
  196. return( INVALID_HANDLE_VALUE );
  197. }
  198. /*----------------------------------------------------------------------------------------
  199. ** Get a handle to the volume.
  200. */
  201. _stprintf( volume_name, _TEXT( "\\\\.\\%c:" ), drive + 'A' );
  202. volume = CreateFile( volume_name, access_flags, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL );
  203. // assert (volume != INVALID_HANDLE_VALUE);
  204. if ( volume == INVALID_HANDLE_VALUE ) {
  205. // DebugString ("Unable to open drive %c: for ejection\n", drive + 'A');
  206. Msg( __LINE__, TEXT(__FILE__), TEXT("Unable to open drive %c: for ejection"), drive + 'A' - 1 );
  207. }
  208. return( volume );
  209. }
  210. /***********************************************************************************************
  211. * CDControlClass::Close_Removable_Volume -- Close the handle to a removable volume *
  212. * *
  213. * INPUT: HANDLE of volume to close *
  214. * *
  215. * OUTPUT: Nothing *
  216. * *
  217. * WARNINGS: None *
  218. * *
  219. * HISTORY: *
  220. * 2/16/99 11:27PM ST : Created *
  221. *=============================================================================================*/
  222. bool CDControlClass::Close_Removable_Volume(HANDLE volume)
  223. {
  224. assert (WinVersion.Is_WinNT());
  225. return ((CloseHandle(volume)) ? true : false);
  226. }
  227. /***********************************************************************************************
  228. * CDControlClass::Lock_Volume -- Prevent access by other threads to a given volume *
  229. * *
  230. * INPUT: HANDLE to volume *
  231. * *
  232. * OUTPUT: true if locked *
  233. * *
  234. * WARNINGS: None *
  235. * *
  236. * HISTORY: *
  237. * 2/16/99 11:29PM ST : Created *
  238. *=============================================================================================*/
  239. bool CDControlClass::Lock_Volume( HANDLE volume )
  240. {
  241. assert( WinVersion.Is_WinNT( ));
  242. unsigned long bytes_returned = 0;
  243. unsigned long sleep_amount = LOCK_TIMEOUT / LOCK_RETRIES;
  244. /*
  245. ** Do this in a loop until a timeout period has expired
  246. */
  247. for ( int trycount = 0; trycount < LOCK_RETRIES; trycount++ ) {
  248. if ( DeviceIoControl( volume, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &bytes_returned, NULL )) {
  249. return( true );
  250. }
  251. // Msg( __LINE__, TEXT(__FILE__), TEXT("DeviceIoControl failed to lock volume. Error %d - %s"), GetLastError(), Last_Error_Text());
  252. Last_Error_Text( _TEXT( "DeviceIoControl failed to lock volume." ), GetLastError());
  253. // Sleep( sleep_amount );
  254. Sleep( LOCK_TIMEOUT );
  255. }
  256. return( false );
  257. }
  258. /***********************************************************************************************
  259. * CDControlClass::Unlock_Volume -- Allow access by other threads to a given volume *
  260. * *
  261. * INPUT: HANDLE to volume *
  262. * *
  263. * OUTPUT: true if unlocked *
  264. * *
  265. * WARNINGS: None *
  266. * *
  267. * HISTORY: *
  268. * 2/16/99 11:29PM ST : Created *
  269. *=============================================================================================*/
  270. bool CDControlClass::Unlock_Volume(HANDLE volume)
  271. {
  272. assert( WinVersion.Is_WinNT());
  273. unsigned long bytes_returned;
  274. unsigned long sleep_amount = LOCK_TIMEOUT / LOCK_RETRIES;
  275. /*
  276. ** Do this in a loop until a timeout period has expired
  277. */
  278. for ( int trycount = 0; trycount < LOCK_RETRIES; trycount++ ) {
  279. if ( DeviceIoControl( volume, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &bytes_returned, NULL )) return( true );
  280. // DebugString ("DeviceIoControl failed to unlock volume. Error %d - %s\n", GetLastError(), Last_Error_Text());
  281. // Msg( __LINE__, __FILE__, "DeviceIoControl failed to unlock volume. Error %d - %s", GetLastError(), Last_Error_Text());
  282. Last_Error_Text( _TEXT( "DeviceIoControl failed to unlock volume." ), GetLastError());
  283. // Sleep( sleep_amount );
  284. Sleep( LOCK_TIMEOUT );
  285. }
  286. return( false );
  287. }
  288. /***********************************************************************************************
  289. * CDControlClass::Dismount_Volume -- Dismount the given volume *
  290. * *
  291. * INPUT: HANDLE of volume to dismount *
  292. * *
  293. * OUTPUT: true if volume dismounted OK *
  294. * *
  295. * WARNINGS: None *
  296. * *
  297. * HISTORY: *
  298. * 2/16/99 11:31PM ST : Created *
  299. *=============================================================================================*/
  300. bool CDControlClass::Dismount_Volume(HANDLE volume)
  301. {
  302. assert( WinVersion.Is_WinNT());
  303. unsigned long bytes_returned;
  304. bool result = ((DeviceIoControl( volume, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &bytes_returned, NULL)) ? true : false );
  305. if (result == false) {
  306. // DebugString ("DeviceIoControl failed to dismount volume. Error %d - %s\n", GetLastError(), Last_Error_Text());
  307. // Msg( __LINE__, __FILE__, "DeviceIoControl failed to dismount volume. Error %d - %s", GetLastError(), Last_Error_Text());
  308. Last_Error_Text( _TEXT( "DeviceIoControl failed to dismount volume." ), GetLastError());
  309. }
  310. return( result );
  311. }
  312. /***********************************************************************************************
  313. * CDControlClass::Prevent_Removal_Of_Volume -- Disable the eject button on the given drive *
  314. * *
  315. * INPUT: HANDLE of volume to enable/disable *
  316. * true to prevent removal. false to allow it. *
  317. * *
  318. * OUTPUT: true if status changed OK *
  319. * *
  320. * WARNINGS: None *
  321. * *
  322. * HISTORY: *
  323. * 2/16/99 11:32PM ST : Created *
  324. *=============================================================================================*/
  325. bool CDControlClass::Prevent_Removal_Of_Volume( HANDLE volume, bool prevent )
  326. {
  327. assert( WinVersion.Is_WinNT());
  328. unsigned long bytes_returned;
  329. PREVENT_MEDIA_REMOVAL pmrbuffer;
  330. pmrbuffer.PreventMediaRemoval = prevent;
  331. bool result = ((DeviceIoControl( volume, IOCTL_STORAGE_MEDIA_REMOVAL, &pmrbuffer, sizeof(PREVENT_MEDIA_REMOVAL), NULL, 0, &bytes_returned, NULL)) ? true : false);
  332. if (result == false) {
  333. // DebugString ("DeviceIoControl failed to prevent media removal. Error %d - %s\n", GetLastError(), Last_Error_Text());
  334. // Msg( __LINE__, __FILE__, "DeviceIoControl failed to prevent media removal. Error %d - %s", GetLastError(), Last_Error_Text());
  335. Last_Error_Text( _TEXT( "DeviceIoControl failed to prevent media removal." ), GetLastError());
  336. }
  337. return( result );
  338. }
  339. /***********************************************************************************************
  340. * CDControlClass::Auto_Eject_Volume -- Eject the removable media *
  341. * *
  342. * INPUT: HANDLE of volume to eject *
  343. * *
  344. * OUTPUT: true if ejection occured *
  345. * *
  346. * WARNINGS: None *
  347. * *
  348. * HISTORY: *
  349. * 2/16/99 11:34PM ST : Created *
  350. *=============================================================================================*/
  351. bool CDControlClass::Auto_Eject_Volume(HANDLE volume)
  352. {
  353. assert (WinVersion.Is_WinNT());
  354. unsigned long bytes_returned;
  355. bool result = ((DeviceIoControl( volume, IOCTL_STORAGE_EJECT_MEDIA, NULL, 0, NULL, 0, &bytes_returned, NULL)) ? true : false);
  356. if (result == false) {
  357. // DebugString ("DeviceIoControl failed to eject media. Error %d - %s\n", GetLastError(), Last_Error_Text());
  358. // Msg( __LINE__, __FILE__, "DeviceIoControl failed to eject media. Error %d - %s", GetLastError(), Last_Error_Text());
  359. Last_Error_Text( TEXT("DeviceIoControl failed to eject media."), GetLastError());
  360. }
  361. return (result);
  362. }
  363. /***********************************************************************************************
  364. * CDControlClass::Eject_CD -- Force the CD drive to eject *
  365. * *
  366. * INPUT: drive number *
  367. * *
  368. * OUTPUT: true if ejected *
  369. * *
  370. * WARNINGS: None *
  371. * *
  372. * HISTORY: *
  373. * 2/16/99 11:35PM ST : Created *
  374. *=============================================================================================*/
  375. bool CDControlClass::Eject_CD(char drive)
  376. {
  377. assert (WinVersion.Is_WinNT());
  378. HANDLE volume;
  379. bool ejected = false;
  380. volume = Open_Removable_Volume(drive);
  381. if (volume == INVALID_HANDLE_VALUE) return (false);
  382. /*
  383. ** Lock and dismount the volume.
  384. */
  385. if (Lock_Volume(volume) && Dismount_Volume(volume)) {
  386. /*
  387. ** Set prevent removal to false and eject the volume.
  388. */
  389. if (Prevent_Removal_Of_Volume(volume, false) && Auto_Eject_Volume(volume)) {
  390. ejected = true;
  391. }
  392. }
  393. /*
  394. ** Close the volume so other processes can use the drive.
  395. */
  396. Close_Removable_Volume(volume);
  397. return (ejected);
  398. }
  399. /***********************************************************************************************
  400. * CDControlClass::Lock_CD_Drive -- Lock the CD tray and prevent ejection *
  401. * *
  402. * INPUT: drive number *
  403. * *
  404. * OUTPUT: true if locked *
  405. * *
  406. * WARNINGS: None *
  407. * *
  408. * HISTORY: *
  409. * 2/17/99 0:11AM ST : Created *
  410. *=============================================================================================*/
  411. bool CDControlClass::Lock_CD_Drive(char drive)
  412. {
  413. assert (WinVersion.Is_WinNT());
  414. HANDLE volume;
  415. bool retval = false;
  416. volume = Open_Removable_Volume(drive);
  417. if (volume == INVALID_HANDLE_VALUE) return (false);
  418. /*
  419. ** Lock the volume.
  420. */
  421. if (Lock_Volume(volume)) {
  422. /*
  423. ** Set prevent removal to false
  424. */
  425. if (Prevent_Removal_Of_Volume(volume, true)) {
  426. retval = true;
  427. }
  428. }
  429. /*
  430. ** Close the volume so other processes can use the drive.
  431. */
  432. Unlock_Volume(volume);
  433. Close_Removable_Volume(volume);
  434. return (true);
  435. }
  436. /***********************************************************************************************
  437. * CDControlClass::Unlock_CD_Drive -- Unlock the CD tray and allow ejection *
  438. * *
  439. * INPUT: drive number *
  440. * *
  441. * OUTPUT: true if unlocked *
  442. * *
  443. * WARNINGS: None *
  444. * *
  445. * HISTORY: *
  446. * 2/17/99 0:11AM ST : Created *
  447. *=============================================================================================*/
  448. bool CDControlClass::Unlock_CD_Drive(char drive)
  449. {
  450. assert (WinVersion.Is_WinNT());
  451. HANDLE volume;
  452. bool retval = false;
  453. volume = Open_Removable_Volume(drive);
  454. if (volume == INVALID_HANDLE_VALUE) return (false);
  455. /*
  456. ** Lock the volume.
  457. */
  458. if (Lock_Volume(volume)) {
  459. /*
  460. ** Set prevent removal to false
  461. */
  462. if (Prevent_Removal_Of_Volume(volume, false)) {
  463. retval = true;
  464. }
  465. }
  466. /*
  467. ** Close the volume so other processes can use the drive.
  468. */
  469. Unlock_Volume(volume);
  470. Close_Removable_Volume(volume);
  471. return (true);
  472. }
  473. /***********************************************************************************************
  474. * CDControlClass::Eject_CD_Win95 -- Eject the cd in the given drive *
  475. * *
  476. * INPUT: drive. 0=a etc. *
  477. * *
  478. * OUTPUT: Nothing *
  479. * *
  480. * WARNINGS: None *
  481. * *
  482. * HISTORY: *
  483. * 2/17/99 1:04AM ST : Created *
  484. *=============================================================================================*/
  485. void CDControlClass::Eject_CD_Win95 (char drive)
  486. {
  487. assert (WinVersion.Is_Win9x());
  488. HANDLE vwin32 = INVALID_HANDLE_VALUE;
  489. drive++;
  490. vwin32 = Open_VWin32 ();
  491. assert (vwin32 != INVALID_HANDLE_VALUE);
  492. /*
  493. ** Make sure no other applications are using the drive.
  494. */
  495. bool drive_locked = Lock_Logical_Volume (vwin32, drive, 0, 0);
  496. // assert (drive_locked);
  497. if (!drive_locked) {
  498. // DebugString("Unable to lock volume %c:\n", 'A' + drive - 1);
  499. Msg( __LINE__, TEXT(__FILE__), TEXT("Unable to lock volume %c: "), 'A' + drive - 1 );
  500. return;
  501. }
  502. /*
  503. ** Make sure there is no software lock keeping the media in the drive.
  504. */
  505. if (!Unlock_Volume_95 (vwin32, drive)) {
  506. // DebugString("Could not unlock media from drive %c:\n", 'A' + drive - 1);
  507. Msg( __LINE__, TEXT(__FILE__), TEXT("Could not unlock media from drive %c: "), 'A' + drive - 1 );
  508. Unlock_Logical_Volume (vwin32, drive);
  509. return;
  510. }
  511. /*
  512. ** Eject!
  513. */
  514. if (!Auto_Eject_Volume_95 (vwin32, drive)) {
  515. // DebugString("Could not eject media from drive %c:\n", 'A' + drive - 1);
  516. Msg( __LINE__, TEXT(__FILE__), TEXT("Could not eject media from drive %c: "), 'A' + drive - 1 );
  517. }
  518. Unlock_Logical_Volume (vwin32, drive);
  519. Close_VWin32 (vwin32);
  520. }
  521. /***********************************************************************************************
  522. * CDControlClass::Lock_CD_Drive_95 -- Prevent the user from ejecting the cd in the given drive*
  523. * *
  524. * INPUT: drive. 0=a etc. *
  525. * *
  526. * OUTPUT: Nothing *
  527. * *
  528. * WARNINGS: None *
  529. * *
  530. * HISTORY: *
  531. * 2/17/99 1:04AM ST : Created *
  532. *=============================================================================================*/
  533. bool CDControlClass::Lock_CD_Drive_95 (char drive)
  534. {
  535. // DebugString ("CDControlClass::Lock_CD_Drive_95\n");
  536. Msg( __LINE__, TEXT(__FILE__), TEXT("CDControlClass::Lock_CD_Drive_95." ));
  537. bool retval = true;
  538. assert (WinVersion.Is_Win9x());
  539. HANDLE vwin32 = INVALID_HANDLE_VALUE;
  540. // DebugString ("Preventing ejection on CD drive %c\n", drive + 'A');
  541. Msg( __LINE__, TEXT(__FILE__), TEXT("Preventing ejection on CD drive %c: "), 'A' + drive -1 );
  542. drive++;
  543. vwin32 = Open_VWin32();
  544. assert (vwin32 != INVALID_HANDLE_VALUE);
  545. /*
  546. ** Make sure no other applications are using the drive.
  547. */
  548. // DebugString ("About to lock logical volume to enable exclusive access\n");
  549. Msg( __LINE__, TEXT(__FILE__), TEXT("About to lock logical volume to enable exclusive access." ));
  550. bool drive_locked = Lock_Logical_Volume (vwin32, drive, 0, 0);
  551. // assert (drive_locked);
  552. if (!drive_locked) {
  553. // DebugString("Unable to lock volume %c:\n", 'A' + drive - 1);
  554. Msg( __LINE__, TEXT(__FILE__), TEXT("Unable to lock volume %c:"), 'A' + drive - 1 );
  555. return(false);
  556. }
  557. // DebugString ("Volume locked OK\n");
  558. Msg( __LINE__, TEXT(__FILE__), TEXT("Volume locked OK." ));
  559. /*
  560. ** Lock the tray in the closed position.
  561. */
  562. // DebugString ("About to prevent CD tray ejection\n");
  563. Msg( __LINE__, TEXT(__FILE__), TEXT("About to prevent CD tray ejection." ));
  564. if (!Lock_Volume_95 (vwin32, drive)) {
  565. // DebugString("Could not lock CD tray in drive %c:\n", 'A' + drive - 1);
  566. Msg( __LINE__, TEXT(__FILE__), TEXT("Could not lock CD tray in drive %c:"), 'A' + drive - 1 );
  567. retval = false;
  568. }else{
  569. // DebugString ("CD tray ejection disabled OK\n");
  570. Msg( __LINE__, TEXT(__FILE__), TEXT("CD tray ejection disabled OK." ));
  571. }
  572. Unlock_Logical_Volume (vwin32, drive);
  573. Close_VWin32 (vwin32);
  574. // DebugString ("CDControlClass::Lock_CD_Drive_95 returning %s\n", retval ? "true" : "false");
  575. Msg( __LINE__, TEXT(__FILE__), TEXT("CDControlClass::Lock_CD_Drive_95 returning %s."), retval ? "true" : "false" );
  576. return (retval);
  577. }
  578. /***********************************************************************************************
  579. * CDControlClass::Unlock_CD_Drive_95 -- Allow the user to eject the cd in the given drive *
  580. * *
  581. * INPUT: drive. 0=a etc. *
  582. * *
  583. * OUTPUT: Nothing *
  584. * *
  585. * WARNINGS: None *
  586. * *
  587. * HISTORY: *
  588. * 2/17/99 1:04AM ST : Created *
  589. *=============================================================================================*/
  590. bool CDControlClass::Unlock_CD_Drive_95 (char drive)
  591. {
  592. // DebugString ("CDControlClass::Unlock_CD_Drive_95\n");
  593. Msg( __LINE__, TEXT(__FILE__), TEXT("CDControlClass::Unlock_CD_Drive_95 returning %s." ));
  594. bool retval = true;
  595. assert (WinVersion.Is_Win9x());
  596. HANDLE vwin32 = INVALID_HANDLE_VALUE;
  597. // DebugString ("Allowing ejection on CD drive %c\n", drive + 'A');
  598. Msg( __LINE__, TEXT(__FILE__), TEXT("Allowing ejection on CD drive %c."), drive + 'A' - 1 );
  599. drive++;
  600. vwin32 = Open_VWin32();
  601. assert (vwin32 != INVALID_HANDLE_VALUE);
  602. /*
  603. ** Make sure no other applications are using the drive.
  604. */
  605. // DebugString ("About to lock logical volume to enable exclusive access\n");
  606. Msg( __LINE__, TEXT(__FILE__), TEXT("About to lock logical volume to enable exclusive access." ));
  607. bool drive_locked = Lock_Logical_Volume (vwin32, drive, 0, 0);
  608. // assert (drive_locked);
  609. if (!drive_locked) {
  610. // DebugString("Unable to lock volume %c:\n", 'A' + drive - 1);
  611. Msg( __LINE__, TEXT(__FILE__), TEXT("Unable to lock volume %c:."), 'A' + drive - 1 );
  612. return(false);
  613. }
  614. // DebugString ("Volume locked OK\n");
  615. Msg( __LINE__, TEXT(__FILE__), TEXT("Volume locked OK." ));
  616. /*
  617. ** Unlock the tray to allow ejection.
  618. */
  619. // DebugString ("About to allow CD tray ejection\n");
  620. Msg( __LINE__, TEXT(__FILE__), TEXT("About to allow CD tray ejection." ));
  621. if (!Unlock_Volume_95 (vwin32, drive)) {
  622. // DebugString("Could not unlock CD tray in drive %c:\n", 'A' + drive - 1);
  623. Msg( __LINE__, TEXT(__FILE__), TEXT("Could not unlock CD tray in drive %c:"), 'A' + drive - 1 );
  624. retval = false;
  625. }else{
  626. // DebugString ("CD tray ejection enabled OK\n");
  627. Msg( __LINE__, TEXT(__FILE__), TEXT("CD tray ejection enabled OK." ));
  628. }
  629. Unlock_Logical_Volume (vwin32, drive);
  630. Close_VWin32 (vwin32);
  631. // DebugString ("CDControlClass::Unlock_CD_Drive_95 returning %s\n", retval ? "true" : "false");
  632. Msg( __LINE__, TEXT(__FILE__), TEXT("CDControlClass::Unlock_CD_Drive_95 returning %s."), retval ? "true" : "false" );
  633. return (retval);
  634. }
  635. /***********************************************************************************************
  636. * CDControlClass::Unlock_Volume_95 -- Unlocks removable media so that it can be ejected *
  637. * *
  638. * INPUT: Handle to VWIN32 *
  639. * drive to unlock (DOS format) *
  640. * *
  641. * OUTPUT: true if unlocked *
  642. * *
  643. * WARNINGS: None *
  644. * *
  645. * HISTORY: *
  646. * 2/17/99 0:19AM ST : Created *
  647. *=============================================================================================*/
  648. bool CDControlClass::Unlock_Volume_95 (HANDLE vwin32, char drive)
  649. {
  650. assert (WinVersion.Is_Win9x());
  651. DIOC_REGISTERS regs = {0};
  652. PARAMBLOCK unlock_params = {0};
  653. bool result;
  654. unsigned long cb;
  655. /*
  656. ** First, check the lock status. This way, we'll know the number of pending locks we must unlock.
  657. */
  658. unlock_params.bOperation = 2; // return lock/unlock status
  659. regs.reg_EAX = 0x440D;
  660. regs.reg_EBX = drive;
  661. regs.reg_ECX = MAKEWORD(0x48, 0x08);
  662. regs.reg_EDX = (unsigned long)&unlock_params;
  663. result = (DeviceIoControl (vwin32, VWIN32_DIOC_DOS_IOCTL, &regs, sizeof(regs), &regs, sizeof(regs), &cb, 0)) ? true : false;
  664. if (result) {
  665. /*
  666. ** DeviceIoControl succeeded. Now see if the unlock succeeded. It
  667. ** succeeded if the carry flag is not set, or if the carry flag is
  668. ** set but EAX is 0x01 or 0xB0.
  669. **
  670. ** It failed if the carry flag is set and EAX is not 0x01 or 0xB0.
  671. **
  672. ** If the carry flag is clear, then unlock succeeded. However, you
  673. ** don't need to set fResult because it is already TRUE when you get
  674. ** in here.
  675. */
  676. if (regs.reg_Flags & CARRY_FLAG) {
  677. result = (regs.reg_EAX == 0xB0) || (regs.reg_EAX == 0x01);
  678. }
  679. } else {
  680. // DebugString ("DeviceIoControl failed to perform DOS IO control function. Error %d - %s\n", GetLastError(), Last_Error_Text());
  681. // Msg( __LINE__, __FILE__, "DeviceIoControl failed to perform DOS IO control function. Error %d - %s.", GetLastError(), Last_Error_Text() );
  682. Last_Error_Text( TEXT("DeviceIoControl failed to perform DOS IO control function.."), GetLastError());
  683. }
  684. if (!result) return (false);
  685. /*
  686. ** Now we have to unlock the media for every time it was locked. This gets us a lock count of
  687. ** 0 and totally unlocked media.
  688. */
  689. for (int i = 0; i < unlock_params.bNumLocks; ++i) {
  690. unlock_params.bOperation = 1; // unlock the media
  691. regs.reg_EAX = 0x440D;
  692. regs.reg_EBX = drive;
  693. regs.reg_ECX = MAKEWORD(0x48, 0x08); // LOCK/UNLOCK
  694. regs.reg_EDX = (unsigned long)&unlock_params;
  695. result = (DeviceIoControl (vwin32, VWIN32_DIOC_DOS_IOCTL, &regs, sizeof(regs), &regs, sizeof(regs), &cb, 0)) ? true : false;
  696. if (result == false) {
  697. // DebugString ("DeviceIoControl failed to perform DOS IO control function. Error %d - %s\n", GetLastError(), Last_Error_Text());
  698. // Msg( __LINE__, __FILE__, "DeviceIoControl failed to perform DOS IO control function. Error %d - %s.", GetLastError(), Last_Error_Text() );
  699. Last_Error_Text( TEXT("DeviceIoControl failed to perform DOS IO control function.."), GetLastError());
  700. }
  701. /*
  702. ** See if DeviceIoControl and the lock succeeded
  703. */
  704. result = result && !(regs.reg_Flags & CARRY_FLAG);
  705. if (!result) break;
  706. }
  707. return (result);
  708. }
  709. /***********************************************************************************************
  710. * CDControlClass::Lock_Volume_95 -- Locks removable media so that it can't be ejected *
  711. * *
  712. * INPUT: Handle to VWIN32 *
  713. * drive to lock (DOS format) *
  714. * *
  715. * OUTPUT: true if unlocked *
  716. * *
  717. * WARNINGS: None *
  718. * *
  719. * HISTORY: *
  720. * 2/17/99 0:19AM ST : Created *
  721. *=============================================================================================*/
  722. bool CDControlClass::Lock_Volume_95 (HANDLE vwin32, char drive)
  723. {
  724. assert (WinVersion.Is_Win9x());
  725. DIOC_REGISTERS regs = {0};
  726. PARAMBLOCK unlock_params = {0};
  727. bool result;
  728. unsigned long cb;
  729. /*
  730. ** Bring the lock count down to 0.
  731. */
  732. Unlock_Volume_95(vwin32, drive);
  733. /*
  734. ** Increment the lock count.
  735. */
  736. unlock_params.bOperation = 0; // lock the media
  737. regs.reg_EAX = 0x440D;
  738. regs.reg_EBX = drive;
  739. regs.reg_ECX = MAKEWORD(0x48, 0x08); // LOCK/UNLOCK
  740. regs.reg_EDX = (unsigned long)&unlock_params;
  741. result = (DeviceIoControl (vwin32, VWIN32_DIOC_DOS_IOCTL, &regs, sizeof(regs), &regs, sizeof(regs), &cb, 0)) ? true : false;
  742. if (result == false) {
  743. // DebugString ("DeviceIoControl failed to perform DOS IO control function. Error %d - %s\n", GetLastError(), Last_Error_Text());
  744. // Msg( __LINE__, __FILE__, "DeviceIoControl failed to perform DOS IO control function. Error %d - %s.", GetLastError(), Last_Error_Text() );
  745. Last_Error_Text( TEXT("DeviceIoControl failed to perform DOS IO control function."), GetLastError());
  746. }
  747. /*
  748. ** See if DeviceIoControl and the lock succeeded
  749. */
  750. result = result && !(regs.reg_Flags & CARRY_FLAG);
  751. return (result);
  752. }
  753. /***********************************************************************************************
  754. * CDControlClass::Auto_Eject_Volume_95 -- Eject the specified CD drive *
  755. * *
  756. * INPUT: Handle to VWIN32 *
  757. * Drive number (DOS format) *
  758. * *
  759. * OUTPUT: True if ejected *
  760. * *
  761. * WARNINGS: None *
  762. * *
  763. * HISTORY: *
  764. * 2/17/99 0:24AM ST : Created *
  765. *=============================================================================================*/
  766. bool CDControlClass::Auto_Eject_Volume_95 (HANDLE vwin32, char drive)
  767. {
  768. assert (WinVersion.Is_Win9x());
  769. DIOC_REGISTERS regs = {0};
  770. bool result;
  771. unsigned long cb;
  772. regs.reg_EAX = 0x440D;
  773. regs.reg_EBX = drive;
  774. regs.reg_ECX = MAKEWORD(0x49, 0x08); //EJECT
  775. result = (DeviceIoControl (vwin32, VWIN32_DIOC_DOS_IOCTL, &regs, sizeof(regs), &regs, sizeof(regs), &cb, 0)) ? true : false;
  776. if (result == false) {
  777. // DebugString ("DeviceIoControl failed to perform DOS IO control function. Error %d - %s\n", GetLastError(), Last_Error_Text());
  778. // Msg( __LINE__, __FILE__, "DeviceIoControl failed to perform DOS IO control function. Error %d - %s.", GetLastError(), Last_Error_Text() );
  779. Last_Error_Text( TEXT("DeviceIoControl failed to perform DOS IO control function."), GetLastError());
  780. }
  781. /*
  782. ** See if we ejected OK
  783. */
  784. result = result && !(regs.reg_Flags & CARRY_FLAG);
  785. return (result);
  786. }
  787. /***********************************************************************************************
  788. * CDControlClass::Open_VWin32 -- Opens a handle to VWIN32 to issue low-level disk I/O *
  789. * *
  790. * INPUT: Nothing *
  791. * *
  792. * OUTPUT: HANDLE to VWin32 *
  793. * *
  794. * WARNINGS: None *
  795. * *
  796. * HISTORY: *
  797. * 2/17/99 0:26AM ST : Created *
  798. *=============================================================================================*/
  799. HANDLE WINAPI CDControlClass::Open_VWin32 (void)
  800. {
  801. assert (WinVersion.Is_Win9x());
  802. HANDLE result = CreateFile ( TEXT("\\\\.\\vwin32"), 0, 0, NULL, 0, FILE_FLAG_DELETE_ON_CLOSE, NULL);
  803. assert (result != INVALID_HANDLE_VALUE);
  804. return (result);
  805. }
  806. /***********************************************************************************************
  807. * CDControlClass::Close_VWin32 -- Closes the handle opened by Open_VWin32. *
  808. * *
  809. * INPUT: Handle to VWin32 *
  810. * *
  811. * OUTPUT: Nothing *
  812. * *
  813. * WARNINGS: None *
  814. * *
  815. * HISTORY: *
  816. * 2/17/99 0:26AM ST : Created *
  817. *=============================================================================================*/
  818. bool WINAPI CDControlClass::Close_VWin32 (HANDLE vwin32)
  819. {
  820. assert (WinVersion.Is_Win9x());
  821. return ((CloseHandle (vwin32)) ? true : false);
  822. }
  823. /***********************************************************************************************
  824. * CDControlClass::Lock_Logical_Volume -- Take a lock on a logical volume *
  825. * *
  826. * INPUT: Handle to VWin32 *
  827. * drive number (DOS format) *
  828. * lock level *
  829. * permissions *
  830. * *
  831. * OUTPUT: true if locked *
  832. * *
  833. * WARNINGS: None *
  834. * *
  835. * HISTORY: *
  836. * 2/17/99 0:33AM ST : Created *
  837. *=============================================================================================*/
  838. bool WINAPI CDControlClass::Lock_Logical_Volume (HANDLE vwin32, char drive, char lock_level, short permissions)
  839. {
  840. assert (WinVersion.Is_Win9x());
  841. bool result;
  842. DIOC_REGISTERS regs = {0};
  843. char device_cat; // can be either 0x48 or 0x08
  844. unsigned long cb;
  845. /*
  846. ** lock_level
  847. ** Can be 0, 1, 2, or 3. Level 0 is an exclusive lock that can only
  848. ** be taken when there are no open files on the specified drive.
  849. ** Levels 1 through 3 form a hierarchy where 1 must be taken before
  850. ** 2, which must be taken before 3.
  851. **
  852. ** permissions
  853. ** Specifies how the lock will affect file operations when lock levels
  854. ** 1 through 3 are taken. Also specifies whether a formatting lock
  855. ** should be taken after a level 0 lock.
  856. */
  857. /*
  858. ** Try first with device category 0x48 for FAT32 volumes. If it
  859. ** doesn't work, try again with device category 0x08. If that
  860. ** doesn't work, then the lock failed.
  861. */
  862. device_cat = 0;
  863. do {
  864. if (device_cat == 0) {
  865. device_cat = 0x48;
  866. }else{
  867. device_cat = 0x08;
  868. }
  869. /*
  870. ** Set up the parameters for the call.
  871. */
  872. regs.reg_EAX = 0x440D;
  873. regs.reg_EBX = MAKEWORD(drive, lock_level);
  874. regs.reg_ECX = MAKEWORD(0x4A, device_cat);
  875. regs.reg_EDX = permissions;
  876. result = (DeviceIoControl (vwin32, VWIN32_DIOC_DOS_IOCTL, &regs, sizeof(regs), &regs, sizeof(regs), &cb, 0)) ? true : false;
  877. if (result == false) {
  878. // DebugString ("DeviceIoControl failed to perform DOS IO control function. Error %d - %s\n", GetLastError(), Last_Error_Text());
  879. // Msg( __LINE__, __FILE__, "DeviceIoControl failed to perform DOS IO control function. Error %d - %s.", GetLastError(), Last_Error_Text() );
  880. Last_Error_Text( TEXT("DeviceIoControl failed to perform DOS IO control function."), GetLastError());
  881. }
  882. result = result && !(regs.reg_Flags & CARRY_FLAG);
  883. } while (result == false && device_cat != 0x08);
  884. return (result);
  885. }
  886. /***********************************************************************************************
  887. * CDControlClass::Unlock_Logical_Volume -- Unlocks a logical volume *
  888. * *
  889. * INPUT: Handle to VWin32 *
  890. * drive number (DOS format) *
  891. * *
  892. * OUTPUT: true if unlocked *
  893. * *
  894. * WARNINGS: None *
  895. * *
  896. * Must be called the same number of times as LockLogicalVolume() to *
  897. * completely unlock a volume. *
  898. * *
  899. * Only the lock owner can unlock a volume. *
  900. * *
  901. * HISTORY: *
  902. * 2/17/99 0:39AM ST : Created *
  903. *=============================================================================================*/
  904. bool WINAPI CDControlClass::Unlock_Logical_Volume (HANDLE vwin32, char drive)
  905. {
  906. assert (WinVersion.Is_Win9x());
  907. bool result;
  908. DIOC_REGISTERS regs = {0};
  909. char device_cat; // can be either 0x48 or 0x08
  910. unsigned long cb;
  911. /*
  912. ** Try first with device category 0x48 for FAT32 volumes. If it
  913. ** doesn't work, try again with device category 0x08. If that
  914. ** doesn't work, then the unlock failed.
  915. */
  916. device_cat = 0;
  917. do {
  918. if (device_cat == 0) {
  919. device_cat = 0x48;
  920. }else{
  921. device_cat = 0x08;
  922. }
  923. /*
  924. ** Set up the parameters for the call.
  925. */
  926. regs.reg_EAX = 0x440D;
  927. regs.reg_EBX = drive;
  928. regs.reg_ECX = MAKEWORD(0x6A, device_cat);
  929. result = (DeviceIoControl (vwin32, VWIN32_DIOC_DOS_IOCTL, &regs, sizeof(regs), &regs, sizeof(regs), &cb, 0)) ? true : false;
  930. if (result == false) {
  931. // DebugString ("DeviceIoControl failed to perform DOS IO control function. Error %d - %s\n", GetLastError(), Last_Error_Text());
  932. // Msg( __LINE__, __FILE__, "DeviceIoControl failed to perform DOS IO control function. Error %d - %s.", GetLastError(), Last_Error_Text());
  933. Last_Error_Text( TEXT("DeviceIoControl failed to perform DOS IO control function."), GetLastError());
  934. }
  935. result = result && !(regs.reg_Flags & CARRY_FLAG);
  936. } while (result == false && device_cat != 0x08);
  937. return (result);
  938. }
  939. /************************************************************************************************
  940. * Last_Error_Text -- Display error messages based on FormatMessage() and GetLastError(). *
  941. * *
  942. * INPUT: LPSTR - title. *
  943. * HRESULT - last error message. *
  944. * *
  945. * OUTPUT: None *
  946. * *
  947. * WARNINGS: None *
  948. * *
  949. * HISTORY: *
  950. * 6/24/99 4:44PM MML : Created *
  951. *==============================================================================================*/
  952. void Last_Error_Text ( LPTSTR szPrefix, HRESULT hr )
  953. {
  954. LPVOID szMessage;
  955. char szDisplay[1000];
  956. if ( hr == S_OK ) {
  957. _stprintf( szDisplay, TEXT("%s"), szPrefix );
  958. // MessageBox( NULL, szDisplay, TEXT("Msg"),0 );
  959. return;
  960. }
  961. if ( HRESULT_FACILITY( hr ) == FACILITY_WIN32 ) {
  962. hr = HRESULT_CODE( hr );
  963. }
  964. FormatMessage(
  965. FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
  966. NULL,
  967. hr,
  968. MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ),
  969. (LPTSTR)&szMessage,
  970. 0,
  971. NULL );
  972. _stprintf( szDisplay, TEXT( "%s: %s(%lx)" ), szPrefix, szMessage, hr );
  973. Msg( __LINE__, TEXT(__FILE__), TEXT("GetLastError: %s"), szDisplay );
  974. // MessageBox( NULL, szDisplay, TEXT( "GetLastError" ), MB_OK );
  975. LocalFree( szMessage );
  976. }