Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
In questo argomento viene illustrato come utilizzare un linguaggio non gestito, ad esempio C++, per creare un'applicazione che utilizza Sync Framework per produrre un feed RSS da un elenco di file in una cartella. Il feed RSS prodotto da questa applicazione contiene un elemento per ogni file nella cartella specificata. Ogni elemento nel feed include il contenuto del file associato e i metadati FeedSync relativi all'elemento.
Questo argomento presuppone una conoscenza di base dei concetti relativi a C++ e COM.
Gli esempi contenuti in questo argomento riguardano i componenti della sincronizzazione Web di Sync Framework seguenti:
Informazioni sui producer di feed
Un producer di feed è un componente software che produce un feed FeedSync contenente elementi forniti da un provider di sincronizzazione. L'applicazione implementa l'interfaccia IFeedIdConverter per convertire gli ID dal formato del provider nel formato FeedSync e implementa IFeedItemConverter per convertire i dati dell'elemento dal formato del provider nel formato FeedSync.
Per ulteriori informazioni sulla produzione di un feed FeedSync, vedere Produzione di feed RSS e Atom.
Per ulteriori informazioni sui provider di sincronizzazione, vedere Implementazione di un provider standard personalizzato.
Requisiti di compilazione
Synchronization.h, FeedSync.h, FileSyncProvider.h: dichiarazioni per i componenti principali di Sync Framework, i componenti della sincronizzazione Web e il provider di sincronizzazione dei file.
#include <Synchronization.h> #include <FeedSync.h> #include <FileSyncProvider.h>Synchronization.lib, FeedSync.lib, FileSyncProvider.lib: librerie di importazione.
Esempio
Nel codice di esempio di questo argomento viene illustrato come utilizzare un oggetto IFeedProducer per produrre un feed RSS che contiene elementi forniti da un oggetto IFileSyncProvider. Nell'esempio viene anche illustrato come implementare le interfacce che convertono gli ID e i dati dell'elemento dal formato del provider di sincronizzazione dei file nel formato FeedSync.
Implementazione di IFeedIdConverter
Gli ID utilizzati da un provider possono avere qualsiasi formato. Di conseguenza, per Sync Framework è necessario che un'applicazione implementi l'interfaccia IFeedIdConverter per convertire gli ID dal formato del provider nel formato FeedSync e viceversa.
Dichiarazione di IFeedIdConverter
Aggiungere IFeedIdConverter all'elenco di ereditarietà della classe.
class CFileSyncProviderIdConverter : public IFeedIdConverter
Aggiungere i metodi IFeedIdConverter alla dichiarazione della 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);
Metodo GetIdParameters
Sync Framework chiama IFeedIdConverter::GetIdParameters per ottenere lo schema del formato dell'ID utilizzato dal provider. L'implementazione in questo esempio restituisce lo schema del formato dell'ID recuperato dall'oggetto IFileSyncProvider. Per il codice che consente di recuperare e archiviare lo schema, vedere la sezione "Produzione di un feed RSS" più avanti in questo argomento.
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;
}
Metodo ConvertReplicaIdToString
Sync Framework chiama IFeedIdConverter::ConvertReplicaIdToString per convertire un ID replica dal formato del provider in una stringa. La rappresentazione di stringa dell'ID può avere qualsiasi forma e viene scritta testualmente nel feed. Nell'implementazione di questo esempio viene utilizzata la funzione OLE32 StringFromGUID2 per convertire l'ID replica da un GUID in una stringa WCHAR. Viene restituita la stringa risultante tramite il metodo 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;
}
Metodo ConvertItemIdToString
Sync Framework chiama IFeedIdConverter::ConvertItemIdToString per convertire un ID elemento dal formato del provider in una stringa. La rappresentazione di stringa dell'ID può avere qualsiasi forma e viene scritta testualmente nel feed. Nell'implementazione di questo esempio viene convertito un ID elemento formattato come struttura SYNC_GID in una stringa WCHAR. Viene utilizzata la funzione CRT _ui64tow_s per convertire la parte del prefisso da un valore ULONGLONG a una stringa WCHAR. Viene anche utilizzata la funzione OLE32 StringFromGUID2 per convertire la parte GUID dell'ID in una stringa WCHAR. Nell'esempio queste due stringhe vengono concatenate in una e viene restituita la stringa risultante tramite 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;
}
Metodo ConvertStringToReplicaId
Sync Framework chiama IFeedIdConverter::ConvertStringToReplicaId per convertire un ID replica da una stringa al formato del provider. La rappresentazione di stringa è esattamente ciò che viene restituito a Sync Framework nel metodo ConvertReplicaIdToString. Nell'implementazione di questo esempio viene utilizzata la funzione OLE32 CLSIDFromString per convertire l'ID replica da una stringa WCHAR in un GUID. Viene restituito l'ID risultante tramite il metodo 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;
}
Metodo ConvertStringToItemId
Sync Framework chiama IFeedIdConverter::ConvertStringToItemId per convertire un ID elemento da una stringa al formato del provider. La rappresentazione di stringa è esattamente ciò che viene restituito a Sync Framework nel metodo ConvertItemIdToString. Nell'implementazione di questo esempio viene utilizzata la funzione CRT wcstoui64 per convertire la parte del prefisso dell'ID da una stringa WCHAR a un valore ULONGLONG. Viene inoltre utilizzata la funzione OLE32 CLSIDFromString per convertire la parte GUID dell'ID da una stringa WCHAR a un GUID. Nell'esempio viene restituito l'ID risultante formattato come SYNC_GID tramite il metodo 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;
}
Metodi non implementati
Il metodo seguente non è necessario negli scenari di producer di feed di base. Questo metodo può restituire E_NOTIMPL:
Implementazione di IFeedItemConverter
I dati dell'elemento di un provider possono essere in qualsiasi formato. Di conseguenza, per Sync Framework è necessario che un'applicazione implementi l'interfaccia IFeedItemConverter per convertire i dati dell'elemento dal formato del provider nel formato FeedSync e viceversa.
Dichiarazione di IFeedItemConverter
Aggiungere IFeedItemConverter all'elenco di ereditarietà della classe.
class CFileSyncProviderItemConverter : public IFeedItemConverter
Aggiungere i metodi IFeedItemConverter alla dichiarazione della 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 chiama IFeedItemConverter::ConvertItemDataToXmlText per convertire i dati dell'elemento dal formato del provider nel testo XML. ConvertItemDataToXmlText viene chiamato quando IFeedItemConverter::ConvertItemDataToXml restituisce E_NOTIMPL. Nell'implementazione di questo esempio si prevede che i file prodotti contengano XML valido per un elemento RSS, in formato Unicode. Di seguito viene riportato un esempio del contenuto del file.
<item>
<title>Sample</title>
<description>A sample item.</description>
</item>
IFileSyncProvider fornisce il contenuto di un file come oggetto IFileDataRetriever. Nell'implementazione di questo esempio un oggetto IStream viene recuperato dall'oggetto IFileDataRetriever e utilizzato per leggere il contenuto del file in una stringa WCHAR. Viene restituita la stringa risultante tramite il metodo 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;
}
Metodi non implementati
I metodi seguenti non sono necessari negli scenari di producer di feed di base. Questi metodi possono restituire E_NOTIMPL:
Produzione di un feed RSS
Sync Framework fornisce l'interfaccia Interfaccia IFeedProducer per consentire a un provider di produrre elementi dalla replica associata a un feed FeedSync. Nell'implementazione di questo esempio un oggetto IFileSyncProvider viene utilizzato come provider e una cartella nel file system viene utilizzata come replica. Il codice di esempio si attiene alla procedura seguente per produrre il feed:
Crea un oggetto
IFileSyncProvidere lo configura specificando la cartella da sincronizzare e un filtro che include solo file con estensione txt.Crea un oggetto
IStreame lo inizializza con un feed RSS vuoto. Nel codice seguente viene dichiarato il feed RSS vuoto.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";Crea un oggetto
IFeedProducere chiama il metodo IFeedProducer::ProduceFeed.Scrive in un file nella cartella della replica il feed che è stato scritto nell'oggetto
IStreamda Sync Framework.
Il codice seguente produce il feed.
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;
}
Passaggi successivi
Dopo avere creato un producer FeedSync, è necessario creare un consumer di feed. Un consumer di feed è un componente software che estrae elementi da un feed FeedSync e li applica a una replica di destinazione tramite un provider di sincronizzazione. Per ulteriori informazioni, vedere Utilizzo di feed RSS e Atom.
Vedere anche
Concetti
Sincronizzazione di feed Web
Produzione di feed RSS e Atom
Utilizzo di feed RSS e Atom
Conversione di ID ed elementi per feed RSS e Atom
Componenti di sincronizzazione Web di Sync Framework