현재 윈도우 XP는 컴퓨터를 사용하는데 필요한 기능을 모두 가지고 있습니다. 그 중에 가장 눈에 띄는 것이 새롭게 내장된 CD Burn 기능입니다. 이 기능은 MS의 요청에 따라 아답텍에서 만든 IMAPI(Image Mastering API)를 이용하는데, 이지CD 크리에이터의 다이렉트 CD와 같다고 생각하면 됩니다.
기존에 이지CD 크리에이터 사용자라면 혹시 엔진이 불안정하지 않을까 생각할 지도 모릅니다. 실제로 아답텍의 이지CD 크리에이터는 프로그램의 불안정으로 인한 잦은 패치로 사용자들의 불만을 샀기 때문입니다. 초기에 윈도우 XP에 내장된 IMAPI도 이지CD 크리에이터나 네로(Nero) Burn 등의 다른 프로그램과의 호환성 문제 및 CD 기록기기와의 문제가 있었지만 지금은 거의 다 해결된 상태이므로 걱정할 필요는 없습니다.
CD Burn 프로그램 설계·구현
CD에 파일을 저장하거나 복사할 때 운영체제는 사전에 하드 드라이브에 이미지를 마스터한 후 CD를 굽게 됩니다. 이때 사전 마스터링은 기록 과정상에 에러가 생기는 것을 방지하고 고속 기록시에 미디어가 필요 없이 렌더하는 것을 최소화합니다. IMAPI는 이 이미지를 마스터링(혹은 CD Burn)하는 API라는 뜻으로, 현재 줄리엣(Jolliet)과 ISO9660 형식의 데이터 디스크와 레드북 형식의 오디오 디스크를 지원하고 있습니다.
IMAPI와 COM 객체
IMAPI에는 네 개의 주요 COM 객체와 인터페이스가 있습니다.
② MSDiscRecorderObj
③ MSDiscStashObj
④ MSBurnEngineObj
MSDiscStashObj와 MSBurnEngineObj 객체는 IMAPI에 접근하는 내부 인터페이스로, IMAPI 아키텍처를 쉽게 이해할 수 있도록 간단히 언급만 되어 있습니다. MSDiscStashObj(IDiscStash 인터페이스를 통해)는 MSDiscMasterObj에 이용되는 Raw 파일(800MB까지 허용)로 구워질 오디오 이미지나 데이터 디스크라고 생각하면 됩니다. 이 Stash는 로우 레벨 엔진으로부터 굽기가 요청되면(IMSBurnEngine 인터페이스를 통해) MSBurnEngineObj로 건네집니다.
그 외 MSDiscMasterObj 객체는 다음 다이어그램처럼 세 개의 인터페이스를 제공합니다. 그 중 IDiscMaster 인터페이스는 IMAPI 열기와 지원 포맷 나열하기, 포맷 선택하기, 레코더 리스트 보이기, 레코더 선택하기, 굽기, IMAPI 닫기 등을 할 수 있습니다.

그리고 IJolietDiscMaster와 IRedbookDiscMaster 인터페이스는 각각 데이터와 오디오 디스크를 컨트롤하며 IDiscMaster 인터페이스를 통해 포맷을 선택한 후 사용할 수 있습니다. 또 MSDiscRecorderObj 객체는 IDiscRecorder 인터페이스를 통해 접근할 수 있습니다. IMAPI와 호환되는 모든 CD-R과 CD-RW 디바이스는 MSDiscRecorderObj 객체를 가지고 있으며, CD 굽기에 사용될 디바이스를 선택하기 위해 MSDiscRecorderObj 객체의 IDiscRecorder 인터페이스 포인터를 사용합니다. 이를 통해 굽는 속도와 다른 여러 변수들을 설정할 수 있습니다.
이 외에 CD를 굽기 위해 ICDBurn 인터페이스를 사용할 수 있는데 이는 윈도우 셸로, CD에 파일을 쓰기 한 하드웨어가 시스템에 있는지 알아보고 그 디바이스의 drive letter를 알아낼 수 있습니다. 또 staging 파일을 CD로 만들 수 있는데, 이 역시 IMAPI를 기반으로 만들어져 있습니다.

