/*++

Copyright (c) 2000-2001  Microsoft Corporation

Module Name:

    vs_cmxml.cxx

Abstract:

    Implementation of Backup Components Metadata XML wrapper classes

    Brian Berkowitz  [brianb]  3/13/2000

TBD:

    Add comments.

Revision History:

    Name        Date        Comments
    brianb      03/16/2000  Created
    brianb      03/22/2000  Added support for PrepareForBackup and BackupComplete
    brianb      04/25/2000  Cleaned up Critical section stuff
    brianb      05/03/2000  changed for new security model
    ssteiner    11/10/2000  143810 Move SimulateSnapshotXxxx() calls to be hosted by VsSvc.

--*/

#include "vs_sec.hxx"

#include "vs_reg.hxx"

////////////////////////////////////////////////////////////////////////
//  Standard foo for file name aliasing.  This code block must be after
//  all includes of VSS header files.
//
#ifdef VSS_FILE_ALIAS
#undef VSS_FILE_ALIAS
#endif
#define VSS_FILE_ALIAS "INCCXMLH"
//
////////////////////////////////////////////////////////////////////////

const VSS_ID x_idWriterRegistry =
    {
    0xAFBAB4A2,
    0x367D,
    0x4D15,
    {0xA5, 0x86, 0x71, 0xDB, 0xB1, 0x8F, 0x84, 0x85}
    };

const VSS_ID x_idWriterEventLog = 
     {
     0xeee8c692, 
     0x67ed, 
     0x4250, 
     {0x8d, 0x86, 0x39, 0x6, 0x3, 0x7, 0xd, 0x00}
     };

const VSS_ID x_idWriterComREGDB = 
     {
     0x542da469, 
     0xd3e1, 
     0x473c, 
     {0x9f, 0x4f, 0x78, 0x47, 0xf0, 0x1f, 0xc6, 0x4f}
     };

// guid used to identify the snapshot service itself when recording
// the snapshot set description XML stuff.
const VSS_ID idVolumeSnapshotService =
    {
    0xe68b51c0,
    0xa080,
    0x4078,
    {0xa2, 0x79, 0x77, 0xfd, 0x4b, 0x6a, 0x41, 0xf7}
    };



class IVssWriterComponentsInt :
    public IVssWriterComponentsExt
    {
public:
    // initialize
    STDMETHOD(Initialize)(bool fFindToplevel) = 0;

    // has document been changed
    STDMETHOD(IsChanged)(bool *pbChanged) = 0;

    // save document as XML
    STDMETHOD(SaveAsXML)(OUT BSTR *pbstrXMLDocument) = 0;
    };




// Writer property structure
typedef struct _VSS_WRITER_PROP {
    VSS_ID              m_InstanceId;
    VSS_ID              m_ClassId;
    VSS_WRITER_STATE        m_nState;
    VSS_PWSZ            m_pwszName;
    HRESULT             m_hrWriterFailure;
    bool                m_bResponseReceived;
} VSS_WRITER_PROP, *PVSS_WRITER_PROP;




// list of writer data that is gotten from ExposeWriterMetadata and
// SetContent
class CInternalWriterData
    {
public:
    // constructor
    CInternalWriterData()
        {
        m_pDataNext = NULL;
        m_pOwnerToken = NULL;
        }

    ~CInternalWriterData()
        {
        delete m_pOwnerToken;
        }

    // initialize an element
    void Initialize
        (
        IN VSS_ID idInstance,
        IN VSS_ID idWriter,
        IN BSTR bstrWriterName,
        IN BSTR bstrMetadata,
        IN TOKEN_OWNER *pOwnerToken
        )
        {
        m_idInstance = idInstance;
        m_idWriter = idWriter;
        m_bstrWriterName = bstrWriterName;
        m_bstrWriterMetadata = bstrMetadata;
        m_pOwnerToken = pOwnerToken;
        m_bstrWriterComponents.Empty();
        m_nState = VSS_WS_STABLE;
        m_hrWriterFailure = S_OK;
        }

    void SetComponents(IN BSTR bstrComponents)
        {
        m_bstrWriterComponents = bstrComponents;
        }


    // instance id of writer
    VSS_ID m_idInstance;

    // class id of the writer
    VSS_ID m_idWriter;

    // name of the writer
    CComBSTR m_bstrWriterName;

    // XML writer metadata from writer
    CComBSTR m_bstrWriterMetadata;

    // last writer failure
    // maintained in case writer is disabled
    HRESULT m_hrWriterFailure;

    // last writer state
    // maintained in case writer is disabled
    VSS_WRITER_STATE m_nState;

    // XML writer component data
    CComBSTR m_bstrWriterComponents;

    // next pointer
    CInternalWriterData *m_pDataNext;

    // security id for client thread
    TOKEN_OWNER *m_pOwnerToken;
    };



