RopSynchronizationImportReadStateChanges request buffer structure.
        public void MSOXCROPS_S11_TC03_TestRopSynchronizationImportReadStateChanges()
        {
            this.CheckTransportIsSupported();

            this.cropsAdapter.RpcConnect(
                Common.GetConfigurationPropertyValue("SutComputerName", this.Site),
                ConnectionType.PrivateMailboxServer,
                Common.GetConfigurationPropertyValue("UserEssdn", this.Site),
                Common.GetConfigurationPropertyValue("Domain", this.Site),
                Common.GetConfigurationPropertyValue("AdminUserName", this.Site),
                Common.GetConfigurationPropertyValue("PassWord", this.Site));

            // Step 1: Create a message.
            #region Create message

            // Log on to the private mailbox.
            RopLogonResponse logonResponse = Logon(LogonType.Mailbox, this.userDN, out inputObjHandle);

            RopCreateMessageRequest createMessageRequest = new RopCreateMessageRequest();
            RopCreateMessageResponse createMessageResponse;

            // Construct the RopCreateMessage request.
            createMessageRequest.RopId = (byte)RopId.RopCreateMessage;
            
            createMessageRequest.LogonId = TestSuiteBase.LogonId;
            createMessageRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex0;
            createMessageRequest.OutputHandleIndex = TestSuiteBase.OutputHandleIndex1;

            // Set CodePageId to 0x0FFF, which specified the code page of Logon object will be used.
            createMessageRequest.CodePageId = TestSuiteBase.CodePageId;

            createMessageRequest.FolderId = logonResponse.FolderIds[4];
            createMessageRequest.AssociatedFlag = Convert.ToByte(TestSuiteBase.Zero);

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 1: Begin to send the RopCreateMessage request.");

            // Send the RopCreateMessage request and verify the success response.
            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                createMessageRequest,
                this.inputObjHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);
            createMessageResponse = (RopCreateMessageResponse)response;
            Site.Assert.AreEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                createMessageResponse.ReturnValue,
                "if ROP succeeds, the ReturnValue of its response is 0(success)");
            uint targetMessageHandle = responseSOHs[0][createMessageResponse.OutputHandleIndex];

            #endregion

            // Step 2: Save message.
            #region Save message

            RopSaveChangesMessageRequest saveChangesMessageRequest;
            RopSaveChangesMessageResponse saveChangesMessageResponse;

            // Construct the RopSaveChangesMessage request.
            saveChangesMessageRequest.RopId = (byte)RopId.RopSaveChangesMessage;
            saveChangesMessageRequest.LogonId = TestSuiteBase.LogonId;
            saveChangesMessageRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex0;
            saveChangesMessageRequest.ResponseHandleIndex = TestSuiteBase.ResponseHandleIndex1;
            saveChangesMessageRequest.SaveFlags = (byte)SaveFlags.ForceSave;

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 2: Begin to send the RopSaveChangesMessage request.");

            // Send the RopSaveChangesMessage request and verify the success response.
            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                saveChangesMessageRequest,
                targetMessageHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);
            saveChangesMessageResponse = (RopSaveChangesMessageResponse)response;
            Site.Assert.AreEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                saveChangesMessageResponse.ReturnValue,
                "If ROP succeeds, the ReturnValue of its response is 0 (success).");

            #endregion

            // Step 3: Open folder.
            #region Open folder

            RopOpenFolderRequest openFolderRequest;
            RopOpenFolderResponse openFolderResponse;

            // Construct the RopOpenFolder request.
            openFolderRequest.RopId = (byte)RopId.RopOpenFolder;
            openFolderRequest.LogonId = TestSuiteBase.LogonId;
            openFolderRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex0;
            openFolderRequest.OutputHandleIndex = TestSuiteBase.OutputHandleIndex1;
            openFolderRequest.FolderId = logonResponse.FolderIds[4];
            openFolderRequest.OpenModeFlags = (byte)FolderOpenModeFlags.None;

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 3: Begin to send the RopOpenFolder request.");

            // Send the RopOpenFolder request and verify the success response.
            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                openFolderRequest,
                this.inputObjHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);
            openFolderResponse = (RopOpenFolderResponse)response;
            Site.Assert.AreEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                openFolderResponse.ReturnValue,
                "If ROP succeeds, the ReturnValue of its response is 0 (success)");

            // Get the handle of opened folder, which will be used as input handle in RopCreateFolder.
            uint openedFolderHandle = responseSOHs[0][openFolderResponse.OutputHandleIndex];

            #endregion

            // Step 4: Configure a synchronization upload context.
            #region Configure a synchronization upload context

            RopSynchronizationOpenCollectorRequest synchronizationOpenCollectorRequest;
            RopSynchronizationOpenCollectorResponse synchronizationOpenCollectorResponse;

            // Construct the RopSynchronizationOpenCollector request.
            synchronizationOpenCollectorRequest.RopId = (byte)RopId.RopSynchronizationOpenCollector;
            synchronizationOpenCollectorRequest.LogonId = TestSuiteBase.LogonId;
            synchronizationOpenCollectorRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex0;
            synchronizationOpenCollectorRequest.OutputHandleIndex = TestSuiteBase.OutputHandleIndex1;
            synchronizationOpenCollectorRequest.IsContentsCollector = Convert.ToByte(TestSuiteBase.Zero);

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 4: Begin to send the RopSynchronizationOpenCollector request.");

            // Send the RopSynchronizationOpenCollector request and verify the success response.
            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                synchronizationOpenCollectorRequest,
                openedFolderHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);
            synchronizationOpenCollectorResponse = (RopSynchronizationOpenCollectorResponse)response;
            Site.Assert.AreEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                synchronizationOpenCollectorResponse.ReturnValue,
                "If ROP succeeds, the ReturnValue of its response is 0 (success)");
            uint synchronizationUploadContextHandle = responseSOHs[0][synchronizationOpenCollectorResponse.OutputHandleIndex];

            #endregion

            // Step 5: Send the RopSynchronizationImportReadStateChanges request.
            #region RopSynchronizationImportReadStateChanges response

            RopSynchronizationImportReadStateChangesRequest synchronizationImportReadStateChangesRequest =
                new RopSynchronizationImportReadStateChangesRequest();
            MessageReadState[] messageReadStates = new MessageReadState[1];
            MessageReadState messageReadState = new MessageReadState
            {
                MarkAsRead = Convert.ToByte(TestSuiteBase.Zero)
            };

            // Send the RopLongTermIdFromId request to convert a short-term ID into a long-term ID.
            #region RopLongTermIdFromId response

            RopLongTermIdFromIdRequest ropLongTermIdFromIdRequest = new RopLongTermIdFromIdRequest();
            RopLongTermIdFromIdResponse ropLongTermIdFromIdResponse;

            ropLongTermIdFromIdRequest.RopId = (byte)RopId.RopLongTermIdFromId;
            ropLongTermIdFromIdRequest.LogonId = TestSuiteBase.LogonId;
            ropLongTermIdFromIdRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex0;
            ropLongTermIdFromIdRequest.ObjectId = saveChangesMessageResponse.MessageId;

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 5: Begin to send the RopLongTermIdFromId request.");

            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                ropLongTermIdFromIdRequest,
                this.inputObjHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);
            ropLongTermIdFromIdResponse = (RopLongTermIdFromIdResponse)response;

            #endregion

            byte[] messageID = new byte[22];
            Array.Copy(ropLongTermIdFromIdResponse.LongTermId.DatabaseGuid, 0, messageID, 0, 16);
            Array.Copy(ropLongTermIdFromIdResponse.LongTermId.GlobalCounter, 0, messageID, 16, 6);

            messageReadState.MessageId = messageID;
            messageReadState.MessageIdSize = 22;
            messageReadStates[0] = messageReadState;

            // Construct the RopSynchronizationImportReadStateChanges request.
            synchronizationImportReadStateChangesRequest.RopId = (byte)RopId.RopSynchronizationImportReadStateChanges;
            synchronizationImportReadStateChangesRequest.LogonId = TestSuiteBase.LogonId;
            synchronizationImportReadStateChangesRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex0;
            synchronizationImportReadStateChangesRequest.MessageReadStates = messageReadStates;
            synchronizationImportReadStateChangesRequest.MessageReadStateSize = (ushort)messageReadStates[0].Size();

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 5: Begin to send the RopSynchronizationImportReadStateChanges request to invoke success response.");

            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                synchronizationImportReadStateChangesRequest,
                synchronizationUploadContextHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.SuccessResponse);

            // Test RopSynchronizationImportReadStateChanges failure response.
            synchronizationImportReadStateChangesRequest.InputHandleIndex = TestSuiteBase.InputHandleIndex1;

            // Add the debug information
            Site.Log.Add(LogEntryKind.Debug, "Step 5: Begin to send the RopSynchronizationImportReadStateChanges request to invoke failure response.");

            this.responseSOHs = cropsAdapter.ProcessSingleRop(
                synchronizationImportReadStateChangesRequest,
                synchronizationUploadContextHandle,
                ref this.response,
                ref this.rawData,
                RopResponseType.FailureResponse);

            #endregion
        }
        /// <summary>
        /// Imports message read state changes into the server replica.
        /// </summary>
        /// <param name="serverId">A 32-bit signed integer represent the Identity of server.</param>
        /// <param name="objHandleIndex">Sync handle.</param>
        /// <param name="objectHandleIndex">Message handle or folder handle or attachments handle.</param>
        /// <param name="readStatus">A boolean value indicating the message read status, true means read.</param>
        /// <returns>Indicate the result of this ROP operation.</returns>
        public RopResult SynchronizationImportReadStateChanges(int serverId, int objHandleIndex, int objectHandleIndex, bool readStatus)
        {
            uint synchronizationImportReadStateChangesHandle = this.handleContainer[objHandleIndex];
            uint messageHandle = this.handleContainer[objectHandleIndex];
            RopResult result = RopResult.InvalidParameter;

            // Construct RopGetPropertiesSpecificRequest.
            RopGetPropertiesSpecificRequest getPropertiesSpecificRequest = new RopGetPropertiesSpecificRequest
            {
                RopId = 0x07,
                LogonId = 0x00,
                InputHandleIndex = 0x00,
                PropertySizeLimit = 0xFFFF
            };

            // Set PropertySizeLimit, which specifies the maximum size allowed for a property value returned,
            PropertyTag[] tagArray = new PropertyTag[1];
            PropertyTag tag = new PropertyTag(0x65E0, 0x0102);
            tagArray[0] = tag;
            getPropertiesSpecificRequest.PropertyTagCount = (ushort)tagArray.Length;
            getPropertiesSpecificRequest.PropertyTags = tagArray;

            // Get specific properties value.
            RopGetPropertiesSpecificResponse getPropertiesSpecificResponse = (RopGetPropertiesSpecificResponse)this.Process(serverId, getPropertiesSpecificRequest, messageHandle);

            MessageReadState[] messageReadStates = new MessageReadState[1];
            MessageReadState messageReadState = new MessageReadState
            {
                MarkAsRead = readStatus ? (byte)0x01 : (byte)0x00,
                MessageId = new byte[22]
            };
            Array.Copy(getPropertiesSpecificResponse.RowData.PropertyValues[0].Value, 2, messageReadState.MessageId, 0, 22);
            messageReadState.MessageIdSize = (ushort)(getPropertiesSpecificResponse.RowData.PropertyValues[0].Value.Length - 2);
            messageReadStates[0] = messageReadState;

            // Construct the RopSynchronizationImportReadStateChanges request.
            RopSynchronizationImportReadStateChangesRequest synchronizationImportReadStateChangesRequest = new RopSynchronizationImportReadStateChangesRequest
            {
                RopId = 0x80,
                LogonId = 0x00,
                InputHandleIndex = 0x00,
                MessageReadStates = messageReadStates,
                MessageReadStateSize = (ushort)messageReadStates[0].Size()
            };

            RopSynchronizationImportReadStateChangesResponse synchronizationImportReadStateChangesResponse = (RopSynchronizationImportReadStateChangesResponse)this.Process(serverId, synchronizationImportReadStateChangesRequest, synchronizationImportReadStateChangesHandle);
            result = (RopResult)synchronizationImportReadStateChangesResponse.ReturnValue;

            if (result == RopResult.Success)
            {
                // Verify ROP SynchronizationImportReadStateChanges
                this.VerifyRopSynchronizationImportReadStateChanges(synchronizationImportReadStateChangesResponse);
            }

            return result;
        }