| 
			 
			 
    	    
		 | 
			
	RDOFolderSynchronizer object |   
  
RDOFolderSynchronizer allows to 
synchronize Exchange folder contents (regular or hidden messages) and subfolders. 
This object is not available for the stores other than Exchange (PST, IMAP, 
etc). 
RDOFolderSynchronizer object wraps 
the ICS (Incremental Change Synchronization) API in MAPI (IExchangeImportContentsChanges,
IExchangeImportHierarchyChanges, IExchangeExportChanges, etc). 
This is the same API used by the Exchange cached store provider to synchronize 
its folders with an Exchange Server. 
  
Returned by:  
RDOFolder2.ExchangeSynchronizer 
  
ICS API is the only supported method 
of synchronizing Exchange folders. You can use folder events (RDOItems.ItemChange
/ ItemAdd / ItemRemove), but that requires the code to be 
running at all times; plus events can be dropped under heavy loads. Also, if you 
are monitoring multiple folders, you can easily run out of the 255 RPC 
channels/process limit imposed by the Exchange Server. 
ICS API does not require persistent 
connection to the folder, you can synchronize a folder at any moment, be that 
every minute or once a month.  
  
To synchronize messages in a given 
folder (RDOFolder2 object) follow the 
steps below: 
	- 
	
Retrieve RDOFolderSynchronizer 
	object by calling RDOFolder2.ExchangeSynchronizer 
	 
	- 
	
Call 
	RDOFolderSynchronizer.SyncItems method (or SyncHiddenItems in 
	case of hidden messages or SyncFolders in case of subfolders) passing 
	the value of the RDOSyncMessagesCollection.SyncData property from the 
	previous sync cycle. When running for the very first time, pass an empty string; in 
	this case Exchange will return all existing items in the folder in the RDOSyncMessagesCollection collection. The value of the SyncData 
	property must be persisted on the per-folder basis, i.e. you cannot use the 
	value returned by synching a different folder. This value can thought of as 
	a cookie that Exchange will use next time to synchronize the folder. 
	 
	- 
	
Loop through the items in the 
	returned RDOSyncMessagesCollection (or RDOSyncFoldersCollection if calling
	SyncFolders). If you need to identify messages in the folder, it is 
	better to use the RDOSyncMessageItem.SourceKey property (corresponds to the 
	PR_SOURCE_KEY property in MAPI): the value of the entry id is not guaranteed 
	to remain the same between sessions, while source key stays the same for any 
	given message or folder. If you know the value of the source 
	key, you can retrieve the corresponding message using
	RDOExchangeStore.GetMessageFromSourceKey 
	method.  
	- 
	
Save the value of the 
	RDOSyncMessagesCollection.SyncData property for use next time (at step 
	2).  
 
If your code modifies Outlook items, 
and you need to filter out and disregard changes made by your code, compare the 
value of the PR_CHANGE_KEY MAPI property (you can access it using
RDOMail.Fields() and convert to a hex string 
using MAPIUtils.HrArrayToString) retrieved 
immediately after saving the changed item (RDOMail.Save) 
with the value of the corresponding (match by the PR_SOURCE_KEY property)
RDOSyncMessageItem.ChangeKey 
property retrieved later. If the values are the same, your code was the last to 
modify the item, if it is different, the item was modified at a later time after 
you called RDOMail.Save. 
  