// class to access a component from the BACKUP_COMPONENTS document
class CVssComponent :
    public CVssMetadataHelper,
    public IVssComponent
    {
    friend class CVssWriterComponents;
private:
    // constructor (can only be called from CVssWriterComponents)
    CVssComponent
        (
        IXMLDOMNode *pNode,
        IXMLDOMDocument *pDoc,
        CVssWriterComponents *pWriterComponents,
        bool bInRequestor,
        bool bRestore
        ) :
        CVssMetadataHelper(pNode, pDoc),
        m_cRef(0),
        m_pWriterComponents(pWriterComponents),
        m_bInRequestor(bInRequestor),
        m_bRestore(bRestore)
        {
        }

    // 2nd phase constructor
    void Initialize(CVssFunctionTracer &ft)
        {
        InitializeHelper(ft);
        }

public:
    // obtain logical path of component
    STDMETHOD(GetLogicalPath)(OUT BSTR *pbstrPath);

    // obtain component type(VSS_CT_DATABASE or VSS_CT_FILEGROUP)
    STDMETHOD(GetComponentType)(VSS_COMPONENT_TYPE *pct);

    // get component name
    STDMETHOD(GetComponentName)(OUT BSTR *pbstrName);

    // determine whether the component was successfully backed up.
    STDMETHOD(GetBackupSucceeded)(OUT bool *pbSucceeded);

    // get altermative location mapping count
    STDMETHOD(GetAlternateLocationMappingCount)(OUT UINT *pcMappings);

    // get a paraticular alternative location mapping
    STDMETHOD(GetAlternateLocationMapping)
        (
        IN UINT iMapping,
        OUT IVssWMFiledesc **pFiledesc
        );

    // set the backup metadata for a component
    STDMETHOD(SetBackupMetadata)(IN LPCWSTR wszData);

    // get the backup metadata for a component
    STDMETHOD(GetBackupMetadata)(OUT BSTR *pbstrData);

            // indicate that only ranges in the file are to be backed up
    STDMETHOD(AddPartialFile)
        (
        IN LPCWSTR wszPath,
        IN LPCWSTR wszFilename,
        IN LPCWSTR wszRanges,
        IN LPCWSTR wszMetadata
        );

    // get count of partial file declarations
    STDMETHOD(GetPartialFileCount)
        (
        OUT UINT *pcPartialFiles
        );

    // get a partial file declaration
    STDMETHOD(GetPartialFile)
        (
        IN UINT iPartialFile,
        OUT BSTR *pbstrPath,
        OUT BSTR *pbstrFilename,
        OUT BSTR *pbstrRange,
        OUT BSTR *pbstrMetadata
        );

    // determine if the component is selected to be restored
    STDMETHOD(IsSelectedForRestore)
        (
        IN bool *pbSelectedForRestore
        );


    STDMETHOD(GetAdditionalRestores)
        (
        OUT bool *pbAdditionalRestores
        );

    // get count of new target specifications
    STDMETHOD(GetNewTargetCount)
        (
        OUT UINT *pcNewTarget
        );

    STDMETHOD(GetNewTarget)
        (
        IN UINT iNewTarget,
        OUT IVssWMFiledesc **ppFiledesc
        );

    // add a directed target specification
    STDMETHOD(AddDirectedTarget)
        (
        IN LPCWSTR wszSourcePath,
        IN LPCWSTR wszSourceFilename,
        IN LPCWSTR wszSourceRangeList,
        IN LPCWSTR wszDestinationPath,
        IN LPCWSTR wszDestinationFilename,
        IN LPCWSTR wszDestinationRangeList
        );

    // get count of directed target specifications
    STDMETHOD(GetDirectedTargetCount)
        (
        OUT UINT *pcDirectedTarget
        );

    // obtain a particular directed target specification
    STDMETHOD(GetDirectedTarget)
        (
        IN UINT iDirectedTarget,
        OUT BSTR *pbstrSourcePath,
        OUT BSTR *pbstrSourceFileName,
        OUT BSTR *pbstrSourceRangeList,
        OUT BSTR *pbstrDestinationPath,
        OUT BSTR *pbstrDestinationFilename,
        OUT BSTR *pbstrDestinationRangeList
        );

    // set restore metadata associated with the component
    STDMETHOD(SetRestoreMetadata)
        (
        IN LPCWSTR wszRestoreMetadata
        );

    // obtain restore metadata associated with the component
    STDMETHOD(GetRestoreMetadata)
        (
        OUT BSTR *pbstrRestoreMetadata
        );

     // set the restore target
     STDMETHOD(SetRestoreTarget)
        (
        IN VSS_RESTORE_TARGET target
        );

    // obtain the restore target
    STDMETHOD(GetRestoreTarget)
        (
        OUT VSS_RESTORE_TARGET *pTarget
        );

    // set failure message during pre restore event
    STDMETHOD(SetPreRestoreFailureMsg)
        (
        IN LPCWSTR wszPreRestoreFailureMsg
        );

    // obtain failure message during pre restore event
    STDMETHOD(GetPreRestoreFailureMsg)
        (
        OUT BSTR *pbstrPreRestoreFailureMsg
        );

    // set the failure message during the post restore event
    STDMETHOD(SetPostRestoreFailureMsg)
        (
        IN LPCWSTR wszPostRestoreFailureMsg
        );

    // obtain the failure message set during the post restore event
    STDMETHOD(GetPostRestoreFailureMsg)
        (
        OUT BSTR *pbstrPostRestoreFailureMsg
        );

    // set the backup stamp of the backup
    STDMETHOD(SetBackupStamp)
        (
        IN LPCWSTR wszBackupStamp
        );

    // obtain the stamp of the backup
    STDMETHOD(GetBackupStamp)
        (
        OUT BSTR *pbstrBackupStamp
        );


    // obtain the backup stamp that the differential or incremental
    // backup is baed on
    STDMETHOD(GetPreviousBackupStamp)
        (
        OUT BSTR *pbstrBackupStamp
        );

    // obtain backup options for the writer
    STDMETHOD(GetBackupOptions)
        (
        OUT BSTR *pbstrBackupOptions
        );

    // obtain the restore options
    STDMETHOD(GetRestoreOptions)
        (
        IN BSTR *pbstrRestoreOptions
        );

    // obtain count of subcomponents to be restored
    STDMETHOD(GetRestoreSubcomponentCount)
        (
        OUT UINT *pcRestoreSubcomponent
        );

    // obtain a particular subcomponent to be restored
    STDMETHOD(GetRestoreSubcomponent)
        (
        UINT iComponent,
        OUT BSTR *pbstrLogicalPath,
        OUT BSTR *pbstrComponentName,
        OUT bool *pbRepair
        );

    // obtain whether files were successfully restored
    STDMETHOD(GetFileRestoreStatus)
        (
        OUT VSS_FILE_RESTORE_STATUS *pStatus
        );

    // add differenced files by last modify time
    STDMETHOD(AddDifferencedFilesByLastModifyTime)
        (
        IN LPCWSTR wszPath,
        IN LPCWSTR wszFilespec,
        IN BOOL bRecursive,
        IN FILETIME ftLastModifyTime 
        );
    
    STDMETHOD(AddDifferencedFilesByLastModifyLSN)
        (
        IN LPCWSTR wszPath,
        IN LPCWSTR wszFilespec,
        IN BOOL bRecursive,
        IN BSTR bstrLsnString
        );
    
    STDMETHOD(GetDifferencedFilesCount)
        (
        OUT UINT *pcDifferencedFiles
        );
    
    STDMETHOD(GetDifferencedFile)
        (
        IN UINT iDifferencedFile,
        OUT BSTR *pbstrPath,
        OUT BSTR *pbstrFilespec,
        OUT BOOL *pbRecursive,
        OUT BSTR *pbstrLsnString,
        OUT FILETIME *pftLastModifyTime
        );

    // IUnknown methods
    STDMETHOD(QueryInterface)(REFIID, void **);

    STDMETHOD_ (ULONG, AddRef)();

    STDMETHOD_ (ULONG, Release)();
private:
    // common routine for setting backup and restore metadata
    HRESULT SetMetadata(IN bool bRestoreMetadata, IN LPCWSTR bstrMetadata);

    // common routine for adding differenced files
    void AddDifferencedFiles
        (
        IN CVssFunctionTracer& ft,
        IN LPCWSTR wszPath,
        IN LPCWSTR wszFilespec,
        IN BOOL bRecursive,
        IN FILETIME ftLastModifyTime,
        IN  BSTR bstrLsnString
        );
	
    // common routine for retrieving backup and restore metadata
    HRESULT GetMetadata(IN bool bRestoreMetadata, OUT BSTR *pbstrMetadata);

    // get a particular element of a specific type as a file descriptor
    HRESULT CVssComponent::GetFiledescElement
        (
        IN LPCWSTR wszElement,
        IN UINT iMapping,                   // which mapping to select
        OUT IVssWMFiledesc **ppFiledesc     // output file descriptor
        );


    // reference count for AddRef, Release
    LONG m_cRef;

    // pointer to parent writer components document if changes are allowed
    CVssWriterComponents *m_pWriterComponents;

    // are we in the requestor
    bool m_bInRequestor;

    // are we in restore
    bool m_bRestore;
    };

