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

2104 lines
54 KiB
C++

//*****************************************************************************
//
// Microsoft Windows Media
// Copyright (C) Microsoft Corporation. All rights reserved.
//
// FileName: SDKSampleStorageSystem.cpp
//
// Abstract:
//
//*****************************************************************************
#include "stdafx.h"
#include "SDKSampleStoragePlugin.h"
#include "SDKSampleStorageSystem.h"
#include <float.h>
/////////////////////////////////////////////////////////////////////////////
//
// [CSDKSampleStorageSystem]
//
/////////////////////////////////////////////////////////////////////////////
CSDKSampleStorageSystem::CSDKSampleStorageSystem()
{
m_pServerContext = NULL;
m_pClassFactory = NULL;
} // End of CSDKSampleStorageSystem.
/////////////////////////////////////////////////////////////////////////////
CSDKSampleStorageSystem::~CSDKSampleStorageSystem()
{
if ( m_pServerContext )
{
m_pServerContext->Release();
m_pServerContext = NULL;
}
if ( m_pClassFactory )
{
m_pClassFactory->Release();
m_pClassFactory = NULL;
}
}
/////////////////////////////////////////////////////////////////////////////
//
// [OpenDataContainer]
//
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE
CSDKSampleStorageSystem::OpenDataContainer(
IWMSCommandContext *pCommandContext,
IWMSContext *pUserContext,
IWMSContext *pPresentationContext,
LPWSTR pszContainerName,
DWORD dwFlags,
IWMSBufferAllocator *pBufferAllocator,
IWMSDataSourcePluginCallback *pCallback,
QWORD qwContext
)
{
HRESULT hr = S_OK;
CSampleDataContainer *pDataContainer = NULL;
if ( ( NULL == pszContainerName )
|| ( NULL == pBufferAllocator )
|| ( NULL == pCallback ) )
{
// We are returning an error, so we cannot call the callback.
return( E_INVALIDARG );
}
pDataContainer = new CSampleDataContainer;
if ( NULL == pDataContainer )
{
hr = E_OUTOFMEMORY;
goto abort;
}
hr = pDataContainer->Initialize(
pUserContext,
pszContainerName,
dwFlags,
pBufferAllocator,
this,
pCallback,
qwContext
);
if ( FAILED( hr ) )
{
goto abort;
}
abort:
if( NULL != pDataContainer )
{
pDataContainer->Release();
pDataContainer = NULL;
}
return( hr );
} // End of OpenDataContainer.
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE
CSDKSampleStorageSystem::OpenDirectory(
IWMSCommandContext *pCommandContext,
IWMSContext *pUserContext,
IWMSContext *pPresentationContext,
LPWSTR pszContainerName,
DWORD dwFlags,
IWMSBufferAllocator *pBufferAllocator,
IWMSDataSourcePluginCallback *pCallback,
QWORD qwContext
)
{
HRESULT hr = S_OK;
CSampleDirectory *pDirectory = NULL;
if( ( NULL == pszContainerName )
|| ( NULL == pCallback ) )
{
hr = E_INVALIDARG;
goto abort;
}
pDirectory = new CSampleDirectory;
if( NULL == pDirectory )
{
hr = E_OUTOFMEMORY;
goto abort;
}
hr = pDirectory->Initialize(
pUserContext,
pszContainerName,
this,
pCallback,
qwContext
);
if( FAILED( hr ) )
{
goto abort;
}
abort:
if( NULL != pDirectory )
{
pDirectory->Release();
pDirectory = NULL;
}
return( hr );
} // OpenDirectory
/////////////////////////////////////////////////////////////////////////////
//
// [DeleteDataContainer]
//
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE
CSDKSampleStorageSystem::DeleteDataContainer(
LPWSTR pszContainerName,
DWORD dwFlags,
IWMSDataSourcePluginCallback *pCallback,
QWORD qwContext
)
{
HRESULT hr = S_OK;
BOOL fSuccess = TRUE;
if ( ( NULL == pszContainerName )
|| ( NULL == pCallback ) )
{
hr = E_INVALIDARG;
goto abort;
}
fSuccess = DeleteFile( pszContainerName );
if ( !fSuccess )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
goto abort;
}
abort:
if ( NULL != pCallback )
{
// Ignore any error returned by the callback.
pCallback->OnDeleteDataContainer( hr, qwContext );
hr = S_OK; // any error is passed to the callback
}
return( hr );
} // End of DeleteDataContainer.
/////////////////////////////////////////////////////////////////////////////
//
// [GetDataContainerVersion]
//
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE
CSDKSampleStorageSystem::GetDataContainerVersion(
IWMSCommandContext *pCommandContext,
IWMSContext *pUserContext,
IWMSContext *pPresContext,
LPWSTR pszContainerName,
DWORD dwFlags,
IWMSDataSourcePluginCallback *pCallback,
QWORD qwContext
)
{
HRESULT hr = S_OK;
DATE dateOriginLastModifiedTime;
WIN32_FILE_ATTRIBUTE_DATA FileAttributeData;
WIN32_FILE_ATTRIBUTE_DATA * pFileAttributeData;
SYSTEMTIME stLastModifiedTime;
IWMSDataContainerVersion *pVersion = NULL;
QWORD qwFileSize = 0;
BSTR bstrFileSize = NULL;
WCHAR pszFileSize[65];
if ( ( NULL == pszContainerName )
|| ( NULL == pCallback ) )
{
// We are returning an error, so we cannot call the callback.
return( E_INVALIDARG );
}
if( !GetFileAttributesEx( pszContainerName + URL_SCHEME_LENGTH, GetFileExInfoStandard, &FileAttributeData ) )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
goto abort;
}
// can't get the DataContainerVersion for a directory
if( FILE_ATTRIBUTE_DIRECTORY & FileAttributeData.dwFileAttributes )
{
hr = E_FAIL;
goto abort;
}
pFileAttributeData = &FileAttributeData;
//
// Convert the last modified time from FILETIME to DATE format.
//
FileTimeToSystemTime( &pFileAttributeData->ftLastWriteTime, &stLastModifiedTime );
SystemTimeToVariantTime( &stLastModifiedTime, &dateOriginLastModifiedTime );
//
// A null pVersion means (a) we got an error early on or (b) the caller
// only wants to get the current version.
//
hr = m_pClassFactory->CreateInstance( IID_IWMSDataContainerVersion,
(void **) &pVersion );
if( FAILED( hr ) )
{
goto abort;
}
hr = pVersion->SetLastModifiedTime( dateOriginLastModifiedTime );
if( FAILED( hr ) )
{
goto abort;
}
hr = pVersion->SetExpirationTime( (double) DBL_MAX );
if( FAILED( hr ) )
{
goto abort;
}
//
// everything allowed (this will be replaced with the VRoot setting)
//
hr = pVersion->SetCacheFlags( 0xffffffff );
if( FAILED( hr ) )
{
goto abort;
}
hr = pVersion->SetContentSize( pFileAttributeData->nFileSizeLow, pFileAttributeData->nFileSizeHigh );
if( FAILED( hr ) )
{
goto abort;
}
qwFileSize = MAKEQWORD( pFileAttributeData->nFileSizeLow, pFileAttributeData->nFileSizeHigh );
_ui64tow_s( qwFileSize, (LPWSTR) pszFileSize,65, 10 );
bstrFileSize = SysAllocString( (LPWSTR) pszFileSize );
if( NULL == bstrFileSize )
{
hr = E_OUTOFMEMORY;
goto abort;
}
hr = pVersion->SetEntityTag( bstrFileSize );
if( FAILED(hr) )
{
goto abort;
}
abort:
// The HRESULT returned by the callback should be ignored.
pCallback->OnGetDataContainerVersion(
hr,
pVersion,
qwContext
);
hr = S_OK; // any error is passed to the callback
if( NULL != pVersion )
{
pVersion->Release();
pVersion = NULL;
}
if( NULL != bstrFileSize )
{
SysFreeString( bstrFileSize );
bstrFileSize = NULL;
}
// We called the callback, so we MUST return S_OK.
return( S_OK );
} // End of GetDataContainerVersion.
/////////////////////////////////////////////////////////////////////////////
//
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE
CSDKSampleStorageSystem::GetRootDirectories(
LPWSTR *pstrRootDirectoryList,
DWORD dwMaxRoots,
IWMSDataSourcePluginCallback *pCallback,
QWORD qwContext
)
{
HRESULT hr = S_OK;
DWORD dwRootNum = 0;
DWORD dwTotalNumRoots = 0;
DWORD dwBufferSize = 0;
WCHAR tempBuffer[3];
WCHAR *pFullBuffer = NULL;
WCHAR *pEndBuffer;
WCHAR *pStartPath;
WCHAR *pStopPath;
WCHAR *pstrFile;
DWORD dwPathNameLength;
DWORD dwIndex;
if( ( NULL == pstrRootDirectoryList )
|| ( NULL == pCallback ) )
{
return( E_INVALIDARG );
}
// Find out how large the buffer should be.
dwBufferSize = GetLogicalDriveStringsW( 1, tempBuffer );
if( 0 == dwBufferSize )
{
hr = E_FAIL;
goto abort;
}
// Allocate a buffer.
pFullBuffer = new WCHAR[ dwBufferSize + 2 ];
if( NULL == pFullBuffer )
{
hr = E_OUTOFMEMORY;
goto abort;
}
ZeroMemory( pFullBuffer, ( dwBufferSize + 2 ) * sizeof( WCHAR ) );
// Get the actual data.
dwBufferSize = GetLogicalDriveStringsW( dwBufferSize, pFullBuffer );
if( 0 == dwBufferSize )
{
hr = E_FAIL;
goto abort;
}
// Each iteration extracts one root pathname.
pStartPath = pFullBuffer;
pEndBuffer = pFullBuffer + dwBufferSize;
dwRootNum = 0;
dwTotalNumRoots = 0;
while ( pStartPath < pEndBuffer )
{
// Find the end of the current path. This is the next
// NULL character.
pStopPath = pStartPath;
while ( ( *pStopPath ) && ( pStopPath < pEndBuffer ) )
{
pStopPath++;
}
// If we found a non-empty path, then record it.
if( pStopPath > pStartPath )
{
if( dwRootNum < dwMaxRoots )
{
dwPathNameLength = (DWORD)(pStopPath - pStartPath);
pstrFile = (LPWSTR) CoTaskMemAlloc( sizeof(WCHAR) * ( dwPathNameLength + URL_SCHEME_LENGTH + 1 ) );
if( NULL == pstrFile )
{
hr = E_OUTOFMEMORY;
goto abort;
}
pstrFile[ URL_SCHEME_LENGTH + dwPathNameLength ] = L'\0';
wcsncpy_s( pstrFile,( dwPathNameLength + URL_SCHEME_LENGTH + 1 ) , URL_SCHEME, URL_SCHEME_LENGTH );
wcsncpy_s( pstrFile + URL_SCHEME_LENGTH, ( dwPathNameLength + URL_SCHEME_LENGTH + 1 )-URL_SCHEME_LENGTH , pStartPath, dwPathNameLength );
if( L'\0' != pstrFile[ URL_SCHEME_LENGTH + dwPathNameLength ] )
{
hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
goto abort;
}
pstrRootDirectoryList[dwRootNum] = pstrFile;
dwRootNum++;
} // copying a string.
dwTotalNumRoots++;
} // recording a path.
// The next path starts just after the previous path.
pStartPath = pStopPath + 1;
if( ( NULL == *pStartPath ) || ( pStartPath >= pEndBuffer ) )
{
break;
}
} // extracting every path.
// The HRESULT returned by the callback should be ignored.
( void ) pCallback->OnGetRootDirectories(
hr,
dwRootNum,
dwTotalNumRoots,
qwContext
);
hr = S_OK; // any error is passed to the callback
abort:
if( FAILED( hr ) )
{
for ( dwIndex = 0; dwIndex < dwRootNum; dwIndex++ )
{
if( NULL != pstrRootDirectoryList[dwIndex] )
{
CoTaskMemFree( pstrRootDirectoryList[dwIndex] );
pstrRootDirectoryList[dwIndex] = NULL;
}
}
}
if( NULL != pFullBuffer )
{
delete [] pFullBuffer;
}
return( hr );
} // GetRootDirectories
/////////////////////////////////////////////////////////////////////////////
//
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE
CSDKSampleStorageSystem::GetDataSourceAttributes(
DWORD *pdwFlags
)
{
if ( NULL == pdwFlags )
{
return( E_INVALIDARG );
}
*pdwFlags = WMS_DATA_CONTAINER_SUPPORTS_ENUMERATION;
return( S_OK );
} // GetDataSourceAttributes
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE
CSDKSampleStorageSystem::CreateDataSourceDirectory(
IWMSCommandContext *pCommandContext,
LPWSTR pszContainerName,
DWORD dwFlags,
IWMSDataSourcePluginCallback *pCallback,
QWORD qwContext
)
{
return( E_NOTIMPL );
}
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE
CSDKSampleStorageSystem::DeleteDirectory(
LPWSTR pszContainerName,
DWORD dwFlags,
IWMSDataSourcePluginCallback *pCallback,
QWORD qwContext
)
{
return( E_NOTIMPL );
}
/////////////////////////////////////////////////////////////////////////////
//
// [InitializePlugin]
//
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE
CSDKSampleStorageSystem::InitializePlugin(
IWMSContext *pServerContext,
IWMSNamedValues *pNamedValues,
IWMSClassObject *pClassFactory
)
{
HRESULT hr = S_OK;
SYSTEM_INFO sysInfo;
if ( ( NULL == pServerContext )
|| ( NULL == pClassFactory ) )
{
return( E_INVALIDARG );
}
// TODO: Initialize all storage system state
GetSystemInfo( &sysInfo );
m_dwPageSize = sysInfo.dwPageSize;
m_pServerContext = pServerContext;
m_pServerContext->AddRef();
m_pNamedValues = pNamedValues;
m_pNamedValues->AddRef();
m_pClassFactory = pClassFactory;
m_pClassFactory->AddRef();
return( hr );
} // End of InitializePlugin.
/////////////////////////////////////////////////////////////////////////////
//
// [ShutdownPlugin]
//
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE
CSDKSampleStorageSystem::ShutdownPlugin()
{
if( NULL != m_pServerContext )
{
m_pServerContext->Release();
m_pServerContext = NULL;
}
if( NULL != m_pNamedValues )
{
m_pNamedValues->Release();
m_pNamedValues = NULL;
}
if( NULL != m_pClassFactory )
{
m_pClassFactory->Release();
m_pClassFactory = NULL;
}
return( S_OK );
} // End Of ShutdownPlugin
/////////////////////////////////////////////////////////////////////////////
//
// [EnablePlugin]
//
/////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CSDKSampleStorageSystem::EnablePlugin( long *pdwFlags, long *pdwHeartbeatPeriod )
{
if ( NULL == pdwFlags || NULL == pdwHeartbeatPeriod )
{
return ( E_POINTER );
}
*pdwFlags = 0;
*pdwHeartbeatPeriod = 0;
return ( S_OK );
}
/////////////////////////////////////////////////////////////////////////////
//
// [GetCustomAdminInterface]
//
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE
CSDKSampleStorageSystem::GetCustomAdminInterface( IDispatch **ppValue )
{
if ( NULL == ppValue )
{
return( E_INVALIDARG );
}
*ppValue = NULL;
return( S_OK );
}
/////////////////////////////////////////////////////////////////////////////
//
// [OnHeartbeat]
//
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE
CSDKSampleStorageSystem::OnHeartbeat()
{
return( S_OK );
} // End of OnHeartbeat.
/////////////////////////////////////////////////////////////////////////////
//
// [DisablePlugin]
//
/////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CSDKSampleStorageSystem::DisablePlugin()
{
return ( S_OK );
}
/////////////////////////////////////////////////////////////////////////////
//
// DATA CONTAINER
//
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
//
// [CSampleDataContainer]
//
/////////////////////////////////////////////////////////////////////////////
CSampleDataContainer::CSampleDataContainer()
{
m_cRef = 1;
m_pszPathName = NULL;
m_hFile = INVALID_HANDLE_VALUE;
m_pOwnerStorageSystem = NULL;
InitializeCriticalSection( &m_CriticalSection );
} // End of CSampleDataContainer.
/////////////////////////////////////////////////////////////////////////////
//
// [~CSampleDataContainer]
//
/////////////////////////////////////////////////////////////////////////////
CSampleDataContainer::~CSampleDataContainer()
{
Shutdown();
DeleteCriticalSection( &m_CriticalSection );
} // End of ~CSampleDataContainer.
/////////////////////////////////////////////////////////////////////////////
HRESULT CSampleDataContainer::Initialize(
IWMSContext *pUserContext,
LPWSTR pszContainerName,
DWORD dwFlags,
IWMSBufferAllocator *pBufferAllocator,
CSDKSampleStorageSystem *pOwnerStorageSystem,
IWMSDataSourcePluginCallback *pCallback,
QWORD qwContext
)
{
HRESULT hr = S_OK;
DWORD dwSDKSampleStorageSystemFlags = 0;
CHAR *pResult = NULL;
DWORD cbDriveNameLen = 0;
BOOL fSuccess = TRUE;
DWORD dwOpenStyle = 0;
CHAR *pszSDKSampleStorageSystemPathname = NULL;
DWORD dwFileAccess = 0;
DWORD dwSizeHigh = 0, dwError = 0, dwSizeLow = 0;
EnterCriticalSection( &m_CriticalSection );
// If this data container is already open, then don't open it again.
if ( INVALID_HANDLE_VALUE != m_hFile )
{
hr = E_UNEXPECTED;
goto abort;
}
if ( ( NULL == pszContainerName )
|| ( NULL == pCallback )
|| ( NULL == pOwnerStorageSystem ) )
{
hr = E_INVALIDARG;
goto abort;
}
int cchNeeded = WideCharToMultiByte(
CP_ACP,
0,
pszContainerName,
-1,
NULL,
0,
NULL,
NULL
);
if( 0 >= cchNeeded )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
goto abort;
}
m_pszPathName = new CHAR[ cchNeeded ];
if( NULL == m_pszPathName )
{
hr = E_OUTOFMEMORY;
goto abort;
}
int cchConverted = WideCharToMultiByte(
CP_ACP,
0,
pszContainerName,
-1,
m_pszPathName,
cchNeeded,
NULL,
NULL
);
if( cchConverted != cchNeeded )
{
delete [] m_pszPathName;
m_pszPathName = NULL;
hr = E_UNEXPECTED;
goto abort;
}
m_pOwnerStorageSystem = pOwnerStorageSystem;
pOwnerStorageSystem->AddRef();
if ( dwFlags & WMS_DATA_CONTAINER_CREATE_NEW_CONTAINER )
{
dwOpenStyle = OPEN_ALWAYS;
}
else
{
dwOpenStyle = OPEN_EXISTING;
}
dwFileAccess = GENERIC_READ;
if ( ( dwFlags & WMS_DATA_CONTAINER_WRITE_ACCESS )
|| ( dwFlags & WMS_DATA_CONTAINER_CREATE_NEW_CONTAINER ) )
{
dwFileAccess |= GENERIC_WRITE;
}
pszSDKSampleStorageSystemPathname = m_pszPathName + URL_SCHEME_LENGTH;
m_hFile = CreateFileA(
pszSDKSampleStorageSystemPathname,
dwFileAccess,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL,
dwOpenStyle,
dwSDKSampleStorageSystemFlags,
NULL
);
if ( INVALID_HANDLE_VALUE == m_hFile )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
goto abort;
}
else
{
// Get the file type to see if we should open this or not.
DWORD dwFileType = GetFileType( m_hFile );
if( FILE_TYPE_DISK != dwFileType )
{
hr = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
goto abort;
}
}
// Get the file size.
dwSizeLow = GetFileSize( m_hFile, & dwSizeHigh ) ;
// If we failed ...
if( ( dwSizeLow == 0xFFFFFFFF ) &&
( ( dwError = GetLastError() ) != NO_ERROR ) )
{
hr = HRESULT_FROM_WIN32( dwError );
goto abort;
}
m_qwFileSize = MAKEQWORD( dwSizeLow, dwSizeHigh );
m_dwAlignment = 1;
m_dwAlignmentLog2 = 0;
abort:
if( FAILED(hr) && ( INVALID_HANDLE_VALUE != m_hFile ) )
{
// In a failure condition, ensure the file is closed
CloseHandle( m_hFile );
m_hFile = INVALID_HANDLE_VALUE;
}
LeaveCriticalSection( &m_CriticalSection );
if ( NULL != pCallback )
{
// The HRESULT returned by the callback should be ignored.
pCallback->OnOpenDataContainer( hr, this, qwContext );
hr = S_OK; // any error is passed to the callback
}
return( hr );
}
/////////////////////////////////////////////////////////////////////////////
//
// [Shutdown]
//
/////////////////////////////////////////////////////////////////////////////
HRESULT
CSampleDataContainer::Shutdown()
{
HRESULT hr = S_OK;
BOOL fSuccess;
EnterCriticalSection( &m_CriticalSection );
if ( NULL != m_pszPathName )
{
delete m_pszPathName;
m_pszPathName = NULL;
}
if ( INVALID_HANDLE_VALUE != m_hFile )
{
fSuccess = CloseHandle( m_hFile );
if ( !fSuccess )
{
DWORD nErr = GetLastError();
}
m_hFile = INVALID_HANDLE_VALUE;
}
if( NULL != m_pOwnerStorageSystem )
{
m_pOwnerStorageSystem->Release();
m_pOwnerStorageSystem = NULL;
}
LeaveCriticalSection( &m_CriticalSection );
return( hr );
} // End of Shutdown.
/////////////////////////////////////////////////////////////////////////////
inline
STDMETHODIMP_( ULONG )
CSampleDataContainer::AddRef()
{
return( InterlockedIncrement( &m_cRef ) );
}
/////////////////////////////////////////////////////////////////////////////
inline
STDMETHODIMP_( ULONG )
CSampleDataContainer::Release()
{
if ( 0 == InterlockedDecrement( &m_cRef ) )
{
delete this;
return( 0 );
}
return( 0xbad );
} // End of Release.
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CSampleDataContainer::QueryInterface( REFIID riid, void **ppvObject )
{
if ( IID_IWMSDataContainer == riid )
{
*ppvObject = ( IWMSDataContainer * ) this;
AddRef();
return( S_OK );
}
else if ( IID_IUnknown == riid )
{
*ppvObject = ( IUnknown * ) this;
AddRef();
return( S_OK );
}
*ppvObject = NULL;
return( E_NOINTERFACE );
} // End of QueryInterface.
/////////////////////////////////////////////////////////////////////////////
//
// [GetContainerFormat]
//
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE
CSampleDataContainer::GetContainerFormat( GUID *pFormat )
{
if ( NULL == pFormat )
{
return( E_INVALIDARG );
}
// Sample never knows the format of a file.
*pFormat = IID_IWMSUnknownFormat;
return( S_OK );
} // End of GetContainerFormat.
/////////////////////////////////////////////////////////////////////////////
//
// [GetDataSourcePlugin]
//
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE
CSampleDataContainer::GetDataSourcePlugin(
IWMSDataSourcePlugin **ppDataSource
)
{
HRESULT hr = S_OK;
if ( NULL == ppDataSource )
{
return( E_INVALIDARG );
}
*ppDataSource = NULL;
EnterCriticalSection( &m_CriticalSection );
if ( NULL != m_pOwnerStorageSystem )
{
*ppDataSource = m_pOwnerStorageSystem;
m_pOwnerStorageSystem->AddRef();
}
else
{
hr = E_UNEXPECTED;
}
LeaveCriticalSection( &m_CriticalSection );
return( hr );
} // End of GetDataSourcePlugin.
/////////////////////////////////////////////////////////////////////////////
//
// [GetInfo]
//
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE
CSampleDataContainer::GetInfo(
DWORD dwInfoValueId,
IWMSDataContainerCallback *pCallback,
QWORD qwContext
)
{
HRESULT hr = S_OK;
if ( NULL == pCallback )
{
return( E_INVALIDARG );
}
if ( WMS_DATA_CONTAINER_SIZE != dwInfoValueId )
{
return( E_NOTIMPL );
}
EnterCriticalSection( &m_CriticalSection );
// If this data container is not open, then abort.
if ( INVALID_HANDLE_VALUE != m_hFile )
{
// Ignore any error returned by the callback.
( void ) pCallback->OnGetInfo(
S_OK,
WMS_SEEKABLE_CONTAINER | WMS_LOCAL_DATA_CONTAINER,
m_qwFileSize,
qwContext
);
hr = S_OK; // any error is passed to the callback
}
else
{
hr = E_UNEXPECTED;
}
LeaveCriticalSection( &m_CriticalSection );
return( hr );
} // End of GetInfo.
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE
CSampleDataContainer::GetTransferParameters(
QWORD qwDesiredOffset,
DWORD dwDesiredMinSize,
DWORD dwDesiredMaxSize,
QWORD *pqwOffset,
DWORD *pdwSize,
DWORD *pdwBufferAlignment
)
{
HRESULT hr = S_OK;
if( ( NULL == pqwOffset )
|| ( NULL == pdwSize ) )
{
return( E_POINTER );
}
if( ( dwDesiredMaxSize != 0 ) && ( dwDesiredMinSize != 0 ) && ( dwDesiredMaxSize < dwDesiredMinSize ) )
{
return( E_INVALIDARG );
}
if( ( qwDesiredOffset == ~0 ) && ( dwDesiredMinSize == 0 ) )
{
return( E_INVALIDARG );
}
EnterCriticalSection( &m_CriticalSection );
if( pdwBufferAlignment != NULL )
{
*pdwBufferAlignment = m_dwAlignment;
}
if( dwDesiredMinSize != 0 )
{
// Round the offset down to the nearest sector boundary.
*pqwOffset = ( qwDesiredOffset >> m_dwAlignmentLog2 ) << m_dwAlignmentLog2;
// We may have backed the offset up to the nearest sector.
// Make sure we will still read all of the desired bytes.
*pdwSize = dwDesiredMinSize + (DWORD) ( qwDesiredOffset - *pqwOffset );
*pdwSize = ( ( *pdwSize + m_dwAlignment - 1 ) >> m_dwAlignmentLog2 ) << m_dwAlignmentLog2;
if( dwDesiredMaxSize != 0 )
{
if( dwDesiredMaxSize > *pdwSize )
{
DWORD dwTmp = ( dwDesiredMaxSize >> m_dwAlignmentLog2 ) << m_dwAlignmentLog2;
*pdwSize = dwTmp;
}
else
{
*pdwSize = 0;
hr = E_FAIL;
goto abort;
}
}
}
else if( dwDesiredMaxSize != 0 ) // and dwDesiredMinSize == 0
{
*pdwSize = ( dwDesiredMaxSize >> m_dwAlignmentLog2 ) << m_dwAlignmentLog2;
if( qwDesiredOffset >= *pdwSize )
{
*pqwOffset = qwDesiredOffset - dwDesiredMaxSize;
*pqwOffset = ( ( *pqwOffset + m_dwAlignment - 1 ) >> m_dwAlignmentLog2 ) << m_dwAlignmentLog2;
if( *pqwOffset > qwDesiredOffset )
{
*pdwSize = 0;
hr = E_FAIL;
goto abort;
}
}
else
{
// we could make pdwSize smaller now if necessary, so that we don't read
// too much information
*pqwOffset = 0;
*pdwSize = ( ( (DWORD) qwDesiredOffset + m_dwAlignment - 1 ) >> m_dwAlignmentLog2 ) << m_dwAlignmentLog2;
}
}
else
{
*pdwSize = 0;
*pqwOffset = ( ( qwDesiredOffset + m_dwAlignment - 1 ) >> m_dwAlignmentLog2 ) << m_dwAlignmentLog2;
}
abort:
LeaveCriticalSection( &m_CriticalSection );
return( hr );
}
/////////////////////////////////////////////////////////////////////////////
//
// [Read]
//
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE
CSampleDataContainer::Read(
BYTE *pbBuffer,
QWORD qwReadPosition,
DWORD dwMaxDataSize,
DWORD dwFlags,
IWMSDataContainerCallback *pCallback,
QWORD qwContext
)
{
// The dwChangeType and qwChangeParameter values allow a storage
// system to send stream signals to the server when a read completes.
// For example, a storage system that reads from a network feed or
// a live encoder will use this to pass along stream signals such
// as playlist changes.
// Do some work and eventually call the callback. Remember the rules:
//
// 1. You may call the callback from any thread. You may even call the
// callback inside this function before this function returns.
//
// 2. If you call the callback, then this method MUST return S_OK.
// This tells the server that the callback will not be called.
//
// Similarly, if this function returns S_OK, then you must call
// the callback eventually, either from inside this method or
// later as part of an asynchronous action.
//
// 3. If this method returns an error, then it must NOT call the
// callback. The error tells the server that the callback
// will not be called.
HRESULT hr = S_OK;
DWORD dwOffsetLow = 0, dwOffsetHigh = 0;
DWORD dwError = NO_ERROR;
BOOL fSuccess = TRUE;
DWORD dwBytesTransferred = 0;
if ( ( NULL == pbBuffer )
|| ( NULL == pCallback ) )
{
return( E_INVALIDARG );
}
EnterCriticalSection( &m_CriticalSection );
// If this data container is not open, then abort.
if ( ( INVALID_HANDLE_VALUE == m_hFile )
|| ( NULL == m_pOwnerStorageSystem ) )
{
hr = E_UNEXPECTED;
goto abort;
}
dwOffsetLow = LODWORD( qwReadPosition );
dwOffsetHigh = HIDWORD( qwReadPosition );
dwOffsetLow = SetFilePointer( m_hFile, dwOffsetLow, (long*)&dwOffsetHigh, FILE_BEGIN );
if( ( dwOffsetLow == 0xFFFFFFFF ) && ( ( dwError = GetLastError() ) != NO_ERROR ) )
{
hr = HRESULT_FROM_WIN32( dwError );
goto abort;
}
fSuccess = ReadFile(
m_hFile,
pbBuffer,
dwMaxDataSize,
&dwBytesTransferred,
NULL
);
if ( !fSuccess )
{
dwError = GetLastError();
if ( ERROR_HANDLE_EOF != dwError )
{
hr = HRESULT_FROM_WIN32( dwError );
goto abort;
}
}
OnIoCompletion(
dwError,
CSampleDataContainer::IO_READ,
qwReadPosition,
dwBytesTransferred,
pbBuffer,
pCallback,
qwContext
);
// We called the callback, so we MUST return S_OK.
hr = S_OK;
abort:
LeaveCriticalSection( &m_CriticalSection );
return( hr );
} // End of Read.
/////////////////////////////////////////////////////////////////////////////
//
// [Write]
//
/////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE CSampleDataContainer::Write(
BYTE *pbBuffer,
DWORD dwDataSize,
QWORD qwWritePosition,
IWMSDataContainerCallback *pCallback,
QWORD qwContext
)
{
HRESULT hr = S_OK;
BOOL fSuccess = TRUE;
DWORD dwOffsetLow = 0, dwOffsetHigh = 0;
DWORD dwError = NO_ERROR;
DWORD dwBytesTransferred = 0;
if ( ( NULL == pbBuffer )
|| ( NULL == pCallback ) )
{
return( E_INVALIDARG );
}
EnterCriticalSection( &m_CriticalSection );
// If this data container is not open, then abort.
if ( ( INVALID_HANDLE_VALUE == m_hFile )
|| ( NULL == m_pOwnerStorageSystem ) )
{
hr = E_UNEXPECTED;
goto abort;
}
// Do some work and eventually call the callback. Remember the rules:
//
// 1. You may call the callback from any thread. You may even call the
// callback inside this function before this function returns.
//
// 2. If you call the callback, then this method MUST return S_OK.
// This tells the server that the callback will not be called.
//
// Similarly, if this function returns S_OK, then you must call
// the callback eventually, either from inside this method or
// later as part of an asynchronous action.
//
// 3. If this method returns an error, then it must NOT call the
// callback. The error tells the server that the callback
// will not be called.
dwOffsetLow = LODWORD( qwWritePosition );
dwOffsetHigh = HIDWORD( qwWritePosition );
dwOffsetLow = SetFilePointer( m_hFile, dwOffsetLow, (long*)&dwOffsetHigh, FILE_BEGIN );
if( ( dwOffsetLow == 0xFFFFFFFF ) && ( ( dwError = GetLastError() ) != NO_ERROR ) )
{
hr = HRESULT_FROM_WIN32( dwError );
goto abort;
}
fSuccess = WriteFile(
m_hFile,
pbBuffer,
dwDataSize,
&dwBytesTransferred,
NULL
);
if ( !fSuccess )
{
dwError = GetLastError();
hr = HRESULT_FROM_WIN32( GetLastError() );
goto abort;
}
OnIoCompletion( dwError,
CSampleDataContainer::IO_WRITE,
qwWritePosition,
dwBytesTransferred,
pbBuffer,
pCallback,
qwContext );
hr = S_OK;
abort:
LeaveCriticalSection( &m_CriticalSection );
return( hr );
}
/////////////////////////////////////////////////////////////////////////////
void CSampleDataContainer::OnIoCompletion(
DWORD dwError,
DWORD dwIoType,
QWORD qwOffset,
DWORD cbTransferred,
BYTE *pbBuffer,
IWMSDataContainerCallback *pCallback,
QWORD qwContext
)
{
HRESULT hr = HRESULT_FROM_WIN32( dwError );
if ( CSampleDataContainer::IO_READ == dwIoType )
{
if ( ( SUCCEEDED( hr ) )
&& ( qwOffset >= m_qwFileSize )
&& ( 0 == cbTransferred ) )
{
hr = HRESULT_FROM_WIN32( ERROR_HANDLE_EOF );
}
if ( NULL != pCallback )
{
// The HRESULT returned by the callback should be ignored.
pCallback->OnRead( hr,
cbTransferred,
0,
0,
qwContext
);
hr = S_OK; // any error is passed to the callback
}
}
else if ( CSampleDataContainer::IO_WRITE == dwIoType )
{
if ( NULL != pCallback )
{
// The HRESULT returned by the callback should be ignored.
pCallback->OnWrite( hr,
cbTransferred,
qwContext );
hr = S_OK; // any error is passed to the callback
}
}
}
/////////////////////////////////////////////////////////////////////////////
//
// [DoDataContainerExtendedCommand]
//
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE
CSampleDataContainer::DoDataContainerExtendedCommand(
LPWSTR szCommandName,
IWMSCommandContext *pCommand,
DWORD dwCallFlags,
IWMSDataContainerCallback *pCallback,
QWORD qwContext
)
{
if ( NULL == pCallback )
{
// We are returning an error, so we cannot call the callback.
return( E_INVALIDARG );
}
// TODO: Implement any special commands that may be sent from the
// client or server to plugins that are not part of the current command
// set. Currently, this method is not used, and is designed for future
// growth.
// Ignore the result.
pCallback->OnDoDataContainerExtendedCommand( S_OK, qwContext );
// We called the callback, so we MUST return S_OK.
return( S_OK );
} // End of DoDataContainerExtendedCommand.
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE
CSampleDataContainer::FinishParsingPacketlist(
IWMSPacketList *pPacketList
)
{
HRESULT hr = S_OK;
if ( NULL == pPacketList )
{
return( E_INVALIDARG );
}
return( S_OK );
} // FinishParsingPacketlist
/////////////////////////////////////////////////////////////////////////////
//
// [CSampleDirectory]
//
/////////////////////////////////////////////////////////////////////////////
CSampleDirectory::CSampleDirectory()
{
m_cRef = 1;
m_pOwnerStorageSystem = NULL;
InitializeCriticalSection( &m_CriticalSection );
m_pPathName = NULL;
m_dwPathNameLength = 0;
m_pSearchDirName = NULL;
m_pChildren = NULL;
m_pRecentChild = NULL;
m_dwItemNum = 0;
} //End of CSampleDirectory
CSampleDirectory::~CSampleDirectory()
{
Shutdown();
DeleteCriticalSection( &m_CriticalSection );
} // End of ~CSampleDirectory
/////////////////////////////////////////////////////////////////////////////
//
// [Initialize]
//
/////////////////////////////////////////////////////////////////////////////
HRESULT
CSampleDirectory::Initialize(
IWMSContext *pUserContext,
LPWSTR pszContainerName,
CSDKSampleStorageSystem *pOwnerStorageSystem,
IWMSDataSourcePluginCallback *pCallback,
QWORD qwContext )
{
HRESULT hr = S_OK;
WCHAR *pszNtfsPathname = NULL;
size_t sFileName = 0;
DWORD dwFileAttributes = 0;
DWORD dwIndex = 0;
HANDLE hFileEnum = INVALID_HANDLE_VALUE;
BOOL fSuccess = FALSE;
WIN32_FIND_DATA FileInfo;
CSampleDirectoryInfo *pDirInfo = NULL;
DWORD dwUrlLength = 0;
DWORD dwFileNameLength = 0;
DWORD dwFileNameStartPosition =0;
WCHAR cLastCharInPath = L'\0';
EnterCriticalSection( &m_CriticalSection );
//
// Check arguments
//
if( ( NULL == pszContainerName )||
( NULL == pCallback ) ||
( NULL == pOwnerStorageSystem ) )
{
hr = E_INVALIDARG;
goto abort;
}
if( 0 != _wcsnicmp( pszContainerName, URL_SCHEME, URL_SCHEME_LENGTH ) )
{
// The container name doesn't start with the expected scheme
hr = E_INVALIDARG;
goto abort;
}
m_pOwnerStorageSystem = pOwnerStorageSystem;
pOwnerStorageSystem->AddRef();
m_dwItemNum = 0;
//
// Copy the full path
//
m_dwPathNameLength = (DWORD)wcslen( pszContainerName );
m_pPathName = new WCHAR[ m_dwPathNameLength + 1 ];
if( NULL == m_pPathName )
{
hr = E_OUTOFMEMORY;
goto abort;
}
m_pPathName[m_dwPathNameLength] = L'\0';
wcsncpy_s( m_pPathName,m_dwPathNameLength + 1, pszContainerName, m_dwPathNameLength );
if( L'\0' != m_pPathName[m_dwPathNameLength] )
{
hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
goto abort;
}
//
// Make an auxiliary copy of the path, without the scheme
//
pszNtfsPathname = pszContainerName + URL_SCHEME_LENGTH;
sFileName = wcslen( pszNtfsPathname );
m_pSearchDirName = new WCHAR[ sFileName + DIR_MASK_LENGTH + 1 ];
if( NULL == m_pSearchDirName )
{
hr = E_OUTOFMEMORY;
goto abort;
}
m_pSearchDirName[sFileName] = L'\0';
wcsncpy_s( m_pSearchDirName,sFileName + DIR_MASK_LENGTH + 1, pszNtfsPathname, sFileName );
if( L'\0' != m_pSearchDirName[sFileName] )
{
hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
goto abort;
}
//
// Remove any trailing '\' or '/' from the working path
//
if( 0 < sFileName )
{
cLastCharInPath = m_pSearchDirName[sFileName - 1];
if( ( L'\\' == cLastCharInPath )
|| ( L'/' == cLastCharInPath ) )
{
--sFileName;
m_pSearchDirName[sFileName] = L'\0';
}
}
//
// Check if it's really a directory
//
dwFileAttributes = GetFileAttributes( m_pSearchDirName );
if( -1 == dwFileAttributes )
{
// Unable to get the FileAttributes
hr = HRESULT_FROM_WIN32( GetLastError() );
goto abort;
}
else if( !( FILE_ATTRIBUTE_DIRECTORY & dwFileAttributes ) )
{
// This "file" is not a directory
hr = HRESULT_FROM_WIN32( ERROR_DIRECTORY );
goto abort;
}
//
// Append a '\*' mask to the working path and walk through the directory
//
m_pSearchDirName[ sFileName + DIR_MASK_LENGTH ] = L'\0';
wcsncpy_s( &m_pSearchDirName[sFileName],DIR_MASK_LENGTH +1, DIR_MASK, DIR_MASK_LENGTH );
if( L'\0' != m_pSearchDirName[ sFileName + DIR_MASK_LENGTH ] )
{
hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
goto abort;
}
hFileEnum = FindFirstFileW( m_pSearchDirName, &FileInfo );
if( INVALID_HANDLE_VALUE == hFileEnum )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
if( HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ) == hr )
{
// This means we hit the end of the directory, which is
// not an error. Signify S_FALSE for the end of the
// enumeration.
hr = S_FALSE;
goto abort;
}
goto abort;
}
fSuccess = TRUE;
// Advance to the desired position in the directory.
dwIndex = 0;
while ( TRUE )
{
if( !fSuccess )
{
hr = HRESULT_FROM_WIN32( GetLastError() );
if( HRESULT_FROM_WIN32( ERROR_NO_MORE_FILES ) != hr )
{
goto abort;
}
// This means we hit the end of the directory, which is
// not an error.
hr = S_OK;
break;
}
if( ( '\0' == FileInfo.cFileName[0] )
|| ( ( '.' == FileInfo.cFileName[0] ) && ('\0' == FileInfo.cFileName[1] ) )
|| ( ( '.' == FileInfo.cFileName[0] ) && ( '.' == FileInfo.cFileName[1] ) && ( '\0' == FileInfo.cFileName[2] ) )
|| ( FileInfo.dwFileAttributes & FILE_ATTRIBUTE_HIDDEN ) )
{
// if the item is empty or '.' or '..' or hidden file then skip it
// and grab the next file and start the loop again
fSuccess = FindNextFileW( hFileEnum, &FileInfo );
continue;
}
pDirInfo = new CSampleDirectoryInfo;
if( NULL == pDirInfo )
{
hr = E_OUTOFMEMORY;
goto abort;
}
//
// Compose the item's URL
//
dwFileNameLength = (DWORD)wcslen( FileInfo.cFileName );
dwUrlLength = m_dwPathNameLength + dwFileNameLength + 1; // 1 for the '\' separator
pDirInfo->m_pszwName = ( LPOLESTR ) CoTaskMemAlloc( sizeof( OLECHAR ) * ( dwUrlLength + 1 ) );
if( NULL == pDirInfo->m_pszwName )
{
hr = E_OUTOFMEMORY;
goto abort;
}
pDirInfo->m_pszwName[m_dwPathNameLength] = L'\0';
wcsncpy_s( pDirInfo->m_pszwName, ( dwUrlLength + 1 ) , m_pPathName, m_dwPathNameLength );
if( L'\0' != pDirInfo->m_pszwName[m_dwPathNameLength] )
{
hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
goto abort;
}
dwFileNameStartPosition = m_dwPathNameLength;
cLastCharInPath = m_pPathName[m_dwPathNameLength-1];
if( ( L'\\' != cLastCharInPath ) && ( L'/' != cLastCharInPath ) )
{
( pDirInfo->m_pszwName )[m_dwPathNameLength] = L'\\';
( pDirInfo->m_pszwName )[m_dwPathNameLength + 1] = L'\0';
dwFileNameStartPosition++;
}
pDirInfo->m_pszwName[ dwFileNameStartPosition + dwFileNameLength ] = L'\0';
wcsncpy_s( &pDirInfo->m_pszwName[dwFileNameStartPosition],dwFileNameLength+1, FileInfo.cFileName, dwFileNameLength );
if( L'\0' != pDirInfo->m_pszwName[ dwFileNameStartPosition + dwFileNameLength ] )
{
hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
goto abort;
}
//
// Set the item's flags
//
pDirInfo->m_dwFlags = 0;
if( FileInfo.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY )
{
pDirInfo->m_dwFlags |= WMS_DIRECTORY_ENTRY_IS_DIRECTORY;
}
pDirInfo->m_qwSize = MAKEQWORD( FileInfo.nFileSizeLow, FileInfo.nFileSizeHigh );
//
// Insert item's info in list
//
pDirInfo->m_pNext = m_pChildren;
m_pChildren = pDirInfo;
pDirInfo = NULL;
dwIndex++;
fSuccess = FindNextFileW( hFileEnum, &FileInfo );
} // Enumerate every file in the directory.
m_dwItemNum = 1;
m_pRecentChild = m_pChildren;
abort:
LeaveCriticalSection ( &m_CriticalSection );
if( NULL != pDirInfo )
{
delete pDirInfo;
}
if( INVALID_HANDLE_VALUE != hFileEnum )
{
fSuccess = FindClose( hFileEnum );
hFileEnum = INVALID_HANDLE_VALUE;
}
if( NULL != pCallback )
{
// The HRESULT returned by the callback should be ignored.
pCallback->OnOpenDirectory( hr, this, qwContext );
hr = S_OK; // any error is passed to the callback
}
// Any error is passed to the callback.
return( S_OK );
} // End of Initialize
/////////////////////////////////////////////////////////////////////////////
//
// [Shutdown]
//
/////////////////////////////////////////////////////////////////////////////
HRESULT
CSampleDirectory::Shutdown()
{
CSampleDirectoryInfo *pChild = NULL;
if( NULL != m_pOwnerStorageSystem )
{
m_pOwnerStorageSystem->Release();
m_pOwnerStorageSystem = NULL;
}
if( NULL != m_pPathName )
{
delete [] m_pPathName;
m_pPathName = NULL;
}
if( NULL != m_pSearchDirName )
{
delete [] m_pSearchDirName;
m_pSearchDirName = NULL;
}
// delete children
while( NULL != m_pChildren )
{
pChild = m_pChildren;
m_pChildren = m_pChildren->m_pNext;
delete pChild;
}
return( S_OK );
} // End of Shutdown
/////////////////////////////////////////////////////////////////////////////
//
// [AddRef]
//
/////////////////////////////////////////////////////////////////////////////
inline
STDMETHODIMP_( ULONG )
CSampleDirectory::AddRef()
{
return( InterlockedIncrement( &m_cRef ) );
} // End of AddRef
/////////////////////////////////////////////////////////////////////////////
//
// [Release]
//
/////////////////////////////////////////////////////////////////////////////
inline
STDMETHODIMP_( ULONG )
CSampleDirectory::Release()
{
if ( 0 == InterlockedDecrement( &m_cRef ) )
{
delete this;
return( 0 );
}
return( 0xbad );
} // End of Release.
/////////////////////////////////////////////////////////////////////////////
//
// [QueryInterface]
//
/////////////////////////////////////////////////////////////////////////////
STDMETHODIMP
CSampleDirectory::QueryInterface( REFIID riid, void **ppvObject )
{
if ( IID_IWMSDirectory == riid )
{
*ppvObject = ( IWMSDirectory * ) this;
AddRef();
return( S_OK );
}
else if ( IID_IUnknown == riid )
{
*ppvObject = ( IUnknown * ) this;
AddRef();
return( S_OK );
}
*ppvObject = NULL;
return( E_NOINTERFACE );
} // End of QueryInterface.
/////////////////////////////////////////////////////////////////////////////
//
// [GetDataSourcePlugin]
//
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE
CSampleDirectory::GetDataSourcePlugin(
IWMSDataSourcePlugin **ppDataSource
)
{
HRESULT hr = S_OK;
if( NULL == ppDataSource )
{
return( E_INVALIDARG );
}
EnterCriticalSection( &m_CriticalSection );
if( NULL == m_pOwnerStorageSystem )
{
goto abort;
}
*ppDataSource = m_pOwnerStorageSystem;
m_pOwnerStorageSystem->AddRef();
abort:
LeaveCriticalSection( &m_CriticalSection );
return( hr );
} // End of GetDataSourcePlugin
/////////////////////////////////////////////////////////////////////////////
//
// [GetName]
//
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE
CSampleDirectory::GetName(
LPOLESTR *pstrValue
)
{
HRESULT hr = S_OK;
if( NULL == pstrValue )
{
return( E_INVALIDARG );
}
EnterCriticalSection( &m_CriticalSection );
*pstrValue = new WCHAR[ m_dwPathNameLength + 1 ];
if( NULL == *pstrValue )
{
hr = E_OUTOFMEMORY;
goto abort;
}
if( NULL != m_pPathName )
{
*pstrValue[m_dwPathNameLength] = L'\0';
wcsncpy_s( *pstrValue,m_dwPathNameLength + 1, m_pPathName, m_dwPathNameLength );
if( L'\0' != *pstrValue[m_dwPathNameLength] )
{
hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
goto abort;
}
}
else
{
( *pstrValue )[ 0 ] = L'\0';
}
abort:
LeaveCriticalSection( &m_CriticalSection );
return( hr );
} // End of GetName
/////////////////////////////////////////////////////////////////////////////
//
// [GetChildInfo]
//
/////////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE
CSampleDirectory::GetChildInfo(
DWORD dwIndex,
WMSDirectoryEntryInfo *pInfo
)
{
HRESULT hr = S_OK;
DWORD dwUrlLength = 0;
if( NULL == pInfo )
{
return( E_INVALIDARG );
}
EnterCriticalSection( &m_CriticalSection );
// We cannot go backwards. If the client asked for a previous
// directory entry, then reset the state to the beginning and
// then go forward to the desired position.
if( ( dwIndex < m_dwItemNum ) || ( NULL == m_pRecentChild ) )
{
m_dwItemNum = 1;
m_pRecentChild = m_pChildren;
} // resetting the count.
// Advance to the desired position in the directory.
while ( ( m_dwItemNum < dwIndex ) && ( NULL != m_pRecentChild ) )
{
m_pRecentChild = m_pRecentChild->m_pNext;
m_dwItemNum++;
} // advancing to the desired position.
if( NULL == m_pRecentChild )
{
// This means we hit the end of the directory, which is
// not an error. Signify S_FALSE for the end of the enumeration.
hr = S_FALSE;
goto abort;
}
dwUrlLength = (DWORD)wcslen( m_pRecentChild->m_pszwName );
pInfo->pstrName = ( LPOLESTR ) CoTaskMemAlloc( sizeof(OLECHAR) * ( dwUrlLength + 1 ) );
if( NULL == pInfo->pstrName )
{
hr = E_OUTOFMEMORY;
goto abort;
}
pInfo->pstrName[dwUrlLength] = L'\0';
wcsncpy_s( pInfo->pstrName,( dwUrlLength + 1 ) , m_pRecentChild->m_pszwName, dwUrlLength );
if( L'\0' != pInfo->pstrName[dwUrlLength] )
{
hr = HRESULT_FROM_WIN32( ERROR_INSUFFICIENT_BUFFER );
goto abort;
}
pInfo->dwFlags = m_pRecentChild->m_dwFlags;
pInfo->qwSize = m_pRecentChild->m_qwSize;
abort:
LeaveCriticalSection( &m_CriticalSection );
return( hr );
} // End of GetChildInfo