Developing ActiveSync Service Providers: Desktop Part Implementation
What You Already Know
Here, you have reached a point where all your last coding will result in some viewable outcome. In the previous article, you covered the device part of ActiveSync Service Provider implementation. Now, you are ready to conquer its desktop components.
Desktop stuff requires much more effort and coding to get it working. As usual, you have to implement fully functional COM components to interface with MS ActiveSync. Partially, you saw it in previous article, but here you will add some new stuff. The following sections will guide you through all required stages.
MS ActiveSync Data Storage
As noted earlier, MS ActiveSync has no idea about what your data is. It uses a generic approach to access and manipulate such data via HREPLFLDR and HREPLITEM pointers. ActiveSync places all such data to one single file named repl.dat for each device.
Usually, you will have many items and few folders, so you have to keep in mind not to break some rational limits of the information you define for each item or folder. Here is a typical implementation:
class CBaseFolder; // // ================== class CReplObject ========================= // class CReplObject { public: enum IDD_OBJ_TYPE{ ASPSIMPLE_OBJ_FOLDER = 1, ASPSIMPLE_OBJ_ITEM = 2 }; protected: IDD_OBJ_TYPE m_eType; // type of this object folder/item public: CReplObject(IDD_OBJ_TYPE eType) { m_eType = eType;} IDD_OBJ_TYPE GetType(){ return m_eType;} virtual ~CReplObject(){}; }; // // ================== class CReplFolder ========================== // class CReplFolder: public CReplObject { protected: TCHAR m_szName[_MAX_PATH]; CBaseFolder *m_pFolder; public: CReplFolder(LPTSTR pszName, CBaseFolder *pFolder) : CReplObject(ASPSIMPLE_OBJ_FOLDER) { ::_tcscpy(m_szName, pszName); m_pFolder = pFolder; // stores ptr to real folder return; } virtual ~CReplFolder(){} const LPTSTR GetName(){ return m_szName;} CBaseFolder* GetFolder(){ return m_pFolder;} CReplFolder& operator=(const CReplFolder& rhs) // overloaded // operator= { // // TODO: If you add/modify the members of this class, // you will also need to modify the code below. // ::_tcscpy(m_szName, rhs.m_szName); m_pFolder = rhs.m_pFolder; return *this; } }; // // ================== class CReplItem =========================== // class CReplItem: public CReplObject { protected: TCHAR m_szId[_MAX_PATH]; // unique id to identify // this object FILETIME m_ftModified; // stores the last modified // time of this item public: CReplItem(LPTSTR pszId) : CReplObject(ASPSIMPLE_OBJ_ITEM) { ::_tcscpy(m_szId, pszId); return; } virtual ~CReplItem(){} FILETIME& GetModified(){ return m_ftModified;} void SetModified(FILETIME& ft){ m_ftModified = ft;} CReplItem& operator=(const CReplItem&rhs) // overloaded // operator= { // // TODO: If you add/modify the members of this class, // you will also need to modify the code below. // ::_tcscpy(m_szId, rhs.m_szId); m_ftModified = rhs.m_ftModified; return *this; } // // Compare function compares this object with another one //of the same type. Returns -1, 0 or 1 accordingly. // int Compare(const CReplItem* prhs) { return ::_tcscmp(m_szId, prhs->m_szId); } const LPTSTR GetId() { return m_szId; } };
Folders are usually characterized by their names, whereas Items have a modification time stamp.
IReplStore Implementation
The IReplStore interface allows ActiveSync to obtain relevant info and manipulate all synchronized entities such as stores, folders, and items. Let me place your sample implementation's declaration here, categorized by functionality:
class CBaseFolder; class CASPSimpleStore: public IReplStore { protected: long m_cRef; BOOL m_fInitialized; IReplNotify *m_pNotify; CBaseFolder *m_pFolders[ASPSIMPLE_NUM_FOLDERS]; private: static const LPTSTR m_pszCLSID; static const LPTSTR m_pszProgId; static const LPTSTR m_pszDesc; public: static const LPTSTR GetCLSID(){ return m_pszCLSID;} static const LPTSTR GetProgId(){ return m_pszProgId;} static const LPTSTR GetDesc(){ return m_pszDesc;} private: ~CASPSimpleStore(); public: CASPSimpleStore(); CBaseFolder* GetFolderByName(LPTSTR szName); //========= IUnknown methods ==========// STDMETHODIMP QueryInterface(const IID& iid, void **ppvObject); STDMETHODIMP_(ULONG) AddRef(void); STDMETHODIMP_(ULONG) Release(void); //========= IReplStore methods ==========// STDMETHODIMP Initialize(IReplNotify *, UINT uFlags); STDMETHODIMP GetStoreInfo(PSTOREINFO pStoreInfo); STDMETHODIMP ReportStatus(HREPLFLD hFolder, HREPLITEM hItem, UINT uStatus, UINT uReserved); STDMETHODIMP_(int) CompareStoreIDs(LPBYTE lpbID1, UINT cbID1, LPBYTE lpbID2, UINT cbID2); // ============ Object related routines ===========// STDMETHODIMP_(int) CompareItem(HREPLITEM hItem1, HREPLITEM hItem2); STDMETHODIMP_(BOOL) IsItemChanged(HREPLFLD hFolder, HREPLITEM hItem, HREPLITEM hItemComp); STDMETHODIMP_(BOOL) IsItemReplicated(HREPLFLD hFolder, HREPLITEM hItem); STDMETHODIMP_(void) UpdateItem(HREPLFLD hFolder, HREPLITEM hItemDst, HREPLITEM hItemSrc); // ============ Folder related routines ===========// STDMETHODIMP GetFolderInfo(LPSTR lpszName, HREPLFLD *phFolder, IUnknown **ppObjHandler); STDMETHODIMP IsFolderChanged(HREPLFLD hFolder, BOOL *pfChanged); // ============ Enumeration of folder objects =======// STDMETHODIMP FindFirstItem(HREPLFLD hFolder, HREPLITEM *phItem, BOOL *pfExist); STDMETHODIMP FindNextItem(HREPLFLD hFolder, HREPLITEM *phItem, BOOL *pfExist); STDMETHODIMP FindItemClose(HREPLFLD hFolder); // ============ Standard management routines ===========// STDMETHODIMP_(UINT) ObjectToBytes(HREPLOBJ hObject, LPBYTE lpb); STDMETHODIMP_(HREPLOBJ) BytesToObject(LPBYTE lpb, UINT cb); STDMETHODIMP_(void) FreeObject(HREPLOBJ hObject); STDMETHODIMP_(BOOL) CopyObject(HREPLOBJ hObjSrc, HREPLOBJ hObjDst); STDMETHODIMP IsValidObject(HREPLFLD hFolder, HREPLITEM hObject, UINT uFlags); // ============ UI related routines ================// STDMETHODIMP ActivateDialog(UINT uDlg, HWND hWnd, HREPLFLD hFolder, IEnumReplItem *penum); STDMETHODIMP GetObjTypeUIData(HREPLFLD hFolder, POBJUIDATA pData); STDMETHODIMP GetConflictInfo(PCONFINFO pConfInfo); STDMETHODIMP RemoveDuplicates(LPSTR lpszObjType, UINT uFlags); };
Let's discuss some of the above categories (I'll skip the IUnknown part). You will find more details in the accompanying sample project.
Page 1 of 3