開発環境 Microsoft Visual C++ 2010 Express (SP1)
実行環境 Microsoft Windows XP Home Edition (SP3)
プロジェクトの種類 Win32 コンソール アプリケーション
プロジェクト名 readtrack
アプリケーションの種類 コンソール アプリケーション
追加のオプション 空のプロジェクト
文字セット Unicode

Windows Driver Kit Version 7.1.0

参考

readtrack.cpp
/*
[構成プロパティ]-[VC++ ディレクトリ]-[インクルード ディレクトリ]
C:\WinDDK\7600.16385.1\src\storage\tools\spti
 
Unicode文字セット
*/
#include <Windows.h>
#include <tchar.h>
#include <locale.h>
#include <stddef.h>
#include <stdio.h>
 
#include <ntddscsi.h>
#include <spti.h>
 
#define REVWORD(w) (((w<<8)&0xff00)|((w>>8)&0xff))
#define REVDWORD(dw) (((dw<<24)&0xff000000)|((dw<<8)&0xff0000)|((dw>>8)&0xff00)|((dw>>24)&0xff))
 
struct READTOC {
	WORD wLen;
	BYTE byStartTrack;
	BYTE byEndTrack;
	struct TRACKDESC {
		BYTE d0;
		BYTE data;
		BYTE byTrack;
		BYTE d1;
		DWORD dwLBA;
	} td[100];
};
 
// 関数プロトタイプ宣言
int ReadTrack(TCHAR cDrv, UINT uTrack, LPCTSTR pszFile);
DWORD ExecCommand(
	HANDLE hDev,		// デバイスハンドル
	PUCHAR pucCdb,		// コマンド(SCSI command descriptor block)
	UCHAR ucCdbLen,		// コマンドの長さ
	PVOID pvData,		// バッファ
	ULONG ulDataLen);	// バッファの長さ
int WriteWaveHeader(FILE *pFile, DWORD dwSampleLen);
 
//==============================================================================
int _tmain(int argc, LPTSTR argv[])
{
	TCHAR szDrv[] = _T("@:\\");
	UINT ur;
 
	_tsetlocale(LC_CTYPE, _T(""));
	if (argc != 4) {
		_ftprintf(stderr, _T("usage: readtrack drive track file\n"));
		return 1;
	}
	szDrv[0] = argv[1][0];
	ur = GetDriveType(szDrv);
	if (ur != DRIVE_CDROM) {
		_ftprintf(stderr, _T("CD-ROMドライブではありません。\n"));
		return 1;
	}
	ReadTrack(szDrv[0], _ttoi(argv[2]), argv[3]);
	return 0;
}
 
//------------------------------------------------------------------------------
#define CDDASECT 2352
#define READSECT 15
int ReadTrack(TCHAR cDrv, UINT uTrack, LPCTSTR pszFile)
{
	int nRet = -1;	// 失敗
 
	// デバイスのオープン
	TCHAR szDev[] = _T("\\\\.\\@:");
	HANDLE hDev;
	BOOL br;
 
	szDev[4] = cDrv;
	hDev = CreateFile(szDev, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ,
		NULL, OPEN_EXISTING, 0, NULL);
	if (hDev == INVALID_HANDLE_VALUE) {
		return nRet;
	}
 
	// TOCの読み込み
	BYTE byBuf[sizeof (READTOC) + 0xf];	// パラグラフ境界
	READTOC *ptoc = (READTOC *)(((UINT_PTR)byBuf + 0xf) & ~0xf);
	UCHAR ucCdb[16];
	DWORD dw;
 
	ZeroMemory(ptoc, sizeof *ptoc);
	ZeroMemory(ucCdb, sizeof ucCdb);
	ucCdb[0] = SCSIOP_READ_TOC;
	ucCdb[6] = 1;
	*(PWORD)(ucCdb + 7) = REVWORD(sizeof *ptoc);
 
	dw = ExecCommand(hDev, ucCdb, 10, ptoc, sizeof *ptoc);
	if (dw == 0) {
		goto Exit;
	}
 
	// トラックチェック
	if (uTrack < 1 || ptoc->byEndTrack < uTrack) {
		goto Exit;
	}
	if (ptoc->td[uTrack-1].data & 0x04) {	// データトラック
		goto Exit;
	}
 
	// ファイルのオープン
	FILE *pFile = NULL;
	errno_t er = _tfopen_s(&pFile, pszFile, _T("wb"));
	if (er != 0) {
		goto Exit;
	}
 
	// トラックLBA
	DWORD dwStartAddr = REVDWORD(ptoc->td[uTrack-1].dwLBA);
	DWORD dwEndAddr = REVDWORD(ptoc->td[uTrack].dwLBA);
	DWORD dwLen = dwEndAddr - dwStartAddr;
	_tprintf(_T("Track %u, LBA %u-%u, Len %u\n"), uTrack, dwStartAddr, dwEndAddr, dwLen);
 
	WriteWaveHeader(pFile, CDDASECT * dwLen);
 
	// バッファ
	BYTE byBuf2[CDDASECT * READSECT + 0xf];	// パラグラフ境界
	PBYTE pbyBuf = (PBYTE)(((UINT_PTR)byBuf2 + 0xf) & ~0xf);
 
	ZeroMemory(pbyBuf, CDDASECT * READSECT);
	ZeroMemory(ucCdb, sizeof ucCdb);
	ucCdb[0] = 0xbe;	// SCSIOP_READ_CD
	ucCdb[9] = 16;		// コマンド長
 
	for (DWORD dwLBA = dwStartAddr; dwLBA < dwEndAddr; ) {
		DWORD dwReadSize;
		if (dwEndAddr < dwLBA + READSECT) {
			dwReadSize = dwEndAddr - dwLBA;
		} else {
			dwReadSize = READSECT;
		}
		*(PDWORD)(ucCdb + 2) = REVDWORD(dwLBA);
		ucCdb[8] = (UCHAR)dwReadSize;
		dw = ExecCommand(hDev, ucCdb, 12, pbyBuf, CDDASECT * READSECT);
		if (dw == 0) {
			goto Exit;
		}
		fwrite(pbyBuf, sizeof (BYTE), CDDASECT * dwReadSize, pFile);
		dwLBA += dwReadSize;
		_tprintf(_T("\r%6u/%6u"), dwLBA, dwEndAddr);
	}
 
	nRet = 0;	// 成功
Exit:
	if (pFile) {
		int nr = fclose(pFile);
	}
	br = CloseHandle(hDev);
	return nRet;
}
 