IMAPI를 이용한 구현
그럼 이제 IMAPI를 이용해 애플리케이션을 만들어 봅니다. 이해하기 쉽도록 단계별로 설명합니다. 먼저 MSDiscMasterObj의 인스턴스를 생성하여 IDiscMaster 인터페이스를 요청합니다.
IID_IDiscMaster, (void**)&m_pDiscMaster);
이제 IDiscMaster::Open을 불러 IMAPI에 접근하면 MSDiscMasterObj에 구현된 모든 인터페이스와 메소드를 사용할 수 있습니다.
다음은 EnumDiscMasterFormats을 이용해 지원 포맷을 나열합니다. Enumerator에서 돌아오는 포맷은 IJolietDiscMaster와 IRedbookDiscMaster의 인터페이스 IID입니다. 그리고 Image Mastering 객체는 여러 포맷을 지원할 수 있지만 특정 레코더에서 포맷을 지원하지 않을 수 있으므로 SetActiveDiscMasterFormat으로 포맷을 선택한 후 SetActiveDiscRecorder로 레코더를 선택해야 합니다. 현재 IMAPI는 줄리엣과 Redbook 만을 지원하고 있으므로 유의하기 바랍니다.
while(m_penumFormat->Next(1, &guidFormat, &nRet) == S_OK)
// 오디오일 경우는 IID_IRedbookDiscMaster로 변경한다.
if(guidFormat == IID_IJolietDiscMaster)
break;
이제 지원하는 포맷에서 액티브 시킬 포맷을 선택합니다.
앞에서 말한 것처럼 이제 EnumDiscRecorders를 이용해 지원하는 레코더를 나열합니다. 여기서 IDiscRecorder 인터페이스는 물리적인 디바이스를 나타냅니다.
while(m_penumRecorder->Next(1, &m_pDiscRecorder, &nRet) == S_OK){
……
}
만약 일반적인 레코더 프로그램과 같이 드라이브 정보를 사용자에게 보여주고자 한다면 next를 누른 후에 <리스트 1>과 같은 코드를 이용해 정보를 보여줍니다.