// components associated with a specific writer
class CVssWriterComponents :
    public CVssMetadataHelper,
    public IVssWriterComponentsInt
    {
public:
    // constructor (can only be called from CVssBackupComponents)
    CVssWriterComponents
        (
        IXMLDOMNode *pNode,
        IXMLDOMDocument *pDoc,
        bool bWriteable,
        bool bRequestor,
        bool bRestore
        ) :
        CVssMetadataHelper(pNode, pDoc),
        m_cRef(0),
        m_bWriteable(bWriteable),
        m_bChanged(false),
        m_bInRequestor(bRequestor),
        m_bRestore(bRestore)
        {
        }

    // 2nd phase construction
    void Initialize(CVssFunctionTracer &ft)
        {
        InitializeHelper(ft);
        }


    // get count of components
    STDMETHOD(GetComponentCount)(OUT UINT *pcComponents);

    // get information about the writer
    STDMETHOD(GetWriterInfo)
        (
        OUT VSS_ID *pidInstance,
        OUT VSS_ID *pidWriter
        );

    // obtain a specific component
    STDMETHOD(GetComponent)
        (
        IN UINT iComponent,
        OUT IVssComponent **ppComponent
        );

    STDMETHOD(IsChanged)
        (
        OUT bool *pbChanged
        );

    STDMETHOD(SaveAsXML)
        (
        OUT BSTR *pbstrXMLDocument
        );

    // initialize writer components document to point at writer components
    // element
    STDMETHOD(Initialize)(bool fFindToplevel);


    STDMETHODIMP QueryInterface(REFIID, void **)
        {
        return E_NOTIMPL;
        }

    STDMETHOD_ (ULONG, AddRef)();

    STDMETHOD_ (ULONG, Release)();

    // indicate that document is changed
    void SetChanged()
        {
        BS_ASSERT(m_bWriteable);
        m_bChanged = TRUE;
        }

private:
    // reference count for AddRef, Release
    LONG m_cRef;

    // can components be changed
    bool m_bWriteable;

    // is document changed
    bool m_bChanged;

    // are we in the requestor
    bool m_bInRequestor;

    // are we in restore
    bool m_bRestore;
    };



// components associated with a specific writer
class CVssNULLWriterComponents :
    public IVssWriterComponentsInt
    {
public:
    CVssNULLWriterComponents
        (
        VSS_ID idInstance,
        VSS_ID idWriter
        )
        {
        m_cRef = 0;
        m_idInstance = idInstance;
        m_idWriter = idWriter;
        }

    // initialize
    STDMETHOD(Initialize)(bool fFindToplevel)
        {
        UNREFERENCED_PARAMETER(fFindToplevel);
        return S_OK;
        }

    // get count of components
    STDMETHOD(GetComponentCount)(OUT UINT *pcComponents);

    // get information about the writer
    STDMETHOD(GetWriterInfo)
        (
        OUT VSS_ID *pidInstance,
        OUT VSS_ID *pidWriter
        );

    // obtain a specific component
    STDMETHOD(GetComponent)
        (
        IN UINT iComponent,
        OUT IVssComponent **ppComponent
        );

    STDMETHOD(IsChanged)
        (
        OUT bool *pbChanged
        );

    STDMETHOD(SaveAsXML)
        (
        OUT BSTR *pbstrXMLDocument
        );

    STDMETHODIMP QueryInterface(REFIID, void **)
        {
        return E_NOTIMPL;
        }

    STDMETHOD_ (ULONG, AddRef)();

    STDMETHOD_ (ULONG, Release)();

private:
    // id of writer class
    VSS_ID m_idWriter;

    // id of writer instance
    VSS_ID m_idInstance;

    // reference count for AddRef, Release
    LONG m_cRef;
    };


// state of CVssBackupComponents object
enum VSS_BACKUPCALL_STATE
    {
    x_StateUndefined = 0,
    x_StateInitialized,
    x_StateSnapshotSetCreated,
    x_StatePrepareForBackup,
    x_StatePrepareForBackupSucceeded,
    x_StatePrepareForBackupFailed,
    x_StateDoSnapshot,
    x_StateDoSnapshotSucceeded,
    x_StateDoSnapshotFailed,
    x_StateBackupComplete,
    x_StateBackupCompleteSucceeded,
    x_StateBackupCompleteFailed,
    x_StateAborting,
    x_StateAborted,
    x_StatePreRestore,
    x_StatePreRestoreSucceeded,
    x_StatePreRestoreFailed,
    x_StatePostRestore,
    x_StatePostRestoreSucceeded,
    x_StatePostRestoreFailed,
    x_StateGatheringWriterMetadata,
    x_StateGatheringWriterStatus
    };


