Electronics, PCB Design and PCB Layout Daycounter, Inc.
Engineering Services

Custom Firmware, Electronics Design, and PCB Layout


Water Level Sensor


ActiveSync Service Provider Development FAQ

How can I diagnose why my ActiveSync provider has become disabled?

ActiveSync maintains a log file called wcesmgr.log, which is located in the TEMP directory. This file should tell you why a provider has become disabled. To find where the current user's TEMP directory is located, run set TEMP. This will tell you the path.  

There are numerous reasons why a provider will become disabled. One common reason is if ActiveSync can't find the store DLL which is listed in the registry key string value "Store":

[HLM\Windows CE Services\Synchronization\Objects\YourProvider]

If the "Store" string value is missing the null terminator, this will also cause erratic behavior, where the provider becomes disabled after a disconnect and reconnect of the device. 

Why is it that ActiveSync works fine until I disconnect the device and then reconnect, and then my provider's icon becomes disabled?  

The problem may be due to a malformed registry setting on the device.  If your "Store" string value in the device's registry doesn't have a null terminator, then it will cause this behavior. "The Store" string is located under the key: 

[HLM\Windows CE Services\Synchronization\Objects\YourProvider]

You can diagnose this by looking at the wcesmgr.log file. 

What's going on with ObjectNotify?

Object notify is the most critical function on the device side.  Yet it is also the most cryptic.  There are three phases which need to be treated separately. It would have been far easier to understand if the function had been split into three separate functions.  Instead you have to figure out which phase you are in by the flags which are passed in.  Ironically, the MS ActiveSync documentation actually gives a complete explanation of how to treat each phase. Unfortunately, the samples seem to lump the three phases together making it very difficult to understand what is happening at any given time.

ObjectNotify is a method which allows you to stake your claim on any object which is synced by active sync.  If you want to claim an object then this function should return true. Likewise, if the object doesn't belong to your provider ObjectNotify should return false.  

The three phases of ObjectNotify,  are determined by whether or not the device has just connected or just synced an object. The provider can decipherer which phase it is in by looking at the dwFlags in the OBJNOTIFY structure. Depending upon the phase, the members of the OBJNOTIFY structure change meaning, and may or may not be present.  Also depending on the phase, the OBJECTNOTIFY parameters which are passed back including: cOidDel, cOidChg, and poid have different meanings.

Phase 1.  The device has just connected, and all objects are enumerated. Please note that a large number of objects call this routine, it could be hundreds of objects. If you write to a log file from this function you will see a whole rush of items pore into your log file.  It's important that this routine is compact and optimized. You can determine if it is Phase 1 because neither the ONF_DELETED, ONF_CHANGED nor ONF_CLEAR_CHANGE flags are set. However, one of the object type flags should be set such as ONF_RECORD.  If your provider only deals with a single object type such as records you return false if the record type doesn't match. For this phase, all of the members of OBJNOTIFY are present.  The must useful member is the OBJNOTIFY ::oidInfo.infRecord.oidParent member, because you can compare the OID of the object to your database OID to see if the function should claim the object. 

If the object belongs to your provider and has changed since the last sync, then set cOidChg to 1 (assuming you are only syncing a single object) and cOidDel to 0, and set poid to the SyncID.  The SyncID is normally the CEOID of the object, however you could set it to anything with in the specified guidelines. If the object hasn't changed then set cOidChg to 0 (assuming you are only syncing a single object) and cOidDel to 1, and set poid to the SyncID.  Please not that this is an example of why ObjectNotify is so confusing.  For this case cOidDel has nothing to do with deletion, but is used to donote the number of unchanged object. 

Please note that individual record objects from a property database are not enumerated in phase 1. You need to use the FindObjects function to enumerate all of the records. This fact of course is not documented, and the documentation falsely leads you to believe that all objects are enumerated.  

Phase 2. The device has already connected and gone through phase 2.  The provider can tell if it is in this phasebecause either the ONF_DELETED or ONF_CHANGED will be set, and the ONF_CLEAR_CHANGE will be cleared. If you write to a log file from this routine, you will see logs from this phase as you modify records on the device from your device app.   One of the object type flags should be set such as ONF_RECORD. 

If the ONF_DELETED flag has been set, then the object has been deleted from the store, and the only way you can know if the object belongs to your provider is by comparing the OBJNOTIFY::oidInfo.infRecord.oidParent parameter. For the deleted case set cOidDel to 1, and cOidChg to 0 and set poid to the SyncID. 

If the ONF_CHANGED  has been set, then the object has been changed in the device store.  For this case set cOidDel to 0, and cOidChg to 1 and set poid to the SyncID.

Phase 3. This phase can be called after either phase 1 or 2. The provider can tell if it is in this phase because ONF_CLEAR_CHANGE is set.  This phase is called to let you determine if the object has been changed on the device since it was sent up to the desktop. You can determine if the object has changed, by having your device app set a dirty flag or flags whenever it modifies an existing object.  The ObjectNotify function should clear this flag in phase 1 and 2. If the dirty flag is set in phase 3 then we need to resync the object and should return true, otherwise we should return false even though the object belongs to this provider.  For this most of the parameters in OBJNOTIFY are all set to zero except the flags. Also the OBJNOTIFY::oidObject parameter is not the CEOID of the object but the SyncID which you passed back the poid parameter from phase 1 or 2.  Also the parameter OBJNOTIFY::oidInfo.infRecord.oidParent is not valid, so you need to query the object to figure out it's parent to determine if the provider owns the object. 

  Phase 1 Phase 2 Phase 3
ONF_DELETED  Not Present Present Not Present
ONF_CHANGED   Not Present Present Not Present
ONF_CLEAR_CHANGE  Not Present Not Present Present
return value meaning True: Claim Object

False: Don't Claim Object

True: Claim Object

False: Don't Claim Object

True: Object has been modified since last sync

False: Object has not been modified since last sync.

cOidDel If changed return 0.

if unchanged return 1.

if deleted return 1.

else return 0

if changed since last sync return 0, else return 1. 
cOidChg If changed return 1.

if unchanged return 0.

If changed return 1

else return 0

if changed since last sync return 1, else return 0.
oidInfo.infRecord.oidParent valid valid not valid


How do I implement a Provider which will sync between two host computers?

The object that you would like to sync should be have a defined flags member with two dirty bits, one for each host computer.  ActiveSync automatically keeps track of which computer you are syncing two with the use of two partner bits.  The device app should always set both bits to dirty when an object is created or modified. The device provider should clear the corresponding partner bit when an object is synced.  In the case, when an object is created on the desktop and sent to the device, the partner bit should be cleared for the currently connected host, and the other partner bit should be set  by the provider.   

In the function FindObjects what do I set the lpbVolumeID parameter to.

Microsoft has inserted an unbelievably terrible bug into the FindObjects function.  If you set the parameter lpbVolumeID parameter to anything but 0, an Access Violation error may occur in the desktop provider, right before ObjectToBytes() gets called.  Note that the StockPor sample sets this parameter to the GUID of the database volume, so perhaps under some cases this works.   This bug is completely unintuitive, because it shows up so far down the stream that it is near impossible to track down.  Microsoft has no mention of this bug in its knowledge base, which is absurd, since it has to know about it. 


Daycounter specializes in contract electronics design.  Do you need some help on your project?  Contact us to get a quote. 



[Employment] [Downloads] [Articles] [Contact Us]

Salt Lake City, UT, USA

Disclaimer: Daycounter, Inc. doesn't guarantee the accuracy of any of it's content. Use at your own risk.

© Copyright 2016 Daycounter, Inc. All rights Reserved.

Soil Moisture Sensor Probe