如何使用 DeviceIOControl() 从 CD 中获取“曲目信息”?
Posted
技术标签:
【中文标题】如何使用 DeviceIOControl() 从 CD 中获取“曲目信息”?【英文标题】:How to fetch "Track Information" from a CD with DeviceIOControl()? 【发布时间】:2014-02-23 01:15:34 【问题描述】:我正在尝试将 DeviceIoControl() 与 SCSI_PASS_THROUGH_DIRECT 一起使用,以获取 TRACK_INFO。
此代码“有效”,但它通过将 ScsiStatus 设置为 2 来返回。 关于“跟踪”数据字段的大小似乎存在相互矛盾的文档。 mmc 文档说它有 1 位长,但是,在网上我发现它是 2 位长的参考资料。
然而,不管怎样,它都失败了。
我整天绞尽脑汁,一无所获。有人明白吗?
#define kSCSICmd_READ_TRACK_INFORMATION 0x52
// Read Track Information Format
struct CDTrackInfo
UInt16 dataLength;
UInt8 trackNumberLSB;
UInt8 sessionNumberLSB;
UInt8 reserved;
#ifdef __LITTLE_ENDIAN__
UInt8 trackMode:4;
UInt8 copy:1;
UInt8 damage:1;
UInt8 reserved3:2;
UInt8 dataMode:4;
UInt8 fixedPacket:1;
UInt8 packet:1;
UInt8 blank:1;
UInt8 reservedTrack:1;
UInt8 nextWritableAddressValid:1;
UInt8 lastRecordedAddressValid:1;
UInt8 reserved5:6;
#else /* !__LITTLE_ENDIAN__ */
UInt8 reserved3:2;
UInt8 damage:1;
UInt8 copy:1;
UInt8 trackMode:4;
UInt8 reservedTrack:1;
UInt8 blank:1;
UInt8 packet:1;
UInt8 fixedPacket:1;
UInt8 dataMode:4;
UInt8 reserved5:6;
UInt8 lastRecordedAddressValid:1;
UInt8 nextWritableAddressValid:1;
#endif /* !__LITTLE_ENDIAN__ */
UInt32 trackStartAddress;
UInt32 nextWritableAddress;
UInt32 freeBlocks;
UInt32 fixedPacketSize;
UInt32 trackSize;
UInt32 lastRecordedAddress;
UInt8 trackNumberMSB;
UInt8 sessionNumberMSB;
UInt8 reserved6;
UInt8 reserved7;
;
typedef struct CDTrackInfo CDTrackInfo;
/*
from mmc r10a
6.2.8 Read CD
table 140
page 110
*/
typedef struct
UInt8 op_code;
#if TARGET_RT_BIG_ENDIAN
UInt8 reserved0 : 7; // <-- possibly 6?
UInt8 track : 1; // <-- possibly 2?
#else
UInt8 track : 1;
UInt8 reserved0 : 7;
#endif
UInt32 lba_or_track_number;
UInt8 reserved1;
UInt16 alloc_len;
UInt8 control;
SCSICommandDescriptorBlock_ReadTrackInfo;
OSStatus CRawDiscReader::GetTrackInfo(int trackI, CDTrackInfo *trackInfoP)
OSStatus err = noErr;
if (i_deviceH == NULL)
ERR(Open());
if (!err)
SCSI_PASS_THROUGH_DIRECT pass_thru = 0 ;
SCSICommandDescriptorBlock_ReadTrackInfo& cdb(*(SCSICommandDescriptorBlock_ReadTrackInfo *)&pass_thru.Cdb[0]);
CF_ASSERT(sizeof(cdb) == kSCSICDBSize_10Byte);
structclr(*trackInfoP);
cdb.op_code = kSCSICmd_READ_TRACK_INFORMATION;
cdb.track = true;
cdb.lba_or_track_number = trackI;
cdb.alloc_len = sizeof(CDTrackInfo);
DWORD numRead = 0;
pass_thru.Length = sizeof(pass_thru);
pass_thru.CdbLength = sizeof(cdb);
pass_thru.DataIn = SCSI_IOCTL_DATA_IN;
pass_thru.TimeOutValue = kTimeOutSeconds;
pass_thru.DataBuffer = (PVOID)trackInfoP;
pass_thru.DataTransferLength = cdb.alloc_len;
if (!DeviceIoControl(
i_deviceH,
IOCTL_SCSI_PASS_THROUGH_DIRECT,
(PVOID)&pass_thru,
(DWORD)sizeof(pass_thru),
(PVOID)&pass_thru,
(DWORD)sizeof(pass_thru),
&numRead, NULL)
)
err = GetLastError();
LogErr("reading CD:", err);
else if (numRead != pass_thru.Length)
err = GetLastError();
LogErr("reading CD:", err);
err = noErr;
if (err && err != ERR_Already_Reported)
#if OPT_WINOS
if (err == ERROR_INVALID_PARAMETER)
err = paramErr;
else
#endif
err = EIO;
return err;
【问题讨论】:
也许我正在“艰难地”做这件事。我看到 msdev 网站上有一个“TRACK_INFORMATION2”结构,这是我想要的,但我找不到有关如何获取它的信息。 我意识到 lba_or_track_number 和 alloc_len 是大端的。我已经在我的代码中修复了这个问题,但无济于事:仍然无法正常工作 【参考方案1】:答案似乎是“不要使用 IOCTL_SCSI_PASS_THROUGH_DIRECT”。
OSStatus CRawDiscReader::GetTrackInfo(IDiscRecorder2Ex *discP, int trackI, CDTrackInfo *trackInfoP)
OSStatus err = noErr;
HRESULT resultL = 0;
BYTE *dataP = NULL;
ULONG_IMAPI2_TRACK_INFORMATION outSize = 0;
structclr(*trackInfoP);
resultL = discP->GetTrackInformation(
trackI,
IMAPI_READ_TRACK_ADDRESS_TYPE_TRACK,
&dataP, &outSize);
XTE(TrapError("GetTrackInformation", resultL));
if (!err)
CDTrackInfo *returnInfoP = (CDTrackInfo *)dataP;
*trackInfoP = *returnInfoP;
CoTaskMemFree(dataP);
dataP = NULL;
SwapTrackInfo(trackInfoP);
return err;
【讨论】:
以上是关于如何使用 DeviceIOControl() 从 CD 中获取“曲目信息”?的主要内容,如果未能解决你的问题,请参考以下文章
如何通过 C#.net 中的 DeviceIoControl 使用 IOCTL_SCSI_MINIPORT?
如何在 C# 中使用 DeviceIoControl 和 FSCTL_MAKE_MEDIA_COMPATIBLE 完成 Live File System (LiveUDF) 光盘?