ralln 2021-11-29 14:45 采纳率: 50%
浏览 106
已结题

如何通过IMAPI2来实现光盘的追加刻录?

问题遇到的现象和发生背景

我通过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设置了最后可写位置,但是还是不能追加复刻,请问是为啥呢?

我想要达到的结果

我希望能够正常进行追加刻录文件。

  • 写回答

0条回答 默认 最新

    报告相同问题?

    问题事件

    • 系统已结题 12月7日
    • 创建了问题 11月29日

    悬赏问题

    • ¥15 我这模型写的不对吗?为什么lingo解出来的下面影子价格这一溜少一个变量
    • ¥50 树莓派安卓APK系统签名
    • ¥15 maple软件,用solve求反函数出现rootof,怎么办?
    • ¥65 汇编语言除法溢出问题
    • ¥15 Visual Studio问题
    • ¥20 求一个html代码,有偿
    • ¥100 关于使用MATLAB中copularnd函数的问题
    • ¥20 在虚拟机的pycharm上
    • ¥15 jupyterthemes 设置完毕后没有效果
    • ¥15 matlab图像高斯低通滤波