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