Mindfire Solutions - 1 - MS Active Sync: Sync with External Memory Files Author: Rahul Gaur Mindfire Solutions,
Mindfire Solutions - 2 - Table of Contents Overview 3 Target Audience 3 Conventions...3 1. Introduction.4 2. RAPI & ActiveSync 5 3. Tools & SDKs Used 6 4. Sample Application 6 4.1. Creating Sync Service Providers (SSP) 7 4.2. Device Side SSP.11 4.3. Desktop Side SSP...15 4.4. Registering Desktop SSP...20 4.5. Registering Device SSP. 20 4.6. Synchronizing.21 5. Conclusion.24
Mindfire Solutions - 3 - Overview How do I quickly start with Active Sync Technology? Can my RAPI code be started when Active Sync starts? Can my RAPI executable be integrated with Active Sync as a Conduit? These are some of the questions most of pocket pc developers need to answer when they start dealing with a sync process of higher complexity. In this document, we have tried to compile our experience of developing and integrating RAPI with ActiveSync, with an aim to provide help to our developer community which faces similar situations in due course of windows mobile application development. Target Audience This document is intended for Windows CE developers who are familiar with Remote APIs (RAPIs) and are looking for a quick way of integrating their RAPI Code with Microsoft Active Sync. Conventions Throughout this document, any important text is in Bold-Times New Roman Font. The code snippets are in Courier New Font with code comments in italics.
Mindfire Solutions - 4-1. Introduction Active Sync Conduits are used for PocketPCs to transfer information from PC to PocketPC and vice versa. It can be sync of data or transfer of files or whatever you may want your conduit to achieve. Data synchronization is different from data transfer. A data transfer simply transfers a set of data between two devices without doing any validations, no checking for differences between data on source and destination. Data synchronization, on the other hand, updates the data on both sides based on relevant changes (addition, updating, and deletion) since the last synchronization. Synchronizing application data implies that there are two applications interested in the data being synchronized. One application resides on the device, and the other on the user s desktop computer. Each of these applications implements some mechanism for storing a user s data. The particular data repository for each application is called a Data Store. As a Win-CE developer, one has two options when it comes to Data Synchronization: a) Remote APIs The Win-CE Remote API provides a way for Desktop PC applications to access a connected Win-CE device. These APIs can be used to read files, databases & even registry of the device. One can also write to files, databases, or registry entries on the device. The application, an exe file, resides on the user s desktop computer b) Microsoft ActiveSync Conduit This conduit technology is based on the client/server architecture. The server is implemented by the Win-CE OS and is called ActiveSync Service Manager. It is one of the components of the Win-CE services package that a user installs on a Desktop PC when configuring a device such as a PocketPC or a Smartphone. The clients are called the ActiveSync Service Providers. These are actually two self-registering Dynamic Link Libraries (dll), one residing on the device & the other on the user s PC. The application programmer has to program these two service providers in order to achieve his goal. Majority of the Win-CE developers go with the first choice. The reason is that many Pocket-PC & Smartphone users keep there Data on External Memory like SD Card. ActiveSync simply fails to sync from the External Memory.
Mindfire Solutions - 5-2. RAPI and ActiveSync The sync should occur whenever ActiveSync runs, even when we use the RAPI code, otherwise it defeats the purpose of sync. In order to run the RAPI exe when ActiveSync starts we have to make an entry in the Window s Registry: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows CE Services\AutoStartOnConnect Figure 1: Setting RAPI exe to run with ActiveSync This though has a limitation that we do not see this sync application as a conduit of ActiveSync. Hence the user may find it strange that something which is not showing up in ActiveSync is working with it. Hence, now we have to integrate RAPI app with ActiveSync so that user could manage the sync process using ActiveSync and utilize the powers it shares. A simple way to do it is: 1. Create a Simple File Sync Provider using ActiveSync Application Wizard which creates a dummy file to be used for synching at both ends. 2. Once the ActiveSync Conduit starts it starts our RAPI Application. 3. Wait & Hold the ActiveSync Conduit in its Start State until the processing of RAPI Application completes. 4. Once the RAPI Application completes its execution and exits, it notifies the ActiveSync Conduit so it can continue with its own processing 5. In the End State of the ActiveSync, Conduit checks and deletes the dummy files from both Desktop & Device The following article discusses how the said ideas were transformed into a success by discussing a sample example in detail.
Mindfire Solutions - 6-3. Tools & SDKs Used a) Microsoft Embedded Visual C++ with Service Pack 3 b) Microsoft Visual C++ 6.0 c) Microsoft Pocket PC 2003 SDK d) Microsoft ActiveSync 4.0.0 4. Sample Application Firstly one needs an Application Wizard File so that VC++ 6 can create ActiveSync service providers. The file is called SyncWiz.awx. It can be found in the directory \Windows CE Tools\wce420\POCKET PC 2003\Activesync\Activesync wizard Figure 2: ActiveSync Wizard File Location
Mindfire Solutions - 7 - Copy the file SyncWiz.awx to \Microsoft Visual Studio\Common\MSDev98\Template directory Figure 3: ActiveSync Wizard File Destination 4.1 Creating Sync Service Providers (SSP) Now we are ready to create our ActiveSync Service Providers. Start Microsoft Visual C++. Click on File & then click on New Figure 4: Create New ActiveSync Project in Visual C++ 6.0
Mindfire Solutions - 8 - Select Projects Tab and click on ActiveSync Service Provider Wizard. We name the project as SyncApp and set the location to C:\ drive Figure 5: ActiveSync Project Named SyncApp Click on the OK Button. The Wizard starts and displays the Step 1 dialog box. Select the radio button displaying a simple file sync provider text Figure 6: Select Service Provider as File Sync Provider
Mindfire Solutions - 9 - Click on the Next Button. The Wizard now displays the Step 2 dialog box. Change the different editbox texts as shown in the figure below. This step generally displays the information needed to register the SSP (Sync Service Provider) with ActiveSync. Figure 7: Information Type for the SSPs Click on the Next Button. The Wizard now displays the Step 3 dialog box. It displays the options regarding the polling of the service providers by ActiveSync manager. Select the radio button displaying a poll my provider periodically (defaults to 5 secs) text. We will later on change this in the code Figure 8: Select the Polling Frequency
Mindfire Solutions - 10 - Click on the Finish Button. The wizard now shows the details of this project. Figure 9: Details of Our Device Side & Desktop Side Projects As one can see the Wizard generates two projects :- a) SyncApp.dll (Desktop Side SSP) b) DevSyncApp.dll (Device Side SSP) The two projects are now discussed in detail followed by their registration & configuration on Desktop & Device respectively.
Mindfire Solutions - 11-4.2 Device Side SSP Project Both the projects are meant for Visual C++, however if we try to open the Device Side SSP(DevSyncApp.dsw) project in VC++ it displays an Error Message Box. Figure 10: Opening Device Side Project in VC++ 6.0 Since it s a Project for building a Win-CE DLL we can use Embedded Visual C++ to help us overcome this issue. Start evc++, click on File & then click on New Figure 11: Creating the Same Device Side Project in evc++ 4.0 Step 1
Mindfire Solutions - 12 - Select Projects Tab and click on WCE Dynamic-Link Library. We name the project as DevSyncApp and set the location to C:\SYNCAPP\DEVICE\ Figure 12: Creating the Same Device Side Project in evc++ 4.0 - Step 2 Click the OK Button and select An empty Windows CE DLL project Figure 13: Creating the Same Device Side Project in evc++ 4.0 - Step 3
Mindfire Solutions - 13 - Clicking on Finish Button will display the New Project Information dialog. Click OK button to complete the Wizard. Now we have an empty project with an output same as that of Device Side SSP Project i.e. DevSyncApp.dll. We now have to add the corresponding files to this project namely: a) basefolder.h b) DevSyncApp.h c) DevSyncAppFldr.h d) DevSyncAppobjhand.h e) DevSyncApp.cpp f) DevSyncAppFldr.cpp g) DevSyncAppobjhand.cpp h) DevSyncApp.def After adding these files set Active Configuration as Win32(WCE ARMV4) Release, Active Platform as POCKET PC 2003 and Default Device as Pocket PC 2003 Device and build the Project. The output is DevSyncApp.dll in C:\SyncApp\Device\ARMV4Rel directory. In case you get the following error :- fatal error C1083: Cannot open include file: 'cesync.h': No such file or directory you have to set the following path :- \Windows CE Tools\wce420\POCKET PC 2003\Activesync\Inc in the Additional Include Directories: option. Figure 14: Additional Include Directories for evc++ 4.0
Mindfire Solutions - 14 - More changes are required in this Device Side SSP Project namely: a) In DevSyncAppFldr.cpp, change the function CSyncAppFolder::Initialize to: BOOL CSyncAppFolder::Initialize(IReplObjHandler** ppobjhandler, UINT upartnerbit) if(ppobjhandler == NULL) return FALSE; *ppobjhandler = new CSyncAppObjHandler(this); if(*ppobjhandler == NULL) return FALSE; // Store partner info. Which partner are we // connected to - first or second partner. if(upartnerbit & 0x01) m_upartner = 0; else if(upartnerbit & 0x02) m_upartner = 1; return TRUE; b) In DevSyncApp.cpp change the CSyncAppStore::ReportStatus function to: BOOL CSyncAppStore::ReportStatus(LPWSTR lpszobjtype, UINT ucode, UINT uparam) // TODO: Called to inform provider of sync events. // Add code to handle these events. int i = 0; switch(ucode) case RSC_BEGIN_SYNC: break; case RSC_END_SYNC: //Delete Both the Files When Sync Completes for(i = 0; i < SYNCAPP_NUM_FOLDERS; i++) CSyncAppFolder* pfolder = (CSyncAppFolder*)m_pFolders[i]; if(pfolder) ::DeleteFile( pfolder->getdatafilename() ); ::DeleteFile( pfolder->getsyncfilename() ); break; return TRUE;
Mindfire Solutions - 15 - c) Build the Project. You can now delete DevSyncApp.dsw & DevSyncApp.dsp as they are no longer needed. The obvious question in one s mind would be; what does our device side project actually do? And the answer is, it just deletes the files on device after the Active Sync completes itself on the device side. Now we can concentrate on Desktop Side. 4.3 Desktop Side SSP Project This project is for making Self-Registering DLL SyncApp.dll. To avoid registration of this dll each time the project is build, go to the Custom Build tab of the Project Settings and delete the text in: a) Description box b) Commands box c) Outputs box Make sure that the Settings For: choice box has All Configurations Selected. Also set the Active Project Configuration as Win32 Release Figure 15: Deleting the Commands in Custom Build Tab in VC++ 6.0 In case the DLL gets registered accidentally, you can run the following command to
Mindfire Solutions - 16 - unregister it: regsvr32 /s /u "C:\SyncApp\Release\SyncApp.dll" Now for the changes required in this Desktop Side SSP Project. We assume that our RAPI Application named SampleRAPIApp.exe resides in the C:\ directory a) In SyncAppStore.h, modify the class definition of CSyncAppStore by adding some variables & functions as given below :- private: //A variable that stores the Time Gap value in milliseconds //so that our RAPI application does not run again //in one ActiveSync Session; ULONG m_synctimegap; //Its a check variable //In case the SampleRAPIApp.exe is not found //this variable will prevent the Active Sync from //running into an infinite while loop in RSC_ENDCHECK bool m_stopsync; //Stores the time value in millisecond ULONG m_timervalue; public: //A Function that starts the RAPI Application void StartRapiApp(); //A Function that makes our Application Wait for the RAPI // Application to finish bool WaitForRapiApp(); //Gets the time in millisecond unsigned long GetCurrentTimeMilli() return GetTickCount(); b) Many changes are required in SyncAppStore.cpp namely :- 1. In the CSyncAppStore constructor, add following m_synctimegap = 5000; m_timervalue = 0; m_stopsync = false; 2. In the CSyncAppStore::GetStoreInfo function change pinfo->uflags to pinfo->uflags = SCF_SINGLE_THREAD; 3. Add the definition of CSyncAppStore::StartRapiApp as given below
Mindfire Solutions - 17 - void CSyncAppStore::StartRapiApp() //First find whether it is already running //If yes then set it as foreground window and If no //then start it HWND hcal = FindWindow(NULL, "SampleRAPIApp"); if(hcal!= NULL) SetForegroundWindow(hCal); else UINT returnval = WinExec("C:\\SampleRAPIApp.exe", SW_SHOW); //Not Successful //Set the check variable as true as it will //prevent the Active Sync to run into an Empty //Loop if(returnval <= 31) m_stopsync = true; 4. Add the definition of CSyncAppStore::WaitForRapiApp as given below bool CSyncAppStore::WaitForRapiApp() HKEY htestkey; BYTE buffer[128]; DWORD rec = 0, size = 128; //Open the Key HKEY_LOCAL_MACHINE\\SOFTWARE\\SampleRapiApp if( RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\SampleRapiApp\\"), 0, KEY_READ, &htestkey) == ERROR_SUCCESS ) memset(buffer, NULL, size); //Query the Value of RAPIAPPSTATE RegQueryValueEx(hTestKey,"RAPIAPPSTATE", NULL, &rec, buffer, &size); RegCloseKey(hTestKey); //If ON return true if( strcmp( (char*)buffer, "ON" ) == 0 ) return true; return false; 5. Changes in CSyncAppStore::ReportStatus function. This function is called by the
Mindfire Solutions - 18 - ActiveSync Manager to report the status on the sync process. Three statuses are important to us - RSC_END_SYNC, RSC_BEGIN_CHECK & RSC_END_CHECK. The modifications are as follows case RSC_BEGIN_CHECK: //Check the m_timervalue variable. If the next call is within the // m_synctimegap period, SampleRAPIApp.exe should not be called if( GetCurrentTimeMilli() - m_timervalue < m_synctimegap ) //We don't need to start the Active Sync session m_stopsync = true; else //Setting the Timer Value to zero again m_timervalue = 0; //Yes we need to start the Active Sync session m_stopsync = false; break; //If m_stopsync = false, start our RapiApp if(!m_stopsync) StartRapiApp(); case RSC_END_CHECK: if(!m_stopsync) //Holding Application from completing itself // until & unless Our RAPI Application completes while( WaitForRapiApp() ) Sleep(200); //Our Application is ON, Checking it Again //This is done in case some failure occurs //while reading the registry or the App //accidentally exits, SampleRAPIApp is the //caption name on dialog based RAPI App if(!findwindow(null, "SampleRAPIApp") ) //We Break out break; //Get the time in millisecond m_timervalue = GetCurrentTimeMilli(); break;
Mindfire Solutions - 19 - case RSC_END_SYNC: int i = 0; CSyncAppFolder* pappfolder =(CSyncAppFolder*)m_pFolders[i]; //Delete the Files When Sync Completes for(i = 0; i < SYNCAPP_NUM_FOLDERS; i++) ::DeleteFile( pappfolder->getsyncfilename() ); The Desktop Side is also complete. Build the project. The output would be SyncApp.dll in C:\SyncApp\Release folder. What does our desktop side project actually do? Without diving deep into the ActiveSync s technological jargon, our desktop project does a very simple task - It calls the RAPI Application and holds the Desktop Side SSP from completing itself until RAPI code returns. For this project one can say that the two notifications RSC_BEGIN_CHECK & RSC_END_CHECK together constitute one ActiveSync Session. In RSC_BEGIN_CHECK we call SampleRAPIApp.exe. This executable opens a Registry Key - HKEY_LOCAL_MACHINE\SOFTWARE\SampleRapiApp. This Registry Key is made by the Desktop Installer which installs our RAPI application & Desktop Side SSP on the user's PC. This Key has a String Value of RAPIAPPSTATE with default value OFF. For trial purpose one can create the said registry by using regedit*. When our SampleRAPIApp.exe starts it sets RAPIAPPSTATE as ON and when it ends it sets RAPIAPPSTATE as OFF. After RSC_BEGIN_CHECK the ActiveSync Manager sets the status as RSC_END_CHECK. It is in this notification or status that we hold our application from completing itself. As long as the RAPIAPPSTATE is set to ON, our application is struck in a while loop. As soon as the SampleRAPIApp.exe completes its task, the RAPIAPPSTATE is set to OFF and the processing of RSC_END_CHECK completes. Ultimately when the status of the ActiveSync Session is RSC_END_SYNC, we delete the desktop side file (sample.txt). These two projects (Desktop and Device side) need to be properly configured and registered so that the ActiveSync Conduit can actually work. Since we won t discuss any Desktop or Device Side Installer, some points need to be kept in mind before configuring the two projects: 1) SampleRAPIApp.exe is in C:\ drive 2) There is no Registry entry for SampleRAPIApp.exe in
Mindfire Solutions - 20 - HKEY_ LOCAL_MACHINE\SOFTWARE\Microsoft\Windows CE Services\AutoStartOnConnect 3) There is a Registry Key by the name of SampleRapiApp in HKEY_ LOCAL_MACHINE\SOFTWARE with a String Value of RAPIAPPSTATE set to OFF 4) The Test Machine should be in Administrator Mode so that the registries can be easily read & modified *Possible only in Administrator mode 4.4 Registering Desktop Side SSP It can be easily registered from the command line by using following command regsvr32 /s "C:\SyncApp\Release\SyncApp.dll" For unregistering use following command regsvr32 /s /u "C:\SyncApp\Release\SyncApp.dll" 4.5 Registering Device Side SSP 1. Copy the DevSyncApp.dll from C:\SyncApp\Device\ARMV4Rel folder to the device s root directory manually using the ActiveSync Mobile Devices Folder window. 2. Open the file register.bat in C:\SyncApp\Device folder and enter the complete path for the cabwiz.exe. The cabwiz.exe file can be found under \Windows CE Tools\wce420\Pocket PC 2003\Tools\ directory. 3. Run the register.bat file (Make sure that the device is connected) which will create all the required registry entries on the device. Now the Device Side SSP is also registered. For unregistering it go to the Remove Programs on Device. Select CompanyName SyncApp & click on Remove. This will remove the corresponding registry entries from the device. Now delete DevSyncApp.dll from the device s root directory.
Mindfire Solutions - 21-4.6 Synchronizing When both Desktop & Device Side SSPs are registered, disconnect & re-connect the device. Select Standard Partnership Figure 16: Selecting the Standard Partnership Select Synchronize with this desktop computer Figure 17: Selecting Desktop or Server for Synchronization
Mindfire Solutions - 22 - Enter a unique name for your device Figure 18: Entering a Unique Name for the Device Select your Active Sync Service Provider(SyncApp) and click on the Next Button Figure 19: Selecting Our SyncApp Service Provider
Mindfire Solutions - 23 - The setup for enabling Standard Partnership is complete. Click on the Finish Button Figure 20: Selecting Our SyncApp Service Provider The SyncApp Conduit starts and in turns call our RAPI Application. You can start your RAPI application in a minimized state so that the user is not disturbed Figure 22: Our SyncApp Service Provider Running
Mindfire Solutions - 24-5. Conclusion Hope you found a quick and a convinient way of integarting an existing RAPI code into an ActiveSync Conduit. If you have any questions, please contact us and we would be glad to extend our support where we can. ========================= THE END ========================= Author of this article is associated with Mindfire Solutions (www.mindfiresolutins.com), which is an offshore software development company and provides customized software solutions to global clients.