이제 지원하는 레코더에서 액티브 시킬 레코더를 선택합니다.
Progress callback을 위해 IDiscMaster::ProgressAdvise를 사용합니다. 이를 통해 데이터가 더해지는 상황이나 구워지는 상황, 그리고 다 구워졌는지, 닫는 중인지 등에 대한 정보를 알 수 있습니다. 하지만 CD 지우기의 경우 진행상황을 알려주지 않으므로 이 점을 유의해야 합니다.
m_pDiscMasterProgessEvent = m_pEvent;
m_pDiscMaster-> ProgressAdvise(m_pDiscMasterProgessEvent, &nCookie);
이로써 나만의 오디오와 데이터 디스크 제작 프로그램을 만들기 위한 준비를 마쳤습니다. IMAPI는 오디오와 데이터 디스크를 구분하므로 지금부터는 오디오와 데이터를 구분하여 설명합니다.
오디오 디스크 만들기
『오디오는 트랙으로 각 곡을 구분하므로 오디오 트랙이 새로 시작된 것을 알리기 위해 IRedbookDiscMaster:: Create AudioTrack을 사용합니다. 여기서 문제가 하나 있는데 현재 IMAPI는 RIFF 타입의 PCM, 스테레오, 44.1KHz, 16비트의 WAV 파일만을 지원하며 이외의 파일은 오디오 디스크를 만들어 보면 재생시에 빠르게 들리거나 느리게 들립니다. 따라서 속성이 같은지 확인해야 합니다. 만약 Directshow를 사용할 수 있다면 변환 필터를 만들어서 앞서 설명한 것과 같은 형태로 만들면 됩니다.
dwRead = sourceFile.Read(&RiffHeader, sizeof(RiffHeader));
strnicmp(RiffHeader.id, “RIFF”, 4);
strnicmp(RiffHeader.wave_id, “WAVE”, 4);
while(TRUE){
dwRead = sourceFile.Read(&RiffChunk, sizeof(RiffChunk));
if(strnicmp(RiffChunk.id, “data”, 4) == 0)
break;
dwRead = sourceFile.Read(&RiffChunk.len, RiffChunk.len);
}
nBlocks = RiffChunk.len / 2352;
if(RiffChunk.len % 2352)
nBlocks++;
m_pRedbookDiscMaster->CreateAudioTrack(nBlocks);
트랙에 오디오 데이터를 추가하기 위해 IRedbookDisc Master::AddAudioTrackBlocks을 사용합니다. 디스크에 대한 정보가 필요하다면 GetAvailableAudioTrackBlocks, GetTotalAudioBlocks와 GetUsedAudioBlocks을 먼저 사용해 정보를 얻습니다.』①
for(int k = 0; k memset(blocks, 0, 2352); if(k == (nBlocks - 1)) dwReadLen = RiffChunk.len % 2352; sourceFile.Read(blocks, dwReadLen); m_pRedbookDiscMaster-> AddAudioTrackBlocks(blocks, 2352); } sourceFile.Close();
이제 IRedbookDiscMaster::CloseAudioTrack을 이용하여 트랙을 닫습니다.
만약 오디오 데이터를 여러 개 추가하는 상황이라면 『 』①부분을 반복합니다. 단 트랙은 99개까지만 추가할 수 있으므로 유의하기 바랍니다.
데이터 디스크 만들기
『데이터 디스크 이미지 제작에는 IJolietDiscMaster:: AddData를 사용합니다. 디스크에 대한 정보가 필요하다면 GetTotalDataBlocks와 GetUsedDataBlocks을 먼저 사용해 정보를 얻어옵니다. 여기서 AddData를 하기 위해 IStorage 타입의 Storage를 먼저 만들어야 합니다.』 ②
오디오와 마찬가지로 데이터를 여러 개 추가하려면 『 』②를 반복합니다. 이제 마지막으로 IDiscMaster:: RecordDisc를 사용해 디스크를 굽습니다. 만약 첫 번째 파라미터를 true로 놓으면 액티브 디스크 레코더에 있는 미디어는 실제로 구워지지 않고 simulated burn이 실행됩니다. 두 번째 파라미터는 구운 후에 미디어가 나오는지 여부를 가리킵니다. true로 놓으면 미디어가 eject됩니다.
이제 굽기가 끝났으므로 진행 상황 등을 통보하는 것을 끝냅니다.
delete m_pEvent;
마지막으로 IDiscMaster::Close를 이용하여 IMAPI를 닫으면 CD Burn이 끝나게 됩니다.
IMAPI 인터페이스
지금까지 간단한 CD Burn 프로그램을 작성해 보았습니다. 하지만 제대로 작동하는 프로그램을 만들기 위해서는 앞의 작업 외에 다음과 같은 작업을 추가로 해 주어야 합니다. 먼저 레코더가 CD-R인지 CD-RW인지 알아야 합니다. 그래야 CD-RW 미디어를 지우거나 구울 때 문제가 생기지 않습니다.
그 다음 레코더에 들어 있는 미디어의 타입을 알아야 합니다. 앞에서와 마찬가지로 레코더에 미디어가 들어 있는지, 아니면 미디어에 데이터가 있는지 알아야 구울 때 문제가 생기지 않습니다. CD-RW의 경우 세션을 열어두면 데이터를 다시 넣을 수 있기 때문입니다.
m_pDiscRecorder->QueryMediaType(&fMediaType, &fMediaFlags);
m_pDiscRecorder->Close();
그리고 미디어의 정보를 얻어옵니다. 미디어의 용량이 얼마이고 남은 용량이 얼마인지 알 수 있습니다.
m_pDiscRecorder->QueryMediaInfo(&pbsessions, &pblasttrack, &ulstartadress,
&ulnextwritable, &ulfreeblocks);
m_pDiscRecorder->Close();
또 데이터 디스크의 속성을 얻어와 설정할 수 있습니다. VolumeName은 레코딩 후의 디스크 볼륨 이름으로, 기본으로 현재 날짜가 설정되어 있습니다. 이외에 GetRecorder Properties를 사용하여 WriteSpeed, AudioGapSize를 설정할 수 있습니다. 단 디스크 불륨 이름은 IStorage spec상 unicode 32글자까지만 가능합니다.