//------------------------------------------------------------------------------
DWORD ExecCommand(
	HANDLE hDev,		// デバイスハンドル
	PUCHAR pucCdb,		// コマンド(SCSI command descriptor block)
	UCHAR ucCdbLen,		// コマンドの長さ
	PVOID pvData,		// バッファ
	ULONG ulDataLen)	// バッファの長さ
{
	SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER swb;
	DWORD dwRet;
	BOOL br;
 
	ZeroMemory(&swb, sizeof swb);
	swb.sptd.Length			= sizeof swb.sptd;
	//
	swb.sptd.CdbLength		= ucCdbLen;
	swb.sptd.SenseInfoLength	= sizeof swb.ucSenseBuf;
	swb.sptd.DataIn			= SCSI_IOCTL_DATA_IN;
	swb.sptd.DataTransferLength	= ulDataLen;
	swb.sptd.TimeOutValue		= 10;	// 秒
	swb.sptd.DataBuffer		= pvData;
	swb.sptd.SenseInfoOffset = offsetof(SCSI_PASS_THROUGH_DIRECT_WITH_BUFFER, ucSenseBuf);
	memcpy_s(&swb.sptd.Cdb, sizeof swb.sptd.Cdb, pucCdb, ucCdbLen);
 
	br = DeviceIoControl(
		hDev,
		IOCTL_SCSI_PASS_THROUGH_DIRECT,
		&swb, sizeof swb,
		&swb, sizeof swb,
		&dwRet,
		NULL);
	if (br == FALSE) {
		return 0;
	}
	return dwRet;
}
 
//------------------------------------------------------------------------------
int WriteWaveHeader(FILE *pFile, DWORD dwSampleLen)
{
	WAVEFORMATEX wf;
	DWORD dw;
 
	wf.wFormatTag		= WAVE_FORMAT_PCM;
	wf.nChannels		= 2;
	wf.nSamplesPerSec	= 44100;
	wf.nAvgBytesPerSec	= 44100 * 2 * 2;
	wf.nBlockAlign		= 2 * 2;	// 16bit 2ch
	wf.wBitsPerSample	= 16;
	wf.cbSize		= 0;
 
	fwrite("RIFF", sizeof (BYTE), 4, pFile);
	dw = 4 + 8 + sizeof (WAVEFORMATEX) + 12 + 8 + dwSampleLen;
	fwrite(&dw, sizeof (DWORD), 1, pFile);	// RIFFチャンクサイズ
	fwrite("WAVE", sizeof (BYTE), 4, pFile);
 
	fwrite("fmt ", sizeof (BYTE), 4, pFile);
	dw = sizeof (WAVEFORMATEX);
	fwrite(&dw, sizeof (DWORD), 1, pFile);	// fmtチャンクサイズ
	fwrite(&wf, sizeof (WAVEFORMATEX), 1, pFile);
 
	fwrite("fact", sizeof (BYTE), 4, pFile);
	dw = sizeof (DWORD);
	fwrite(&dw, sizeof (DWORD), 1, pFile);	// factチャンクサイズ
	fwrite(&dwSampleLen, sizeof (DWORD), 1, pFile);
 
	fwrite("data", sizeof (BYTE), 4, pFile);
	fwrite(&dwSampleLen, sizeof (DWORD), 1, pFile);	// dataチャンクサイズ
 
	return 0;
}
 

出力
C:\projects\vc++\readtrack\Debug>readtrack e 2 track02.wav
Track 2, LBA 5412-34540, Len 29128
 34540/ 34540
最終更新:2012年10月12日 22:58