// class used by the backup application to interact with the writer
class ATL_NO_VTABLE CVssBackupComponents :
    public CComObjectRoot,
    public IVssBackupComponents,
    public CVssMetadataHelper,
    public IDispatchImpl<IVssWriterCallback, &IID_IVssWriterCallback, &LIBID_VssEventLib, 1, 0>,
    public IVssCoordinatorCallback
    {
public:
    friend class CVssAsyncBackup;
    friend class CVssAsyncCover;

    BEGIN_COM_MAP(CVssBackupComponents)
        COM_INTERFACE_ENTRY(IDispatch)
        COM_INTERFACE_ENTRY(IVssWriterCallback)
        COM_INTERFACE_ENTRY(IVssCoordinatorCallback)
    END_COM_MAP()

    // constructor
    CVssBackupComponents();

    // destructor
    ~CVssBackupComponents();

    // get count of writer components
    STDMETHOD(GetWriterComponentsCount)(OUT UINT *pcComponents);

    // obtain a specific writer component
    STDMETHOD(GetWriterComponents)
        (
        IN UINT iWriter,
        OUT IVssWriterComponentsExt **ppWriter
        );

    // initialize for backup
    STDMETHOD(InitializeForBackup)(IN BSTR bstrXML = NULL);

    // set backup state for backup components document
    STDMETHOD(SetBackupState)
        (
        IN bool bSelectComponents,
        IN bool bBackupBootableState,
        IN VSS_BACKUP_TYPE backupType,
        IN bool bPartialFileSupport
        );

    STDMETHOD(SetRestoreState)
		(
		IN VSS_RESTORE_TYPE restoreType
		);
	
    // initialize for restore
    STDMETHOD(InitializeForRestore)
        (
        IN BSTR bstrXML
        );


    // gather writer metadata
    STDMETHOD(GatherWriterMetadata)
        (
        OUT IVssAsync **ppAsync
        );

    // get count of writers
    STDMETHOD(GetWriterMetadataCount)
        (
        OUT UINT *pcWriters
        );

    // get writer metadata for a specific writer
    STDMETHOD(GetWriterMetadata)
        (
        IN UINT iWriter,
        OUT VSS_ID *pidInstance,
        OUT IVssExamineWriterMetadata **ppMetadata
        );

    // free XML data gathered from writers
    STDMETHOD(FreeWriterMetadata)();

    // Called to set the context for subsequent snapshot-related operations
    STDMETHOD(SetContext)
        (
        IN LONG lContext
        );

    // start a snapshot set
    STDMETHOD(StartSnapshotSet)
        (
        OUT VSS_ID *pSnapshotSetId
        );

    // add a volume to a snapshot set
    STDMETHOD(AddToSnapshotSet)
        (
        IN  VSS_PWSZ    pwszVolumeName,
        IN  VSS_ID      ProviderId,
        OUT VSS_ID      *pSnapshotId
        );

    // add a component to the BACKUP_COMPONENTS document
    STDMETHOD(AddComponent)
        (
        IN VSS_ID instanceId,
        IN VSS_ID writerId,
        IN VSS_COMPONENT_TYPE ct,
        IN LPCWSTR wszLogicalPath,
        IN LPCWSTR wszComponentName
        );

    // dispatch PrepareForBackup event to writers
    STDMETHOD(PrepareForBackup)
        (
        OUT IVssAsync **ppAsync
        );

    // create the snapshot set
    STDMETHOD(DoSnapshotSet)
        (
        OUT IVssAsync** ppAsync
        );


    // abort the backup
    STDMETHOD(AbortBackup)();

    // dispatch the Identify event so writers can expose their metadata
    STDMETHOD(GatherWriterStatus)
        (
        OUT IVssAsync **ppAsync
        );

    // get count of writers with status
    STDMETHOD(GetWriterStatusCount)
        (
        OUT UINT *pcWriters
        );


    // obtain status information about writers
    STDMETHOD(GetWriterStatus)
        (
        IN UINT iWriter,
        OUT VSS_ID *pidInstance,
        OUT VSS_ID *pidWriter,
        OUT BSTR *pbstrWriterName,
        OUT VSS_WRITER_STATE *pStatus,
        OUT HRESULT *phrWriterFailure
        );

    // free data gathered using GetWriterStatus
    STDMETHOD(FreeWriterStatus)();

    // indicate whether backup succeeded on a component
    STDMETHOD(SetBackupSucceeded)
        (
        IN VSS_ID instanceId,
        IN VSS_ID writerId,
        IN VSS_COMPONENT_TYPE ct,
        IN LPCWSTR wszLogicalPath,
        IN LPCWSTR wszComponentName,
        IN bool bSucceded
        );

    // set backup options for the writer
    STDMETHOD(SetBackupOptions)
        (
        IN VSS_ID writerId,
        IN VSS_COMPONENT_TYPE ct,
        IN LPCWSTR wszLogicalPath,
        IN LPCWSTR wszComponentName,
        IN LPCWSTR wszBackupOptions
        );

    // indicate that a given component is selected to be restored
    STDMETHOD(SetSelectedForRestore)
        (
        IN VSS_ID writerId,
        IN VSS_COMPONENT_TYPE ct,
        IN LPCWSTR wszLogicalPath,
        IN LPCWSTR wszComponentName,
        IN bool bSelectedForRestore
        );


    // set restore options for the writer
    STDMETHOD(SetRestoreOptions)
        (
        IN VSS_ID writerId,
        IN VSS_COMPONENT_TYPE ct,
        IN LPCWSTR wszLogicalPath,
        IN LPCWSTR wszComponentName,
        IN LPCWSTR wszRestoreOptions
        );

    // indicate that additional restores will follow
    STDMETHOD(SetAdditionalRestores)
        (
        IN VSS_ID writerId,
        IN VSS_COMPONENT_TYPE ct,
        IN LPCWSTR wszLogicalPath,
        IN LPCWSTR wszComponentName,
        IN bool bAdditionalRestores
        );

    // requestor indicates whether files were successfully restored
    STDMETHOD(SetFileRestoreStatus)
        (
        IN VSS_ID writerId,
        IN VSS_COMPONENT_TYPE ct,
        IN LPCWSTR wszLogicalPath,
        IN LPCWSTR wszComponentName,
        IN VSS_FILE_RESTORE_STATUS status
        );

    // add a new location target for a file to be restored
    STDMETHOD(AddNewTarget)
        (
        IN VSS_ID writerId,
        IN VSS_COMPONENT_TYPE ct,
        IN LPCWSTR wszLogicalPath,
        IN LPCWSTR wszComponentName,
        IN LPCWSTR wszPath,
        IN LPCWSTR wszFileName,
        IN bool bRecursive,
        IN LPCWSTR wszAlternatePath
        ) ;

         // add a new location for the ranges file in case it was restored to
    // a different location
    STDMETHOD(SetRangesFilePath)
    		(
		IN VSS_ID writerId,
		IN VSS_COMPONENT_TYPE ct,
		IN LPCWSTR wszLogicalPath,
		IN LPCWSTR wszComponentName,    		
    		IN UINT iPartialFile,
    		IN LPCWSTR wszRangesFile
    		);

    // set the backup stamp that the differential or incremental
    // backup is based on
    STDMETHOD(SetPreviousBackupStamp)
        (
        IN VSS_ID writerId,
        IN VSS_COMPONENT_TYPE ct,
        IN LPCWSTR wszLogicalPath,
        IN LPCWSTR wszComponentName,
        IN LPCWSTR wszPreviousBackupStamp
        );

    // delete a set of snapshots
    STDMETHOD(DeleteSnapshots)
        (
        IN VSS_ID           SourceObjectId,
        IN VSS_OBJECT_TYPE  eSourceObjectType,
        IN BOOL             bForceDelete,
        IN LONG*            plDeletedSnapshots,
        IN VSS_ID*          pNondeletedSnapshotID
        );

    // Break the snapshot set
    STDMETHOD(BreakSnapshotSet)
        (
        IN VSS_ID           SnapshotSetId
        );

    STDMETHOD(ImportSnapshots)
        (
        OUT IVssAsync**     ppAsync
        );

    // Get snapshot properties
    STDMETHOD(GetSnapshotProperties)
        (
        IN VSS_ID       SnapshotId,
        OUT VSS_SNAPSHOT_PROP   *pProp
        );

    // do a generic query using the coordinator
    STDMETHOD(Query)
        (
        IN VSS_ID           QueriedObjectId,
        IN VSS_OBJECT_TYPE eQueriedObjectType,
        IN VSS_OBJECT_TYPE eReturnedObjectsType,
        IN IVssEnumObject **ppEnum
        );


    // save BACKUP_COMPONENTS document as XML string
    STDMETHOD(SaveAsXML)(BSTR *pbstrXML);

    // signal BackupComplete event to the writers
    STDMETHOD(BackupComplete)(OUT IVssAsync **ppAsync);

    // add an alternate mapping on restore
    STDMETHOD(AddAlternativeLocationMapping)
        (
        IN VSS_ID writerId,
        IN VSS_COMPONENT_TYPE componentType,
        IN LPCWSTR wszLogicalPath,
        IN LPCWSTR wszComponentName,
        IN LPCWSTR wszPath,
        IN LPCWSTR wszFilespec,
        IN bool bRecursive,
        IN LPCWSTR wszDestination
        );

    // add a subcomponent to be restored
    STDMETHOD(AddRestoreSubcomponent)
        (
        IN VSS_ID writerId,
        IN VSS_COMPONENT_TYPE componentType,
        IN LPCWSTR wszLogicalPath,
        IN LPCWSTR wszComponentName,
        IN LPCWSTR wszSubLogicalPath,
        IN LPCWSTR wszSubComponentName,
        IN bool bRepair
        );


    // signal PreRestore event to the writers
    STDMETHOD(PreRestore)(OUT IVssAsync **ppAsync);

    // signal PostRestore event to the writers
    STDMETHOD(PostRestore)(OUT IVssAsync **ppAsync);

    // IWriterCallback methods

    // called by writer to expose its WRITER_METADATA XML document
    STDMETHOD(ExposeWriterMetadata)
        (
        IN BSTR WriterInstanceId,
        IN BSTR WriterClassId,
        IN BSTR bstrWriterName,
        IN BSTR strWriterXMLMetadata
        );

    // called by the writer to obtain the WRITER_COMPONENTS document for it
    STDMETHOD(GetContent)
        (
        IN  BSTR WriterInstanceId,
        OUT BSTR* pbstrXMLDOMDocContent
        );

    // called by the writer to obtain the WRITER_COMPONENTS document for it
    STDMETHOD(CoordGetContent)
        (
        IN  BSTR WriterInstanceId,
        IN  ULONG cbSid,
        IN  BYTE *pbSid,
        OUT BSTR* pbstrXMLDOMDocContent
        );


    // called by the writer to update the WRITER_COMPONENTS document for it
    STDMETHOD(SetContent)
        (
        IN BSTR WriterInstanceId,
        IN BSTR bstrXMLDOMDocContent
        );

    // called by the writer to update the WRITER_COMPONENTS document for it
    STDMETHOD(CoordSetContent)
        (
        IN BSTR WriterInstanceId,
        IN ULONG cbSid,
        IN BYTE *pbSid,
        IN BSTR bstrXMLDOMDocContent
        );


    // called by the writer to get information about the backup
    STDMETHOD(GetBackupState)
        (
        OUT BOOL *pbBootableSystemStateBackedUp,
        OUT BOOL *pbAreComponentsSelected,
        OUT VSS_BACKUP_TYPE *pBackupType,
        OUT BOOL *pbPartialFileSupport,
        OUT LONG *plContext
        );
	
    // called by the writer to get information about the backup
    STDMETHOD(CoordGetBackupState)
        (
        OUT BOOL *pbBootableSystemStateBackedUp,
        OUT BOOL *pbAreComponentsSelected,
        OUT VSS_BACKUP_TYPE *pBackupType,
        OUT BOOL *pbPartialFileSupport,
        OUT LONG *plContext        
        );
 
    STDMETHOD(GetRestoreState)
		(
		OUT VSS_RESTORE_TYPE *pRestoreType
		);
    STDMETHOD(CoordGetRestoreState)
		(
		OUT VSS_RESTORE_TYPE *pRestoreType
		);
   
    // called by the writer to indicate its status
    STDMETHOD(ExposeCurrentState)
        (
        IN BSTR WriterInstanceId,
        IN VSS_WRITER_STATE nCurrentState,
        IN HRESULT hrWriterFailure
        );

    // Called by the requestor to check if a certain volume is supported.
    STDMETHOD(IsVolumeSupported)
        (
        IN VSS_ID ProviderId,
        IN VSS_PWSZ pwszVolumeName,
        IN BOOL * pbSupportedByThisProvider
        );
 
    // called to disable writer classes
    STDMETHOD(DisableWriterClasses)
        (
        IN const VSS_ID *rgWriterClassId,
        IN UINT cClassId
        );

    // called to enable specific writer classes.  Note that once specific
    // writer classes are enabled, only enabled classes are called.
    STDMETHOD(EnableWriterClasses)
        (
        IN const VSS_ID *rgWriterClassId,
        IN UINT cClassId
        );

    // called to disable an event call to a writer instance
    STDMETHOD(DisableWriterInstances)
        (
        IN const VSS_ID *rgWriterInstanceId,
        IN UINT cInstanceId
        );

    // called to expose a snapshot
    STDMETHOD(ExposeSnapshot)
        (
        IN VSS_ID SnapshotId,
        IN VSS_PWSZ wszPathFromRoot,
        IN LONG lAttributes,
        IN VSS_PWSZ wszExpose,
        OUT VSS_PWSZ *pwszExposed
        );

    STDMETHOD(RevertToSnapshot)
        (
        IN VSS_ID SnapshotId,
        IN BOOL bForceDismount
        );
    
    STDMETHOD(QueryRevertStatus)
        (
        IN VSS_PWSZ pwszVolume,
        OUT IVssAsync **ppAsync
        );

private:

    // replace writer instance ids during restore to correspond
    // to those found in writer metadata
    void EnableWritersForRestore();

    // determine if a writer component has components selected for
    // restore
    bool IsComponentSelectedForRestore();

    // free XML component data gathered from writers
    void FreeWriterComponents();

    // validatate that the object has been initialized
    void ValidateInitialized(CVssFunctionTracer &ft);

    // basic initialization
    void BasicInit(IN CVssFunctionTracer &ft);

    // internal PrepareForBackup call
    HRESULT InternalPrepareForBackup(volatile LONG& finishing);

    // internal BackupComplete call
    HRESULT InternalBackupComplete(volatile LONG& finishing);

    // internal PreRestore call
    HRESULT InternalPreRestore(volatile LONG& finishing);

    // internal PostRestore call
    HRESULT InternalPostRestore(volatile LONG& finishing);


    // internal GatherWriterMetadata call
    HRESULT InternalGatherWriterMetadata(volatile LONG& finishing);

    // internal GatherWriterStatus call
    HRESULT InternalGatherWriterStatus(volatile LONG& finishing);

    // operation called at completion of GatherWriterMetadata
    // both by InternalGatherWriterMetadata and IVssAsync::Cancel
    HRESULT PostGatherWriterMetadata(volatile LONG& finishing, VSS_BACKUPCALL_STATE stateSaved, HRESULT hrSuccess,
    								 bool bCheckRequiredWriters);

    // called by IVssAsync::Cancel and InternalGatherWriterStatus 
    // at completion of GatherWriterStatus
    HRESULT PostGatherWriterStatus(volatile LONG& finishing, VSS_BACKUPCALL_STATE stateSaved, HRESULT hrSuccess,
    						  bool bCheckResponses);

    // called by IVssAsync::Cancel and InternalPrepareForBackup
    // at completion of PrepareForBackup
    HRESULT PostPrepareForBackup(volatile LONG& finishing, HRESULT hrSuccess);

    // called by IVssAsync::Cancel and InternalBackupComplete
    // at completion of BackupComplete
    HRESULT PostBackupComplete(volatile LONG& finishing, HRESULT hrSuccess);

    // called by IVssAsync::Cancel and InternalPreRestore
    // at completion of PostPreRestore
    HRESULT PostPreRestore(volatile LONG& finishing, HRESULT hrSuccess);

    // called by IVssAsync::Cancel and InternalPostRestore
    // at completion of PostRestore
    HRESULT PostPostRestore(volatile LONG& finishing, HRESULT hrSuccess);


    // called by IVssAsync::Cancel and IVssAsync::QueryStatus
    // at completion of DoSnapshotSet
    HRESULT PostDoSnapshotSet(volatile LONG& finishing, bool bRebuild,
					bool bFree, bool bSucceeded);

    // Get an IVssCoordinator proxy for the current thread
    // This performs internally an AddRef. It is caller responsibility to do a Release
    void GetCoordinatorInterface(
            IN  CVssFunctionTracer &ft,
            OUT CComPtr<IVssCoordinator> & ptrCoord // pass it by reference
            );
    
    // position on a WRITER_COMPONENTS element
    CXMLNode PositionOnWriterComponents
        (
        IN CVssFunctionTracer &ft,
        IN VSS_ID *pinstanceId,
        IN VSS_ID writerId,
        IN bool bCreateIfNotThere,
        OUT bool &bCreated,
        IN UINT uStartFromIndex = 0
        ) throw(HRESULT);

    // position on/create a specific component,
    CXMLNode FindComponent
        (
        IN CVssFunctionTracer &ft,
        IN VSS_ID *pinstanceId,
        IN VSS_ID writerId,
        IN LPCWSTR wszComponentType,
        IN LPCWSTR wszLogicalPath,
        IN LPCWSTR wszComponentName,
        IN bool bCreate
        );

    // rebuild component data after PrepareForBackup
    void RebuildComponentData(IN CVssFunctionTracer &ft);

    // get an IVssWriterCallback interface.  Implements GetComponent
    void GetCallbackInterface(CVssFunctionTracer &ft, IDispatch **ppDispatch);

    // setup writers interface
    void SetupWriter
        (
        CVssFunctionTracer &ft,
        IVssWriter **ppWriter,
        bool bMetadataFire
        );

    // add writer data to queue
    HRESULT AddWriterData
        (
        BSTR WriterInstanceId,
        BSTR WriterClassId,
        BSTR WriterName,
        BSTR bstrWriterXMLDocument,
        bool bReinitializing
        );

    // add writer data to queue and validate using supplied sid
    HRESULT AddWriterDataWithSid
        (
        BSTR WriterInstanceId,
        PSID WriterSid,
        BSTR bstrWriterXMLDocument
        );


    // get actual content for the instance
    HRESULT DoGetContent
        (
        VSS_ID idInstance,
        BSTR *pbstrXMLDocContent
        );


    // find writer data with a particular instance id
    CInternalWriterData *FindWriterData
        (
        VSS_ID idInstance,
        bool bIsWriterId,
        UINT *piWriter = NULL
        );

    // find writer data and validate the sid
    void FindAndValidateWriterData
        (
        IN VSS_ID idInstance,
        bool bIsWriterId,
        OUT UINT *piWriter
        );

    // find writer data and validate using supplied sid
    void FindAndValidateWriterDataWithSid
        (
        IN VSS_ID idInstance,
        IN PSID psid,
        OUT UINT *piWriter
        );


    // free all data about all writers
    void FreeAllWriters();

    // trim writers that are not in the backup components document
    void TrimWriters();

    // add a writer class to the writer class array
    void AddWriterClass(const VSS_ID &id);

    // remove a writer class from the writer class array
    void RemoveWriterClass(const VSS_ID &id);

    // is a writer class disabled
    bool IsWriterClassDisabled(const VSS_ID &id);

    // is a writer instance disabled
    bool IsWriterInstanceDisabled(const VSS_ID &id);

    // load the components XML document
    void LoadComponentsDocument(BSTR bstr);

    // set snapshot set description (by coordinator)
    HRESULT SetSnapshotSetDescription(LPCWSTR wszXML);

    // semaphore to serialize access to state-changing operations in class
    HANDLE m_hOperation;

    // used to indicate when an operation can be canceled
    HANDLE m_hCancelEvent;
    
    // current state we are in in a callback situation
    // protected by m_hOperation
    VSS_BACKUPCALL_STATE m_state;

    // snapshot id
    CComBSTR m_bstrSnapshotSetId;

    // GUID form of the snapshot set ID
    VSS_ID m_guidSnapshotSetId;

    // Global pointer to IGlobalInterfaceTable
    CVssSafeComPtr<IVssCoordinator> m_spCoordinator;
    
    // synchronization protecting m_pMetadataFirst and m_cWriters
    CVssSafeCriticalSection m_csWriters;

    // count of writers,
    // protected by m_csWriters
    UINT m_cWriters;

    // # of writer instances
    UINT m_cWriterInstances;

    // array of writer instances participating in the backup
    VSS_ID *m_rgWriterInstances;

    // count of writer classes to exclude
    UINT m_cWriterClasses;

    // writer classes to exclude
    VSS_ID *m_rgWriterClasses;

    // writer data,
    // protected by m_csWriters
    CInternalWriterData *m_pDataFirst;

    CComPtr<IVssWriterCallback> m_pCallback;

    // writer properties in GatherWriterStatus, GetWriterStatus
    VSS_WRITER_PROP *m_rgWriterProp;

    // is this a restore
    bool m_bRestore;

    // has this structure been initialized
    bool m_bInitialized;

    // has gather writer metdata completed
    bool m_bGatherWriterMetadataComplete;

    // has gather writer status completed
    bool m_bGatherWriterStatusComplete;

    // has SetBackupState been called
    bool m_bSetBackupStateCalled;

    // are writer classes excluded or included
    bool m_bIncludeWriterClasses;

    bool m_bWritersInSequence;
    
    // root node of document
    CComPtr<IXMLDOMNode> m_pNodeRoot;

    // context used
    LONG m_lContext;

   // encapsulates the list of writer sids that are allowed to call back into the class
    CVssSidCollection m_SidCollection;

    // Used to keep track the last writer-related events
    CVssDiag m_diagnose;

    // has gather writer metdata been called? Do not call it twice on the same instance (BUG# 650274)
    bool m_bGatherWriterMetadataCalled;
    };