The example below synchronizes the 
contents of the default Inbox folder. On the first run it will report all items 
in the folder as changed (since the sync never ran before), displays a message 
boxes to wait to the user to modify something in the folder (new message, modify 
an existing message, delete a message), then performs the sync again and reports 
the items that were added/modified/deleted while the prompt was displayed. 
  
  
    | 
	 MAPI_NO_CACHE = &H200 
	MAPI_BEST_ACCESS = &H10   
	' Optional SQL restriction: 
	' the restriction must be static, it cannot change, otherwise you will get 
	'all items in the folder back 
	' In most cases no restriction is used (pass an empty string for a 
	restriction) 
	strSQLRestriction = " MessageClass = 'IPM.Post' " 
	 
	set Session = CreateObject("Redemption.RDOSession") 
	Session.Logon ' retrieve the 
	folder to be synchronized 
	' the folder must either come from an online store (no cached mode for the 
	profile) 
	' or it can be reopened in the online mode even if the store is cached (MAPI_NO_CACHE 
	flag below) ' otherwise 
	Redemption will attempt to reopen the online version of the folder 
	' set Folder = Session.GetFolderfromID(Application.ActiveExplorer.CurrentFolder.EntryID, , 
	MAPI_BEST_ACCESS or MAPI_NO_CACHE) 
	set Folder = Session.GetDefaultFolder(olFolderInbox) 
	 
	' first synchronization 
	set Synchonizer = Folder.ExchangeSynchonizer 
	strPreviousSyncData = "" 'no data at first run, this really needs to come 
	from some persistent storage saved after the previous sync 
	set SyncItems = Synchonizer.SyncItems(strPreviousSyncData, 
	strSQLRestriction) 
	'first run will report all items in the folder as modified since 
	strPreviousSyncData is empty 
	for each Item in SyncItems 
    Debug.Print Item.Item.Subject 
	next 
	' remember/store the sync cookie 
	strPreviousSyncData = SyncItems.SyncData 
	 
	' Now modify something and report what was modified 
	' this is just an example... 
	MsgBox "Waiting for modifications. Modify an item in the folder and click Ok 
	when done" 
	 
	' collect new modifications 
	' since we are using strPreviousSyncData from the sync above, only 
	messages added/modified/deleted while the message box 
	' above was displayed will be returned 
	set SyncItems = Synchonizer.SyncItems(strPreviousSyncData, strSQLRestriction) 
	if SyncItems.Count = 0 Then     
	Debug.Print "There were no changes in the folder" 
	Else     
	Debug.Print "There were " & SyncItems.Count & " changes in the folder. The 
	list of changes follows:" 
    for each Item in SyncItems 
        if Item.Kind = 0 Then 'sikChanged 
            'modification 
	            if 
	Item.IsNewMessage Then               Debug.Print 
	"New: " & Item.Item.Subject             
	Else 
 
            Debug.Print 
	"Modified: " & Item.Item.Subject             
	End  If 
        Elseif Item.Kind = 1 Then 'sikDeleted 
            'deletion. 
	Since the item is gone, RDOSyncMessageItem.Item will be NULL 
            Debug.Print 
	"Deletion. Source key = " & Item.SourceKey 
        Elseif Item.Kind = 2 Then 'sikReadStatusChanged 
            'read/unread 
	state changed 
            Debug.Print 
	"Read/unread state changed: " & Item.Item.Subject 
        End If 
   next EndIf   
	' remember the value of the strPreviousSyncData property, we will need it 
	next time strPreviousSyncData 
	= SyncItems.SyncData ' strPreviousSyncData 
	now needs to be persisted to be used in the next sync instead of using an 
	empty string  | 
   
 
  
