CD-ROMのイジェクト(Win9x)

解説

 メディアのイジェクトはWindows 9x系とWindows NT系で方法が異なる。また、イジェクトの 際にはボリュームのロックなどの手順を踏まないとメディアが壊れる(ことがあるらしい)。



使用例


	CDnpMediaEject9x	cEject;

	cEject.EjectVolume(_T('F'));



ソースコード


//
//	メディアのイジェクト(9x系用)
//
//	Windows95/98/Me系は以下のURLを参照
//		http://support.microsoft.com/kb/q168180/
//
class	CDnpMediaEject9x
{
protected:

	//-----------------------------------------------------------------------
	// DeviceIoControl infrastructure

	#if !defined (VWIN32_DIOC_DOS_IOCTL)
	#define VWIN32_DIOC_DOS_IOCTL      1

	typedef struct _DIOC_REGISTERS
	{
		DWORD reg_EBX;
		DWORD reg_EDX;
		DWORD reg_ECX;
		DWORD reg_EAX;
		DWORD reg_EDI;
		DWORD reg_ESI;
		DWORD reg_Flags;
	} DIOC_REGISTERS, *PDIOC_REGISTERS;
	#endif

	// Intel x86 processor status flags
	#define CARRY_FLAG             0x0001

	//-----------------------------------------------------------------------
	// DOS IOCTL function support

	#pragma pack(1)

	// Parameters for locking/unlocking removable media
	typedef struct _PARAMBLOCK
	{
		BYTE bOperation;
		BYTE bNumLocks;
	} PARAMBLOCK, *PPARAMBLOCK;

	#pragma pack()