class IVssLunInformation : public IUnknown
    {
public:
    STDMETHOD(SetLunBasicType)
        (
        IN UCHAR DeviceType,
        IN UCHAR DeviceTypeModifier,
        IN BOOL bCommandQueueing,
        IN LPCSTR wszVendorId,
        IN LPCSTR wszProductId,
        IN LPCSTR wszProductRevision,
        IN LPCSTR wszSerialNumber,
        IN VDS_STORAGE_BUS_TYPE busType
        ) = 0;

    STDMETHOD(GetLunBasicType)
        (
        OUT UCHAR *pDeviceType,
        OUT UCHAR *pDeviceTypeModifier,
        OUT BOOL *pbCommandQueueing,
        OUT LPSTR *pstrVendorId,
        OUT LPSTR *pstrProductId,
        OUT LPSTR *pstrProductRevision,
        OUT LPSTR *pstrSerialNumber,
        OUT VDS_STORAGE_BUS_TYPE *pBusType
        ) = 0;

    STDMETHOD(GetDiskSignature)
        (
        OUT VSS_ID *pidSignature
        ) = 0;

    STDMETHOD(SetDiskSignature)
        (
        IN VSS_ID idSignature
        ) = 0;

    STDMETHOD(AddInterconnectAddress)
        (
        IN VDS_INTERCONNECT_ADDRESS_TYPE type,
        ULONG cbPort,
        const BYTE *pbPort,
        ULONG cbAddress,
        const BYTE *pbAddress
        ) = 0;

    STDMETHOD(GetInterconnectAddressCount)
        (
        OUT UINT *pcAddresses
        ) = 0;

    STDMETHOD(GetInterconnectAddress)
        (
        IN UINT iAddress,
        OUT VDS_INTERCONNECT_ADDRESS_TYPE *pType,
        OUT ULONG *pcbPort,
        OUT LPBYTE *ppbPort,
        OUT ULONG *pcbAddress,
        OUT LPBYTE *ppbAddress
        ) = 0;

    STDMETHOD(SetStorageDeviceIdDescriptor)
        (
        IN STORAGE_DEVICE_ID_DESCRIPTOR *pDescriptor
        ) = 0;


    STDMETHOD(GetStorageDeviceIdDescriptor)
        (
        OUT STORAGE_DEVICE_ID_DESCRIPTOR **ppDescriptor
        ) = 0;

    };