Methods 
Events 
  
    
	
		
  | 
	 
	
		
		Derived from: 
		IDispatch
		 | 
	 
	
		
  | 
	 
	
		
		Properties | 
	 
	
		
  | 
	 
    
		| IncludeSyncProperties  | 
	     PropList Collection that allows to specify which properties must be included 
		for sync, which can significantly reduce the network traffic during 
		synchronization  
		 | 
	    set Synchonizer = Folder.ExchangeSynchonizer 
		 
		set syncProps = Synchonizer.IncludeSyncProperties 
		syncProps.Clear 
		syncProps.Add(0x0FFF0102) 'PR_ENTRYID 
		syncProps.Add(0x0037001F) 'PR_SUBJECT_W 
		syncProps.Add(0x65E00102) 'PR_SOURCE_KEY 
		syncProps.Add(0x65E20102) 'PR_CHANGE_KEY 
		 
		 | 
	 
	
		
		
  | 
	 
	
		
		Methods | 
	 
	
		
		
  | 
	 
	
		| 
		 SyncItems(PreviousSyncData, 
		SQLRestriction)  | 
		
		 Synchronizes the folder 
		contents (messages); returns an instance of the 
		RDOSyncMessagesCollection object. 
		  
		PreviousSyncData - the 
		value returned by RDOSyncMessagesCollection.SyncData property during the 
		previous sync cycle. For the very first sync, pass an empty string. 
		  
		SQLRestriction - 
		optional, string. An optional SQL restriction (e.g. " MessageClass = 'IPM.Post' 
		"). The restriction must never change on subsequent syncs, or all items 
		in the folder will be returned 
		   | 
		
		 see example above  | 
	 
	
		| 
		 SyncHiddenItems(PreviousSyncData, 
		SQLRestriction)  | 
		
		 Synchronizes the folder 
		associated contents (hidden messages); returns an instance of the 
		RDOSyncMessagesCollection object. 
		  
		PreviousSyncData - the 
		value returned by RDOSyncMessagesCollection.SyncData property during the 
		previous sync cycle. For the very first sync, pass an empty string. 
		  
		SQLRestriction - 
		optional, string. An optional SQL restriction. The restriction must 
		never change on subsequent syncs, or all items in the folder will be 
		returned 
		   | 
		
		  | 
	 
	
		| 
		 SyncFolders(PreviousSyncData, 
		SQLRestriction)  | 
		
		 Synchronizes the subfolders; 
		returns an instance of the RDOSyncFoldersCollection object. 
		  
		PreviousSyncData - the 
		value returned by RDOSyncFoldersCollection.SyncData property during the 
		previous sync cycle. For the very first sync, pass an empty string. 
		  
		SQLRestriction - 
		optional, string. An optional SQL restriction. The restriction must 
		never change on subsequent syncs, or all subfolders in the folder will 
		be returned 
		   | 
		
		  | 
	 
	
		
		
  | 
	 
	
		
		Events
		 | 
	 
	
		
		
  | 
	 
	
		| 
		 OnProgress(Step, 
		Progress, ByRef Cancel)  | 
		
		 Occurs every time Redemption 
		calls IExchangeExportChanges::Synchronize() MAPI method. 
		  
		Step - integer 
		Progress - integer 
		Cancel (by reference) 
		-  boolean, set this parameter to TRUE to cancel the sync process.  | 
		
		    | 
	 
	
		| 
		 OnSyncFolder(Folder, 
		ByRef Cancel) 
		   | 
		
		 Occurs each time ICS sends a 
		subfolder change/delete notification. 
		  
		Folder -
		RDOSyncFolderItem object. 
		  
		Cancel (by reference) 
		- boolean, set this parameter to TRUE to cancel the sync process. 
		   | 
		
		    | 
	 
	
		| 
		 OnSyncHiddenItem(Item, 
		RyRef TargetMessage, ByRef Cancel) 
		   | 
		
		 Occurs each time ICS sends a 
		hidden message add/change/delete notification. 
		  
		Item -
		RDOSyncMessageItem object 
		representing added/changed/deleted message in the folder. 
		  
		TargetMessage (by 
		reference) - RDOMail object. Redemption passes NULL to the event 
		handler. You optionally can return a message from your callback; in this 
		case ICS will populate it with the changed properties from the source 
		message (see an example below) 
		  
		Cancel (by reference) 
		- boolean, set this parameter to TRUE to cancel the sync process. 
		   | 
		
		    | 
	 
	
		| 
		 OnSyncItem(Item, RyRef 
		TargetMessage, ByRef Cancel) 
		   | 
		
		 Occurs each time ICS sends a 
		message add/change/delete notification. 
		  
		Item -
		RDOSyncMessageItem object 
		representing added/changed/deleted message in the folder. 
		  
		TargetMessage (by 
		reference) - RDOMail object. Redemption passes NULL to the event 
		handler. You optionally can return a message from your callback; in this 
		case ICS will populate it with the changed properties from the source 
		message (see an example below) 
		  
		Cancel (by reference) 
		- boolean, set this parameter to TRUE to cancel the sync process. 
		   | 
		
		
		 private 
		RDOSession 
		session = null;
		
		private 
		RDOFolderSynchronizer 
		synchronizer = null;
		
		private 
		string strSyncData 
		= "";
		
		  
		
		private 
		void button1_Click(object 
		sender, EventArgs 
		e) 
		{ 
		  
		if (session ==
		null) 
		  { 
		    session =
		new 
		RDOSession(); 
		    
		session.Logon("Test",
		"", 
		false, 
		true, 0, 
		false); 
		  } 
		  
		RDOFolderSynchronizer 
		synchronizer = ((RDOFolder2)session.GetDefaultFolder(rdoDefaultFolders.olFolderDrafts)).ExchangeSynchonizer; 
		  
		synchronizer.OnSyncItem += new
		
		IRDOFolderSynchronizerEvents_OnSyncItemEventHandler(synchronizer_OnSyncItem); 
		  
		RDOSyncMessagesCollection 
		items = synchronizer.SyncItems(strSyncData, 
		""); 
		  strSyncData = 
		items.SyncData; 
		} 
		
		
		void 
		synchronizer_OnSyncItem(RDOSyncMessageItem 
		Item, out
		RDOMail 
		TargetMessage, ref
		bool Cancel) 
		{ 
		  
		//Item parameter 
		
		   
		if (Item.Kind !=
		rdoSyncItemKind.sikDeleted)
		  { 
		     
		//just a simple example of a user 
		notification.
		
		     
		//We check above for 
		RDOSyncMessageItem.Kind != rdoSyncItemKind.sikDeleted
		
		
		    //since for the 
		deleted messages we cannot access the RDOSyncMessageItem.Item
		
		     
		//property and retrieve any message 
		properties
		
		     
		MessageBox.Show(Item.Item.Subject);
		  } 
		   
		//TargetMessage parameter - if this 
		parameter is set to an RDOMail object by the event handler,
		
		
		  //ICS will populate the message 
		properties.
		
		   
		//This is optional, you can simply do 
		nothing.
		
		   
		//This parameter is only valid for the 
		sikChanged notifications, other notification
		
		   
		//kinds (sikDeleted and 
		sikReadStatusChanged) are easy to handle explicitly
		
		  TargetMessage =  
		null; 
		//we may set it below, it is an optional 
		step
		
		   
		if (Item.Kind ==
		rdoSyncItemKind.sikChanged)
		  { 
		     
		//this check is not really necessary, you 
		can return a new/existing message
		
		     
		//We do this just for the simplicity sake 
		so that we won't have to search for an existing message 
		
		   
		  if (Item.IsNewMessage)
		
		    { 
		     
		 //lets create a new message in the 
		Deleted Items folder and let Exchange populate its properties
		
		     
		 //this is optional and not very 
		real-life like, but why not?
		
		      
		TargetMessage = session.GetDefaultFolder( rdoDefaultFolders.olFolderDeletedItems).Items.Add("IPM.Note");
		    } 
		  } 
		   
		//Cancel parameter
		
		
		  //this is a good place to display 
		a progress UI and allow the user to cancel 
		
		
		  //the sync by setting the Cancel 
		parameter to true
		
		
		  //Note that 
		RDOFolderSynchronizer.SyncItems/SyncHiddenItems will return a
		
		
		  //MAPI_E_USER_CANCEL error if the 
		sync is canceled.
		
		
		  //Cancel = true;
		
		}  
		
		   | 
	 
	
		| 
		 | 
	 
	 
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
  
                 |