How to: Create an Unmanaged Synchronization Provider
This topic describes how to use an unmanaged language, such as C++, to create a Sync Framework synchronization provider that synchronizes data from a custom data store.
This topic assumes a basic familiarity with C++ and COM concepts.
The examples in this topic focus on the following Sync Framework interfaces:
Understanding Synchronization Providers
A synchronization provider is a software component that represents a replica during synchronization. This enables the replica to synchronize its data with other replicas. For synchronization to occur, an application first creates a synchronization session object, connects it to two ISyncProvider objects, and starts the session. One of the providers represents the source replica. The source replica supplies metadata for changed items through its IKnowledgeSyncProvider::GetChangeBatch method and item data through an ISynchronousDataRetriever object. The other provider represents the destination replica. The destination replica receives metadata for changed items through its IKnowledgeSyncProvider::ProcessChangeBatch method and applies the changes to its item store by using a Sync Framework-supplied ISynchronousChangeApplier object together with its own ISynchronousChangeApplierTarget object.
For more information about the role of the synchronization provider, see Implementing a Standard Custom Provider.
Synchronization.h: declarations for Sync Framework components.
Synchronizationerrors.h: custom error codes.
Synchronization.lib: import library.
The example code in this topic shows how to implement the basic interface methods that are required for a replica to participate in a Sync Framework synchronization community, both as a source and as a destination. The replica in this example is an XML file, and the items to synchronize are XML nodes that are contained in this file. In the code, the XML nodes are represented by the IXMLDOMNode interface. This example also uses a custom metadata store that is implemented by using themetadata storage service API. For information about the metadata storage service and other Sync Framework components, see Sync Framework Metadata Storage Service.
The metadata store and XML store are both declared as members of the provider class.
Implementing ISyncProvider and IKnowledgeSyncProvider
The entry point into the provider is the ISyncProvider interface. This interface is intended to function as a base class for other, more powerful provider interfaces. This example uses the IKnowledgeSyncProvider interface.
Add IKnowledgeSyncProvider to the class inheritance list.
Add the ISyncProvider methods to the class declaration.
Add the IKnowledgeSyncProvider methods to the class declaration.
Sync Framework calls ISyncProvider::GetIdParameters on both the source and destination providers when the ISyncSession object is created. This method returns the ID format schema that is used by the provider. This schema must be the same for both providers. The implementation in this example uses a global constant because the ID formats are constant for the provider.
Using a global constant makes implementing this method very easy.
Sync Framework then calls IKnowledgeSyncProvider::BeginSession on both the source and destination providers. This method informs a provider that it is joining a synchronization session and passes the provider an object that contains session state information. This implementation stores the session state object.
Sync Framework then calls IKnowledgeSyncProvider::GetSyncBatchParameters on the destination provider. This method retrieves the number of changes the source provider should include in a change batch, and obtains the destination provider's current knowledge. The implementation extracts the knowledge from the metadata store, and sets the batch size to 10.
The synchronization session starts in earnest when Sync Framework calls IKnowledgeSyncProvider::GetChangeBatch on the source provider. This method retrieves a batch of changes to send to the destination provider and also returns the data retriever interface. The destination provider uses this interface to retrieve item data for changes that were applied to the destination replica. Sync Framework calls GetChangeBatch repeatedly until the last batch is sent. The source provider indicates that a batch is the last batch by calling the ISyncChangeBatchBase::SetLastBatch method. This implementation delegates the change enumeration task to the GetChangeBatch method of the metadata store. The XML item store object implements a data retriever interface; therefore, its IUnknown interface is returned.
The GetChangeBatch method implemented by the metadata store enumerates the items in the metadata store and checks the version of each one against the destination's knowledge. If the destination replica does not know about a change, the change is added to the change batch that is returned.
After Sync Framework has obtained a batch of changes from the source provider by calling its GetChangeBatch method, Sync Framework calls IKnowledgeSyncProvider::ProcessChangeBatch on the destination provider. This method applies the changes to the destination replica. This method is called one time for each batch that is retrieved by using GetChangeBatch from the source provider. This implementation uses the GetItemBatchVersions method of the metadata store to obtain local version information for items from the source provider. It then creates an ISynchronousNotifyingChangeApplier object implemented by Sync Framework and calls its ISynchronousNotifyingChangeApplier::ApplyChanges method.
The GetItemBatchVersions method of the metadata store enumerates the changes sent in the change batch from the source provider. If an item is in the destination metadata, its version information is added to a new batch created expressly to hold the version information. If an item does not exist in the destination metadata, it is flagged as a new item in the version batch. The method then returns the version batch.
After the source provider sends its last batch and the destination provider has applied the changes to its data store, Sync Framework calls IKnowledgeSyncProvider::EndSession on both the source and destination providers. This method informs a provider that it is leaving a synchronization session and should free any resources that are associated with the session. This implementation frees the session state object that it stored in the BeginSession call.
Methods That Are Not Implemented
The following methods are not required because this sample never removes items marked as deleted in the metadata store. These methods can return E_NOTIMPL:
This interface is provided to Sync Framework when the destination provider calls the ISynchronousNotifyingChangeApplier::ApplyChanges method, typically in the ProcessChangeBatch method. ISynchronousNotifyingChangeApplierTarget contains methods that are called during change application. These methods are only called on the destination provider.
Add ISynchronousNotifyingChangeApplierTarget to your class inheritance list.
Add the ISynchronousNotifyingChangeApplierTarget methods to your class declaration.
Sync Framework calls ISynchronousNotifyingChangeApplierTarget::GetIdParameters to retrieve the ID format schema of the provider. This example uses the same class to implement both IKnowledgeSyncProvider and ISynchronousNotifyingChangeApplierTarget. Therefore, this implementation is the same as that for ISyncProvider::GetIdParameters.
Sync Framework calls ISynchronousNotifyingChangeApplierTarget::GetCurrentTickCount to increment and retrieve the tick count for the replica. This implementation calls the GetNextTickCount method of the metadata store.
The GetNextTickCount method of the metadata store increments the tick count of the replica and returns it.
During change application, Sync Framework calls ISynchronousNotifyingChangeApplierTarget::SaveChange for each change that is to be applied to the destination replica. This implementation appropriately handles new items, changed items, and deleted items; and updates both the item data in the item store and the item metadata in the metadata store.
After processing each change batch, Sync Framework calls ISynchronousNotifyingChangeApplierTarget::SaveKnowledge so that the destination provider can save the knowledge that contains the new changes. This implementation saves the knowledge object to the metadata store and overwrites previously existing knowledge.
Methods Not Implemented
The following methods are not required for basic synchronization scenarios and can return only E_NOTIMPL:
ISynchronousDataRetriever is returned to Sync Framework by the source provider in response to the GetChangeBatch call. ISynchronousDataRetriever is sent to the destination provider in the ProcessChangeBatch call, where it is typically passed on to the ApplyChanges method of a change applier. The change applier then calls ISynchronousDataRetriever::LoadChangeData to obtain an IUnknown interface that represents the item data. The change applier passes this interface to the SaveChange method of the destination provider. The destination provider uses this IUnknown interface to retrieve item data for new or changed items and applies the item data to the destination replica.
Add ISynchronousDataRetriever to the class inheritance list.
Add the ISynchronousDataRetriever methods to the class declaration.
Sync Framework calls ISynchronousDataRetriever::GetIdParameters to retrieve the ID format schema of the provider. This implementation is basically the same as that for ISyncProvider::GetIdParameters.
During change application, Sync Framework calls ISynchronousDataRetriever::LoadChangeData to obtain an IUnknown interface that the destination provider can use to retrieve item data. This implementation finds the item in the item store, clones it, and returns its IUnknown interface.
Now that you have created a synchronization provider, you might want to create an application that can host the synchronization session and connect it to the provider. For information about how to do this, see How to: Create an Unmanaged Synchronization Application.
Another next step that you could take is to enhance the provider to handle change units. For more information about change units, see Synchronizing Change Units.
You might also want to create a custom metadata store. For more information about how to handle synchronization metadata, see Managing Metadata for Standard Providers.