class IVssLunMapping : public IUnknown
    {
public:
    STDMETHOD(AddDiskExtent)
        (
        IN ULONGLONG startingOffset,
        IN ULONGLONG length
        ) = 0;

    STDMETHOD(GetDiskExtentCount)
        (
        OUT UINT *pcExtents
        ) = 0;

    STDMETHOD(GetDiskExtent)
        (
        IN UINT iExtent,
        OUT ULONGLONG *pllStartingOffset,
        OUT ULONGLONG *pllLength
        ) = 0;

    STDMETHOD(GetSourceDevice)
        (
        OUT BSTR *pbstrSourceDevice
        ) = 0;

    STDMETHOD(SetSourceDevice)
        (
        IN LPCWSTR wszSourceDevice
        ) = 0;


    STDMETHOD(GetSourceLun)
        (
        OUT IVssLunInformation **ppLun
        ) = 0;

    STDMETHOD(GetDestinationLun)
        (
        OUT IVssLunInformation **ppLun
        ) = 0;
    };



class IVssSnapshotDescription : public IUnknown
    {
public:
    STDMETHOD(GetSnapshotId)
        (
        OUT VSS_ID *pidSnapshot
        ) = 0;

    STDMETHOD(GetProviderId)
        (
        OUT VSS_ID *pidProvider
        ) = 0;

    STDMETHOD(GetTimestamp)
        (
        OUT VSS_TIMESTAMP *pTimestamp
        ) = 0;

    STDMETHOD(SetTimestamp)
        (
        IN VSS_TIMESTAMP timestamp
        ) = 0;

    STDMETHOD(GetAttributes)
        (
        OUT LONG *plAttributes
        ) = 0;


    STDMETHOD(SetAttributes)
        (
        IN LONG lAttributes
        ) = 0;

    STDMETHOD(GetOrigin)
        (
        OUT BSTR *pbstrOriginatingMachine,
        OUT BSTR *pbstrOriginalVolume
        ) = 0;

    STDMETHOD(SetOrigin)
        (
        IN LPCWSTR wszOriginatingMachine,
        IN LPCWSTR wszOriginalVolume
        ) = 0;

    STDMETHOD(IsDynamicVolume)
        (
        OUT bool *pbIsDynamic
        ) = 0;

    STDMETHOD(SetIsDynamicVolume)
        (
        IN bool bIsDynamic
        ) = 0;

    STDMETHOD(GetServiceMachine)
        (
        OUT BSTR *pbstrServiceMachine
        ) = 0;

    STDMETHOD(SetServiceMachine)
        (
        IN LPCWSTR wszServiceMachine
        ) = 0;

    STDMETHOD(GetDeviceName)
        (
        OUT BSTR *pbstrDeviceName
        ) = 0;

    STDMETHOD(SetDeviceName)
        (
        IN LPCWSTR wszDeviceName
        ) = 0;

    STDMETHOD(GetExposure)
        (
        OUT BSTR *pbstrExposedName,
        OUT BSTR *pbstrExposedPath
        ) = 0;

    STDMETHOD(SetExposure)
        (
        IN LPCWSTR wszExposedName,
        IN LPCWSTR wszExposedPath
        ) = 0;

    STDMETHOD(GetLunCount)
        (
        OUT UINT *pcLuns
        ) = 0;

    STDMETHOD(AddLunMapping)
        (
        ) = 0;

    STDMETHOD(GetLunMapping)
        (
        UINT iMapping,
        IVssLunMapping **pLunMapping
        ) = 0;
    };


