2313 lines
62 KiB
C++
2313 lines
62 KiB
C++
/*++
|
|
|
|
Copyright (c) 2005 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
imapi2sample.c
|
|
|
|
Abstract:
|
|
|
|
A user mode console app that demenstrates the IMAPIv2 interfaces.
|
|
|
|
Environment:
|
|
|
|
User mode only
|
|
|
|
Revision History:
|
|
|
|
01-01-05 : Created
|
|
|
|
--*/
|
|
#include "imapi2sample.h"
|
|
#include <ntverp.h>
|
|
|
|
#define BOOLEAN_STRING(_x) ((_x)?"TRUE":"FALSE")
|
|
|
|
VOID
|
|
PrintHelp(
|
|
WCHAR * selfName
|
|
)
|
|
{
|
|
printf("%S: %s\n"
|
|
"Usage:\n"
|
|
"%S -list\n"
|
|
"%S -write <dir> [-multi] [-close] [-drive <#>] [-boot <file>]\n"
|
|
"%S -audio <dir> [-close] [-drive <#>]\n"
|
|
"%S -raw <dir> [-close] [-drive <#>]\n"
|
|
"%S -image <file>[-close] [-drive <#>] [-bufe | -bufd]\n"
|
|
"%S -erase [-drive <#>]\n"
|
|
"\n"
|
|
"\tlist -- list the available writers and their index.\n"
|
|
"\terase -- quick erases the chosen recorder.\n"
|
|
"\tfullerase -- full erases the chosen recorder.\n"
|
|
"\twrite -- Writes a directory to the disc.\n"
|
|
"\t <dir> -- Directory to be written.\n"
|
|
"\t [-SAO] -- Use Cue Sheet recording.\n"
|
|
"\t [-close] -- Close disc (not appendable).\n"
|
|
"\t [-drive <#>] -- choose the given recorder index.\n"
|
|
"\t [-iso, -udf, -joliet] -- specify the file system to write.\n"
|
|
"\t [-multi] -- Add an additional session to disc.\n"
|
|
"\t [-boot <file>] -- Create a boot disk. File is a boot image.\n"
|
|
"\teject -- Eject the CD tray\n"
|
|
"\tinject -- Close the CD tray\n",
|
|
selfName, VER_PRODUCTVERSION_STR,
|
|
selfName,selfName,selfName,selfName,selfName,selfName
|
|
);
|
|
return;
|
|
}
|
|
|
|
BOOLEAN
|
|
ParseCommandLine(
|
|
IN DWORD Count,
|
|
IN WCHAR * Arguments[],
|
|
OUT PPROGRAM_OPTIONS Options
|
|
)
|
|
{
|
|
BOOLEAN goodEnough = FALSE;
|
|
// initialize with defaults
|
|
RtlZeroMemory( Options, sizeof(PROGRAM_OPTIONS) );
|
|
|
|
for ( DWORD i = 0; i < Count; i++ )
|
|
{
|
|
if ( (Arguments[i][0] == '/') || (Arguments[i][0] == '-') )
|
|
{
|
|
BOOLEAN validArgument = FALSE;
|
|
Arguments[i][0] = '-'; // minimize checks below
|
|
|
|
//
|
|
// If the first character of the argument is a - or a / then
|
|
// treat it as an option.
|
|
//
|
|
if ( _wcsnicmp(Arguments[i], (L"-write"), strlen("-write")) == 0 )
|
|
{
|
|
Options->Write = TRUE;
|
|
validArgument = TRUE;
|
|
}
|
|
else if ( _wcsnicmp(Arguments[i], (L"-image"), strlen("-image")) == 0 )
|
|
{
|
|
Options->Image = TRUE;
|
|
validArgument = TRUE;
|
|
}
|
|
else if ( _wcsnicmp(Arguments[i], (L"-audio"), strlen("-audio")) == 0 )
|
|
{
|
|
Options->Audio = TRUE;
|
|
validArgument = TRUE;
|
|
}
|
|
else if ( _wcsnicmp(Arguments[i], (L"-raw"), strlen("-raw")) == 0 )
|
|
{
|
|
Options->Raw = TRUE;
|
|
validArgument = TRUE;
|
|
}
|
|
else if ( _wcsnicmp(Arguments[i], (L"-close"), strlen("-close")) == 0 )
|
|
{
|
|
Options->CloseDisc = TRUE;
|
|
validArgument = TRUE;
|
|
}
|
|
else if ( _wcsnicmp(Arguments[i], (L"-multi"), strlen("-multi")) == 0 )
|
|
{
|
|
Options->Multi = TRUE;
|
|
validArgument = TRUE;
|
|
}
|
|
else if ( _wcsnicmp(Arguments[i], (L"-iso"), strlen("-iso")) == 0 )
|
|
{
|
|
Options->Iso = TRUE;
|
|
validArgument = TRUE;
|
|
}
|
|
else if ( _wcsnicmp(Arguments[i], (L"-joliet"), strlen("-joliet")) == 0 )
|
|
{
|
|
Options->Joliet = TRUE;
|
|
validArgument = TRUE;
|
|
}
|
|
else if ( _wcsnicmp(Arguments[i], (L"-udf"), strlen("-udf")) == 0 )
|
|
{
|
|
Options->UDF = TRUE;
|
|
validArgument = TRUE;
|
|
}
|
|
else if ( _wcsnicmp(Arguments[i], (L"-free"), strlen("-free")) == 0 )
|
|
{
|
|
Options->FreeSpace = TRUE;
|
|
validArgument = TRUE;
|
|
}
|
|
else if ( _wcsnicmp(Arguments[i], (L"-inject"), strlen("-inject")) == 0 )
|
|
{
|
|
Options->Close = TRUE;
|
|
validArgument = TRUE;
|
|
}
|
|
else if ( _wcsnicmp(Arguments[i], (L"-eject"), strlen("-eject")) == 0 )
|
|
{
|
|
Options->Eject = TRUE;
|
|
validArgument = TRUE;
|
|
}
|
|
else if ( _wcsnicmp(Arguments[i], (L"-drive"), strlen("-drive")) == 0 )
|
|
{
|
|
// requires second argument
|
|
if ( i+1 < Count )
|
|
{
|
|
i++; // advance argument index
|
|
ULONG tmp = 666;
|
|
if ( (swscanf_s( Arguments[i], (L"%d"), &tmp ) == 1) &&
|
|
(tmp != 666) )
|
|
{
|
|
// Let's do this zero based for now
|
|
Options->WriterIndex = tmp;
|
|
validArgument = TRUE;
|
|
}
|
|
}
|
|
|
|
if ( !validArgument )
|
|
{
|
|
printf("Need a second argument after drive,"
|
|
" which is the one-based index to the\n"
|
|
"writer to use in decimal format. To"
|
|
"get a list of available drives and"
|
|
"their indexes, use \"-list\" option\n"
|
|
);
|
|
}
|
|
}
|
|
else if ( _wcsnicmp(Arguments[i], (L"-boot"), strlen("-boot")) == 0 )
|
|
{
|
|
// requires second argument
|
|
if ( i+1 < Count )
|
|
{
|
|
i++; // advance argument index
|
|
ULONG tmp = 666;
|
|
if ( Arguments[i] != NULL )
|
|
{
|
|
// Let's do this zero based for now
|
|
Options->BootFileName = Arguments[i];
|
|
validArgument = TRUE;
|
|
}
|
|
}
|
|
|
|
if ( !validArgument )
|
|
{
|
|
printf("Need a second argument after boot,"
|
|
" which is the boot file the\n"
|
|
"writer will use\n"
|
|
);
|
|
}
|
|
}
|
|
else if ( _wcsnicmp(Arguments[i], (L"-vol"), strlen("-vol")) == 0 )
|
|
{
|
|
// requires second argument
|
|
if ( i+1 < Count )
|
|
{
|
|
i++; // advance argument index
|
|
ULONG tmp = 666;
|
|
if ( Arguments[i] != NULL )
|
|
{
|
|
// Let's do this zero based for now
|
|
Options->VolumeName = Arguments[i];
|
|
validArgument = TRUE;
|
|
}
|
|
}
|
|
|
|
if ( !validArgument )
|
|
{
|
|
printf("Need a second argument after vol,"
|
|
" which is the volume name for\n"
|
|
"the disc\n"
|
|
);
|
|
}
|
|
}
|
|
else if ( _wcsnicmp(Arguments[i], (L"-list"), strlen("-list")) == 0 )
|
|
{
|
|
Options->ListWriters = TRUE;
|
|
validArgument = TRUE;
|
|
}
|
|
else if ( _wcsnicmp(Arguments[i], (L"-erase"), strlen("-erase")) == 0 )
|
|
{
|
|
Options->Erase = TRUE;
|
|
Options->FullErase = FALSE;
|
|
validArgument = TRUE;
|
|
}
|
|
else if ( _wcsnicmp(Arguments[i], (L"-fullerase"), strlen("-fullerase")) == 0 )
|
|
{
|
|
Options->Erase = TRUE;
|
|
Options->FullErase = TRUE;
|
|
validArgument = TRUE;
|
|
}
|
|
else if ( _wcsnicmp(Arguments[i], (L"-?"), strlen("-?")) == 0 )
|
|
{
|
|
printf("Requesting help\n");
|
|
}
|
|
else
|
|
{
|
|
printf("Unknown option -- %S\n", Arguments[i]);
|
|
}
|
|
|
|
if(!validArgument)
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
else if ( Options->FileName == NULL )
|
|
{
|
|
//
|
|
// The first non-flag argument is the ISO to write name.
|
|
//
|
|
|
|
Options->FileName = Arguments[i];
|
|
|
|
}
|
|
else
|
|
{
|
|
|
|
//
|
|
// Too many non-flag arguments provided. This must be an error.
|
|
//
|
|
|
|
printf("Error: extra argument %S not expected\n", Arguments[i]);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Validate the command-line arguments.
|
|
//
|
|
if ( Options->ListWriters )
|
|
{
|
|
// listing the Writers stands alone
|
|
if ( !(Options->Write || Options->Erase ) )
|
|
{
|
|
goodEnough = TRUE;
|
|
}
|
|
else
|
|
{
|
|
printf("Error: Listing writers must be used alone\n");
|
|
}
|
|
}
|
|
else if ( Options->Write )
|
|
{
|
|
// Write allows erase, but not self-test
|
|
// Write requires at least a filename
|
|
if ( Options->FileName != NULL )
|
|
{
|
|
goodEnough = TRUE;
|
|
}
|
|
else
|
|
{
|
|
printf("Error: Write requires directory\n");
|
|
}
|
|
|
|
// validate erase options?
|
|
}
|
|
else if ( Options->Image )
|
|
{
|
|
// Write allows erase, but not self-test
|
|
// Write requires at least a filename
|
|
if ( Options->FileName != NULL )
|
|
{
|
|
goodEnough = TRUE;
|
|
}
|
|
else
|
|
{
|
|
printf("Error: Image requires filename\n");
|
|
}
|
|
|
|
}
|
|
else if ( Options->Audio )
|
|
{
|
|
// Write allows erase, but not self-test
|
|
// Write requires at least a filename
|
|
if ( Options->FileName != NULL )
|
|
{
|
|
goodEnough = TRUE;
|
|
}
|
|
else
|
|
{
|
|
printf("Error: Audio requires directory\n");
|
|
}
|
|
|
|
}
|
|
|
|
else if ( Options->Raw )
|
|
{
|
|
// Write allows erase, but not self-test
|
|
// Write requires at least a filename
|
|
if ( Options->FileName != NULL )
|
|
{
|
|
goodEnough = TRUE;
|
|
}
|
|
else
|
|
{
|
|
printf("Error: Raw requires directory\n");
|
|
}
|
|
|
|
}
|
|
|
|
else if ( Options->Erase )
|
|
{
|
|
// validate erase options?
|
|
goodEnough = TRUE;
|
|
}
|
|
|
|
|
|
// These are not stand alone options.
|
|
//if ( Options->CloseDisc )
|
|
//{
|
|
// //printf("Option 'DiscOpen' is not yet implemented\n");
|
|
// goodEnough = TRUE;
|
|
//}
|
|
//if ( Options->Multi )
|
|
//{
|
|
// goodEnough = TRUE;
|
|
//}
|
|
|
|
if ( Options->FreeSpace )
|
|
{
|
|
goodEnough = TRUE;
|
|
}
|
|
if ( Options->Eject )
|
|
{
|
|
goodEnough = TRUE;
|
|
}
|
|
if ( Options->Close )
|
|
{
|
|
goodEnough = TRUE;
|
|
}
|
|
|
|
if ( !goodEnough )
|
|
{
|
|
RtlZeroMemory( Options, sizeof(PROGRAM_OPTIONS) );
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//*********************************************************************
|
|
//* FUNCTION: GetSecondsElapsed
|
|
//*
|
|
//* PURPOSE:
|
|
//*********************************************************************
|
|
DWORD
|
|
GetSecondsElapsed(
|
|
SYSTEMTIME * StartTime,
|
|
SYSTEMTIME * EndTime)
|
|
{
|
|
FILETIME Start,End;
|
|
unsigned __int64 Start64=0, End64=0, Elapsed64=0;
|
|
|
|
|
|
//
|
|
//--- Convert System time
|
|
//
|
|
SystemTimeToFileTime(StartTime,&Start);
|
|
SystemTimeToFileTime(EndTime,&End);
|
|
|
|
|
|
//
|
|
//---- Convert start and end file
|
|
//---- time to 2 64 bit usigned integers
|
|
//
|
|
((LPDWORD)(&Start64))[1] = Start.dwHighDateTime;
|
|
((LPDWORD)(&Start64))[0] = Start.dwLowDateTime;
|
|
|
|
((LPDWORD)(&End64))[1] = End.dwHighDateTime;
|
|
((LPDWORD)(&End64))[0] = End.dwLowDateTime;
|
|
|
|
|
|
//
|
|
//--- Calc elpased time
|
|
//
|
|
Elapsed64 = End64 - Start64;
|
|
|
|
//
|
|
//---- Get micro seconds elpased
|
|
//
|
|
Elapsed64 /= 10;
|
|
|
|
//
|
|
//--- Get milly seconds elpased
|
|
//
|
|
Elapsed64 /= 1000;
|
|
|
|
//
|
|
//--- Get Secconds elpased
|
|
//
|
|
Elapsed64 /= 1000;
|
|
|
|
//
|
|
//--- Return the LowDateTime of seconds elapsed
|
|
//--- This will be good enough for ~136 years elapsed
|
|
//
|
|
return(((LPDWORD)(&Elapsed64))[0]);
|
|
}
|
|
|
|
//*********************************************************************
|
|
//* FUNCTION:CalcElapsedTime
|
|
//*
|
|
//* PURPOSE:
|
|
//*********************************************************************
|
|
#define SECONDS_IN_A_DAY ((DWORD)(SECONDS_IN_A_HOUR*24))
|
|
#define SECONDS_IN_A_HOUR ((DWORD)(SECONDS_IN_A_MINUTE*60))
|
|
#define SECONDS_IN_A_MINUTE ((DWORD)(60))
|
|
void
|
|
CalcElapsedTime(
|
|
SYSTEMTIME * StartTime,
|
|
SYSTEMTIME * FinishTime,
|
|
SYSTEMTIME * ElapsedTime)
|
|
{
|
|
DWORD SecondsElapsed;
|
|
|
|
memset(ElapsedTime,0,sizeof(SYSTEMTIME));
|
|
|
|
SecondsElapsed = GetSecondsElapsed(
|
|
StartTime, FinishTime);
|
|
|
|
|
|
if(SecondsElapsed >= SECONDS_IN_A_DAY)
|
|
{
|
|
ElapsedTime->wDay = (WORD) (SecondsElapsed / SECONDS_IN_A_DAY);
|
|
SecondsElapsed -= (ElapsedTime->wDay*SECONDS_IN_A_DAY);
|
|
}
|
|
|
|
|
|
if(SecondsElapsed >= SECONDS_IN_A_HOUR)
|
|
{
|
|
ElapsedTime->wHour = (WORD) (SecondsElapsed / SECONDS_IN_A_HOUR);
|
|
SecondsElapsed -= (ElapsedTime->wHour * SECONDS_IN_A_HOUR);
|
|
}
|
|
|
|
if(SecondsElapsed >= SECONDS_IN_A_MINUTE)
|
|
{
|
|
ElapsedTime->wMinute = (WORD) (SecondsElapsed / SECONDS_IN_A_MINUTE);
|
|
SecondsElapsed -= (ElapsedTime->wMinute * SECONDS_IN_A_MINUTE);
|
|
}
|
|
|
|
|
|
ElapsedTime->wSecond = (WORD) SecondsElapsed;
|
|
|
|
}
|
|
|
|
|
|
// using a simple array due to consecutive zero-based values in this enum
|
|
CHAR * g_MediaTypeStrings[] = {
|
|
"IMAPI_MEDIA_TYPE_UNKNOWN",
|
|
"IMAPI_MEDIA_TYPE_CDROM",
|
|
"IMAPI_MEDIA_TYPE_CDR",
|
|
"IMAPI_MEDIA_TYPE_CDRW",
|
|
"IMAPI_MEDIA_TYPE_DVDROM",
|
|
"IMAPI_MEDIA_TYPE_DVDRAM",
|
|
"IMAPI_MEDIA_TYPE_DVDPLUSR",
|
|
"IMAPI_MEDIA_TYPE_DVDPLUSRW",
|
|
"IMAPI_MEDIA_TYPE_DVDPLUSR_DUALLAYER",
|
|
"IMAPI_MEDIA_TYPE_DVDDASHR",
|
|
"IMAPI_MEDIA_TYPE_DVDDASHRW",
|
|
"IMAPI_MEDIA_TYPE_DVDDASHR_DUALLAYER",
|
|
"IMAPI_MEDIA_TYPE_DISK",
|
|
"IMAPI_MEDIA_TYPE_DVDPLUSRW_DUALLAYER",
|
|
"IMAPI_MEDIA_TYPE_HDDVDROM",
|
|
"IMAPI_MEDIA_TYPE_HDDVDR",
|
|
"IMAPI_MEDIA_TYPE_HDDVDRAM",
|
|
"IMAPI_MEDIA_TYPE_BDROM",
|
|
"IMAPI_MEDIA_TYPE_BDR",
|
|
"IMAPI_MEDIA_TYPE_BDRE",
|
|
"IMAPI_MEDIA_TYPE_MAX"
|
|
};
|
|
//typedef enum _STREAM_DATA_SOURCE {
|
|
// DevZeroStream = 0,
|
|
// SmallImageStream = 1,
|
|
// EightGigStream = 2,
|
|
//} STREAM_DATA_SOURCE, *PSTREAM_DATA_SOURCE;
|
|
|
|
|
|
// Get a disc recorder given a disc index
|
|
HRESULT GetDiscRecorder(__in ULONG index, __out IDiscRecorder2 ** recorder)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IDiscMaster2* tmpDiscMaster = NULL;
|
|
BSTR tmpUniqueId;
|
|
IDiscRecorder2* tmpRecorder = NULL;
|
|
|
|
*recorder = NULL;
|
|
|
|
// create the disc master object
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CoCreateInstance(CLSID_MsftDiscMaster2,
|
|
NULL, CLSCTX_ALL,
|
|
IID_PPV_ARGS(&tmpDiscMaster)
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed CoCreateInstance\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// get the unique id string
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = tmpDiscMaster->get_Item(index, &tmpUniqueId);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed tmpDiscMaster->get_Item\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// Create a new IDiscRecorder2
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CoCreateInstance(CLSID_MsftDiscRecorder2,
|
|
NULL, CLSCTX_ALL,
|
|
IID_PPV_ARGS(&tmpRecorder)
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed CoCreateInstance\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
// Initialize it with the provided BSTR
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = tmpRecorder->InitializeDiscRecorder(tmpUniqueId);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed to init disc recorder\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
// copy to caller or release recorder
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*recorder = tmpRecorder;
|
|
}
|
|
else
|
|
{
|
|
ReleaseAndNull(tmpRecorder);
|
|
}
|
|
// all other cleanup
|
|
ReleaseAndNull(tmpDiscMaster);
|
|
FreeSysStringAndNull(tmpUniqueId);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT ListAllRecorders()
|
|
{
|
|
HRESULT hr = S_OK;
|
|
LONG index = 0;
|
|
IDiscMaster2* tmpDiscMaster = NULL;
|
|
|
|
// create a disc master object
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CoCreateInstance(CLSID_MsftDiscMaster2,
|
|
NULL, CLSCTX_ALL,
|
|
IID_PPV_ARGS(&tmpDiscMaster)
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed CoCreateInstance\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
// Get number of recorders
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = tmpDiscMaster->get_Count(&index);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed to get count\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// Print each recorder's ID
|
|
for (LONG i = 0; i < index; i++)
|
|
{
|
|
IDiscRecorder2* discRecorder = NULL;
|
|
|
|
hr = GetDiscRecorder(i, &discRecorder);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
|
|
BSTR discId;
|
|
BSTR venId;
|
|
|
|
// Get the device strings
|
|
if (SUCCEEDED(hr)) { hr = discRecorder->get_VendorId(&venId); }
|
|
if (SUCCEEDED(hr)) { hr = discRecorder->get_ProductId(&discId); }
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed to get ID's\n");
|
|
PrintHR(hr);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
printf("Recorder %d: %ws %ws", i, venId, discId);
|
|
}
|
|
// Get the mount point
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
SAFEARRAY * mountPoints = NULL;
|
|
hr = discRecorder->get_VolumePathNames(&mountPoints);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Unable to get mount points, failed\n");
|
|
PrintHR(hr);
|
|
}
|
|
else if (mountPoints->rgsabound[0].cElements == 0)
|
|
{
|
|
printf(" (*** NO MOUNT POINTS ***)");
|
|
}
|
|
else
|
|
{
|
|
VARIANT* tmp = (VARIANT*)(mountPoints->pvData);
|
|
printf(" (");
|
|
for (ULONG j = 0; j < mountPoints->rgsabound[0].cElements; j++)
|
|
{
|
|
printf(" %ws ", tmp[j].bstrVal);
|
|
}
|
|
printf(")");
|
|
}
|
|
SafeArrayDestroyDataAndNull(mountPoints);
|
|
}
|
|
// Get the media type
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IDiscFormat2Data* dataWriter = NULL;
|
|
|
|
// create a DiscFormat2Data object
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CoCreateInstance(CLSID_MsftDiscFormat2Data,
|
|
NULL, CLSCTX_ALL,
|
|
IID_PPV_ARGS(&dataWriter)
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed CoCreateInstance on dataWriter\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = dataWriter->put_Recorder(discRecorder);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed dataWriter->put_Recorder\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
// get the current media in the recorder
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IMAPI_MEDIA_PHYSICAL_TYPE mediaType = IMAPI_MEDIA_TYPE_UNKNOWN;
|
|
hr = dataWriter->get_CurrentPhysicalMediaType(&mediaType);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
printf(" (%s)", g_MediaTypeStrings[mediaType]);
|
|
}
|
|
}
|
|
ReleaseAndNull(dataWriter);
|
|
}
|
|
|
|
printf("\n");
|
|
FreeSysStringAndNull(venId);
|
|
FreeSysStringAndNull(discId);
|
|
|
|
}
|
|
else
|
|
{
|
|
printf("Failed to get drive %d\n", i);
|
|
}
|
|
|
|
ReleaseAndNull(discRecorder);
|
|
|
|
}
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
HRESULT GetIsoStreamForDataWriting(__out IStream** result, __out ULONG* sectors2, WCHAR * shortStreamFilename)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
*result = NULL;
|
|
*sectors2 = 0;
|
|
|
|
IStream* data = NULL;
|
|
ULONG tmpSectors = 0;
|
|
|
|
{
|
|
STATSTG stat; RtlZeroMemory(&stat, sizeof(STATSTG));
|
|
// open an ISO image for the stream
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = SHCreateStreamOnFileW(shortStreamFilename,
|
|
STGM_READ | STGM_SHARE_DENY_WRITE,
|
|
&data
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed to open file %S\n",
|
|
shortStreamFilename);
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
// validate size and save # of blocks for use later
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = data->Stat(&stat, STATFLAG_NONAME);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed to get stats for file\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
// validate size and save # of blocks for use later
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
if (stat.cbSize.QuadPart % 2048 != 0)
|
|
{
|
|
printf("File is not multiple of 2048 bytes. File size is %I64d (%I64x)\n",
|
|
stat.cbSize.QuadPart, stat.cbSize.QuadPart);
|
|
hr = E_FAIL;
|
|
}
|
|
else if (stat.cbSize.QuadPart / 2048 > 0x7FFFFFFF)
|
|
{
|
|
printf("File is too large, # of sectors won't fit a LONG. File size is %I64d (%I64x)\n",
|
|
stat.cbSize.QuadPart, stat.cbSize.QuadPart);
|
|
hr = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
tmpSectors = (ULONG)(stat.cbSize.QuadPart / 2048);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
*result = data;
|
|
*sectors2 = tmpSectors;
|
|
}
|
|
else
|
|
{
|
|
ReleaseAndNull(data);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
HRESULT ImageWriter(PROGRAM_OPTIONS options)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IDiscRecorder2* recorder = NULL;
|
|
IDiscFormat2Data* dataWriter = NULL;
|
|
IStream * dataStream = NULL;
|
|
ULONG sectorsInDataStream = 0;
|
|
BOOLEAN dualLayerDvdMedia = FALSE;
|
|
ULONG index = options.WriterIndex;
|
|
CComObject<CTestDataWriter2Event>* eventSink = NULL;
|
|
|
|
// create a DiscFormat2Data object
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CoCreateInstance(CLSID_MsftDiscFormat2Data,
|
|
NULL, CLSCTX_ALL,
|
|
IID_PPV_ARGS(&dataWriter)
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("CoCreateInstance failed\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
// create a DiscRecorder object
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = GetDiscRecorder(index, &recorder);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("CoCreateInstance failed\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// Set the recorder as the recorder for the data writer
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = dataWriter->put_Recorder(recorder);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed put_Recorder()\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
// release the recorder early...
|
|
ReleaseAndNull(recorder);
|
|
|
|
// Set the app name for use with exclusive access
|
|
// THIS IS REQUIRED
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
BSTR appName = ::SysAllocString(L"Imapi2Sample");
|
|
|
|
hr = dataWriter->put_ClientName(appName);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED to set client name for ISO write!\n");
|
|
PrintHR(hr);
|
|
}
|
|
FreeSysStringAndNull(appName);
|
|
}
|
|
|
|
// verify the Current media write speed property gets
|
|
//if (SUCCEEDED(hr))
|
|
//{
|
|
// LONG value = 0;
|
|
// hr = dataWriter->get_CurrentMediaWriteSpeed(&value);
|
|
// if (FAILED(hr))
|
|
// {
|
|
// DoTrace((TRACE_LEVEL_INFORMATION, DebugGeneral,
|
|
// "Failed get_CurrentMediaWriteSpeed() %!HRESULT!",
|
|
// hr
|
|
// ));
|
|
// printf("Ignoring failed get_CurrentWriteSpeed() for now\n");
|
|
// hr = S_OK;
|
|
// }
|
|
//}
|
|
|
|
|
|
// verify the SupportedMediaTypes property gets
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
SAFEARRAY * value = NULL;
|
|
hr = dataWriter->get_SupportedMediaTypes(&value);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed get_SupportedMediaTypes()\n");
|
|
PrintHR(hr);
|
|
}
|
|
SafeArrayDestroyDataAndNull(value);
|
|
}
|
|
|
|
// get a stream to write to the disc
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = GetIsoStreamForDataWriting(&dataStream, §orsInDataStream, options.FileName);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed to create data stream for writing\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// Create the event sink
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CComObject<CTestDataWriter2Event>::CreateInstance(&eventSink);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed to create event sink\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// need to keep a reference to this eventSink
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = eventSink->AddRef();
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED to addref\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// Hookup the event sink
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = eventSink->DispEventAdvise(dataWriter);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed to hookup event sink\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// write the stream
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = dataWriter->Write(dataStream);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed to write stream\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// unhook events
|
|
// unhook events
|
|
if (NULL != eventSink)
|
|
{
|
|
eventSink->DispEventUnadvise(dataWriter);
|
|
}
|
|
|
|
// verify that clearing the disc recorder works
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = dataWriter->put_Recorder(NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed put_Recorder(NULL)\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
ReleaseAndNull(eventSink);
|
|
ReleaseAndNull(dataWriter);
|
|
ReleaseAndNull(dataStream);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
printf("ImageWriter succeeded for drive index %d\n",
|
|
index
|
|
);
|
|
}
|
|
else
|
|
{
|
|
printf("ImageWriter FAILED for drive index %d\n", index);
|
|
PrintHR(hr);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
|
|
|
|
HRESULT EjectClose(PROGRAM_OPTIONS options, BOOLEAN close)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IDiscRecorder2* recorder = NULL;
|
|
ULONG index = options.WriterIndex;
|
|
BOOL disableMCN = FALSE;
|
|
|
|
// create a DiscRecorder object
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = GetDiscRecorder(index, &recorder);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED to get disc recorder for eject/close\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// Try and prevent shell pop-ups
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = recorder->DisableMcn();
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED to enable MCN after Eject/Close\n");
|
|
PrintHR(hr);
|
|
}
|
|
else
|
|
{
|
|
// Will use this flag instead of HR, in case there is a failure later on
|
|
// we still want to enable MCN
|
|
disableMCN = TRUE;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
VARIANT_BOOL canLoad = VARIANT_FALSE;
|
|
hr = recorder->get_DeviceCanLoadMedia(&canLoad);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED recorder->get_DeviceCanLoadMedia\n");
|
|
PrintHR(hr);
|
|
}
|
|
if (canLoad && close)
|
|
{
|
|
hr = recorder->CloseTray();
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED recorder->CloseTray()\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
else if (canLoad)
|
|
{
|
|
hr = recorder->EjectMedia();
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED recorder->EjectMedia()\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
}
|
|
|
|
// re-enable MCN
|
|
if (disableMCN)
|
|
{
|
|
hr = recorder->EnableMcn();
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED to enable MCN after Eject/Close\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
ReleaseAndNull(recorder);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
|
|
}
|
|
else
|
|
{
|
|
printf("EjectClose FAILED for drive index %d\n",
|
|
index
|
|
);
|
|
PrintHR(hr);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
// Write wav files to CD
|
|
HRESULT AudioWriter(PROGRAM_OPTIONS options)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IDiscRecorder2* recorder = NULL;
|
|
IDiscFormat2TrackAtOnce * audioWriter = NULL;
|
|
CComObject<CAudioEvent>* eventSink = NULL;
|
|
|
|
BOOLEAN bReturn = TRUE;
|
|
ULONG index = options.WriterIndex;
|
|
|
|
BSTR dir = ::SysAllocString( options.FileName );
|
|
|
|
// create a IDiscFormat2TrackAtOnce object
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CoCreateInstance(CLSID_MsftDiscFormat2TrackAtOnce,
|
|
NULL, CLSCTX_ALL,
|
|
IID_PPV_ARGS(&audioWriter)
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed CoCreateInstance on dataWriter\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// create a DiscRecorder object
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = GetDiscRecorder(index, &recorder);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed GetDiscRecorder\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// Set the recorder as the recorder for the audio writer
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = audioWriter->put_Recorder(recorder);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed audioWriter->put_Recorder\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// Set the app name for use with exclusive access
|
|
// THIS IS REQUIRED
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
BSTR appName = ::SysAllocString(L"Imapi2Sample");
|
|
|
|
hr = audioWriter->put_ClientName(appName);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED to set client name for Audio!\n");
|
|
PrintHR(hr);
|
|
}
|
|
FreeSysStringAndNull(appName);
|
|
}
|
|
|
|
// get the current media in the recorder
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IMAPI_MEDIA_PHYSICAL_TYPE mediaType = IMAPI_MEDIA_TYPE_UNKNOWN;
|
|
hr = audioWriter->get_CurrentPhysicalMediaType(&mediaType);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED audioWriter->get_CurrentPhysicalMediaType\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
VARIANT_BOOL b;
|
|
hr = audioWriter->IsCurrentMediaSupported(recorder, &b);
|
|
if (FAILED(hr))
|
|
{
|
|
hr = S_OK;
|
|
}
|
|
}
|
|
|
|
// NOW PREPARE THE MEDIA, it will be ready to use
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = audioWriter->PrepareMedia();
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed audioWriter->PrepareMedia()\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
//if (SUCCEEDED(hr) && !options.Close)
|
|
//{
|
|
// hr = audioWriter->put_DoNotFinalizeDisc(VARIANT_FALSE);
|
|
// if (FAILED(hr))
|
|
// {
|
|
// printf("FAILED audioWriter->get_NumberOfExistingTracks\n");
|
|
// PrintHR(hr);
|
|
// }
|
|
//}
|
|
|
|
// hookup events
|
|
// create an event object for the write engine
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CComObject<CAudioEvent>::CreateInstance(&eventSink);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed to create event sink\n");
|
|
PrintHR(hr);
|
|
}
|
|
else
|
|
{
|
|
eventSink->AddRef();
|
|
}
|
|
}
|
|
|
|
// hookup the event
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = eventSink->DispEventAdvise(audioWriter);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed to hookup event sink\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// Add a track
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
WCHAR AppendPath[MAX_PATH];
|
|
WCHAR FullPath[MAX_PATH];
|
|
DWORD ReturnCode;
|
|
// DWORD FileAttributes;
|
|
HANDLE Files;
|
|
WIN32_FIND_DATAW FileData;
|
|
memset(&FileData, 0, sizeof(WIN32_FIND_DATA));
|
|
|
|
|
|
StringCchPrintfW(AppendPath, (sizeof(AppendPath))/(sizeof(AppendPath[0])), (L"%s\\*"), options.FileName);
|
|
Files = FindFirstFileW(AppendPath, &FileData);
|
|
|
|
if (INVALID_HANDLE_VALUE != Files) {
|
|
//We have the search handle for the first file.
|
|
ReturnCode = 1;
|
|
while (ReturnCode) {
|
|
if (FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
//This is a real directory that we should deal with.
|
|
printf("Skipping directory %ws\n", FileData.cFileName);
|
|
}
|
|
else
|
|
{
|
|
// We have a file, let's add it
|
|
IStream * testStream = NULL;
|
|
STATSTG stat;
|
|
|
|
StringCchPrintfW(FullPath, (sizeof(FullPath))/(sizeof(FullPath[0])),
|
|
(L"%s\\%s"), options.FileName, FileData.cFileName);
|
|
printf("Attempting to add %ws\n", FullPath);
|
|
|
|
// get a stream to write to the disc
|
|
hr = SHCreateStreamOnFileW(FullPath,
|
|
STGM_READWRITE,
|
|
&testStream
|
|
);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED to get file stream\n");
|
|
PrintHR(hr);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = testStream->Stat(&stat, STATFLAG_DEFAULT);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED to get testStream->Stat\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// Mod the size so that it is 2352 byte aligned
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ULARGE_INTEGER newSize;
|
|
|
|
newSize.HighPart = stat.cbSize.HighPart;
|
|
newSize.LowPart = stat.cbSize.LowPart - (stat.cbSize.LowPart%2352);
|
|
|
|
hr = testStream->SetSize(newSize);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED testStream->SetSize\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//write the stream
|
|
printf("adding track now...\n");
|
|
hr = audioWriter->AddAudioTrack(testStream);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED audioWriter->AddAudioTrack(testStream)\n");
|
|
PrintHR(hr);
|
|
}
|
|
else
|
|
{
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
ReleaseAndNull(testStream);
|
|
|
|
}
|
|
memset(&FileData, 0, sizeof(WIN32_FIND_DATA));
|
|
ReturnCode = FindNextFileW(Files, &FileData);
|
|
}
|
|
|
|
if (!ReturnCode)
|
|
{
|
|
ReturnCode = GetLastError();
|
|
if (ReturnCode != ERROR_NO_MORE_FILES)
|
|
{
|
|
printf("Error in attempting to get the next file in %s\n.",
|
|
AppendPath);
|
|
}
|
|
else
|
|
{
|
|
printf("No More Files\n");
|
|
}
|
|
}
|
|
FindClose(Files);
|
|
}
|
|
else
|
|
{
|
|
ReturnCode = GetLastError();
|
|
printf("Could not open a search handle on %ws.\n", options.FileName);
|
|
printf("return = %d\n", ReturnCode);
|
|
}
|
|
}
|
|
|
|
// unhook events
|
|
if (NULL != eventSink)
|
|
{
|
|
eventSink->DispEventUnadvise(audioWriter);
|
|
}
|
|
|
|
// Release the media now that we are done
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = audioWriter->ReleaseMedia();
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED audioWriter->ReleaseMedia()\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// Let's clear the recorder also
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = audioWriter->put_Recorder(NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED audioWriter->put_Recorder(NULL)\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
ReleaseAndNull(eventSink);
|
|
ReleaseAndNull(audioWriter);
|
|
ReleaseAndNull(recorder);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
printf("AudioWriter succeeded for drive index %d\n",
|
|
index
|
|
);
|
|
}
|
|
else
|
|
{
|
|
printf("AudioWriter FAILED for drive index %d\n", index);
|
|
PrintHR(hr);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
// Write audio to disc using disc at once
|
|
HRESULT RawWriter(PROGRAM_OPTIONS options)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
::ATL::CComPtr<IRawCDImageCreator> raw;
|
|
::ATL::CComPtr<IStream> resultStream;
|
|
ATL::CComPtr<IDiscRecorder2> iDiscRecorder;
|
|
ATL::CComPtr<IDiscFormat2RawCD> iDiscFormatRaw;
|
|
ATL::CComObject<CTestRawWriter2Event> *events = NULL;
|
|
ULONG index = options.WriterIndex;
|
|
|
|
// cocreate all burning classes
|
|
|
|
// create a DiscRecorder object
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = GetDiscRecorder(index, &iDiscRecorder);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed GetDiscRecorder\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = iDiscFormatRaw.CoCreateInstance(CLSID_MsftDiscFormat2RawCD);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED iDiscFormatRaw.CoCreateInstance\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// attach disc recorder and disc format
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = iDiscFormatRaw->put_Recorder(iDiscRecorder);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED iDiscFormatRaw->put_Recorder\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// Set the app name for use with exclusive access
|
|
// THIS IS REQUIRED
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
BSTR appName = ::SysAllocString(L"Imapi2Sample");
|
|
|
|
hr = iDiscFormatRaw->put_ClientName(appName);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED to set client name for Raw!\n");
|
|
PrintHR(hr);
|
|
}
|
|
FreeSysStringAndNull(appName);
|
|
}
|
|
|
|
// check if the current recorder and media support burning
|
|
VARIANT_BOOL recorderSupported = VARIANT_FALSE;
|
|
VARIANT_BOOL mediaSupported = VARIANT_FALSE;
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = iDiscFormatRaw->IsRecorderSupported(iDiscRecorder, &recorderSupported);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED iDiscFormatRaw->IsRecorderSupported!\n");
|
|
PrintHR(hr);
|
|
}
|
|
|
|
if (recorderSupported != VARIANT_TRUE)
|
|
{
|
|
printf("ERROR: recorder reports it doesn't support burning DAO RAW capabilities!\n");
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = iDiscFormatRaw->IsCurrentMediaSupported(iDiscRecorder, &mediaSupported);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED iDiscFormatRaw->IsCurrentMediaSupported!\n");
|
|
PrintHR(hr);
|
|
}
|
|
|
|
if (mediaSupported != VARIANT_TRUE)
|
|
{
|
|
printf("ERROR: recorder reports the current media doesn't support burning DAO RAW!\n");
|
|
hr = E_FAIL;
|
|
}
|
|
}
|
|
|
|
// create a raw image creator
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = raw.CoCreateInstance(CLSID_MsftRawCDImageCreator);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED raw.CoCreateInstance\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// set the image type
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = raw->put_ResultingImageType(IMAPI_FORMAT2_RAW_CD_SUBCODE_IS_RAW); //IMAPI_FORMAT2_RAW_CD_SUBCODE_PQ_ONLY);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED raw->put_ResultingImageType\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// Add tracks
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
WCHAR AppendPath[MAX_PATH];
|
|
WCHAR FullPath[MAX_PATH];
|
|
DWORD ReturnCode;
|
|
HANDLE Files;
|
|
WIN32_FIND_DATAW FileData;
|
|
memset(&FileData, 0, sizeof(WIN32_FIND_DATA));
|
|
LONG index = 0;
|
|
|
|
|
|
StringCchPrintfW(AppendPath, (sizeof(AppendPath))/(sizeof(AppendPath[0])), (L"%s\\*"), options.FileName);
|
|
Files = FindFirstFileW(AppendPath, &FileData);
|
|
|
|
if (INVALID_HANDLE_VALUE != Files) {
|
|
//We have the search handle for the first file.
|
|
ReturnCode = 1;
|
|
while (ReturnCode) {
|
|
if (FileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
//This is a real directory that we should deal with.
|
|
printf("Skipping directory %ws\n", FileData.cFileName);
|
|
}
|
|
else
|
|
{
|
|
// We have a file, let's add it
|
|
IStream * testStream = NULL;
|
|
STATSTG stat;
|
|
|
|
StringCchPrintfW(FullPath, (sizeof(FullPath))/(sizeof(FullPath[0])),
|
|
(L"%s\\%s"), options.FileName, FileData.cFileName);
|
|
printf("Attempting to add %ws\n", FullPath);
|
|
|
|
// get a stream to write to the disc
|
|
hr = SHCreateStreamOnFileW(FullPath,
|
|
STGM_READWRITE,
|
|
&testStream
|
|
);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED to get file stream\n");
|
|
PrintHR(hr);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = testStream->Stat(&stat, STATFLAG_DEFAULT);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED to get testStream->Stat\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// Mod the size so that it is 2352 byte aligned
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ULARGE_INTEGER newSize;
|
|
|
|
newSize.HighPart = stat.cbSize.HighPart;
|
|
newSize.LowPart = stat.cbSize.LowPart - (stat.cbSize.LowPart%2352);
|
|
|
|
hr = testStream->SetSize(newSize);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED testStream->SetSize\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
//Add the track to the stream
|
|
printf("adding track now...\n");
|
|
hr = raw->AddTrack(IMAPI_CD_SECTOR_AUDIO, testStream, &index);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED raw->AddTrack(testStream)\n");
|
|
PrintHR(hr);
|
|
}
|
|
else
|
|
{
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
ReleaseAndNull(testStream);
|
|
|
|
}
|
|
memset(&FileData, 0, sizeof(WIN32_FIND_DATA));
|
|
ReturnCode = FindNextFileW(Files, &FileData);
|
|
}
|
|
|
|
if (!ReturnCode)
|
|
{
|
|
ReturnCode = GetLastError();
|
|
if (ReturnCode != ERROR_NO_MORE_FILES)
|
|
{
|
|
printf("Error in attempting to get the next file in %s\n.",
|
|
AppendPath);
|
|
}
|
|
else
|
|
{
|
|
printf("No More Files\n");
|
|
}
|
|
}
|
|
FindClose(Files);
|
|
}
|
|
else
|
|
{
|
|
ReturnCode = GetLastError();
|
|
printf("Could not open a search handle on %ws.\n", options.FileName);
|
|
printf("return = %d\n", ReturnCode);
|
|
}
|
|
}
|
|
|
|
// create the disc image
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
raw->CreateResultImage(&resultStream);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED raw->CreateResultImage\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// prepare media
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = iDiscFormatRaw->PrepareMedia();
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED iDiscFormatRaw->PrepareMedia\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// set up options on disc format
|
|
// NOTE: this will change later to put a different mode when it's fully implemented
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = iDiscFormatRaw->put_RequestedSectorType(IMAPI_FORMAT2_RAW_CD_SUBCODE_IS_RAW); //IMAPI_FORMAT2_RAW_CD_SUBCODE_PQ_ONLY);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED iDiscFormatRaw->put_RequestedSectorType\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// connect events
|
|
//if (SUCCEEDED(hr))
|
|
//{
|
|
// hr = events->DispEventAdvise(iDiscFormatRaw);
|
|
|
|
// if (FAILED(hr))
|
|
// {
|
|
// printf("FAILED events->DispEventAdvise\n");
|
|
// PrintHR(hr);
|
|
// }
|
|
//}
|
|
|
|
// burn stream
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = iDiscFormatRaw->WriteMedia(resultStream);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED iDiscFormatRaw->WriteMedia\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// unadvise events
|
|
//if (events != NULL)
|
|
//{
|
|
// events->DispEventUnadvise(iDiscFormatRaw);
|
|
//}
|
|
|
|
// release media (even if the burn failed)
|
|
hr = iDiscFormatRaw->ReleaseMedia();
|
|
|
|
return hr;
|
|
}
|
|
|
|
// Function for writing a dir to disc
|
|
HRESULT DataWriter(PROGRAM_OPTIONS options)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
IDiscRecorder2* discRecorder = NULL;
|
|
IDiscFormat2Data* dataWriter = NULL;
|
|
IStream* dataStream = NULL;
|
|
BOOLEAN dualLayerDvdMedia = FALSE;
|
|
ULONG index = options.WriterIndex;
|
|
VARIANT_BOOL isBlank = FALSE;
|
|
|
|
SYSTEMTIME startTime;
|
|
SYSTEMTIME endTime;
|
|
SYSTEMTIME elapsedTime;
|
|
|
|
IFileSystemImage * image = NULL;
|
|
IFileSystemImageResult * fsiresult = NULL;
|
|
IFsiDirectoryItem * root = NULL;
|
|
BSTR dir = ::SysAllocString( options.FileName );
|
|
IBootOptions * pBootOptions = NULL;
|
|
IStream * bootStream = NULL;
|
|
|
|
CComObject<CTestDataWriter2Event>* eventSink = NULL;
|
|
|
|
// create a DiscFormat2Data object
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CoCreateInstance(CLSID_MsftDiscFormat2Data,
|
|
NULL, CLSCTX_ALL,
|
|
IID_PPV_ARGS(&dataWriter)
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED CoCreateInstance\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
// create a DiscRecorder object
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = GetDiscRecorder(index, &discRecorder);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED GetDiscRecorder\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// Set the recorder as the recorder for the data writer
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = dataWriter->put_Recorder(discRecorder);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED to put_Recorder\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// Set the app name for use with exclusive access
|
|
// THIS IS REQUIRED
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
BSTR appName = ::SysAllocString(L"Imapi2Sample");
|
|
|
|
hr = dataWriter->put_ClientName(appName);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED to set client name for erase!\n");
|
|
PrintHR(hr);
|
|
}
|
|
FreeSysStringAndNull(appName);
|
|
}
|
|
|
|
// verify the SupportedMediaTypes property gets
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
SAFEARRAY * value = NULL;
|
|
hr = dataWriter->get_SupportedMediaTypes(&value);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED to get_SupportedMediaTypes\n");
|
|
PrintHR(hr);
|
|
}
|
|
SafeArrayDestroyDataAndNull(value);
|
|
}
|
|
|
|
// Close the disc if specified
|
|
if (SUCCEEDED(hr) && options.CloseDisc)
|
|
{
|
|
printf("Disc will be closed\n");
|
|
hr = dataWriter->put_ForceMediaToBeClosed(VARIANT_TRUE);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED to put_ForceMediaToBeClosed\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// verify the StartAddressOfPreviousSession property
|
|
// ALSO -- for DVD+R DL, if from sector zero, set to finalize media
|
|
//if (SUCCEEDED(hr))
|
|
//{
|
|
// LONG value = 0;
|
|
// hr = dataWriter->get_StartAddressOfPreviousSession(&value);
|
|
// if (FAILED(hr))
|
|
// {
|
|
// printf("FAILED to get_StartAddressOfPreviousSession\n");
|
|
// PrintHR(hr);
|
|
// }
|
|
// else if (value == ((ULONG)-1))
|
|
// {
|
|
// hr = dataWriter->put_ForceMediaToBeClosed(VARIANT_TRUE);
|
|
// if (FAILED(hr))
|
|
// {
|
|
// printf("FAILED to put_ForceMediaToBeClosed\n");
|
|
// PrintHR(hr);
|
|
// }
|
|
// }
|
|
//}
|
|
//
|
|
// get a stream to write to the disc
|
|
// create a ID_IFileSystemImage object
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CoCreateInstance(CLSID_MsftFileSystemImage,
|
|
NULL, CLSCTX_ALL,
|
|
IID_PPV_ARGS(&image)
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed CoCreate for filesystem\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// Set the filesystems to use if specified
|
|
if (SUCCEEDED(hr) && (options.Iso || options.Joliet || options.UDF))
|
|
{
|
|
FsiFileSystems fileSystem = FsiFileSystemNone;
|
|
if (options.Iso)
|
|
{
|
|
fileSystem = (FsiFileSystems)(fileSystem | FsiFileSystemISO9660);
|
|
}
|
|
if (options.Joliet)
|
|
{
|
|
fileSystem = (FsiFileSystems)(fileSystem | FsiFileSystemJoliet);
|
|
fileSystem = (FsiFileSystems)(fileSystem | FsiFileSystemISO9660);
|
|
}
|
|
if (options.UDF)
|
|
{
|
|
fileSystem = (FsiFileSystems)(fileSystem | FsiFileSystemUDF);
|
|
}
|
|
|
|
hr = image->put_FileSystemsToCreate(fileSystem);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed to put PileSystemsToCreate\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// Get the root dir
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = image->get_Root(&root);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed to get root directory\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
// create the BootImageOptions object
|
|
if (SUCCEEDED(hr) && (NULL != options.BootFileName))
|
|
{
|
|
hr = CoCreateInstance(CLSID_BootOptions,
|
|
NULL, CLSCTX_ALL,
|
|
IID_PPV_ARGS(&pBootOptions)
|
|
);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("FAILED cocreate bootoptions\n");
|
|
PrintHR(hr);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = SHCreateStreamOnFileW(options.BootFileName,
|
|
STGM_READ | STGM_SHARE_DENY_WRITE,
|
|
&bootStream
|
|
);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed SHCreateStreamOnFileW for BootImage\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = pBootOptions->AssignBootImage(bootStream);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed BootImage put_BootImage\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = image->put_BootImageOptions(pBootOptions);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed BootImage put_BootImageOptions\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check if media is blank
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = dataWriter->get_MediaHeuristicallyBlank(&isBlank);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed to get_MediaHeuristicallyBlank\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
if (SUCCEEDED(hr) && !options.Multi && !isBlank)
|
|
{
|
|
printf("*** WRITING TO NON-BLANK MEDIA WITHOUT IMPORT! ***\n");
|
|
}
|
|
|
|
// ImportFileSystem - Import file data from disc
|
|
if (SUCCEEDED(hr) && options.Multi)
|
|
{
|
|
FsiFileSystems fileSystems;
|
|
SAFEARRAY* multiSession = NULL;
|
|
|
|
// Get mutlisession interface to set in image
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = dataWriter->get_MultisessionInterfaces(&multiSession);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed dataWriter->MultisessionInterfaces\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// Set the multisession interface in the image
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = image->put_MultisessionInterfaces(multiSession);
|
|
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed image->put_MultisessionInterfaces\n");
|
|
PrintHR(hr);
|
|
if (multiSession != NULL)
|
|
{
|
|
SafeArrayDestroy(multiSession);
|
|
}
|
|
}
|
|
multiSession = NULL;
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = image->ImportFileSystem(&fileSystems);
|
|
if (FAILED(hr))
|
|
{
|
|
if (hr == IMAPI_E_EMPTY_DISC)
|
|
{
|
|
printf("Empty Disc\n");
|
|
hr = S_OK;
|
|
}
|
|
else
|
|
{
|
|
printf("Failed to ImportFileSystem\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get free media blocks
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LONG freeBlocks;
|
|
|
|
hr = dataWriter->get_FreeSectorsOnMedia(&freeBlocks);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed to get Free Media Blocks\n");
|
|
PrintHR(hr);
|
|
}
|
|
else
|
|
{
|
|
hr = image->put_FreeMediaBlocks(freeBlocks);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed to put Free Media Blocks\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Add a dir to the image
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
printf("Adding %ws", dir);
|
|
GetSystemTime(&startTime); // gets current time
|
|
hr = root->AddTree(dir, false);
|
|
GetSystemTime(&endTime); // gets current time
|
|
if (FAILED(hr))
|
|
{
|
|
printf("\nFailed to add %ws to root dir using AddTree\n", dir);
|
|
PrintHR(hr);
|
|
}
|
|
else
|
|
{
|
|
CalcElapsedTime(&startTime, &endTime, &elapsedTime);
|
|
printf(" - Time: %02d:%02d:%02d\n", elapsedTime.wHour,
|
|
elapsedTime.wMinute,
|
|
elapsedTime.wSecond);
|
|
}
|
|
}
|
|
|
|
// Free our bstr
|
|
FreeSysStringAndNull( dir );
|
|
|
|
// Check what file systems are being used
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
FsiFileSystems fileSystems;
|
|
hr = image->get_FileSystemsToCreate(&fileSystems);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed image->get_FileSystemsToCreate\n");
|
|
PrintHR(hr);
|
|
}
|
|
else
|
|
{
|
|
printf("Supported file systems: ");
|
|
if (fileSystems & FsiFileSystemISO9660)
|
|
{
|
|
printf("ISO9660 ");
|
|
}
|
|
if (fileSystems & FsiFileSystemJoliet)
|
|
{
|
|
printf("Joliet ");
|
|
}
|
|
if (fileSystems & FsiFileSystemUDF)
|
|
{
|
|
printf("UDF ");
|
|
}
|
|
printf("\n");
|
|
}
|
|
}
|
|
|
|
// Get count
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
LONG numFiles = 0;
|
|
LONG numDirs = 0;
|
|
if (SUCCEEDED(hr)) { hr = image->get_FileCount(&numFiles); }
|
|
if (SUCCEEDED(hr)) { hr = image->get_DirectoryCount(&numDirs); }
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed image->get_FileCount\n");
|
|
PrintHR(hr);
|
|
}
|
|
else
|
|
{
|
|
printf("Number of Files: %d\n", numFiles);
|
|
printf("Number of Directories: %d\n", numDirs);
|
|
}
|
|
}
|
|
|
|
//Set the volume name
|
|
if (SUCCEEDED(hr) && (NULL != options.VolumeName))
|
|
{
|
|
BSTR volName = options.VolumeName;
|
|
hr = image->put_VolumeName(volName);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed setting Volume Name\n");
|
|
PrintHR(hr);
|
|
}
|
|
|
|
FreeSysStringAndNull(volName);
|
|
}
|
|
|
|
// Create the result image
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = image->CreateResultImage(&fsiresult);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed to get result image, returned %08x\n", hr);
|
|
}
|
|
}
|
|
|
|
// Get the stream
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = fsiresult->get_ImageStream(&dataStream);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed to get stream, returned %08x\n", hr);
|
|
}
|
|
else
|
|
{
|
|
printf("Image ready to write\n");
|
|
}
|
|
}
|
|
|
|
// Create event sink
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CComObject<CTestDataWriter2Event>::CreateInstance(&eventSink);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed to create event sink\n");
|
|
PrintHR(hr);
|
|
}
|
|
else
|
|
{
|
|
eventSink->AddRef();
|
|
}
|
|
}
|
|
|
|
// hookup event sink
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = eventSink->DispEventAdvise(dataWriter);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed to hookup event sink\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// write the stream
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
GetSystemTime(&startTime);
|
|
hr = dataWriter->Write(dataStream);
|
|
GetSystemTime(&endTime);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed to write stream\n");
|
|
PrintHR(hr);
|
|
}
|
|
else
|
|
{
|
|
CalcElapsedTime(&startTime, &endTime, &elapsedTime);
|
|
printf(" - Time to write: %02d:%02d:%02d\n", elapsedTime.wHour,
|
|
elapsedTime.wMinute,
|
|
elapsedTime.wSecond);
|
|
}
|
|
}
|
|
// unhook events
|
|
if (NULL != eventSink)
|
|
{
|
|
eventSink->DispEventUnadvise(dataWriter);
|
|
}
|
|
|
|
// verify the WriteProtectStatus property gets
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
IMAPI_MEDIA_WRITE_PROTECT_STATE value = (IMAPI_MEDIA_WRITE_PROTECT_STATE)0;
|
|
hr = dataWriter->get_WriteProtectStatus(&value);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed get_WriteProtectStatus()\n");
|
|
PrintHR(hr);
|
|
}
|
|
}
|
|
|
|
// verify that clearing the disc recorder works
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = dataWriter->put_Recorder(NULL);
|
|
if (FAILED(hr))
|
|
{
|
|
printf("Failed put_Recorder(NULL)\n");
|
|
PrintHR(hr);
|
|
}
|
|
|
|
}
|
|
|
|
ReleaseAndNull(eventSink);
|
|
ReleaseAndNull(image);
|
|
ReleaseAndNull(fsiresult);
|
|
ReleaseAndNull(dataWriter);
|
|
ReleaseAndNull(dataStream);
|
|
ReleaseAndNull(discRecorder);
|
|
ReleaseAndNull(pBootOptions);
|
|
ReleaseAndNull(bootStream);
|
|
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
printf("DataWriter succeeded for drive index %d\n",
|
|
index
|
|
);
|
|
}
|
|
else
|
|
{
|
|
printf("DataWriter FAILED for drive index %d\n",
|
|
index
|
|
);
|
|
PrintHR(hr);
|
|
}
|
|
return hr;
|
|
}
|
|
|
|
class CConsoleModule :
|
|
public ::ATL::CAtlExeModuleT<CConsoleModule>
|
|
{
|
|
};
|
|
CConsoleModule _AtlModule;
|
|
|
|
int __cdecl wmain(int argc, WCHAR *argv[])
|
|
{
|
|
HRESULT coInitHr = S_OK;
|
|
HRESULT hr = S_OK;
|
|
PROGRAM_OPTIONS options;
|
|
|
|
SYSTEMTIME startTime;
|
|
SYSTEMTIME endTime;
|
|
SYSTEMTIME elapsedTime;
|
|
|
|
if ( !ParseCommandLine( argc-1, argv+1, &options ) )
|
|
{
|
|
PrintHelp(argv[0]);
|
|
hr = E_INVALIDARG;
|
|
return hr;
|
|
}
|
|
else
|
|
{
|
|
//PrintOptions(&options);
|
|
}
|
|
|
|
// Get start time for total time
|
|
GetSystemTime(&startTime);
|
|
|
|
if (CAtlBaseModule::m_bInitFailed)
|
|
{
|
|
printf("AtlBaseInit failed...\n");
|
|
coInitHr = E_FAIL;
|
|
}
|
|
else
|
|
{
|
|
// printf("AtlBaseInit passed...\n");
|
|
coInitHr = S_OK;
|
|
}
|
|
|
|
if ( SUCCEEDED(coInitHr) && options.ListWriters )
|
|
{
|
|
hr = ListAllRecorders();
|
|
}
|
|
if ( SUCCEEDED(coInitHr) && options.Erase )
|
|
{
|
|
hr = EraseMedia( options.WriterIndex, options.FullErase );
|
|
}
|
|
if ( SUCCEEDED(coInitHr) && options.Write )
|
|
{
|
|
hr = DataWriter(options);
|
|
}
|
|
if ( SUCCEEDED(coInitHr) && options.Image )
|
|
{
|
|
hr = ImageWriter(options);
|
|
}
|
|
if ( SUCCEEDED(coInitHr) && options.Audio )
|
|
{
|
|
hr = AudioWriter(options);
|
|
}
|
|
if ( SUCCEEDED(coInitHr) && options.Raw )
|
|
{
|
|
hr = RawWriter(options);
|
|
}
|
|
if ( SUCCEEDED(coInitHr) && options.Eject )
|
|
{
|
|
hr = EjectClose(options, FALSE);
|
|
}
|
|
if ( SUCCEEDED(coInitHr) && options.Close )
|
|
{
|
|
hr = EjectClose(options, TRUE);
|
|
}
|
|
|
|
if (SUCCEEDED(coInitHr))
|
|
{
|
|
CoUninitialize();
|
|
}
|
|
|
|
GetSystemTime(&endTime);
|
|
|
|
CalcElapsedTime(&startTime, &endTime, &elapsedTime);
|
|
printf(" - Total Time: %02d:%02d:%02d\n", elapsedTime.wHour,
|
|
elapsedTime.wMinute,
|
|
elapsedTime.wSecond);
|
|
|
|
if (SUCCEEDED(hr))
|
|
return 0;
|
|
else
|
|
{
|
|
PrintHR(hr);
|
|
return 1;
|
|
}
|
|
}
|
|
|