问题遇到的现象和发生背景
我通过VS2013,尝试通过IMAPI2来实现光盘刻录,但是遇到了光盘复刻存在问题,无法进行追加刻录。
我是用的是DVD刻录机,光盘为DVD+R。我准备了一堆只有几个字节的TXT文件用于测试刻录。
每次刻录之后发现,对于同一张光盘,每次复刻之后,上一次的文件都无法在资源管理器中看到,仅能看到本次刻录的内容。
问题相关代码,请勿粘贴截图
以下是我的测试代码,基本也是从别人的例子中扒下来的。
//Com环境初始化,COINIT_MULTITHREADED允许在多个线程中使用COM对象
CoInitializeEx( NULL, COINIT_MULTITHREADED );
//--------------------------------------------------------------------begin----------------------------------------------------------------------------------------------------------
IDiscMaster2* m_discMaster = NULL; //声明一个IDiscMaster2 接口
IDiscRecorder2* m_discRecorder = NULL; //声明一个IDiscRecorder2 接口
IDiscFormat2Data* m_discFormatData = NULL; //声明一个IDiscFormat2Data 接口
IFileSystemImage* image = NULL; //声明一个IFileSystemImage 接口
//初始化一个IDiscMaster2的实例
HRESULT m_hResult = CoCreateInstance( __uuidof( MsftDiscMaster2 ), NULL, CLSCTX_INPROC_SERVER, __uuidof( IDiscMaster2 ), ( void** )&m_discMaster );
//获得当前环境(硬件、用户权限)是否允许刻录操作
VARIANT_BOOL isSupported = VARIANT_FALSE;
m_hResult = m_discMaster->get_IsSupportedEnvironment( &isSupported );
//获得当前环境下有多少光驱设备
long totalDevices = 0;
m_hResult = m_discMaster->get_Count( &totalDevices );
//获得某个光驱设备的唯一描述字符串
string strOutput;
BSTR uniqueID = NULL;
for( long deviceIndex = 0; deviceIndex < totalDevices; ++deviceIndex )
{
HRESULT m_hResult2 = m_discMaster->get_Item( deviceIndex, &uniqueID );
strOutput = _com_util::ConvertBSTRToString( uniqueID );
printf( "%s\n", strOutput.c_str() );
break;// 这里测试就拿第一个,正常应该判定光驱可用性的,比如最大磁盘空间之类的
}
//初始化一个IDiscRecorder2的实例
m_hResult = CoCreateInstance( __uuidof( MsftDiscRecorder2 ), NULL, CLSCTX_INPROC_SERVER, __uuidof( IDiscRecorder2 ), ( void** )&m_discRecorder );
//光驱设备的唯一描述字符串与IDiscRecorder2 接口进行绑定
m_hResult = m_discRecorder->InitializeDiscRecorder( uniqueID );
//获取光驱盘符
SAFEARRAY* m_volumePathNames;
m_hResult = m_discRecorder->get_VolumePathNames( &m_volumePathNames );
ULONG totalVolumePaths = m_volumePathNames->rgsabound[0].cElements;//这里的[0]是固定的
printf( "%d\n", totalVolumePaths );
BSTR volumePath = ((VARIANT*)(m_volumePathNames->pvData))[0].bstrVal;//这里的[0]标识是第一个光驱,多个光驱时需要更改,需要改为对应的值
strOutput = _com_util::ConvertBSTRToString( volumePath );
printf( "%s\n", strOutput.c_str() );
//获取光驱产品ID
BSTR productId = NULL;
m_discRecorder->get_ProductId( &productId );
strOutput = _com_util::ConvertBSTRToString( productId );
printf( "%s\n", strOutput.c_str() );
//获取对设备的独占访问权限。
BSTR clientName = _bstr_t( "test" );
m_hResult = m_discRecorder->AcquireExclusiveAccess( VARIANT_TRUE, clientName );
//初始化一个IDiscRecorder2的实例
m_hResult = CoCreateInstance( __uuidof( MsftDiscFormat2Data ), NULL, CLSCTX_INPROC_SERVER, __uuidof( IDiscFormat2Data ), ( void** )&m_discFormatData );
//IDiscRecorder2与IDiscFormat2Data绑定
isSupported = VARIANT_FALSE;
m_hResult = m_discFormatData->IsRecorderSupported( m_discRecorder, &isSupported );
m_hResult = m_discFormatData->put_Recorder( m_discRecorder );
//设置名称,好像没啥用
m_hResult = m_discFormatData->put_ClientName( clientName );
//是否允许继续往光盘里写入
m_hResult = m_discFormatData->put_ForceMediaToBeClosed( VARIANT_FALSE );
//DVD专用,影响后续写入
m_hResult = m_discFormatData->put_DisableConsumerDvdCompatibilityMode( VARIANT_TRUE );
//确定数据流是否包含写入后间隙。
m_hResult = m_discFormatData->put_PostgapAlreadyInImage( VARIANT_TRUE );
//确定数据编写器是否必须在可覆盖的媒体类型上覆盖光盘。
m_hResult = m_discFormatData->put_ForceOverwrite( VARIANT_TRUE );
///////////////////////////////////////////////////////////////////////
//获取当前的媒体状态
IMAPI_FORMAT2_DATA_MEDIA_STATE iState = IMAPI_FORMAT2_DATA_MEDIA_STATE_UNKNOWN;
m_hResult = m_discFormatData->get_CurrentMediaStatus( &iState ); //
printf( "MediaStatus: %x\n", iState );
//获取当前的磁盘类型
IMAPI_MEDIA_PHYSICAL_TYPE mediaType = IMAPI_MEDIA_TYPE_UNKNOWN;
m_discFormatData->get_CurrentPhysicalMediaType( &mediaType );
printf( "mediaType: %x\n", mediaType );
//初始化一个IFileSystemImage的实例
HRESULT hr = CoCreateInstance( CLSID_MsftFileSystemImage, NULL, CLSCTX_ALL, __uuidof( IFileSystemImage ), ( void** )&image );
//设置文件系统
image->put_FileSystemsToCreate( ( FsiFileSystems )( FsiFileSystemUDF | FsiFileSystemISO9660 ) );
//设置卷名称
CString m_volumeLabel = CTime::GetCurrentTime().Format( _T( "%Y_%m_%d" ) );
image->put_VolumeName( m_volumeLabel.AllocSysString() );
//获取磁盘下一个可写入的地址
long valeTest = 0;
m_hResult = m_discFormatData->get_NextWritableAddress( &valeTest );
printf( "NextWritableAddress: %d\n", valeTest );
m_hResult = image->put_SessionStartBlock( valeTest ); //设置录制会话的起始块地址。
//获取剩余空间大小
LONG lFreeSectorOnMedia = 0;
m_hResult = m_discFormatData->get_FreeSectorsOnMedia( &lFreeSectorOnMedia );
printf( "FreeSectorsOnMedia: %d\n", lFreeSectorOnMedia );
m_hResult = image->put_FreeMediaBlocks( lFreeSectorOnMedia );
//检索根目录项。
IFsiDirectoryItem* rootItem = NULL;
hr = image->get_Root( &rootItem );
////////////////////////////////////下面是添加刻录文件相关////////////////////////////////////////////////
IStream* m_pStream = NULL;
LPCWSTR m_Filepath = TEXT( "C:\\Users\\Administrator\\Desktop\\1.txt" );
SHCreateStreamOnFileEx( m_Filepath,
STGM_READ | STGM_SHARE_DENY_NONE | STGM_DELETEONRELEASE,
FILE_ATTRIBUTE_NORMAL,
FALSE,
NULL,
&m_pStream );
hr = rootItem->AddFile( _bstr_t(TEXT("1.txt")), m_pStream );//1->2
printf( "%S\n", m_Filepath );
// LPCWSTR m_Dirpath = TEXT( "C:\\Users\\Administrator\\Desktop\\dir1" );
// hr = rootItem->AddTree( _bstr_t( m_Dirpath ), VARIANT_TRUE );
// printf( "%S\n", m_Dirpath );
IFileSystemImageResult* imageResult = NULL;
hr = image->CreateResultImage( &imageResult );
hr = imageResult->get_ImageStream( &m_pStream );
////////////////////////////////////上面是添加刻录文件相关////////////////////////////////////////////////
#ifdef XXXXXXXX
goto TestTab;
#endif // XXXXXXXX
//执行刻录动作
printf( "Write............\n" );
m_hResult = m_discFormatData->Write( m_pStream );
printf( "Write............end . \n" );
#ifdef XXXXXXXX
TestTab:
#endif // XXXXXXXX
#ifndef XXXXXXXX
//弹出光驱
m_hResult = m_discRecorder->EjectMedia();
#endif // XXXXXXXX
//释放对设备的独占访问权限。
m_hResult = m_discRecorder->ReleaseExclusiveAccess();//对应AcquireExclusiveAccess
//各种析构
m_pStream->Release();
imageResult->Release();
rootItem->Release();
image->Release();
m_discFormatData->Release();
m_discRecorder->Release();
m_discMaster->Release();
//---------------------------------------------------------------------end------------------------------------------------------------------------------------
CoUninitialize();
运行结果及报错内容
用空光盘刻录1.txt后,重新插入光盘,可以看到1.txt。我想对这个光盘进行追加刻录2.txt,但是每次刻录之后都是只剩下了2.txt,1.txt不见了。
我的解答思路和尝试过的方法
我把put_ForceMediaToBeClosed设置了VARIANT_FALSE,put_DisableConsumerDvdCompatibilityMode设置了VARIANT_TRUE
也同样把put_SessionStartBlock设置了最后可写位置,但是还是不能追加复刻,请问是为啥呢?
我想要达到的结果
我希望能够正常进行追加刻录文件。