// description of a snapshot set
class IVssSnapshotSetDescription : public IUnknown
    {
public:
    STDMETHOD(SaveAsXML)
        (
        OUT BSTR *pbstrXML
        ) = 0;

    STDMETHOD(GetToplevelNode)
        (
        OUT IXMLDOMNode **pNode,
        OUT IXMLDOMDocument **ppDoc
        ) = 0;

    STDMETHOD(GetSnapshotSetId)
        (
        OUT VSS_ID *pidSnapshotSet
        ) = 0;

    STDMETHOD(GetDescription)
        (
        OUT BSTR *pbstrDescription
        ) = 0;

    STDMETHOD(SetDescription)
        (
        IN LPCWSTR wszDescription
        ) = 0;

    STDMETHOD(GetMetadata)
        (
        OUT BSTR *pbstrMetadata
        ) = 0;

    STDMETHOD(SetMetadata)
        (
        IN LPCWSTR wszMetadata
        ) = 0;

    STDMETHOD(GetContext)
        (
        OUT LONG *plContext
        ) = 0;

    STDMETHOD(GetSnapshotCount)
        (
        OUT UINT *pcSnapshots
        ) = 0;

    STDMETHOD(GetOriginalSnapshotCount)
        (
        OUT LONG *plSnapshotsCount
        ) = 0;

    STDMETHOD(SetOriginalSnapshotCount)
        (
        IN LONG lSnapshotsCount
        ) = 0;

    STDMETHOD(GetSnapshotDescription)
        (
        IN UINT iSnapshot,
        OUT IVssSnapshotDescription **pSnapshot
        ) = 0;

    STDMETHOD(FindSnapshotDescription)
        (
        IN VSS_ID SnapshotId,
        OUT IVssSnapshotDescription **pSnapshot
        ) = 0;


    STDMETHOD(AddSnapshotDescription)
        (
        IN VSS_ID idSnapshot,
        IN VSS_ID idProvider
        ) = 0;

    STDMETHOD(DeleteSnapshotDescription)
        (
        IN VSS_ID idSnapshot
        ) = 0;

    };




class CVssSnapshotSetDescription :
    public CVssMetadataHelper,
    public IVssSnapshotSetDescription
    {
public:
    // constructor
    CVssSnapshotSetDescription() :
        m_cRef(0)
        {
        }

    CVssSnapshotSetDescription
        (
        IXMLDOMNode *pNode,
        IXMLDOMDocument *pDoc
        ) :
        CVssMetadataHelper(pNode, pDoc),
        m_cRef(0)
        {
        }

    // 2nd phase of initialization
    void Initialize(CVssFunctionTracer &ft)
        {
        InitializeHelper(ft);
        }

    void LoadFromXML(LPCWSTR wszXML);

    STDMETHOD(SaveAsXML)
        (
        OUT BSTR *pbstrXML
        );

    STDMETHOD(GetToplevelNode)
        (
        IXMLDOMNode **ppNode,
        IXMLDOMDocument **ppDoc
        );


    STDMETHOD(GetSnapshotSetId)
        (
        OUT VSS_ID *pidSnapshotSet
        );

    STDMETHOD(GetDescription)
        (
        OUT BSTR *pbstrDescription
        );

    STDMETHOD(SetDescription)
        (
        IN LPCWSTR wszDescription
        );

    STDMETHOD(GetMetadata)
        (
        OUT BSTR *pbstrMetadata
        );

    STDMETHOD(SetMetadata)
        (
        IN LPCWSTR wszMetadata
        );

    STDMETHOD(GetContext)
        (
        OUT LONG *plContext
        );

    STDMETHOD(GetSnapshotCount)
        (
        OUT UINT *pcSnapshots
        );

    STDMETHOD(GetOriginalSnapshotCount)
        (
        OUT LONG *pcSnapshots
        );

    STDMETHOD(SetOriginalSnapshotCount)
        (
        IN LONG cSnapshots
        );


    STDMETHOD(GetSnapshotDescription)
        (
        IN UINT iSnapshot,
        OUT IVssSnapshotDescription **pSnapshot
        );

    STDMETHOD(FindSnapshotDescription)
        (
        IN VSS_ID SnapshotId,
        OUT IVssSnapshotDescription **pSnapshot
        );


    STDMETHOD(AddSnapshotDescription)
        (
        IN VSS_ID idSnapshot,
        IN VSS_ID idProvider
        );

    STDMETHOD(DeleteSnapshotDescription)
        (
        IN VSS_ID idSnapshot
        );



    // IUnknown methods
    STDMETHOD(QueryInterface)(REFIID, void **);

    STDMETHOD_ (ULONG, AddRef)();

    STDMETHOD_ (ULONG, Release)();

private:
    LONG m_cRef;
    };