이제 레코더의 상태를 알아야 합니다. 이를 통해 레코더가 사용할 수 있는 상태인지 아닌지를 알 수 있습니다.
if(fRecorderState != RECORDER_DOING_NOTHING)
return;
끝으로 디스크를 지울 수 있습니다. 그런데 full erase는 때때로 1시간을 초과할 정도로 매우 긴 동작이 될 수 있으므로 quick erase로 디스크를 지웁니다.
m_pDiscRecorder->Erase(FALSE);
m_pDiscRecorder->Close();
ProgressAdvise를 위해서는 IDiscMasterProgressEvents를 상속받은 CDiscMasterProgressEvents 클래스를 생성하여 IMAPI가 호출하였을 때 해줄 일을 작성해야 합니다. 이를 통해 Progress를 만들어 동작시킬 수 있습니다.
HRESULT _stdcall NotifyPnPActivity();
HRESULT _stdcall NotifyAddProgress(long nCompleteSteps, long nTotalSteps);
HRESULT _stdcall NotifyBlockProgress(long nCompleted, long nTotal);
HRESULT _stdcall NotifyTrackProgress(long nCurrentTrack, long nTotalTracks);
HRESULT _stdcall NotifyPreparingBurn(long nEstimatedSeconds);
HRESULT _stdcall NotifyClosingDisc(long nEstimatedSeconds);
HRESULT _stdcall NotifyBurnComplete(HRESULT status);
HRESULT _stdcall NotifyEraseComplete(HRESULT status);
그리고 Storage를 만들어야 합니다. 폴더일 경우 다음과 같이 recursive로 폴더와 파일을 Storage로 만들어 줍니다.
파일일 경우 다음과 같이 파일을 읽어 Stream으로 만들어 준다.
…
pIStream->Write(buf, dwRead, pcbWritten);
그리고 최종적으로 root Storage를 만들어 준다.
STGM_READWRITE
0, NULL, NULL, IID_IStorage, (void**)&pIStorage);
이외에도 미디어가 Insert되고 Removal 되는 것을 확인해야 하고 CD를 굽기 위해 준비하는 동안 레코더를 Lock 시켜 놓아야 안전하게 레코딩을 할 수 있습니다. 또 레코딩하는 동안 로그오프를 하지 못하도록 메시지 처리를 해 주는 것도 중요합니다.
윈도우 XP CD Burn 기능의 문제점과 개선방안
지금까지 간단한 CD Burn 프로그램을 작성하여 보았는데 이제 윈도우 XP CD Burn 프로그램에서는 IMAPI를 어떻게 사용하는지 알아보도록 하겠습니다.
앞에서 말한 것처럼 윈도우 XP에서는 단순히 끌어서 놓기만으로 CD Burn 기능을 사용할 수 있습니다. 하지만 윈도우 XP에서는 끌어서 놓기를 한 파일이나 폴더를 먼저 %userprofile%Local SettingsApplication Data MicrosoftCD Burning으로 복사해 놓은 후에 CD 굽기를 실행합니다.
이는 윈도우 XP에 내장된 CD Burn 기능의 목적이 CD를 하드 드라이브를 사용하듯이 쓰는데 있기 때문인데 굽고자 하는 파일이나 폴더가 다른 하드 드라이브에 있을 경우 복사하는데 많은 시간이 소요되는 문제가 있습니다. 따라서 프로그램을 작성할 때 이 점에 유의해서 스토리지를 먼저 만들어 복사 시간을 없애야 합니다.
그리고 시스템에서 Image Mastering API를 통해 MSDiscMasterObj의 여러 인스턴스를 액티브할 수 있는데 윈도우 XP의 CD Burn은 한번에 오직 single disc stash만 열 수 있도록 하였습니다. 따라서 구조를 잘 만들면 제약사항이 있기는 하겠지만 2개 이상의 레코더에서 동시에 CD를 지우거나 구울 수도 있을 것입니다.
또 CD를 굽거나 지울 때의 진행상황이 정확하지 않은데, 이는 CD Burn 기능의 문제라기보다 IMAPI의 문제입니다. IMAPI에서 지원을 하지만 부정확한 정보를 넘겨주거나 CD 지우기 경우처럼 IMAPI에서 진행상황을 알려주지 않기 때문입니다. 따라서 프로그램 제작시에 이 점을 유의해야 합니다.
그리고 IMAPI를 사용할 때는, 이 API가 일반 CD Burn 프로그램을 작성할 수 있도록 만들어져 있기는 하지만 다이렉트 CD와 같은 방식의 CD Burn 프로그램을 만드는데 사용된 것을 생각한다면 일반적인 CD Burn 프로그램을 만들 경우 많은 사항을 고려하여 만들어야 된다는 것을 명심해야 할 것입니다.
지금까지 윈도우 XP의 CD Burn 프로그램의 문제점에 대해서 알아봤는데 윈도우 XP CD Burn 프로그램은 장점이 많습니다. 첫째 IMAPI를 통해 CD 굽기 기능을 쉽게 사용할 수 있으며, 둘째 드라이브 접근을 지원하여 한결 편리합니다. 셋째 Removable 스토리지처럼 쓸 수 있습니다. 넷째 드래그 앤 드롭 기능을 들 수 있습니다. 다섯째 특별한 애플리케이션이 필요 없습니다.
여섯째 운영체제에서 지원합니다. 일곱째 매체를 초기화하는 시간이 필요 없습니다. 여덟째 더욱 매력적인 것은 차세대 운영체제(Longhorn)에서도 이를 발전/사용할 수 있다는 것입니다(이름하야 IMAPI V2). 여러분들도 이런 점들을 감안하여 프로그램을 작성한다면 더 좋은 프로그램을 만들 수 있을 것입니다.
IMAPI의 미래
MS는 내년 출시 예정인 차세대 운영체제 롱혼(Longhorn)에 DVD(+RW/+R) Writing 기능 지원을 계획하고 있다고 합니다. 예를 들어 개인 자료를 쉽게 백업하거나 PC 사이에 기가급의 여러 파일들을 쉽게 전달하고 가족이나 친구와 캠코더로 찍은 비디오를 쉽게 전달할 수 있도록 DVD Writing을 지원할 예정입니다. 또 사용 편리성을 위해 드래그 앤 드롭 스타일의 Writing을 여전히 지원할 것으로 보입니다.
또한 CD-RW/-R, DVD-RW/-R, DVD-RAM, DVD+ RW/+R을 지원하며 IMAPI와 burn-engine 기능을 둘 다 사용할 수 있게 확장할 계획이라고 하니 기대가 됩니다. 지금까지 IMAPI에 대해 알아보고 이를 이용한 간단한 CD Burn 프로그램을 작성해 보았습니다. 여러분도 한번 직접 프로그램을 만들어 보기 바랍니다. 자기가 만든 프로그램을 다른 사람들이 유용하게 쓰는 것만큼 좋은 일은 없는 것 같습니다. @
* 이 기사는 ZDNet Korea의 자매지인 마이크로소프트웨어에 게재된 내용입니다.
지금 뜨는 기사
이시각 헤드라인
ZDNet Power Center
