解説
メディアのイジェクトは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;
}
};