	//
	//	メディアのアンロック
	//
	bool	UnlockMedia (HANDLE hVWin32, BYTE bDrive)
	{
		DIOC_REGISTERS	regs = {0};
		PARAMBLOCK		unlockParams = {0};
		int		i;
		bool	fResult;
		DWORD	cb;

		// First, check the lock status. This way, you'll know the number of
		// pending locks you must unlock.

		unlockParams.bOperation = 2;   // return lock/unlock status

		regs.reg_EAX = 0x440D;
		regs.reg_EBX = bDrive;
		regs.reg_ECX = MAKEWORD(0x48, 0x08);
		regs.reg_EDX = (DWORD)&unlockParams;

		fResult = ::DeviceIoControl(hVWin32,VWIN32_DIOC_DOS_IOCTL,®s, sizeof(regs), ®s, sizeof(regs),&cb,0) ? true : false;

		// See if DeviceIoControl and the unlock succeeded.
		if(fResult)
		{
			/*
			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)
				fResult = (regs.reg_EAX == 0xB0) || (regs.reg_EAX == 0x01);
		}

		if(!fResult)
			return false;

		//全アンロック
		for (i = 0; i < unlockParams.bNumLocks; ++i)
		{
			unlockParams.bOperation = 1;   // unlock the media

			regs.reg_EAX = 0x440D;
			regs.reg_EBX = bDrive;
			regs.reg_ECX = MAKEWORD(0x48, 0x08);
			regs.reg_EDX = (DWORD)&unlockParams;

			fResult = ::DeviceIoControl(hVWin32, VWIN32_DIOC_DOS_IOCTL,®s, sizeof(regs), ®s, sizeof(regs),&cb, 0) ? true : false;

			// See if DeviceIoControl and the lock succeeded
			fResult = fResult && !(regs.reg_Flags & CARRY_FLAG);
			if (!fResult)
				break;
		}
		return	fResult;
	}




	//
	//	イジェクト
	//
	bool	EjectMedia (HANDLE hVWin32, BYTE bDrive)
	{
		DIOC_REGISTERS	regs = {0};
		bool	fResult;
		DWORD	cb;

		regs.reg_EAX = 0x440D;
		regs.reg_EBX = bDrive;
		regs.reg_ECX = MAKEWORD(0x49, 0x08);

		fResult = ::DeviceIoControl(hVWin32,VWIN32_DIOC_DOS_IOCTL,®s, sizeof(regs), ®s, sizeof(regs),&cb, 0) ? true : false;

		// See if DeviceIoControl and the lock succeeded
		fResult = fResult && !(regs.reg_Flags & CARRY_FLAG);

		return fResult;
	}



	//
	//	ローレベルディスクI/Oを開く
	//
	HANDLE WINAPI OpenVWin32(void)
	{
		return ::CreateFile("\\\\.\\vwin32",0,0,NULL,0,FILE_FLAG_DELETE_ON_CLOSE, NULL);
	}



	bool	CloseVWin32 (HANDLE hVWin32)
	{
		return ::CloseHandle(hVWin32) ? true : false;
	}


	//
	//	ボリュームのロック
	//
	bool	LockLogicalVolume(HANDLE hVWin32,BYTE bDriveNum,BYTE bLockLevel,WORD wPermissions)
	{
		bool	fResult;
		BYTE	bDeviceCat;
		DWORD	cb;
		DIOC_REGISTERS	regs = {0};

		//	0x48(FAT32)で試行、ダメなら0x08で再試行、これでダメなら失敗。
		bDeviceCat = 0x48;
		while(1)
		{
			regs.reg_EAX = 0x440D;
			regs.reg_EBX = MAKEWORD(bDriveNum, bLockLevel);
			regs.reg_ECX = MAKEWORD(0x4A, bDeviceCat);
			regs.reg_EDX = wPermissions;

			fResult = ::DeviceIoControl (hVWin32, VWIN32_DIOC_DOS_IOCTL,®s, sizeof(regs), ®s, sizeof(regs),&cb, 0) ? true : false;

			// See if DeviceIoControl and the lock succeeded
			fResult = fResult && !(regs.reg_Flags & CARRY_FLAG);

			if(fResult || (bDeviceCat == 0x08))
				break;

			bDeviceCat = 0x08;
		}

		return fResult;
	}





	//
	//	LockLogicalVolumeによりロックされたボリュームの開放
	//
	bool	UnlockLogicalVolume(HANDLE hVWin32,BYTE bDriveNum)
	{
		bool	fResult;
		BYTE	bDeviceCat;
		DWORD	cb;
		DIOC_REGISTERS	regs = {0};

		//	0x48(FAT32)で試行、ダメなら0x08で再試行、これでダメなら失敗。
		bDeviceCat = 0x48;
		while(1)
		{
			regs.reg_EAX = 0x440D;
			regs.reg_EBX = bDriveNum;
			regs.reg_ECX = MAKEWORD(0x6A, bDeviceCat);

			fResult = ::DeviceIoControl (hVWin32, VWIN32_DIOC_DOS_IOCTL,®s, sizeof(regs), ®s, sizeof(regs),&cb,0) ? true : false;

			// See if DeviceIoControl and the unlock succeeded
			fResult = fResult && !(regs.reg_Flags & CARRY_FLAG);

			if(fResult || (bDeviceCat == 0x08))
				break;

			bDeviceCat = 0x08;
		}

		return fResult;
	}


public:

	bool	EjectVolume(TCHAR cbDrive)
	{
		HANDLE	hVWin32;
		BYTE	btDrive;
		bool	ret;
		bool	fDriveLocked;

		// convert command line arg 1 from a drive letter to a DOS drive number
		btDrive = (_totupper(cbDrive) - _T('A')) + 1;

		hVWin32 = OpenVWin32();
		if(hVWin32 == INVALID_HANDLE_VALUE)
			return	false;

		ret = false;
		fDriveLocked = LockLogicalVolume(hVWin32,btDrive,0,0);
		if(fDriveLocked)
			ret = UnlockMedia(hVWin32,btDrive);
		if(ret)
			ret = EjectMedia(hVWin32,btDrive);

		if(fDriveLocked)
			UnlockLogicalVolume(hVWin32,btDrive);

		if(hVWin32 != INVALID_HANDLE_VALUE)
			CloseVWin32(hVWin32);

		return	ret;
	}
};




カテゴリー「VC++ TIPS」 のエントリー