October 30, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Developing ActiveSync Service Providers: Desktop Part Implementation

  • October 10, 2005
  • By Alex Gusev
  • Send Email »
  • More Articles »

IReplStore methods

All functions from this group work at the Store level. You will be focused on one of them, GetStoreInfo, as a main part of this functional group. All the rest is simply to get and implement; see, for example, the Initialize code below:

STDMETHODIMP CASPSimpleStore::Initialize(IReplNotify *pNotify,
                                         UINT uFlags)
{
   if(pNotify == NULL)
      return E_INVALIDARG;
   //
   // TODO: ActiveSync manager will call this function to let you
   // initialize your store. Add any store level initialization
   // code here. Store the IReplNotify interface passed away in
   // our m_pNotify member. If you want to do real-time store
   // change notifications, you will have to use this pointer.
   //
   m_pNotify = pNotify;
   m_pNotify->AddRef();
   m_fInitialized = TRUE;
   return S_OK;
}

The more interesting part is the GetStoreInfo function. There, your provider will populate the STOREINFO struct with information about the store. It will be called twice: first to get the buffer size required to keep the store's unique ID and then to copy this ID to the buffer. Take a look at the next code snippet:

STDMETHODIMP CASPSimpleStore::GetStoreInfo(PSTOREINFO pInfo)
{
   if((pInfo == NULL)||(pInfo->szProgId == NULL)
                     ||(pInfo->szStoreDesc == NULL))
      return E_INVALIDARG;
   //
   // The store info flags are used to specify how this store
   // can be called by the activeSync manager and also the
   // method for notifying of changes to this store. The flag
   // SCF_SINGLE_THREAD specifies that this store can only
   // handle single-threaded calls(it is not thread-safe).
   // The flag SCF_SIMULATE_RTS specifies that we need to be
   // polled by the ActiveSync manager for any changes in the
   // store. If this flag is not set, ActiveSync assumes that
   // you will notify it of any changes using the IReplNotify
   // call back interface.The default polling frequency is
   // (5000 msecs), as set by the pInfo->uTimerRes member.
   // To be polled only when the ActiveSync window is activated
   // set uTimerRes to 0.
   //
   pInfo->uFlags = SCF_SINGLE_THREAD|SCF_SIMULATE_RTS;
   // default freq of 5 secs
   //
   // Set the ProgId & description of the store
   //
   ::lstrcpy(pInfo->szProgId,    m_pszProgId);
   ::lstrcpy(pInfo->szStoreDesc, m_pszDesc);
   //
   // bail if store is not yet initialized
   //
   if(!m_fInitialized)
      return S_OK;
   //
   // TODO: Construct something that will uniquely identify this
   // store. We just use a UINT number by default. If you need an
   // alternate way to identify your store, you will need to
   // modify the code section below.
   //
   pInfo->cbStoreId = sizeof(UINT);
   if(pInfo->cbStoreId > pInfo->cbMaxStoreId)
      return E_OUTOFMEMORY;
   if(pInfo->lpbStoreId == NULL)
      return E_POINTER;
   UINT *puId = reinterpret_cast<PUINT>(pInfo->lpbStoreId);
   *puId = 12345;
   return S_OK;
}

In the sample, you use some predefined number for the store ID. You may choose some other strategy. ReportStatus and CompareStoreIDs are in the sample's zip file.

Enumeration of folder objects

This group of functions perform item enumeration within a folder. Your data may be stored everywhere, so this is a place where you can iterate through different items, also providing information about modification timestamps:

HRESULT CASPSimpleFolder::FindFirstItem(HREPLITEM *phItem,
                                        BOOL *pfExist)
{
   *phItem  = NULL;
   *pfExist = FALSE;
   //
   // We need to get info about our file and set the new
   // CReplItem's members.
   // If our file has been deleted, we simply return success.
   //
   WIN32_FILE_ATTRIBUTE_DATA atrFile;
   ::ZeroMemory(&atrFile, sizeof(atrFile));
   if(!::GetFileAttributesEx(GetSyncFileName(),
      GetFileExInfoStandard, &atrFile))
      return S_OK;    // file does not exist
   //
   // We create a new CReplItem object for our one & only file
   // here and initialize its members.
   //
   CReplItem *pItem = new CReplItem(GetSyncFileName());
   if(pItem == NULL)
   return E_OUTOFMEMORY;
   pItem->SetModified(atrFile.ftLastWriteTime);
   *phItem = reinterpret_cast<HREPLITEM>(pItem);
   *pfExist = TRUE;
   return S_OK;
}
HRESULT CASPSimpleFolder::FindNextItem(HREPLITEM *phItem,
                                       BOOL *pfExist)
{
   //
   // TODO: Find the Next item in your folder, create a new
   // CReplItem object set its members & return it thru hItem ptr.
   // You can free any additional memory allocated in this call
   // when FindItemClose() is called. If there are no more items
   // in the folder, set *pfExist to FALSE.
   //
   *pfExist = FALSE;
   return S_OK;
}
HRESULT CASPSimpleFolder::FindItemClose()
{
   //
   // TODO: Sync manager calls this function after enumerating
   // all the items in your folder(thru calls to FindFirstItem()
   // & FindNextItem()). Add clean up code here - you will
   // have to free any memory that was allocated.
   //
   return S_OK;
}

This implementation works with a single flat file. You may want to have multiple files and manipulate them here.

I won't discuss all the rest of the methods; additional details are in the sample project. My goal is to highlight important points you need to pay attantion to, that's all. You have seen the 'Standard management routines' section in the previous article, so please refer to it if you need to. Being said in a couple of words, you have to focus on item iteration and serialization routines. The following picture shows the results of the ActivateDialog call:



Click here for a larger image.





Page 2 of 3



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel