Como criar um produtor de feed não gerenciado
Este tópico mostra como usar uma linguagem não gerenciada, como C++, para criar um aplicativo que usa o Sync Framework para produzir um RSS feed a partir de uma lista de arquivos em uma pasta. O RSS feed produzido por esse aplicativo contém um item para cada arquivo na pasta especificada. Cada item no feed contém o conteúdo do arquivo associado e também os metadados do FeedSync sobre o item.
Este tópico pressupõe uma familiaridade básica com os conceitos de C++ e COM.
Os exemplos neste tópico se concentram nos seguintes componentes de sincronização da Web do Sync Framework:
Noções básicas sobre produtores de feed
Um produtor de feed é um componente de software que produz um feed do FeedSync contendo itens fornecidos por um provedor de sincronização. O aplicativo implementa a interface IFeedIdConverter para converter IDs do formato do provedor para o formato do FeedSync e implementa IFeedItemConverter para converter dados de item do formato do provedor para o formato do FeedSync.
Para obter mais informações sobre como produzir um feed do FeedSync, consulte Produzindo RSS e Atom feeds.
Para obter mais informações sobre provedores de sincronização, consulte Implementando um provedor personalizado padrão.
Requisitos de compilação
Synchronization.h, FeedSync.h, FileSyncProvider.h: declarações para os componentes principais do Sync Framework, componentes de sincronização da Web e o provedor de sincronização de arquivos.
#include <Synchronization.h> #include <FeedSync.h> #include <FileSyncProvider.h>
Synchronization.lib, FeedSync.lib, FileSyncProvider.lib: bibliotecas de importação.
Exemplo
O código de exemplo neste tópico mostra como usar um objeto IFeedProducer para produzir um RSS feed que contém itens fornecidos por um objeto IFileSyncProvider. O exemplo também mostra como implementar as interfaces que convertem IDs e dados do item do formato do provedor de sincronização de arquivos no formato do FeedSync.
Implementando IFeedIdConverter
As IDs usadas por um provedor podem estar em qualquer formato. Portanto, o Sync Framework exige que um aplicativo implemente a interface IFeedIdConverter para converter as IDs do formato do provedor no formato do FeedSync e vice-versa.
Declarando IFeedIdConverter
Adicione IFeedIdConverter
à lista de herança de classe.
class CFileSyncProviderIdConverter : public IFeedIdConverter
Adicione os métodos IFeedIdConverter
à declaração 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étodo GetIdParameters
O Sync Framework chama IFeedIdConverter::GetIdParameters para obter o esquema de formato de ID usado pelo provedor. A implementação neste exemplo retorna o esquema de formato de ID recuperado do objeto IFileSyncProvider
. Para obter o código que recupera e armazena o esquema, consulte a seção "Produzindo um RSS feed", mais adiante neste tópico.
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étodo ConvertReplicaIdToString
O Sync Framework chama IFeedIdConverter::ConvertReplicaIdToString para converter uma ID de réplica do formato do provedor em uma cadeia de caracteres. A representação da cadeia de caracteres da ID pode estar em qualquer forma e pode ser gravada literalmente no feed. A implementação neste exemplo usa a função OLE32 StringFromGUID2
para converter a ID de réplica de uma GUID para uma cadeia de caracteres WCHAR. Ela retorna a cadeia de caracteres resultante usando o método 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étodo ConvertItemIdToString
O Sync Framework chama IFeedIdConverter::ConvertItemIdToString para converter uma ID de item do formato do provedor em uma cadeia de caracteres. A representação da cadeia de caracteres da ID pode estar em qualquer forma e pode ser gravada literalmente no feed. A implementação neste exemplo converte uma ID de item formatada como uma estrutura SYNC_GID em uma cadeia de caracteres WCHAR. Ela usa a função CRT _ui64tow_s
para converter a parte do prefixo de um ULONGLONG em uma cadeia de caracteres WCHAR. Também usa a função OLE32 StringFromGUID2
para converter a parte de GUID da ID em uma cadeia de caracteres WCHAR. O exemplo concatena essas duas cadeias de caracteres em uma e retorna a cadeia resultante usando 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étodo ConvertStringToReplicaId
O Sync Framework chama IFeedIdConverter::ConvertStringToReplicaId para converter uma ID de réplica de uma cadeia de caracteres no formato do provedor. A representação da cadeia de caracteres é exatamente o que foi retornado para o Sync Framework no método ConvertReplicaIdToString
. A implementação neste exemplo usa a função OLE32 CLSIDFromString
para converter a ID de réplica de uma cadeia de caracteres WCHAR em uma GUID. Ela retorna a ID resultante usando o método 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étodo ConvertStringToItemId
O Sync Framework chama IFeedIdConverter::ConvertStringToItemId para converter uma ID de item de uma cadeia de caracteres no formato do provedor. A representação da cadeia de caracteres é exatamente o que foi retornado para o Sync Framework no método ConvertItemIdToString
. A implementação neste exemplo usa a função CRT wcstoui64
para converter a parte do prefixo da ID de uma cadeia de caracteres WCHAR em um ULONGLONG. Também usa a função OLE32 CLSIDFromString
para converter a parte da GUID da ID de uma cadeia de caracteres WCHAR em uma GUID. O exemplo retorna a ID resultante formatada como uma SYNC_GID
usando o método 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étodos não implementados
O método a seguir não é necessário para cenários básicos de produtor de feed. Este método pode retornar E_NOTIMPL:
Implementando IFeedItemConverter
Os dados de item de um provedor podem estar em qualquer formato. Portanto, o Sync Framework exige que um aplicativo implemente a interface IFeedItemConverter para converter os dados de item do formato do provedor no formato do FeedSync e vice-versa.
Declarando IFeedItemConverter
Adicione IFeedItemConverter
à lista de herança de classe.
class CFileSyncProviderItemConverter : public IFeedItemConverter
Adicione os métodos IFeedItemConverter
à declaração 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
O Sync Framework chama IFeedItemConverter::ConvertItemDataToXmlText para converter dados do item do formato do provedor em texto XML. ConvertItemDataToXmlText
é chamado quando IFeedItemConverter::ConvertItemDataToXml retorna E_NOTIMPL. A implementação neste exemplo espera que os arquivos gerados contenham XML válido para um item de RSS, no formato Unicode. Veja a seguir um exemplo do conteúdo do arquivo.
<item>
<title>Sample</title>
<description>A sample item.</description>
</item>
IFileSyncProvider
fornece o conteúdo de um arquivo como um objeto IFileDataRetriever
. A implementação neste exemplo obtém um objeto IStream
do objeto IFileDataRetriever
e o usa para ler o conteúdo do arquivo em uma cadeia de caracteres WCHAR. Ela retorna a cadeia de caracteres resultante usando o método 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étodos não implementados
Os métodos a seguir não são necessários para cenários básicos de produtor de feed. Estes métodos podem retornar E_NOTIMPL:
Produzindo um RSS feed
O Sync Framework fornece a interface Interface IFeedProducer para ajudar um provedor na produção de itens a partir de suas réplicas associadas para um feed do FeedSync. A implementação neste exemplo usa um objeto IFileSyncProvider
como o provedor e uma pasta no sistema de arquivos como a réplica. O código de exemplo realiza as seguintes etapas para produzir o feed:
Cria um objeto
IFileSyncProvider
e o configura especificando a pasta para sincronizar e um filtro que só inclui arquivos que têm a extensão .txt.Cria um objeto
IStream
e o inicializa com um RSS feed vazio. O código a seguir declara o RSS feed vazio.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";
Cria um objeto
IFeedProducer
e chama o método IFeedProducer::ProduceFeed.Grava o feed que foi gravado no objeto
IStream
pelo Sync Framework em um arquivo na pasta de réplicas.
O código a seguir produz o 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;
}
Próximas etapas
Agora que você criou um produtor de FeedSync, pode criar um consumidor de feed. Um consumidor de feed é um componente de software que extrai itens de um feed do FeedSync e os aplica a uma réplica de destino usando um provedor de sincronização. Para obter mais informações, consulte Consumindo RSS e Atom feeds.
Consulte também
Conceitos
Sincronizando Web feeds
Produzindo RSS e Atom feeds
Consumindo RSS e Atom feeds
Convertendo IDs e itens para RSS e Atom Feeds
Componentes de sincronização da Web do Sync Framework