2025-11-28 00:35:46 +09:00

1087 lines
30 KiB
C++

//*****************************************************************************
//
// Microsoft Windows Media
// Copyright ( C) Microsoft Corporation. All rights reserved.
//
// FileName: NetWrite.cpp
//
// Abstract: CNetWrite class implementation.
//
//
//*****************************************************************************
#include "wmsdk.h"
#include "NetWrite.h"
#include <TCHAR.H>
#include <stdio.h>
#include <assert.h>
#include <conio.h>
//----------------------------------------------------------------------------
// Name: CNetWrite::CNetWrite()
// Desc: Constructor.
//----------------------------------------------------------------------------
CNetWrite::CNetWrite()
{
m_pReaderHeaderInfo = NULL;
m_pWriterHeaderInfo = NULL;
m_pWriterAdvanced = NULL;
m_pReaderAdvanced = NULL;
m_pReader = NULL;
m_pWriter = NULL;
m_pNetSink = NULL;
m_pPushSink = NULL;
m_pPushSinkCallbackCtrl = NULL;
m_hEvent = NULL;
m_bEOF = false;
m_qwTime = 0;
m_hrAsync = S_OK;
}
//----------------------------------------------------------------------------
// Name: CNetWrite::~CNetWrite()
// Desc: Destructor.
//----------------------------------------------------------------------------
CNetWrite::~CNetWrite()
{
CloseHandle( m_hEvent );
SAFE_RELEASE( m_pWriterHeaderInfo );
SAFE_RELEASE( m_pWriterAdvanced );
SAFE_RELEASE( m_pWriter );
SAFE_RELEASE( m_pNetSink );
SAFE_RELEASE( m_pPushSinkCallbackCtrl );
SAFE_RELEASE( m_pPushSink );
SAFE_RELEASE( m_pReaderHeaderInfo );
SAFE_RELEASE( m_pReaderAdvanced );
SAFE_RELEASE( m_pReader );
CoUninitialize();
}
//----------------------------------------------------------------------------
// Name: CNetWrite::OnSample()
// Desc: Called when the reader object delivers an uncompressed sample.
// Note: This method implements the IWMReaderCallback::OnSample method. See the
// SDK documentation for a description of the parameters.
//
// The CNetWrite object configures the reader to deliver compressed
// samples, which happens via the OnStreamSample callback method.
// Therefore, if this method is called, it is an error.
//----------------------------------------------------------------------------
HRESULT CNetWrite::OnSample( DWORD dwOutputNum,
QWORD cnsSampleTime,
QWORD cnsSampleDuration,
DWORD dwFlags,
INSSBuffer __RPC_FAR *pSample, void __RPC_FAR *pvContext )
{
if( m_hEvent != NULL )
{
//
//The samples are expected in OnStreamSample.
//
_tprintf( _T( "Error: Received a decompressed sample from the reader.\n" ) );
m_hrAsync = E_UNEXPECTED;
SetEvent( m_hEvent );
}
return S_OK;
}
//----------------------------------------------------------------------------
// Name: CNetWrite::OnStatus()
// Desc: Receives a status message from the reader object or the push sink.
//
// Note: This method implements the IWMStatusCallback::OnStatus method. See the
// SDK documentation for a description of the parameters.
//----------------------------------------------------------------------------
HRESULT CNetWrite::OnStatus( WMT_STATUS Status,
HRESULT hr,
WMT_ATTR_DATATYPE dwType,
BYTE __RPC_FAR *pValue,
void __RPC_FAR *pvContext )
{
// Check whether the push sink object is the caller.
BOOL fFromPushSink = ( m_pPushSink != NULL && pvContext == ( void * ) m_pPushSink );
// For some status messages, we expect the CNetWrite object is waiting
// to receive the message. Signal to the waiting thread by calling SetEvent.
// We also signal to the thread if there is an error message.
// Handle status messages from the push sink.
if( fFromPushSink )
{
switch(Status)
{
case WMT_LOCATING:
_tprintf( _T( "Locating server.\n" ) );
break;
case WMT_CONNECTING:
_tprintf( _T( "Connecting to server.\n" ) );
break;
case WMT_OPENED:
_tprintf( _T( "Connected to server.\n" ) );
m_hrAsync = hr;
SetEvent( m_hEvent ); // Unblock the thread that is waiting.
break;
case WMT_ERROR:
_tprintf( _T( "Error 0x%x during push distribution\n" ), hr );
m_bEOF = true;
m_hrAsync = hr;
SetEvent( m_hEvent );
break;
}
return S_OK;
}
// Handle status messages from the reader.
switch(Status)
{
case WMT_OPENED:
if( SUCCEEDED( hr ))
{
_tprintf( _T( "The reader completed opening the input file.\n" ) );
}
m_hrAsync = hr;
SetEvent( m_hEvent ); // Unblock the thread that is waiting.
break;
case WMT_EOF:
m_bEOF = true;
_tprintf( _T( "EndOfStream detected in reader.\n" ) );
m_hrAsync = hr;
SetEvent( m_hEvent );
break;
case WMT_STARTED:
// Ask the reader object to deliver another block of time.
m_qwTime = 0;
m_qwTime += 1000 * 10000;
hr = m_pReaderAdvanced->DeliverTime( m_qwTime );
m_hrAsync = hr;
break;
case WMT_CLOSED:
m_hrAsync = hr;
SetEvent( m_hEvent ); // Unblock the thread that is waiting.
break;
case WMT_ERROR:
_tprintf( _T( "Error 0x%x reported by the reader\n" ), hr );
m_bEOF = true;
m_hrAsync = hr;
SetEvent( m_hEvent );
break;
}
return S_OK;
}
//----------------------------------------------------------------------------
// Name: CNetWrite::OnStreamSample()
// Desc: Called when the reader object delivers a compressed sample.
//
// Note: This method implements the IWMReaderCallbackAdvanced::OnStreamSample
// method. See the SDK documentation for a description of the parameters.
//----------------------------------------------------------------------------
HRESULT CNetWrite::OnStreamSample( WORD wStreamNum,
QWORD cnsSampleTime,
QWORD cnsSampleDuration,
DWORD dwFlags,
INSSBuffer __RPC_FAR *pSample,
void __RPC_FAR *pvContext )
{
_tprintf( _T( "StreamSample: num=%d, time=%d, duration=%d, flags=%d.\n" ),
wStreamNum, ( DWORD )cnsSampleTime, cnsSampleDuration, dwFlags );
if( m_pWriterAdvanced != NULL )
{
// Give the sample to the writer object.
HRESULT hr = m_pWriterAdvanced->WriteStreamSample( wStreamNum,
cnsSampleTime,
0,
cnsSampleDuration,
dwFlags,
pSample );
if( FAILED( hr ) )
{
_tprintf( _T( "Error 0x%x reported by the writer\n" ), hr );
m_bEOF = true;
m_hrAsync = hr;
SetEvent( m_hEvent );
}
}
return S_OK;
}
//----------------------------------------------------------------------------
// Name: CNetWrite::OnTime()
// Desc: Called when the reader object has delivered all of the data that this
// object requested.
//
// Note: This method implements the IWMReaderCallbackAdvanced::OnTime method.
// See the SDK documentation for a description of the parameters.
//
// This method gets called because the CNetWrite object is driving the
// clock on the reader object.
//----------------------------------------------------------------------------
HRESULT CNetWrite::OnTime( QWORD cnsCurrentTime, void __RPC_FAR *pvContext)
{
// Until the end of the file is reached, ask for another block of time.
if( !m_bEOF )
{
m_qwTime += 10000000;
HRESULT hr=m_pReaderAdvanced->DeliverTime( m_qwTime );
if(FAILED(hr))
return hr;
}
return S_OK;
}
//----------------------------------------------------------------------------
// Name: CNetWrite::Init()
// Desc: Initializes the CNetWrite object.
//----------------------------------------------------------------------------
HRESULT CNetWrite::Init()
{
HRESULT hr = S_OK;
// Initialize the COM library.
hr = CoInitialize( NULL );
if( FAILED( hr ) )
{
_tprintf( _T( "CoInitialize failed: hr = 0x%08x\n" ), hr );
return hr;
}
//
// Create the reader and writer. Query for additional interfaces.
//
hr = WMCreateReader( NULL, 0, &m_pReader );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not create reader (hr=0x%08x).\n" ), hr );
return hr;
}
hr = m_pReader->QueryInterface( IID_IWMReaderAdvanced, ( void** )&m_pReaderAdvanced );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not QI for IWMReaderAdvanced (hr=0x%08x).\n" ), hr );
return hr;
}
hr = WMCreateWriter( NULL, &m_pWriter );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not create Writer (hr=0x%08x).\n" ), hr );
return hr;
}
hr = m_pWriter->QueryInterface( IID_IWMWriterAdvanced, ( void** ) &m_pWriterAdvanced );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not QI for IWMWriterAdvanced (hr=0x%08x).\n" ), hr );
return hr;
}
hr = m_pReader->QueryInterface( IID_IWMHeaderInfo, ( VOID ** )&m_pReaderHeaderInfo );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not QI for IWMHeaderInfo (hr=0x%08x).\n" ), hr );
return hr;
}
hr = m_pWriter->QueryInterface( IID_IWMHeaderInfo, ( VOID ** )&m_pWriterHeaderInfo );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not QI for IWMHeaderInfo (hr=0x%08x).\n" ), hr );
return hr;
}
return hr;
}
//----------------------------------------------------------------------------
// Name: CNetWrite::WritetoNet()
// Desc: Writes a file to the network. Call the Configure method first, to set
// the file name and other parameters.
//----------------------------------------------------------------------------
HRESULT CNetWrite::WritetoNet()
{
if( m_hEvent == NULL ||
m_pWriterAdvanced == NULL ||
m_pReaderAdvanced == NULL ||
( m_pNetSink == NULL && m_pPushSink == NULL ) )
{
return E_UNEXPECTED;
}
HRESULT hr = S_OK;
//
// Start writing.
//
// First, prepare the writer object for writing. Then start the reader.
hr = m_pWriter->BeginWriting( );
if( FAILED( hr ) )
{
_tprintf( _T( "BeginWriting on IWMWriter failed (hr=0x%08x).\n" ), hr );
return hr;
}
hr = m_pReader->Start( 0, 0, 1.0, 0 );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not start IWMReader (hr=0x%08x).\n" ), hr );
return hr;
}
// Wait for all of the read and write operations to finish.
WaitForSingleObject( m_hEvent, INFINITE );
// Check the status of the operation.
if( FAILED( m_hrAsync ) )
{
_tprintf( _T( "Net writing failed (hr=0x%08x).\n" ), m_hrAsync );
return hr;
}
//
// Stop the reader and the writer, and close everything.
//
hr = m_pReader->Stop();
if( FAILED( hr ) )
{
_tprintf( _T( "Could not Stop IWMReader (hr=0x%08x).\n" ), hr );
return hr;
}
hr = m_pWriter->Flush();
if( FAILED( hr ) )
{
_tprintf( _T( "Could not Flush on IWMWriter (hr=0x%08x).\n" ), hr );
return hr;
}
hr = m_pWriter->EndWriting( );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not EndWriting on IWMWriter (hr=0x%08x).\n" ), hr );
return hr;
}
hr = m_pReader->Close();
if( FAILED( hr ) )
{
_tprintf( _T( "Could not close the file (hr=0x%08x).\n" ), hr );
return hr;
}
// Remove the network sink from the writer.
if( m_pNetSink != NULL )
{
hr = m_pWriterAdvanced->RemoveSink( m_pNetSink );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not remove the Network Sink (hr=0x%08x).\n" ), hr );
return hr;
}
hr = m_pNetSink->Close();
if( FAILED( hr ) )
{
_tprintf( _T( "Could not close on IWMWriterNetworkSink (hr=0x%08x).\n" ), hr );
return hr;
}
}
// Remove the push sink from the writer.
if( m_pPushSink != NULL )
{
hr = m_pWriterAdvanced->RemoveSink( m_pPushSink );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not remove the Push Sink (hr=0x%08x).\n" ), hr );
return hr;
}
// End the push session and cancel the advise connection with the push sink.
hr = m_pPushSink->EndSession();
if( FAILED( hr ) )
{
_tprintf( _T( "Could not close on IWMWriterPushSink (hr=0x%08x).\n" ), hr );
return hr;
}
if( m_pPushSinkCallbackCtrl != NULL )
{
hr = m_pPushSinkCallbackCtrl->Unadvise( this, ( void * ) m_pPushSink );
if(FAILED(hr))
return hr;
}
}
//
// Wait for the reader to tell us that it is closed.
//
WaitForSingleObject( m_hEvent, 10000 );
return hr;
}
//----------------------------------------------------------------------------
// Name: CNetWrite::Configure()
// Desc: Configures the object to broadcast a file.
//
// dwPortNum: Port number for the network sink. Use -1 for no network sink.
// pwszFile: The name of a local ASF file to broadcast. Cannot be NULL.
// nMaxClient: Maximum number of client connections.
// pwszServerURL: URL of a publishing point, for the push sink. Use NULL for no push sink.
//
// Note: If dwPortNum is -1, pwszServerURL cannot be NULL, and vice-versa.
//----------------------------------------------------------------------------
HRESULT CNetWrite::Configure( DWORD dwPortNum, const WCHAR *pwszFile, UINT nMaxClient, const WCHAR *pwszServerURL )
{
if( pwszFile == NULL || ( dwPortNum == (DWORD)-1 && pwszServerURL == NULL ) )
{
return E_INVALIDARG;
}
if( dwPortNum > 0xFFFF )
{
_tprintf( _T( "Invalid port number.\n" ) );
return E_INVALIDARG;
}
if( m_pWriterAdvanced == NULL || m_pReaderAdvanced == NULL )
{
return E_UNEXPECTED;
}
HRESULT hr = S_OK;
// If a port number was specified, create the network sink object.
if( dwPortNum != (DWORD)-1 )
{
hr = WMCreateWriterNetworkSink( &m_pNetSink );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not create Writer Network Sink (hr=0x%08x).\n" ), hr );
return hr;
}
}
// If a publishing point URL was specified, create the push sink object.
if( pwszServerURL != NULL )
{
hr = WMCreateWriterPushSink( &m_pPushSink );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not create Writer Push Sink (hr=0x%08x).\n" ), hr );
return hr;
}
// Set up a callback for event notifications.
hr = m_pPushSink->QueryInterface( IID_IWMRegisterCallback,
( void ** ) &m_pPushSinkCallbackCtrl );
if( FAILED( hr ) )
{
return hr;
}
hr = m_pPushSinkCallbackCtrl->Advise( this, ( void * ) m_pPushSink );
if( FAILED( hr ) )
{
return hr;
}
}
//
// Create an event for handling asynchronous calls.
//
m_hrAsync = S_OK;
if( m_hEvent != NULL)
{
CloseHandle(m_hEvent);
}
m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL );
if( NULL == m_hEvent )
{
DWORD err = GetLastError();
_tprintf( _T( "Could not Create Event: (hr=0x%08x).\n" ), err );
return err;
}
if( m_pNetSink != NULL )
{
//
// Configure the network sink.
//
hr = m_pNetSink->SetNetworkProtocol( WMT_PROTOCOL_HTTP );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not Set Network protocol (hr=0x%08x).\n" ), hr );
return hr;
}
hr = m_pNetSink->Open( &dwPortNum);
if( FAILED( hr ) )
{
_tprintf( _T( "Network sink failed to open port no %d (hr=0x%08x).\n" ),
dwPortNum, hr );
return hr;
}
// Find the host URL, to display to the user.
DWORD cchURL = 0;
hr = m_pNetSink->GetHostURL( NULL, &cchURL );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not get the host URL from IWMWriterNEtworkSink (hr=0x%08x).\n" ),
hr );
return hr;
}
WCHAR *pwszURL = new WCHAR[cchURL];
if( pwszURL == NULL )
{
_tprintf( _T( "Insufficient Memory" ) );
return E_OUTOFMEMORY;
}
hr = m_pNetSink->GetHostURL( pwszURL, &cchURL );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not get the host URL from IWMWriterNetworkSink (hr=0x%08x).\n" ),
hr );
SAFE_ARRAYDELETE (pwszURL);
return hr;
}
_tprintf( _T( "Connect to %ws\n" ), pwszURL );
Sleep( 1000 );
SAFE_ARRAYDELETE (pwszURL);
//
// Set the maximum number of clients that can connect to the port.
//
hr = m_pNetSink->SetMaximumClients( nMaxClient );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not Set maximum clients (hr=0x%08x).\n" ), hr );
return hr;
}
//
// Add the network sink to the writer.
//
hr = m_pWriterAdvanced->AddSink(m_pNetSink);
if( FAILED( hr ) )
{
_tprintf( _T( "Could not Add Sink (hr=0x%08x).\n" ), hr );
return hr;
}
}
if( m_pPushSink != NULL )
{
//
// Configure the push sink.
//
_tprintf( _T( "Connecting to %ws\n" ), pwszServerURL );
hr = m_pPushSink->Connect( pwszServerURL, NULL, TRUE );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not connect to server (hr=0x%08x).\n" ), hr );
return hr;
}
//
// Wait for the connection to the server to be established.
//
if( WaitForSingleObject( m_hEvent, 30000 ) == WAIT_TIMEOUT )
{
_tprintf( _T( "Timed out whiletrying to connect to the server\n" ) );
return E_FAIL;
}
if( FAILED( m_hrAsync ) )
{
return m_hrAsync;
}
//
// Add the push sink to the writer object.
//
hr = m_pWriterAdvanced->AddSink(m_pPushSink);
if( FAILED( hr ) )
{
_tprintf( _T( "Could not Add Sink (hr=0x%08x).\n" ), hr );
return hr;
}
}
//
// Open the requested file.
//
hr = m_pReader->Open(pwszFile, this, NULL );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not open file %ws (hr=0x%08x).\n" ), pwszFile ,hr );
return hr;
}
//
// Wait for the open to finish.
//
if( WaitForSingleObject( m_hEvent, 30000 ) == WAIT_TIMEOUT )
{
_tprintf( _T( "Timed out whiletrying to open the input file\n" ) );
return E_FAIL;
}
if( FAILED( m_hrAsync ) )
{
hr = m_hrAsync;
_tprintf( _T( "Open failed (hr=0x%08x).\n" ), m_hrAsync );
return hr;
}
//
// Turn on manual stream selection, so we get all streams. This prevents the reader
// from disabling any streams if there are mutual exclusions on some streams.
//
hr = m_pReaderAdvanced->SetManualStreamSelection( TRUE );
if( FAILED( hr ) )
{
_tprintf( _T( "Failed to set manual stream selection (hr=0x%08x).\n" ), hr );
return hr;
}
IWMProfile *pProfile = NULL;
IWMStreamConfig *pStream = NULL;
// Declare a dummy 'do' loop. On failure, we can break from the loop.
do
{
hr = m_pReader->QueryInterface( IID_IWMProfile, ( VOID ** )&pProfile );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not QI for IWMProfile (hr=0x%08x).\n" ), hr );
break;
}
// Loop through all the output streams on the reader. For each stream, configure
// the reader to deliver compressed samples. This prevents the reader from decoding
// each sample. (We want to give the writer compressed samples.)
DWORD dwStreams = 0;
hr = pProfile->GetStreamCount( &dwStreams );
if( FAILED( hr ) )
{
_tprintf( _T( "GetStreamCount on IWMProfile failed (hr=0x%08x).\n" ), hr );
break;
}
for ( DWORD i = 0; i < dwStreams; i++ )
{
hr = pProfile->GetStream( i, &pStream );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not get Stream %d of %d from IWMProfile (hr=0x%08x).\n" ),
i, dwStreams, hr );
break;
}
WORD wStreamNumber = 0;
//
//Get the stream number of the current stream.
//
hr = pStream->GetStreamNumber( &wStreamNumber );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not get stream number from IWMStreamConfig %d of %d (hr=0x%08x).\n" ),
i, dwStreams, hr );
break;
}
SAFE_RELEASE( pStream );
//
//Set the stream to be received in compressed mode.
//
hr = m_pReaderAdvanced->SetReceiveStreamSamples( wStreamNumber, TRUE );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not SetReceivedStreamSamples for stream number %d (hr=0x%08x).\n" ),
wStreamNumber, hr );
break;
}
}
if( FAILED( hr ) )
break;
//
// Turn on the user clock. The CNetWrite object will drive the clock, in order
// to make the reader run as quickly as possible.
//
hr = m_pReaderAdvanced->SetUserProvidedClock( TRUE );
if( FAILED( hr ) )
{
_tprintf( _T( "SetUserProvidedClock failed (hr=0x%08x).\n" ), hr );
break;
}
//
// Set same profile on the writer object that we got from the reader.
//
hr = m_pWriter->SetProfile( pProfile );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not set profile on IWMWriter (hr=0x%08x).\n" ), hr );
break;
}
} while(FALSE);
SAFE_RELEASE( pStream );
SAFE_RELEASE( pProfile );
if(FAILED(hr))
{
return hr; // Something has failed within the do-while loop.
}
DWORD cInputs = 0;
hr = m_pWriter->GetInputCount( &cInputs );
if( FAILED( hr ) )
{
_tprintf( _T( "Could not get input count from IWMWriter (hr=0x%08x).\n" ), hr );
return hr;
}
// Loop through all of the inputs on the writer. For each input, set the
// input properties to NULL. This tells the writer not to encode the
// samples it receives. We do this because we are getting encoded samples
// from the reader.
for( DWORD i = 0; i < cInputs; i++ )
{
hr = m_pWriter->SetInputProps( i, NULL );
if(FAILED(hr))
{
return hr;
}
}
//
// Copy header attributes from the reader to the writer.
//
hr = WriteHeader( g_wszWMTitle);
if( FAILED( hr ) )
return hr;
hr = WriteHeader( g_wszWMAuthor);
if( FAILED( hr ) )
return hr;
hr = WriteHeader( g_wszWMDescription);
if( FAILED( hr ) )
return hr;
hr = WriteHeader( g_wszWMRating);
if( FAILED( hr ) )
return hr;
hr = WriteHeader( g_wszWMCopyright);
if( FAILED( hr ) )
return hr;
hr = WriteHeader( g_wszWMAlbumTitle);
if( FAILED( hr ) )
return hr;
hr = WriteHeader( g_wszWMTrack);
if( FAILED( hr ) )
return hr;
hr = WriteHeader( g_wszWMPromotionURL);
if( FAILED( hr ) )
return hr;
hr = WriteHeader( g_wszWMAlbumCoverURL);
if( FAILED( hr ) )
return hr;
hr = WriteHeader( g_wszWMGenre);
if( FAILED( hr ) )
return hr;
hr = WriteHeader( g_wszWMYear);
if( FAILED( hr ) )
return hr;
hr = WriteHeader( g_wszWMGenreID);
if( FAILED( hr ) )
return hr;
hr = WriteHeader( g_wszWMMCDI);
if( FAILED( hr ) )
return hr;
hr = WriteHeader( g_wszWMBannerImageType );
if( FAILED( hr ) )
return hr;
hr = WriteHeader( g_wszWMBannerImageData );
if( FAILED( hr ) )
return hr;
hr = WriteHeader( g_wszWMBannerImageURL );
if( FAILED( hr ) )
return hr;
hr = WriteHeader( g_wszWMCopyrightURL );
if( FAILED( hr ) )
return hr;
//
// Header has been written. Write the script (if any).
//
hr = WriteScript();
return hr;
}
//----------------------------------------------------------------------------
// Name: CNetWrite::WriteHeader()
// Desc: Copies specified metadata from the reader to the writer.
//
// pwszName: Specifies the name of the metadata attribute to copy.
//----------------------------------------------------------------------------
HRESULT CNetWrite::WriteHeader(const WCHAR *pwszName)
{
WORD nstreamNum = 0;
WORD cbLength = 0;
WMT_ATTR_DATATYPE type;
HRESULT hr = S_OK;
BYTE* pValue = NULL;
//
// Get the number of bytes to allocate for the attribute data.
//
hr = m_pReaderHeaderInfo->GetAttributeByName( &nstreamNum,
pwszName,
&type,
NULL,
&cbLength );
if( FAILED( hr ) && hr != ASF_E_NOTFOUND )
{
_tprintf( _T( "GetAttributeByName failed for Attribute name %ws (hr=0x%08x).\n" ), pwszName, hr);
return hr;
}
if( cbLength == 0 && hr == ASF_E_NOTFOUND )
{
return S_OK;
}
// Allocate a buffer.
pValue = new BYTE[ cbLength ];
if( NULL == pValue )
{
_tprintf( _T( "Unable to allocate memory for the Attribute name %ws" ), pwszName);
return E_OUTOFMEMORY;
}
// Declare a dummy 'do' loop. On failure, we can break from the loop.
do
{
// Get the value of the attribute from the reader.
hr = m_pReaderHeaderInfo->GetAttributeByName( &nstreamNum,
pwszName,
&type,
pValue,
&cbLength );
if( FAILED( hr ) )
{
_tprintf( _T( "GetAttributeByName failed for Attribute name %ws (hr=0x%08x).\n" ),
pwszName, hr);
break;
}
// Set the attribute on the writer.
hr = m_pWriterHeaderInfo->SetAttribute( nstreamNum,
pwszName,
type,
pValue,
cbLength );
if( FAILED( hr ) )
{
_tprintf( _T( "SetAttribute failed for Attribute name %ws (hr=0x%08x).\n" ),
pwszName, hr);
break;
}
}
while(FALSE);
SAFE_ARRAYDELETE( pValue );
return hr;
}
//----------------------------------------------------------------------------
// Name: CNetWrite::WriteScript()
// Desc: Copies all scripts from the reader's header to the writer's header.
//----------------------------------------------------------------------------
HRESULT CNetWrite::WriteScript()
{
HRESULT hr = S_OK;
WCHAR* pwszCommand = NULL;
WCHAR* pwszType = NULL;
QWORD cnsScriptTime = 0;
WORD cScript = 0;
WORD cchTypeLen = 0;
WORD cchCommandLen = 0;
// Get the number of scripts in the header. This might be zero.
hr = m_pReaderHeaderInfo->GetScriptCount( &cScript );
if( FAILED( hr ) )
{
_tprintf( _T( "GetScriptCount failed (hr=0x%08x).\n" ), hr);
return hr;
}
// Loop through the scripts. For each script, copy it to the writer's header.
for( int i = 0; i < cScript; i++)
{
//
// Get the memory required for this script.
//
hr = m_pReaderHeaderInfo->GetScript( (WORD)i ,
NULL ,
&cchTypeLen ,
NULL ,
&cchCommandLen ,
&cnsScriptTime );
if( FAILED( hr ) )
{
_tprintf( _T( "GetScript failed for Script no %d (hr=0x%08x).\n" ), i, hr );
break;
}
// Allocate buffers.
pwszType = new WCHAR[cchTypeLen];
pwszCommand = new WCHAR[cchCommandLen];
if( pwszType == NULL || pwszCommand == NULL)
{
_tprintf( _T( "Insufficient Memory" ) );
hr = E_OUTOFMEMORY;
break;
}
//
// Get the script.
//
hr = m_pReaderHeaderInfo->GetScript( (WORD)i ,
pwszType ,
&cchTypeLen ,
pwszCommand ,
&cchCommandLen ,
&cnsScriptTime );
if( FAILED( hr ) )
{
_tprintf( _T( "GetScript failed for Script no %d (hr=0x%08x).\n" ), i, hr);
break;
}
//
// Add the script to the writer.
//
hr = m_pWriterHeaderInfo->AddScript( pwszType ,
pwszCommand ,
cnsScriptTime );
if( FAILED( hr ) )
{
_tprintf( _T( "AddScript failed for Script no %d (hr=0x%08x).\n" ), i, hr);
break;
}
SAFE_ARRAYDELETE( pwszType );
SAFE_ARRAYDELETE( pwszCommand );
pwszType = pwszCommand = NULL;
cchTypeLen = 0;
cchCommandLen = 0;
}
SAFE_ARRAYDELETE( pwszType );
SAFE_ARRAYDELETE( pwszCommand );
return hr;
}