Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этом разделе показано, как написать на неуправляемом языке, например C++, приложение, которое будет использовать платформу Sync Framework для создания RSS-канала из списка файлов в папке. RSS-канал, создаваемый этим приложением, содержит один элемент для каждого файла в указанной папке. Каждый элемент в канале включает содержимое связанного файла, а также метаданные FeedSync об элементе.
В этом разделе предполагается, что читатель знаком с основными понятиями языка C++ и модели COM.
Примеры, приведенные в разделе, посвящены следующим компонентам веб-синхронизации платформы Sync Framework.
Основные сведения о производителях каналов
Производитель канала — это программный компонент, который создает канал FeedSync, содержащий элементы, переданные службой синхронизации. В приложении реализован интерфейс IFeedIdConverter для преобразования идентификаторов из формата службы в формат FeedSync, а также интерфейс IFeedItemConverter — для преобразования данных элементов из формата службы в формат FeedSync.
Дополнительные сведения о создании канала FeedSync см. в разделе Создание RSS- и Atom-каналов.
Дополнительные сведения о службах синхронизации см. в разделе Реализация стандартного пользовательского поставщика.
Требования построения
Synchronization.h, FeedSync.h, FileSyncProvider.h: объявления основных компонентов служб Sync Framework, компонентов веб-синхронизации и файла службы синхронизации.
#include <Synchronization.h> #include <FeedSync.h> #include <FileSyncProvider.h>Synchronization.lib, FeedSync.lib, FileSyncProvider.lib: библиотеки импорта.
Пример
В примере кода в этом разделе показано, как использовать объект IFeedProducer для создания RSS-канала, который содержит элементы, переданные объектом IFileSyncProvider. В примере также показано, как реализовать интерфейсы, которые преобразуют идентификаторы и данные элементов из формата службы синхронизации файлов в формат FeedSync.
Реализация интерфейса IFeedIdConverter
Идентификаторы, используемые службой, могут иметь любой формат. Поэтому для платформ Sync Framework необходимо, чтобы в приложении был реализован интерфейс IFeedIdConverter для преобразования идентификаторов из формата поставщика в формат FeedSync и обратно.
Объявление интерфейса IFeedIdConverter
Добавьте IFeedIdConverter в список наследования класса.
class CFileSyncProviderIdConverter : public IFeedIdConverter
Добавьте методы IFeedIdConverter в декларацию класса.
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);
Метод GetIdParameters
Платформы Sync Framework вызывают метод IFeedIdConverter::GetIdParameters, чтобы получить схему форматов идентификаторов, используемую поставщиком. Реализация в этом примере возвращает схему форматов идентификаторов, полученную из объекта IFileSyncProvider. Код, который получает и сохраняет эту схему, см. в подразделе «Создание RSS-канала» далее в этом разделе.
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;
}
Метод ConvertReplicaIdToString
Чтобы преобразовать идентификатор реплики из формата поставщика в строку, платформы Sync Framework вызывают метод IFeedIdConverter::ConvertReplicaIdToString. Строковое представление идентификатора может иметь любую форму и непосредственно передается в канал. Реализация в этом примере использует функцию OLE32 StringFromGUID2, чтобы преобразовать идентификатор реплики из идентификатора GUID в строку типа WCHAR. Она возвращает результирующую строку с помощью метода 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;
}
Метод ConvertItemIdToString
Чтобы преобразовать идентификатор элемента из формата поставщика в строку, платформы Sync Framework вызывают метод IFeedIdConverter::ConvertItemIdToString. Строковое представление идентификатора может иметь любую форму и непосредственно передается в канал. Реализация в этом примере преобразует идентификатор элемента, форматированный в виде структуры SYNC_GID, в строку типа WCHAR. Затем она использует функцию CRT _ui64tow_s, чтобы преобразовать часть префикса из формата ULONGLONG в строку типа WCHAR. Также используется функция OLE32 StringFromGUID2,чтобы преобразовать часть идентификатора, занимаемую идентификатором GUID, в строку типа WCHAR. В примере эти две строки объединяются, а результирующая строка возвращается с помощью метода 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;
}
Метод ConvertStringToReplicaId
Чтобы преобразовать идентификатор реплики из формата поставщика в строку, платформы Sync Framework вызывают метод IFeedIdConverter::ConvertStringToReplicaId. Это строковое представление полностью совпадает с тем, которое было возвращено платформой Sync Framework в методе ConvertReplicaIdToString. Реализация в этом примере использует функцию OLE32 CLSIDFromString, чтобы преобразовать идентификатор реплики из строки типа WCHAR в идентификатор GUID. Она возвращает результирующий идентификатор с помощью метода 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;
}
Метод ConvertStringToItemId
Чтобы преобразовать идентификатор элемента из строки в формат поставщика, платформы Sync Framework вызывают метод IFeedIdConverter::ConvertStringToItemId. Это строковое представление полностью совпадает с тем, которое было возвращено платформой Sync Framework в методе ConvertItemIdToString. Реализация в этом примере использует функцию CRT wcstoui64, чтобы преобразовать часть идентификатора, занимаемую префиксом, из строки типа WCHAR в значение ULONGLONG. Также используется функция OLE32 CLSIDFromString, чтобы преобразовать часть идентификатора, занимаемую идентификатором GUID, из строки типа WCHAR в идентификатор GUID. В примере возвращается результирующий идентификатор, имеющий формат SYNC_GID, с помощью метода 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;
}
Нереализованные методы
Следующий метод не является необходимым для распространенных сценариев использования производителя канала. Этот метод может возвращать значение E_NOTIMPL:
Реализация интерфейса IFeedItemConverter
Данные элементов, получаемые от службы, могут иметь любой формат. Поэтому для платформ Sync Framework необходимо, чтобы в приложении был реализован интерфейс IFeedItemConverter для преобразования данных элемента из формата поставщика в формат FeedSync и обратно.
Объявление интерфейса IFeedItemConverter
Добавьте IFeedItemConverter в список наследования класса.
class CFileSyncProviderItemConverter : public IFeedItemConverter
Добавьте методы IFeedItemConverter в декларацию класса.
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 вызывают метод IFeedItemConverter::ConvertItemDataToXmlText, чтобы преобразовать данные элементов из формата поставщика в XML-текст. Метод ConvertItemDataToXmlText вызывается, когда метод IFeedItemConverter::ConvertItemDataToXml возвращает значение E_NOTIMPL. Реализация в этом примере предполагает, что передаваемые файлы содержат допустимый XML-код для элемента RSS-канала в формате Юникод. Далее представлен пример содержимого файла.
<item>
<title>Sample</title>
<description>A sample item.</description>
</item>
Объект IFileSyncProvider передает содержимое файла в виде объекта IFileDataRetriever. Реализация в этом примере получает объект IStream из объекта IFileDataRetriever и использует его для считывания содержимого файла в строку типа WCHAR. Она возвращает результирующую строку с помощью метода 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;
}
Нереализованные методы
Следующие методы не являются необходимыми для распространенных сценариев использования производителя канала. Эти методы могут возвращать значение E_NOTIMPL:
Создание RSS-канала
Платформы Sync Framework предоставляют интерфейс Интерфейс IFeedProducer, помогающий поставщику передавать элементы из связанной с ним реплики в канал FeedSync. Реализация в этом примере использует объект IFileSyncProvider в качестве службы, а папку в файловой системе — в качестве реплики. В примере кода для создания канала выполняются следующие действия.
Создается объект IFileSyncProvider и настраивается путем указания папки для синхронизации и фильтра, который включает только TXT-файлы.
Создается объект IStream и инициализируется с пустым RSS-каналом. В следующем коде объявляется пустой RSS-канал.
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";Создается объект IFeedProducer и вызывается его метод IFeedProducer::ProduceFeed.
Канал, который был записан в объект IStream платформами Sync Framework, записывается в файл в папке реплики.
В следующем коде создается канал.
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;
}
Следующие шаги
После создания производителя канала FeedSync может понадобиться создать потребитель канала. Потребитель канала — это программный компонент, который принимает элементы из канала FeedSync и применяет их к реплике-назначения с помощью службы синхронизации. Дополнительные сведения см. в разделе Использование данных из RSS- и Atom-каналов.
См. также
Другие ресурсы
Использование данных из RSS- и Atom-каналов
Преобразование идентификаторов и элементов для RSS- и Atom-каналов