在社区发贴询问也没人解答,最后通过自己摸索终于搞定。
在9X下锁定光驱的方法和2000以上系统中不一样,需要用到 ASPI(Advanced SCSI Programming Interface)驱动。
首先需要定义一些常量和命令结构:
// Request ASPI struct
#define SHORTTIMEOUT 1L*1000L
#define SRB_DIR_SCSI 0x00
#define SCSI_Cmd_PreventAllow 0x1E
#define SRB_POSTING 0x01 //Enable posting. See “Waiting for Completion” for more information. This flag and SRB_EVENT_NOTIFY are mutually exclusive.
#define SRB_ENABLE_RESIDUAL_COUNT 0x04 //Enables residual byte counting assuming it is supported.Whenever a data underrun occurs the SRB_BufLen field
//is updated to reflect the remaining bytes to transfer.
#define SRB_DIR_IN 0x08 //Data transfer is from SCSI target to host. Mutually exclusive with SRB_DIR_OUT.
#define SRB_DIR_OUT 0x10 //Data transfer is from host to SCSI target. Mutually exclusive with SRB_DIR_IN.
#define SRB_EVENT_NOTIFY 0x40 //Enable event notification. See “Waiting for Completion”
//for more infomration. This flag and SRB_POSTING are mutually exclusive.
#define SS_PENDING 0x00 // SRB being processed
#define SS_COMP 0x01 // SRB completed without error
#define DTYPE_CDROM 0x05 // cdrom device
#define SS_INVALID_HA 0x81 // Invalid host adapter number
#define SENSE_LEN 128 // Default sense buffer length
#define SC_HA_INQUIRY 0x00 //Queries ASPI for information on specific host adapters.
#define SC_GET_DEV_TYPE 0x01 //Requests the SCSI device type for a specific SCSI target.
#define SC_EXEC_SCSI_CMD 0x02 //Sends a SCSI command (arbitrary CDB) to a SCSI target.
#define SC_ABORT_SRB 0x03 //Requests that ASPI cancel a previously submitted request.
#define SC_RESET_DEV 0x04 //Sends a BUS DEVICE RESET message to a SCSI target.
#define SC_GET_DISK_INFO 0x06 //Returns BIOS information for a SCSI target (Win98 only).
#define SC_RESCAN_SCSI_BUS 0x07 //Requests a rescan of a host adapter’s SCSI bus.
#define SC_GETSET_TIMEOUTS 0x08 //Sets SRB timeouts for specific SCSI targets.
#define DISK_NOT_INT13 0x00 //Device is not controlled by Int 13h services
#define DISK_INT13_AND_DOS 0x01 //Device is under Int 13h control and is claimed by DOS
#define DISK_INT13 0x02 //Device is under Int 13h control but not claimed by DOS
typedef struct SCSI_Cdb_PreventAllow_s {
unsigned int CommandCode : 8;
unsigned int Reserved1 : 5;
unsigned int Lun : 3;
unsigned int Reserved2 : 8;
unsigned int Reserved3 : 8;
unsigned int Prevent : 1;
unsigned int Reserved4 : 7;
unsigned int Link : 1;
unsigned int Flag : 1;
unsigned int Reserved5 : 4;
unsigned int VendorSpecific : 2;
} SCSI_Cdb_PreventAllow_t;
typedef struct
{
BYTE SRB_Cmd; // ASPI command code = SC_GET_DEV_TYPE
BYTE SRB_Status; // ASPI command status byte
BYTE SRB_HaId; // ASPI host adapter number
BYTE SRB_Flags; // Reserved, MUST = 0
DWORD SRB_Hdr_Rsvd; // Reserved, MUST = 0
BYTE SRB_Target; // Target's SCSI ID
BYTE SRB_Lun; // Target's LUN number
BYTE SRB_DeviceType; // Target's peripheral device type
BYTE SRB_Rsvd1; // Reserved, MUST = 0
}
SRB_GDEVBlock, *PSRB_GDEVBlock;
typedef struct
{
BYTE SRB_Cmd; // ASPI command code = SC_GET_DISK_INFO
BYTE SRB_Status; // ASPI command status byte
BYTE SRB_HaId; // ASPI host adapter number
BYTE SRB_Flags; // Reserved
DWORD SRB_Hdr_Rsvd; // Reserved
BYTE SRB_Target; // Target's SCSI ID
BYTE SRB_Lun; // Target's LUN number
BYTE SRB_DriveFlags; // Driver flags
BYTE SRB_Int13HDriveInfo; // Host Adapter Status
BYTE SRB_Heads; // Preferred number of heads translation
BYTE SRB_Sectors; // Preferred number of sectors translation
BYTE SRB_Rsvd1[10]; // Reserved
}
SRB_GetDiskInfo, *PSRB_GetDiskInfo;
typedef struct {
BYTE SRB_Cmd; // ASPI command code = SC_EXEC_SCSI_CMD
BYTE SRB_Status; // ASPI command status byte
BYTE SRB_HaId; // ASPI host adapter number
BYTE SRB_Flags; // ASPI request flags
DWORD SRB_Hdr_Rsvd; // Reserved
BYTE SRB_Target; // Target's SCSI ID
BYTE SRB_Lun; // Target's LUN number
WORD SRB_Rsvd1; // Reserved for Alignment
DWORD SRB_BufLen; // Data Allocation Length
BYTE *SRB_BufPointer; // Data Buffer Pointer
BYTE SRB_SenseLen; // Sense Allocation Length
BYTE SRB_CDBLen; // CDB Length
BYTE SRB_HaStat; // Host Adapter Status
BYTE SRB_TargStat; // Target Status
void *SRB_PostProc; // Post routine
void *SRB_Rsvd2; // Reserved
BYTE SRB_Rsvd3[16]; // Reserved for alignment
BYTE SRB_CDBByte[16]; // SCSI CDB
BYTE SRB_SenseArea[SENSE_LEN+2]; // Request Sense buffer
} SRB_ExecSCSICmd, *PSRB_ExecSCSICmd;
// end struct
然后调用ASPI接口函数,发送命令:
BOOL Lock9xCDROM(BOOL bLock)
{
DWORD dwASPI32Status;
BYTE target_id=0,adapter_id= 0;
BYTE dwAdpid;
SRB_GDEVBlock srbGDEVBlock;
int iCDRomCount=0;
BOOL bResult=FALSE;
hAspi32 = LoadLibrary ("WNASPI32.DLL");
if(hAspi32==NULL)
{
MessageBox(NULL,"加载动态库失败!","光驱控制",MB_OK|MB_ICONWARNING|MB_SETFOREGROUND);
return FALSE;
}
m_pfnGetASPI32SupportInfo = (PFNGETASPI32SUPPORTINFO)GetProcAddress (hAspi32, "GetASPI32SupportInfo");
m_pfnSendASPI32Command = (PFNSENDASPI32COMMAND)GetProcAddress (hAspi32, "SendASPI32Command");
if(m_pfnGetASPI32SupportInfo==NULL || m_pfnSendASPI32Command==NULL)
{
FreeLibrary (hAspi32);
MessageBox(NULL,"获取库函数失败!","光驱控制",MB_OK|MB_ICONWARNING|MB_SETFOREGROUND);
return FALSE;
}
dwASPI32Status = m_pfnGetASPI32SupportInfo();
switch (HIBYTE(LOWORD(dwASPI32Status)))
{
case SS_COMP:
dwAdpid = LOBYTE(LOWORD(dwASPI32Status));
break;
default:
FreeLibrary (hAspi32);
MessageBox(NULL,"ASPI32错误,可能没有光驱!","光驱控制",MB_OK|MB_ICONWARNING|MB_SETFOREGROUND);
return FALSE;
}
memset( &srbGDEVBlock, 0, sizeof(SRB_GDEVBlock) );
for (adapter_id = 0; adapter_id < dwAdpid; adapter_id ++)
{
for(target_id = 0; target_id < 8; target_id ++)
{
memset( &srbGDEVBlock, 0, sizeof(SRB_GDEVBlock) );
srbGDEVBlock.SRB_Cmd = SC_GET_DEV_TYPE;
srbGDEVBlock.SRB_HaId = adapter_id;
srbGDEVBlock.SRB_Target = target_id;
m_pfnSendASPI32Command ((LPBYTE)&srbGDEVBlock);
if( srbGDEVBlock.SRB_Status != SS_COMP ) continue;
if( srbGDEVBlock.SRB_DeviceType == DTYPE_CDROM )
{
// A CD-ROM exists at HA/ID/LUN = byHaId/byTarget/0.
// Do whatever you want with it from here!
CString strDrv,strMsg;
strDrv = GetDrvNameFormIndex(target_id,adapter_id);
iCDRomCount++;
HANDLE hEvent;
SCSI_Cdb_PreventAllow_t cdb;
SRB_ExecSCSICmd srbExec;
// Create event to notify completion
hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (!hEvent)// Could not create event
{
FreeLibrary (hAspi32);
if(bLock)
{
strMsg.Format("锁定光驱 %s 失败!",strDrv);
}
else
{
strMsg.Format("解锁光驱 %s 失败!",strDrv);
}
MessageBox(NULL,strMsg,"光驱控制",MB_OK|MB_ICONWARNING|MB_SETFOREGROUND);
return FALSE;
}
memset(&cdb,0,sizeof(cdb));
cdb.CommandCode = SCSI_Cmd_PreventAllow;
cdb.Lun = 0;
cdb.Prevent = bLock;
memset(&srbExec,0,sizeof(srbExec));
srbExec.SRB_Cmd = SC_EXEC_SCSI_CMD;
srbExec.SRB_HaId = adapter_id;
srbExec.SRB_Target = target_id;
srbExec.SRB_Lun = 0;
srbExec.SRB_PostProc = hEvent;
srbExec.SRB_Flags = SRB_DIR_SCSI|SRB_EVENT_NOTIFY;
srbExec.SRB_BufPointer=NULL;
srbExec.SRB_BufLen = 0;
memcpy(srbExec.SRB_CDBByte,&cdb,6);
srbExec.SRB_CDBLen = 6;
srbExec.SRB_SenseLen = SENSE_LEN;
ResetEvent(hEvent);
m_pfnSendASPI32Command ((LPBYTE)&srbExec);
if (srbExec.SRB_Status == SS_PENDING)
{
DWORD dwWaitResult;
dwWaitResult=WaitForSingleObject(hEvent,SHORTTIMEOUT);
if(dwWaitResult==WAIT_OBJECT_0)// event completed
{
ResetEvent(hEvent);
}
}
CloseHandle(hEvent);
if( srbExec.SRB_Status == SS_COMP )
{
bResult=TRUE;
if(bLock)
{
strMsg.Format("锁定光驱 %s 成功!",strDrv);
}
else
{
strMsg.Format("解锁光驱 %s 成功!",strDrv);
}
MessageBox(NULL,strMsg,"光驱控制",MB_OK|MB_ICONINFORMATION|MB_SETFOREGROUND);
}
else
{
if(bLock)
{
strMsg.Format("锁定光驱 %s 失败!",strDrv);
}
else
{
strMsg.Format("解锁光驱 %s 失败!",strDrv);
}
MessageBox(NULL,strMsg,"光驱控制",MB_OK|MB_ICONWARNING|MB_SETFOREGROUND);
}
}
}
}
FreeLibrary (hAspi32);
if(iCDRomCount==0)
{
MessageBox(NULL,"没有一个真实的光驱!","光驱控制",MB_OK|MB_ICONWARNING|MB_SETFOREGROUND);
return FALSE;
}
return bResult;
}