class CVssSnapshotDescription :
    public CVssMetadataHelper,
    public IVssSnapshotDescription
    {
    friend class CVssSnapshotSetDescription;

private:
    // can only be called by CVssSnapshotSetDescription
    CVssSnapshotDescription
        (
        IXMLDOMNode *pNode,
        IXMLDOMDocument *pDoc
        ) :
        CVssMetadataHelper(pNode, pDoc),
        m_cRef(0)
        {
        }

    // 2nd phase of initialization
    void Initialize(CVssFunctionTracer &ft)
        {
        InitializeHelper(ft);
        }


public:
    STDMETHOD(GetSnapshotId)
        (
        OUT VSS_ID *pidSnapshot
        );

    STDMETHOD(GetProviderId)
        (
        OUT VSS_ID *pidProvider
        );

    STDMETHOD(GetTimestamp)
        (
        OUT VSS_TIMESTAMP *pTimestamp
        );

    STDMETHOD(SetTimestamp)
        (
        IN VSS_TIMESTAMP timestamp
        );

    STDMETHOD(GetAttributes)
        (
        OUT LONG *plAttributes
        );


    STDMETHOD(SetAttributes)
        (
        IN LONG lAttributes
        );

    STDMETHOD(GetOrigin)
        (
        OUT BSTR *pbstrOriginatingMachine,
        OUT BSTR *pbstrOriginalVolume
        );

    STDMETHOD(SetOrigin)
        (
        IN LPCWSTR wszOriginatingMachine,
        IN LPCWSTR wszOriginalVolume
        );

    STDMETHOD(IsDynamicVolume)
        (
        OUT bool *pbIsDynamic
        );

    STDMETHOD(SetIsDynamicVolume)
        (
        IN bool bIsDynamic
        );


    STDMETHOD(GetServiceMachine)
        (
        OUT BSTR *pbstrServiceMachine
        );

    STDMETHOD(SetServiceMachine)
        (
        IN LPCWSTR wszServiceMachine
        );

    STDMETHOD(GetDeviceName)
        (
        OUT BSTR *pbstrDeviceName
        );

    STDMETHOD(SetDeviceName)
        (
        IN LPCWSTR wszDeviceName
        );

    STDMETHOD(GetExposure)
        (
        OUT BSTR *pbstrExposedName,
        OUT BSTR *pbstrExposedPath
        );

    STDMETHOD(SetExposure)
        (
        IN LPCWSTR wszExposedName,
        IN LPCWSTR wszExposedPath
        );

    STDMETHOD(GetLunCount)
        (
        OUT UINT *pcLuns
        );

    STDMETHOD(AddLunMapping)
        (
        );

    STDMETHOD(GetLunMapping)
        (
        UINT iMapping,
        IVssLunMapping **ppLunMapping
        );

    // IUnknown methods
    STDMETHOD(QueryInterface)(REFIID, void **);

    STDMETHOD_ (ULONG, AddRef)();

    STDMETHOD_ (ULONG, Release)();


private:
    LONG m_cRef;
    };


class CVssLunMapping :
    public CVssMetadataHelper,
    public IVssLunMapping
    {
    friend class CVssSnapshotDescription;

private:
    // can only be called by CVssSnapshotDescription
    CVssLunMapping
        (
        IXMLDOMNode *pNode,
        IXMLDOMDocument *pDoc
        ) :
        CVssMetadataHelper(pNode, pDoc),
        m_cRef(0)
        {
        }

    // 2nd phase of initialization
    void Initialize(CVssFunctionTracer &ft)
        {
        InitializeHelper(ft);
        }


public:

    STDMETHOD(AddDiskExtent)
        (
        IN ULONGLONG startingOffset,
        IN ULONGLONG length
        );

    STDMETHOD(GetDiskExtentCount)
        (
        OUT UINT *pcExtents
        );

    STDMETHOD(GetDiskExtent)
        (
        IN UINT iExtent,
        OUT ULONGLONG *pllStartingOffset,
        OUT ULONGLONG *pllLength
        );

    STDMETHOD(GetSourceDevice)
        (
        OUT BSTR *pbstrSourceDevice
        );

    STDMETHOD(SetSourceDevice)
        (
        IN LPCWSTR wszSourceDevice
        );


    STDMETHOD(GetSourceLun)
        (
        OUT IVssLunInformation **ppLun
        );

    STDMETHOD(GetDestinationLun)
        (
        OUT IVssLunInformation **ppLun
        );



    // IUnknown methods
    STDMETHOD(QueryInterface)(REFIID, void **);

    STDMETHOD_ (ULONG, AddRef)();

    STDMETHOD_ (ULONG, Release)();

private:

    HRESULT GetLunInformation
                (
                IN LPCWSTR wszElement,
                OUT IVssLunInformation **ppLun
                );

    LONG m_cRef;
    };


class CVssLunInformation :
    public CVssMetadataHelper,
    public IVssLunInformation
    {
    friend class CVssLunMapping;

private:
    // can only be called by CVssLunMapping
    CVssLunInformation
        (
        IXMLDOMNode *pNode,
        IXMLDOMDocument *pDoc
        ) :
        CVssMetadataHelper(pNode, pDoc),
        m_cRef(0)
        {
        }

    // 2nd phase of initialization
    void Initialize(CVssFunctionTracer &ft)
        {
        InitializeHelper(ft);
        }


public:
    STDMETHOD(SetLunBasicType)
        (
        IN UCHAR DeviceType,
        IN UCHAR DeviceTypeModifier,
        IN BOOL bCommandQueueing,
        IN LPCSTR szVendorId,
        IN LPCSTR szProductId,
        IN LPCSTR szProductRevision,
        IN LPCSTR szSerialNumber,
        IN VDS_STORAGE_BUS_TYPE busType
        );

    STDMETHOD(GetLunBasicType)
        (
        OUT UCHAR *pDeviceType,
        OUT UCHAR *pDeviceTypeModifier,
        OUT BOOL *pbCommandQueueing,
        OUT LPSTR *pstrVendorId,
        OUT LPSTR *pstrProductId,
        OUT LPSTR *pstrProductRevision,
        OUT LPSTR *pstrSerialNumber,
        OUT VDS_STORAGE_BUS_TYPE *pBusType
        );

    STDMETHOD(GetDiskSignature)
        (
        OUT VSS_ID *pidSignature
        );

    STDMETHOD(SetDiskSignature)
        (
        IN VSS_ID idSignature
        );

    STDMETHOD(AddInterconnectAddress)
        (
        IN VDS_INTERCONNECT_ADDRESS_TYPE type,
        IN ULONG cbPort,
        IN const BYTE *pbPort,
        IN ULONG cbAddress,
        IN const BYTE *pbAddress
        );

    STDMETHOD(GetInterconnectAddressCount)
        (
        OUT UINT *pcAddresses
        );

    STDMETHOD(GetInterconnectAddress)
        (
        IN UINT iAddress,
        OUT VDS_INTERCONNECT_ADDRESS_TYPE *pType,
        OUT ULONG *pcbPort,
        OUT LPBYTE *ppbPort,
        OUT ULONG *pcbAddress,
        OUT LPBYTE *ppbInterconnectAddress
        );

    STDMETHOD(SetStorageDeviceIdDescriptor)
        (
        IN STORAGE_DEVICE_ID_DESCRIPTOR *pDescriptor
        );

    STDMETHOD(GetStorageDeviceIdDescriptor)
        (
        OUT STORAGE_DEVICE_ID_DESCRIPTOR **ppDescriptor
        );

    // IUnknown methods
    STDMETHOD(QueryInterface)(REFIID, void **);

    STDMETHOD_ (ULONG, AddRef)();

    STDMETHOD_ (ULONG, Release)();

private:
    LONG m_cRef;
    };




__declspec(dllexport)
HRESULT STDAPICALLTYPE CreateVssSnapshotSetDescription
    (
    IN VSS_ID idSnapshotSet,
    IN LONG lContext,
    OUT IVssSnapshotSetDescription **ppSnapshotSet
    );

__declspec(dllexport)
HRESULT STDAPICALLTYPE LoadVssSnapshotSetDescription
    (
    IN  LPCWSTR wszXML,
    OUT IVssSnapshotSetDescription **ppSnapshotSet
    );


