/// <summary>
        /// Get the properties' value from the rows of the table.
        /// </summary>
        /// <param name="tableHandle">The table handle.</param>
        /// <param name="rowCount">The amount of the rows.</param>
        /// <param name="properties">The properties need to show.</param>
        /// <returns>The property rows in the specified table object.</returns>
        protected List<PropertyRow> GetTableRowValue(uint tableHandle, ushort rowCount, PropertyTag[] properties)
        {
            #region The client calls RopSetColumns operation to set the property information to show.

            RopSetColumnsRequest setColumnsRequest = new RopSetColumnsRequest();
            object ropResponse = new object();
            setColumnsRequest.RopId = (byte)RopId.RopSetColumns;
            setColumnsRequest.LogonId = Constants.CommonLogonId;
            setColumnsRequest.InputHandleIndex = Constants.CommonInputHandleIndex;
            setColumnsRequest.PropertyTagCount = (ushort)properties.Length;
            setColumnsRequest.PropertyTags = properties;
            setColumnsRequest.SetColumnsFlags = (byte)AsynchronousFlags.None;
            this.Adapter.DoRopCall(setColumnsRequest, tableHandle, ref ropResponse, ref this.responseHandles);
            #endregion

            #region The client calls RopQueryRows operation to query the folder which have the special properties.

            RopQueryRowsRequest queryRowsRequest = new RopQueryRowsRequest();
            ropResponse = new object();
            queryRowsRequest.RopId = (byte)RopId.RopQueryRows;
            queryRowsRequest.LogonId = Constants.CommonLogonId;
            queryRowsRequest.InputHandleIndex = Constants.CommonInputHandleIndex;
            queryRowsRequest.RowCount = (ushort)rowCount;
            queryRowsRequest.QueryRowsFlags = (byte)QueryRowsFlags.Advance;
            queryRowsRequest.ForwardRead = 0x01;
            this.Adapter.DoRopCall(queryRowsRequest, tableHandle, ref ropResponse, ref this.responseHandles);
            RopQueryRowsResponse queryRowsResponse = (RopQueryRowsResponse)ropResponse;
            Site.Assert.AreEqual<uint>(Constants.SuccessCode, queryRowsResponse.ReturnValue, "RopQueryRows ROP operation performs successful!");
            #endregion

            List<PropertyRow> propertyRows = null;

            if (queryRowsResponse.RowData != null)
            {
                propertyRows = queryRowsResponse.RowData.PropertyRows;
            }

            return propertyRows;
        }
        public void MSOXCMSG_S01_TC01_RopCreateMessageAndRopSaveChangesMessage()
        {
            this.CheckMapiHttpIsSupported();
            this.ConnectToServer(ConnectionType.PrivateMailboxServer);

            #region Call RopLogon to log on a private mailbox.
            RopLogonResponse logonResponse = this.Logon(LogonType.Mailbox, out this.insideObjHandle);
            #endregion

            #region Call RopOpenFolder to open inbox folder
            uint openedFolderHandle = this.OpenSpecificFolder(logonResponse.FolderIds[4], this.insideObjHandle);
            #endregion

            #region Call RopGetContentsTable to get the contents table of inbox folder before create message.
            RopGetContentsTableRequest getContentsTableRequest = new RopGetContentsTableRequest()
            {
                RopId = (byte)RopId.RopGetContentsTable,
                LogonId = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,
                OutputHandleIndex = CommonOutputHandleIndex,
                TableFlags = (byte)FolderTableFlags.None
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getContentsTableRequest, openedFolderHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopGetContentsTableResponse getContentsTableResponse = (RopGetContentsTableResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, getContentsTableResponse.ReturnValue, "Call RopGetContentsTable should success.");
            uint rowCount = getContentsTableResponse.RowCount;
            #endregion

            #region Call RopCreateMessage to create new not FAI Message object.
            RopCreateMessageRequest createMessageRequest = new RopCreateMessageRequest()
            {
                RopId = (byte)RopId.RopCreateMessage,
                LogonId = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,
                OutputHandleIndex = CommonOutputHandleIndex,
                CodePageId = 0x0FFF, // Code page of Logon object is used
                FolderId = logonResponse.FolderIds[4], // Create a message in INBOX which root is mailbox 
                AssociatedFlag = 0x00 // NOT an FAI message
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(createMessageRequest, this.insideObjHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopCreateMessageResponse createMessageResponse = (RopCreateMessageResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, createMessageResponse.ReturnValue, "Call RopCreateMessage should success.");
            uint targetMessageHandle = this.ResponseSOHs[0][createMessageResponse.OutputHandleIndex];

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R991, The HasMessageId field is {0}", createMessageResponse.HasMessageId);

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R991
            bool isVerifiedR991 = createMessageResponse.HasMessageId == 0x00 && createMessageResponse.MessageId == null;

            this.Site.CaptureRequirementIfIsTrue(
                isVerifiedR991,
                991,
                @"[In RopCreateMessage ROP Response Buffer] [HasMessageId] The value 0x00 means this is the last byte in the buffer.");
            #endregion

            #region Call RopGetContentsTable to get the contents table of inbox folder before save message.
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getContentsTableRequest, openedFolderHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            getContentsTableResponse = (RopGetContentsTableResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, createMessageResponse.ReturnValue, "Call RopGetContents should success.");

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R339");

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R339
            this.Site.CaptureRequirementIfAreEqual<uint>(
                rowCount,
                getContentsTableResponse.RowCount,
                339,
                @"[In Receiving a RopCreateMessage ROP Request] When processing the RopCreateMessage ROP ([MS-OXCROPS] section 2.2.6.2), the server MUST NOT commit the new Message object until it [server] receives a RopSaveChangesMessage ROP request ([MS-OXCROPS] section 2.2.6.3).");
            #endregion

            #region Call RopSaveChangesMessage to commit the Message object created.
            RopSaveChangesMessageResponse saveChangesMessageResponse = this.SaveMessage(targetMessageHandle, (byte)SaveFlags.ForceSave);
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, saveChangesMessageResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R728");

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R728
            this.Site.CaptureRequirementIfAreEqual<int>(
                8,
                BitConverter.GetBytes(saveChangesMessageResponse.MessageId).Length,
                728,
                @"[In RopSaveChangesMessage ROP Response Buffer] Message Id: 8 bytes containing the MID ([MS-OXCDATA] section 2.2.1.2) for the saved Message object.");

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R372, the MID in RopSaveChangesMessage Response is {0}.", saveChangesMessageResponse.MessageId);

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R372
            // Because the R728 verify the RopSaveChangesMessage ROP response contains a MID and it's length is 8 bytes.
            // So R372 will be verified directly.
            this.Site.CaptureRequirement(
                372,
                @"[In Receiving a RopSaveChangesMessage ROP Request] The response contains the MID ([MS-OXCDATA] section 2.2.1.2) of the committed message.");

            #endregion

            #region Call RopGetContentsTable to get the contents table of inbox folder after save message.
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(getContentsTableRequest, openedFolderHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            getContentsTableResponse = (RopGetContentsTableResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, createMessageResponse.ReturnValue, "Call RopGetContents should success.");
            uint contentTableHandle = this.ResponseSOHs[0][getContentsTableResponse.OutputHandleIndex];

            #region Verify MS-OXCMSG_R700, MS-OXCMSG_R687
            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R687");

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R687
            // If the e-mail in the Inbox one more than before Call RopSaveChangeMessage, then R687 will be verified.
            this.Site.CaptureRequirementIfAreEqual<uint>(
                rowCount + 1,
                getContentsTableResponse.RowCount,
                687,
                @"[In RopCreateMessage ROP] The RopCreateMessage ROP ([MS-OXCROPS] section 2.2.6.2) is used to create a new Message object.");

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R700");

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R700
            this.Site.CaptureRequirementIfAreEqual<uint>(
                rowCount + 1,
                getContentsTableResponse.RowCount,
                700,
                @"[In RopSaveChangesMessage ROP] The RopSaveChangesMessage ROP ([MS-OXCROPS] section 2.2.6.3) commits the changes made to the Message object.");
            #endregion
            #endregion

            #region Call RopSetColumns to sets the properties visible on contents table.
            PropertyTag[] propertyTags = new PropertyTag[1];

            // The PropertyTag of PidTagMid.
            propertyTags[0] = new PropertyTag(0x674A, (ushort)PropertyType.PtypInteger64);
            RopSetColumnsRequest setColumnsRequest = new RopSetColumnsRequest()
            {
                RopId = (byte)RopId.RopSetColumns,
                LogonId = CommonLogonId,

                // Set InputHandleIndex to 0x00, which specifies the location in the Server object handle table where the handle
                // for the input Server object is stored, as specified in [MS-OXCROPS].
                InputHandleIndex = CommonInputHandleIndex,
                SetColumnsFlags = (byte)AsynchronousFlags.None,
                PropertyTagCount = (ushort)propertyTags.Length,
                PropertyTags = propertyTags
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(setColumnsRequest, contentTableHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopSetColumnsResponse setColumnsResponse = (RopSetColumnsResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, setColumnsResponse.ReturnValue, "Call RopSetColumns should success.");
            #endregion

            #region Call RopQueryRows to retrieve rows from contents table.
            RopQueryRowsRequest queryRowsRequest = new RopQueryRowsRequest()
            {
                RopId = (byte)RopId.RopQueryRows,
                LogonId = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,
                QueryRowsFlags = (byte)QueryRowsFlags.Advance,
                ForwardRead = 0x01,
                RowCount = 0x1000
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(queryRowsRequest, contentTableHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopQueryRowsResponse queryRowsResponse = (RopQueryRowsResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, setColumnsResponse.ReturnValue, "Call RopQueryRowsRequest should success.");

            ulong messageID = 0;
            foreach (PropertyRow row in queryRowsResponse.RowData.PropertyRows)
            {
                ulong actualMID = BitConverter.ToUInt64(row.PropertyValues[0].Value, 0);

                if (actualMID == saveChangesMessageResponse.MessageId)
                {
                    messageID = actualMID;
                    break;
                }
            }

            Site.Assert.AreNotEqual<ulong>(messageID, 0, "The Message ID should in the contents table of the specified Folder object");
            #endregion

            #region Call RopOpenMessage to open the specific Message object.
            RopOpenMessageRequest openMessageRequest = new RopOpenMessageRequest()
            {
                RopId = (byte)RopId.RopOpenMessage,
                LogonId = CommonLogonId,
                InputHandleIndex = CommonInputHandleIndex,
                OutputHandleIndex = CommonOutputHandleIndex,
                CodePageId = 0x0FFF, // Code page of Logon object is used
                FolderId = logonResponse.FolderIds[4],
                OpenModeFlags = 0x00,
                MessageId = messageID
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(openMessageRequest, this.insideObjHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);

            RopOpenMessageResponse openMessageResponse = (RopOpenMessageResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, setColumnsResponse.ReturnValue, "Call RopOpenMessage should success.");

            #region Verify MS-OXCMSG_R647, MS-OXCMSG_R372
            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R647");

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R647
            this.Site.CaptureRequirementIfAreEqual<uint>(
                TestSuiteBase.Success,
                openMessageResponse.ReturnValue,
                647,
                @"[In RopOpenMessage ROP] The RopOpenMessage ROP ([MS-OXCROPS] section 2.2.6.1) provides access to an existing Message object, which is identified by the message ID (MID), whose structure is specified in [MS-OXCDATA] section 2.2.1.2.<7>");

            // Add the debug information
            this.Site.Log.Add(LogEntryKind.Debug, "Verify MS-OXCMSG_R251");

            // Verify MS-OXCMSG requirement: MS-OXCMSG_R251
            this.Site.CaptureRequirementIfAreEqual<uint>(
                TestSuiteBase.Success,
                openMessageResponse.ReturnValue,
                251,
                @"[In Sending a RopOpenMessage ROP Request] The MID is accessible from the contents table of the Folder object that contains the Message object by including the PidTagMid property ([MS-OXCFXICS] section 2.2.1.2.1) in a RopSetColumns ROP request ([MS-OXCROPS] section 2.2.5.1), as specified in [MS-OXCTABL] section 2.2.2.2.");
            #endregion
            #endregion

            #region Call RopRelease to release all resources
            this.ReleaseRop(targetMessageHandle);
            #endregion
        }
        /// <summary>
        /// Get the properties' value from the rows of the table.
        /// </summary>
        /// <param name="tableHandle">The table handle.</param>
        /// <param name="rowCount">The amount of the rows.</param>
        /// <param name="properties">The properties need to show.</param>
        /// <returns>The property rows in the specified table object.</returns>
        private List<PropertyRow> GetTableRowValue(uint tableHandle, ushort rowCount, PropertyTag[] properties)
        {
            #region The client calls RopSetColumns operation to set the property information to show.

            RopSetColumnsRequest setColumnsRequest = new RopSetColumnsRequest
            {
                RopId = (byte)RopId.RopSetColumns,
                LogonId = TestSuiteBase.LogonId,
                InputHandleIndex = TestSuiteBase.InputHandleIndex0,
                PropertyTagCount = (ushort)properties.Length,
                PropertyTags = properties,
                SetColumnsFlags = (byte)AsynchronousFlags.None
            };
            this.responseSOHs = this.cropsAdapter.ProcessSingleRop(
                    setColumnsRequest,
                    tableHandle,
                    ref this.response,
                    ref this.rawData,
                    RopResponseType.SuccessResponse);
            RopSetColumnsResponse setColumnsResponse = (RopSetColumnsResponse)this.response;

            Site.Assert.AreEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                setColumnsResponse.ReturnValue,
                "if ROP succeeds, the ReturnValue of its response is 0(success)");

            #endregion

            #region The client calls RopQueryRows operation to query the folder which have the special properties.

            RopQueryRowsRequest queryRowsRequest = new RopQueryRowsRequest
            {
                RopId = (byte)RopId.RopQueryRows,
                LogonId = TestSuiteBase.LogonId,
                InputHandleIndex = TestSuiteBase.InputHandleIndex0,
                RowCount = (ushort)rowCount,
                QueryRowsFlags = (byte)QueryRowsFlags.Advance,
                ForwardRead = 0x01
            };
            this.responseSOHs = this.cropsAdapter.ProcessSingleRop(
                    queryRowsRequest,
                    tableHandle,
                    ref this.response,
                    ref this.rawData,
                    RopResponseType.SuccessResponse);
            RopQueryRowsResponse queryRowsResponse = (RopQueryRowsResponse)this.response;

            Site.Assert.AreEqual<uint>(
                TestSuiteBase.SuccessReturnValue,
                queryRowsResponse.ReturnValue,
                "if ROP succeeds, the ReturnValue of its response is 0(success)");

            #endregion

            return queryRowsResponse.RowData.PropertyRows;
        }
        /// <summary>
        /// Set the specified columns that want to be returned.
        /// </summary>
        /// <param name="propertyTags">The specified columns.</param>
        /// <param name="objHandle">The object handle.</param>
        protected void SetColumnsSuccess(PropertyTag[] propertyTags, uint objHandle)
        {
            RopSetColumnsRequest setColumnsRequest = new RopSetColumnsRequest()
            {
                RopId = (byte)RopId.RopSetColumns,
                LogonId = CommonLogonId,

                // Set InputHandleIndex to 0x00, which specifies the location in the Server object handle table where the handle for the input Server object is stored, as specified in [MS-OXCROPS] section 2.2.5.1.1.
                InputHandleIndex = CommonInputHandleIndex,
                SetColumnsFlags = (byte)AsynchronousFlags.None,
                PropertyTagCount = (ushort)propertyTags.Length,
                PropertyTags = propertyTags
            };
            this.ResponseSOHs = this.MSOXCMSGAdapter.DoRopCall(setColumnsRequest, objHandle, ref this.response, ref this.rawData, GetPropertiesFlags.None);
            RopSetColumnsResponse setColumnsResponse = (RopSetColumnsResponse)this.response;
            Site.Assert.AreEqual<uint>(TestSuiteBase.Success, setColumnsResponse.ReturnValue, TestSuiteBase.ROPSucceedMsg);
        }