Procédure : créer un producteur de flux non managé
Cette rubrique indique comment utiliser un langage non managé, tel que C++, pour créer une application qui utilise Sync Framework pour produire un flux RSS à partir d'une liste de fichiers dans un dossier. Le flux RSS produit par cette application contient un élément pour chaque fichier dans le dossier spécifié. Chaque élément dans le flux inclut le contenu de son fichier associé ainsi que les métadonnées FeedSync sur l'élément.
Cette rubrique suppose une connaissance de base des concepts C++ et COM.
Les exemples de cette rubrique reposent sur les composants de synchronisation Web Sync Framework suivants :
Présentation des producteurs de flux
Un producteur de flux est un composant logiciel qui produit un flux FeedSync qui contient des éléments fournis par un fournisseur de synchronisation. L'application implémente l'interface IFeedIdConverter pour convertir les ID du format du fournisseur au format FeedSync, et implémente IFeedItemConverter pour convertir les données d'élément du format du fournisseur au format FeedSync.
Pour plus d'informations sur la production d'un flux FeedSync, consultez Production de flux RSS et Atom.
Pour plus d'informations sur les fournisseurs de synchronisation, consultez Implémentation d'un fournisseur personnalisé standard.
Configuration de génération
Déclarations Synchronization.h, FeedSync.h, FileSyncProvider.h : pour les composants principaux Sync Framework, les composants de synchronisation Web et le fournisseur de synchronisation de fichiers.
#include <Synchronization.h> #include <FeedSync.h> #include <FileSyncProvider.h>
Synchronization.lib, FeedSync.lib, FileSyncProvider.lib : bibliothèques d'importation.
Exemple
L'exemple de code de cette rubrique montre comment utiliser un objet IFeedProducer pour produire un flux RSS qui contient des éléments fournis par un objet IFileSyncProvider. L'exemple montre également comment implémenter les interfaces qui convertissent les ID et données d'élément du format du fournisseur de synchronisation de fichiers au format FeedSync.
Implémentation d'IFeedIdConverter
Les ID utilisés par un fournisseur peuvent être de tout format. Par conséquent, Sync Framework nécessite qu'une application implémente l'interface IFeedIdConverter pour convertir les ID du format de fournisseur au format FeedSync, et inversement.
Déclaration d'IFeedIdConverter
Ajoutez IFeedIdConverter à la liste d'héritage de classe.
class CFileSyncProviderIdConverter : public IFeedIdConverter
Ajoutez les méthodes IFeedIdConverter à la déclaration de classe.
STDMETHOD(GetIdParameters)(
ID_PARAMETERS * pIdParameters);
STDMETHOD(ConvertReplicaIdToString)(
const BYTE * pbReplicaId,
IFeedIdConverterCallback * pCallback);
STDMETHOD(ConvertItemIdToString)(
const BYTE * pbItemId,
IFeedIdConverterCallback * pCallback);
STDMETHOD(ConvertStringToReplicaId)(
LPCWSTR wszStringId,
IFeedIdConverterCallback * pCallback);
STDMETHOD(ConvertStringToItemId)(
LPCWSTR wszStringId,
IFeedIdConverterCallback * pCallback);
STDMETHOD(GenerateAnonymousReplicaId)(
LPCWSTR wszWhen,
ULONG ulSequence,
IFeedIdConverterCallback * pCallback);
Méthode GetIdParameters
Sync Framework appelle IFeedIdConverter::GetIdParameters pour obtenir le schéma du format d'ID utilisé par le fournisseur. L'implémentation de cet exemple retourne le schéma du format d'ID récupéré à partir de l'objet IFileSyncProvider. Pour afficher le code qui récupère et stocke le schéma, consultez la section « Production d'un flux RSS », plus loin dans cette rubrique.
STDMETHODIMP CFileSyncProviderIdConverter::GetIdParameters(
ID_PARAMETERS * pIdParameters)
{
HRESULT hr = E_FAIL;
if (NULL == pIdParameters)
{
return E_POINTER;
}
else
{
*pIdParameters = m_idParams;
return S_OK;
}
return hr;
}
Méthode ConvertReplicaIdToString
Sync Framework appelle IFeedIdConverter::ConvertReplicaIdToString pour convertir un ID de réplica du format du fournisseur en une chaîne. La représentation sous forme de chaîne de l'ID peut être de toute forme et est écrite mot pour mot dans le flux. L'implémentation de cet exemple utilise la fonction OLE32 StringFromGUID2 pour convertir l'ID de réplica d'un GUID en une chaîne WCHAR. La chaîne obtenue est retournée à l'aide de la méthode IFeedIdConverterCallback::ConvertReplicaIdToStringComplete.
STDMETHODIMP CFileSyncProviderIdConverter::ConvertReplicaIdToString(
const BYTE * pbReplicaId,
IFeedIdConverterCallback * pCallback)
{
HRESULT hr = E_FAIL;
if (NULL == pbReplicaId || NULL == pCallback)
{
hr = E_POINTER;
}
else
{
OLECHAR olestrReplicaId[64];
DWORD cchId = 64;
GUID* pguidReplicaId = (GUID*)pbReplicaId;
int cchCopied = StringFromGUID2(*pguidReplicaId, olestrReplicaId, cchId);
if (0 < cchCopied)
{
hr = pCallback->ConvertReplicaIdToStringComplete(olestrReplicaId);
}
}
return hr;
}
Méthode ConvertItemIdToString
Sync Framework appelle IFeedIdConverter::ConvertItemIdToString pour convertir un ID d'élément du format du fournisseur en une chaîne. La représentation sous forme de chaîne de l'ID peut être de toute forme et est écrite mot pour mot dans le flux. L'implémentation de cet exemple convertit un ID d'élément mis en forme comme une structure SYNC_GID en une chaîne WCHAR. Elle utilise la fonction CRT _ui64tow_s pour convertir la partie préfixe d'un ULONGLONG en une chaîne WCHAR. Elle utilise également la fonction OLE32 StringFromGUID2 pour convertir la partie GUID de l'ID en une chaîne WCHAR. L'exemple concatène ces deux chaînes en une et retourne la chaîne obtenue à l'aide d'IFeedIdConverterCallback::ConvertItemIdToStringComplete.
STDMETHODIMP CFileSyncProviderIdConverter::ConvertItemIdToString(
const BYTE * pbItemId,
IFeedIdConverterCallback * pCallback)
{
HRESULT hr = E_FAIL;
if (NULL == pbItemId || NULL == pCallback)
{
hr = E_POINTER;
}
else
{
SYNC_GID* pgid = (SYNC_GID*)pbItemId;
// Convert the prefix to a string.
errno_t err;
WCHAR wszId[64];
DWORD cchId = 64;
err = _ui64tow_s(pgid->ullGidPrefix, wszId, cchId, 16);
if (0 == err)
{
// Convert the GUID part to a string, appended to the prefix string.
size_t cchPrefix = wcslen(wszId);
int cchCopied = StringFromGUID2(pgid->guidUniqueId, &(wszId[cchPrefix]), cchId - cchPrefix);
if (0 < cchCopied)
{
// Send the converted ID.
hr = pCallback->ConvertItemIdToStringComplete(wszId);
}
}
else
{
hr = HRESULT_FROM_WIN32(err);
}
}
return hr;
}
Méthode ConvertStringToReplicaId
Sync Framework appelle IFeedIdConverter::ConvertStringToReplicaId pour convertir un ID de réplica d'une chaîne au format du fournisseur. La représentation de chaîne est exactement ce qui a été retourné à Sync Framework dans la méthode ConvertReplicaIdToString. L'implémentation de cet exemple utilise la fonction OLE32 CLSIDFromString pour convertir l'ID de réplica d'une chaîne WCHAR en un GUID. L'ID obtenu est retourné à l'aide de la méthode IFeedIdConverterCallback::ConvertStringToReplicaIdComplete.
STDMETHODIMP CFileSyncProviderIdConverter::ConvertStringToReplicaId(
LPCWSTR wszStringId,
IFeedIdConverterCallback * pCallback)
{
HRESULT hr = E_FAIL;
if (NULL == wszStringId || NULL == pCallback)
{
hr = E_POINTER;
}
else
{
GUID guidReplicaId;
hr = CLSIDFromString((LPOLESTR)wszStringId, &guidReplicaId);
if (SUCCEEDED(hr))
{
hr = pCallback->ConvertStringToReplicaIdComplete((BYTE*)&guidReplicaId);
}
}
return hr;
}
Méthode ConvertStringToItemId
Sync Framework appelle IFeedIdConverter::ConvertStringToItemId pour convertir un ID d'élément d'une chaîne au format du fournisseur. La représentation de chaîne est exactement ce qui a été retourné à Sync Framework dans la méthode ConvertItemIdToString. L'implémentation de cet exemple utilise la fonction CRT wcstoui64 pour convertir la partie préfixe de l'ID d'une chaîne WCHAR en un ULONGLONG. Elle utilise également la fonction OLE32 CLSIDFromString pour convertir la partie GUID de l'ID d'une chaîne WCHAR en un GUID. L'exemple retourne l'ID obtenu sous la forme SYNC_GID en utilisant la méthode IFeedIdConverterCallback::ConvertStringToItemIdComplete.
STDMETHODIMP CFileSyncProviderIdConverter::ConvertStringToItemId(
LPCWSTR wszStringId,
IFeedIdConverterCallback * pCallback)
{
HRESULT hr = E_FAIL;
if (NULL == wszStringId || NULL == pCallback)
{
hr = E_POINTER;
}
else
{
SYNC_GID gid;
// Convert the prefix from the string.
WCHAR* pwszGuid = NULL;
gid.ullGidPrefix = _wcstoui64(wszStringId, &pwszGuid, 16);
// Convert the GUID part from the string.
hr = CLSIDFromString(pwszGuid, &(gid.guidUniqueId));
if (SUCCEEDED(hr))
{
// Send the converted ID.
hr = pCallback->ConvertStringToItemIdComplete((BYTE*)&gid);
}
}
return hr;
}
Méthodes qui ne sont pas implémentées
La méthode suivante n'est pas requise pour les scénarios de producteur de flux de base. Cette méthode peut retourner E_NOTIMPL :
Implémentation d'IFeedItemConverter
Les données d'élément d'un fournisseur peuvent être de tout format. Par conséquent, Sync Framework nécessite qu'une application implémente l'interface IFeedItemConverter pour convertir les donnés d'élément du format de fournisseur au format FeedSync, et inversement.
Déclaration d'IFeedItemConverter
Ajoutez IFeedItemConverter à la liste d'héritage de classe.
class CFileSyncProviderItemConverter : public IFeedItemConverter
Ajoutez les méthodes IFeedItemConverter à la déclaration de classe.
STDMETHOD(ConvertItemDataToXml)(
IUnknown *pItemData,
IFeedItemConverterCallback *pCallback);
STDMETHOD(ConvertItemDataToXmlText)(
IUnknown *pItemData,
IFeedItemConverterCallback *pCallback);
STDMETHOD(ConvertXmlToItemData)(
IUnknown * pItemXml,
IFeedItemConverterCallback *pCallback);
STDMETHOD(ConvertXmlTextToItemData)(
LPCWSTR wszItemXmlText,
IFeedItemConverterCallback *pCallback);
ConvertItemDataToXmlText
Sync Framework appelle IFeedItemConverter::ConvertItemDataToXmlText pour convertir les données d'élément du format de fournisseur en texte XML. ConvertItemDataToXmlText est appelé lorsque IFeedItemConverter::ConvertItemDataToXml retourne E_NOTIMPL. L'implémentation de cet exemple part du principe que les fichiers produits contiennent des données XML valides pour un élément RSS, sous un format Unicode. Un exemple du contenu du fichier figure ci-dessous.
<item>
<title>Sample</title>
<description>A sample item.</description>
</item>
IFileSyncProvider fournit le contenu d'un fichier comme un objet IFileDataRetriever. L'implémentation de cet exemple obtient un objet IStream à partir de l'objet IFileDataRetriever et l'utilise pour lire le contenu du fichier dans une chaîne WCHAR. La chaîne obtenue est retournée à l'aide de la méthode IFeedItemConverterCallback::ConvertItemDataToXmlTextComplete.
STDMETHODIMP CFileSyncProviderItemConverter::ConvertItemDataToXmlText(
IUnknown *pItemData,
IFeedItemConverterCallback *pCallback)
{
HRESULT hr = E_UNEXPECTED;
if (NULL == pItemData || NULL == pCallback)
{
hr = E_POINTER;
}
else
{
// Get the data retriever implemented by Sync Services for File Systems.
IFileDataRetriever* pItemRetriever = NULL;
hr = pItemData->QueryInterface(__uuidof(pItemRetriever), (void**)&pItemRetriever);
if (SUCCEEDED(hr))
{
// Get the IStream out of the data retriever.
IStream* pItemStream = NULL;
hr = pItemRetriever->GetFileStream(&pItemStream);
if (SUCCEEDED(hr))
{
STATSTG ssFileData = {0};
hr = pItemStream->Stat(&ssFileData, STATFLAG_DEFAULT);
if (SUCCEEDED(hr))
{
// Only handle a maximum file size that will fit in ULONG, for convenience.
ULONG cbFileData = (ULONG)ssFileData.cbSize.QuadPart;
WCHAR* pwszFileData = (WCHAR*)new BYTE[cbFileData + sizeof(WCHAR)]; // include space for NULL terminator
if (NULL == pwszFileData)
{
hr = E_OUTOFMEMORY;
}
else
{
ULONG cbRead;
hr = pItemStream->Read(pwszFileData, cbFileData, &cbRead);
if (cbRead != cbFileData)
{
hr = E_UNEXPECTED;
}
else
{
// Sync Services for FeedSync expects a NULL terminator on the XML string.
pwszFileData[cbFileData / sizeof(WCHAR)] = L'\0';
if (SUCCEEDED(hr))
{
hr = pCallback->ConvertItemDataToXmlTextComplete(pwszFileData);
delete [] pwszFileData;
}
}
}
}
pItemStream->Release();
}
pItemRetriever->Release();
}
}
return hr;
}
Méthodes qui ne sont pas implémentées
Les méthodes suivantes ne sont pas requises pour les scénarios de producteur de flux de base. Ces méthodes peuvent retourner E_NOTIMPL :
Production d'un flux RSS
Sync Framework fournit l'interface Interface IFeedProducer pour aider un fournisseur à produire des éléments à partir de son réplica associé dans un flux FeedSync. L'implémentation de cet exemple utilise un objet IFileSyncProvider comme fournisseur et un dossier dans le système de fichiers comme réplica. L'exemple de code procède comme suit pour produire le flux :
Crée un objet IFileSyncProvider et le configure en spécifiant le dossier à synchroniser, et un filtre qui inclut uniquement les fichiers qui ont une extension .txt.
Crée un objet IStream et l'initialise avec un flux RSS vide. Le code suivant déclare le flux RSS vide.
const CHAR c_szEmptyRSS[] = "<?xml version=\"1.0\"?>\r\n" "<rss version=\"2.0\" xmlns:sx=\"https://www.microsoft.com/schemas/sse\">\r\n" "\t<channel>\r\n" "\t</channel>\r\n" "</rss>\r\n";
Crée un objet IFeedProducer et appelle sa méthode IFeedProducer::ProduceFeed.
Écrit le flux, qui a été écrit dans l'objet IStream par Sync Framework, dans un fichier dans le dossier de réplica.
Le code suivant produit le flux.
HRESULT CFeedSynchronizerDlg::ProduceFeed(CString* pstrSyncFolder, const GUID* pguidReplica)
{
HRESULT hr;
// Create an IFileSyncProvider to represent the folder to produce.
IFileSyncProvider* pFSP = NULL;
hr = CoCreateInstance(CLSID_FileSyncProvider, NULL, CLSCTX_INPROC_SERVER,
IID_IFileSyncProvider, (void**)&pFSP);
if (SUCCEEDED(hr))
{
IFileSyncScopeFilter* pFilter = NULL;
hr = pFSP->CreateNewScopeFilter(&pFilter);
if (SUCCEEDED(hr))
{
// Filter folder contents to only include files with a .txt extension.
hr = pFilter->SetFilenameIncludes(L"*.txt");
// Keep a metadata store file in the same folder we are synchronizing.
CString strMetaPath(*pstrSyncFolder);
strMetaPath.Append(L"\\metadata.dat");
hr = pFSP->Initialize(*pguidReplica, pstrSyncFolder->GetString(),
strMetaPath.GetString(), pstrSyncFolder->GetString(), 0, pFilter, NULL, NULL);
if (SUCCEEDED(hr))
{
// Save the File Sync Provider's ID format schema so we can return it when asked.
hr = pFSP->GetIdParameters(&(m_IdConverter.m_idParams));
if (SUCCEEDED(hr))
{
// Use the IStorage and IStream implementation provided by OLE32.
IStorage* pStg = NULL;
// Create a structured storage object backed by a temporary file.
hr = StgCreateDocfile(NULL, STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_CREATE
| STGM_DIRECT | STGM_DELETEONRELEASE, 0, &pStg);
if (SUCCEEDED(hr))
{
IStream* pStream = NULL;
// Create an IStream object that can be used to read and write to the IStorage object.
hr = pStg->CreateStream(L"MyRSSStream", STGM_READWRITE | STGM_SHARE_EXCLUSIVE | STGM_DIRECT
| STGM_CREATE, 0, 0, &pStream);
if (SUCCEEDED(hr))
{
// Initialize the stream with an empty RSS feed. This must be a single-byte CHAR
// (not WCHAR) string and must not contain a NULL terminator or ProduceFeed will
// fail with E_FAIL.
hr = pStream->Write(c_szEmptyRSS, sizeof(c_szEmptyRSS) - 1, NULL);
if (SUCCEEDED(hr))
{
// The stream is currently pointed at the end of the stream, so seek back to the beginning.
LARGE_INTEGER liSeek = {0};
hr = pStream->Seek(liSeek, STREAM_SEEK_SET, NULL);
if (SUCCEEDED(hr))
{
// Create the FeedSync producer object.
IFeedProducerConsumerServices* pFeedSvc = NULL;
hr = CoCreateInstance(CLSID_FeedSyncServices, NULL, CLSCTX_INPROC_SERVER,
IID_IFeedProducerConsumerServices, (void**)&pFeedSvc);
if (SUCCEEDED(hr))
{
IFeedProducer* pFeedProducer = NULL;
hr = pFeedSvc->CreateFeedProducer(&pFeedProducer);
if (SUCCEEDED(hr))
{
// Produce the *.txt items in the specified folder to the stream.
hr = pFeedProducer->ProduceFeed(pFSP, &m_IdConverter, &m_ItemConverter, NULL, pStream);
if (SUCCEEDED(hr))
{
// The stream now contains an RSS feed filled with the contents of the .txt files
// from the specified folder and with FeedSync metadata about each item.
// Save the contents of the stream to a file.
STATSTG stat = {0};
hr = pStream->Stat(&stat, STATFLAG_DEFAULT);
if (SUCCEEDED(hr))
{
ULONG cbFeed = (ULONG)stat.cbSize.QuadPart;
CHAR* pszFeed = new CHAR[cbFeed];
if (NULL == pszFeed)
{
hr = E_OUTOFMEMORY;
}
else
{
// Seek to the beginning of the stream.
hr = pStream->Seek(liSeek, STREAM_SEEK_SET, NULL);
if (SUCCEEDED(hr))
{
// Read the contents of the stream.
hr = pStream->Read(pszFeed, cbFeed, NULL);
if (SUCCEEDED(hr))
{
// Write the contents of the stream to a file.
CString strProducedFeed(*pstrSyncFolder);
strProducedFeed.Append(L"\\ProducedFeed.xml");
CFile fileStream(strProducedFeed.GetString(), CFile::modeCreate | CFile::modeWrite
| CFile::shareDenyNone);
fileStream.Write(pszFeed, cbFeed);
}
}
delete [] pszFeed;
}
}
}
pFeedProducer->Release();
}
pFeedSvc->Release();
}
}
}
pStream->Release();
}
pStg->Release();
}
}
}
pFilter->Release();
}
pFSP->Release();
}
return hr;
}
Étapes suivantes
Maintenant que vous avez créé un producteur FeedSync, vous pouvez créer un consommateur de flux. Un consommateur de flux est un composant logiciel qui extrait des éléments d'un flux FeedSync et les applique à un réplica de destination en utilisant un fournisseur de synchronisation. Pour plus d'informations, consultez Consommation de flux RSS et Atom.
Voir aussi
Autres ressources
Production de flux RSS et Atom
Consommation de flux RSS et Atom