CD-ROMのイジェクト(WinNT/2000)

解説

 メディアのイジェクトはCreateFileとDeviceIoControlのIOCTL_STORAGE_EJECT_MEDIAを使う ことで、以下のように簡単に実現できる(この例ではFドライブをイジェクトしている)


	HANDLE	hDrive;
	DWORD	dw;

	hDrive = ::CreateFile("\\\\.\\F:",GENERIC_READ | GENERIC_WRITE
					,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL
					,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
	::DeviceIoControl(hDrive,IOCTL_STORAGE_EJECT_MEDIA,NULL,NULL,NULL,NULL,&dw,NULL);


 しかし単純に上のやり方ではメディアが壊れる(ことがあるらしい)。そのためMicrosoftは イジェクト前にボリュームのロックなどの手順を踏むことを推奨している。



使用例


	CDnpMediaEjectNt	cEject;

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



ソースコード


//
//	メディアのイジェクト(NT系用)
//
//	Windows NT/2000/XP系は以下のURLを参照
//		http://support.microsoft.com/kb/q165721/
//
class	CDnpMediaEjectNt
{
protected:

	//
	//	失敗時はINVALID_HANDLE_VALUE(-1)を返す
	//
	HANDLE OpenVolume(TCHAR cDriveLetter)
	{
		UINT	uDriveType;
		TCHAR	szVolumeName[8];
		TCHAR	szRootName[5];
		DWORD	dwAccessFlags;

		wsprintf(szRootName,_T("%c:\\"),cDriveLetter);

		uDriveType = GetDriveType(szRootName);
		switch(uDriveType)
		{
		case DRIVE_REMOVABLE:
			dwAccessFlags = GENERIC_READ | GENERIC_WRITE;
			break;

		case DRIVE_CDROM:
			dwAccessFlags = GENERIC_READ;
			break;

		default:
			return INVALID_HANDLE_VALUE;
		}

		wsprintf(szVolumeName,_T("\\\\.\\%c:"),cDriveLetter);

		return	::CreateFile(szVolumeName,dwAccessFlags,FILE_SHARE_READ | FILE_SHARE_WRITE,NULL,OPEN_EXISTING,0,NULL);
	}



	bool	CloseVolume(HANDLE hVolume)
	{
		return ::CloseHandle(hVolume) ? true : false;
	}



	bool	LockVolume(HANDLE hVolume,DWORD dwTimeout)
	{
		DWORD	dwBytesReturned;
		DWORD	dwStart;

		dwStart = ::GetTickCount();
		while(1)
		{
			if(::DeviceIoControl(hVolume,FSCTL_LOCK_VOLUME,NULL,0,NULL,0,&dwBytesReturned,NULL))
				return true;

			if(::GetTickCount() - dwStart > dwTimeout)
				return	false;

			::Sleep(20);
		}

		return false;
	}



	bool	DismountVolume(HANDLE hVolume)
	{
		DWORD dwBytesReturned;

		return	::DeviceIoControl(hVolume,FSCTL_DISMOUNT_VOLUME,NULL,0,NULL,0,&dwBytesReturned,NULL) ? true : false;
	}


	bool	PreventRemovalOfVolume(HANDLE hVolume,BOOL fPreventRemoval)
	{
		DWORD	dwBytesReturned;
		PREVENT_MEDIA_REMOVAL	PMRBuffer;

		PMRBuffer.PreventMediaRemoval = fPreventRemoval;

		return	::DeviceIoControl(hVolume,IOCTL_STORAGE_MEDIA_REMOVAL,&PMRBuffer, sizeof(PREVENT_MEDIA_REMOVAL),NULL, 0,&dwBytesReturned,NULL) ? true : false;
	}


	bool	AutoEjectVolume(HANDLE hVolume)
	{
		DWORD dwBytesReturned;

		return	::DeviceIoControl( hVolume,IOCTL_STORAGE_EJECT_MEDIA,NULL, 0,NULL, 0,&dwBytesReturned,NULL) ? true : false;
	}

public:


	bool	EjectVolume(TCHAR cDriveLetter,DWORD dwTimeouts)
	{
		bool	ret;
		HANDLE	hVolume;

		hVolume = OpenVolume(cDriveLetter);
		if(hVolume == INVALID_HANDLE_VALUE)
			return false;

		ret = LockVolume(hVolume,dwTimeouts);
		if(ret)
			ret = DismountVolume(hVolume);
		if(ret)
			ret = PreventRemovalOfVolume(hVolume,FALSE);
		if(ret)
			ret = AutoEjectVolume(hVolume);

		if(!CloseVolume(hVolume))
			return false;

		return	ret;
	}
};




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