Win9x下虚拟光驱的检测
编写 Win9x 下的虚拟光驱需要了解如何编写 Vxd 和 windows driver 的分层架构,但它并非象听上去那么难,并不需要精通中断 和 potr driver 编写技巧。就如同您编写 windows 程序需要了解事件驱动模型、消息机制一样,但需要熟悉的结构较多。关于这部分您可以到 〈侯捷〉先生的网站(www.jjhou.com )下载《Windows 95 系統程式設計 - 虛擬機器與 VxD 程式設計》。上面有很详细的介绍。 由于虚拟光驱的原码不好找,因此, 我在我的主页上放有一个虚拟光驱的汇编原码 (http://go5.163.com/yanjiafu33/ ),您可以下载。但您不要抱太大期望(它只实现了在win9x上建立一个虚拟光驱的盘符,并不能加载镜像文件,我的原意道是想编一支持多种镜像文件的,在看见 daemon tool 后就放弃了)。 检测虚拟光驱,得说明编写风格上的不同。如东石公司扩展名为 VCD 以及 CD Copier Gamer's Edition 扩展名为 FCD 等标准的 port driver 。而 daemon tool 是 NT-style miniport driver 。对于标准的 port driver 可以使用 ASPI 来检测,代码如下:
#include <stdio.h> #include <windows.h>
// Request ASPI struct
#define SENSE_LEN 14 #define SS_COMP 1 // no error #define SS_PENDING 0 // SRB being processed #define SS_INVALID_HA 0x81 // Invalid host adapter number #define DTYPE_CROM 5 // cdrom device
#define SC_GET_DEV_TYPE 1 // Get Device type #define SC_GET_DISK_INFO 0x06 // Get Disk information
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)(void*); // Post routine void *SRB_Rsvd2; // Reserved BYTE SRB_Rsvd3[16]; // Reserved for alignment BYTE CDBByte[16]; // SCSI CDB BYTE SenseArea[SENSE_LEN+2]; // Request Sense buffer } SRB_ExecSCSICmd, *PSRB_ExecSCSICmd;
//*************************************************************************** // %%% SRB - GET DISK INFORMATION - SC_GET_DISK_INFO %%% //***************************************************************************
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; // 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;
// end struct
HINSTANCE hAspi32; DWORD (__cdecl * m_pfnGetASPI32SupportInfo)(VOID); DWORD (__cdecl * m_pfnSendASPI32Command)(LPBYTE);
BYTE GetDrvNameFormIndex (WORD target_id, WORD adapter_id);
void main( int nCmd, char * pchDrv[]) { DWORD dwASPI32Status, dwAdpid; BYTE target_id=7,adapter_id= -1; WORD i, j; SRB_ExecSCSICmd SRBb;
if ( nCmd < 2 ) { printf ( "Usage : program X. X is driver name.\n" ); return; }
hAspi32 = LoadLibrary ("WNASPI32.DLL");
if(hAspi32){ m_pfnGetASPI32SupportInfo = (DWORD (__cdecl *)(VOID))\ GetProcAddress (hAspi32, "GetASPI32SupportInfo"); m_pfnSendASPI32Command = (DWORD (__cdecl *)(LPBYTE))\ GetProcAddress (hAspi32, "SendASPI32Command"); if(!m_pfnGetASPI32SupportInfo || !m_pfnSendASPI32Command) { FreeLibrary (hAspi32); return; } }
dwASPI32Status = m_pfnGetASPI32SupportInfo ( );
switch ( HIBYTE ( LOWORD( dwASPI32Status ))) { case SS_COMP: dwAdpid = LOWORD( LOBYTE ( dwASPI32Status )); break; default: printf (": ASPI32 Error , Maybe have not CDRom. \n" ); return; }
ZeroMemory (&SRBb, sizeof(SRB_ExecSCSICmd));
for (j = 0; j < dwAdpid; j ++) { adapter_id++; if (adapter_id >= (BYTE)dwAdpid) adapter_id = 0;
for(i = 0; i < 8; i ++) { target_id = WORD( ( target_id + 1 )%8 );
SRBb.SRB_Cmd = SC_GET_DEV_TYPE; SRBb.SRB_HaId = adapter_id; SRBb.SRB_Target = target_id;
m_pfnSendASPI32Command ((LPBYTE)&SRBb);
if(SRBb.SRB_Status == SS_COMP) { if(SRBb.SRB_Rsvd1 == DTYPE_CROM) { if ( toupper(*pchDrv[1]) == GetDrvNameFormIndex (target_id, adapter_id) ) { printf ( "Is real CDRom. \n" ); return; } } }
if(SRBb.SRB_Status == SS_PENDING ||SRBb.SRB_Status == SS_INVALID_HA) { return; } } }
printf ( "Not a real CDRom. \n" );
}
//
BYTE GetDrvNameFormIndex (WORD target_id, WORD adapter_id) { SRB_ExecSCSICmd ExSRB; SRB_GetDiskInfo *MySRB;
MySRB = ((SRB_GetDiskInfo*)&ExSRB); ZeroMemory(&ExSRB, sizeof(ExSRB));
MySRB->SRB_Cmd = SC_GET_DISK_INFO; MySRB->SRB_HaId = adapter_id; MySRB->SRB_Flags = 0; MySRB->SRB_Hdr_Rsvd = 0; MySRB->SRB_Target = target_id; MySRB->SRB_Lun = 0;
m_pfnSendASPI32Command ( (LPBYTE) MySRB );
if(MySRB->SRB_Status == SS_COMP) return BYTE( MySRB->SRB_Int13HDriveInfo + 'A' ); return 0; }
// end
ASPI 在内部呼叫微软的 SCSI'izer 驱动 apix.vxd 。apix.vxd 会为 CDRom 建立 SCSI command descriptor blocks,而标准 port driver 虚拟光驱则不会。
对于NT-style miniport driver 的虚拟光驱,上述的代码则无法分辨。daemon tool 和 cloneCD 合起来几乎天衣无缝,限于水平我没有一个好的检测方法。但可以通过比较 SCSI device 的特征字符来判断,不知那位兄台有没有更好的方法,望不吝赐教 [email protected],谢谢。如何获得 SCSI device 的特征字符可以参考 2000DDK (X:\NTDDK\src\win_me\block\wnaspi32 )。
我初次写,很多不足,请见谅。呵呵。。但愿都表达出来了。

|