/// <summary>
        /// Decode this PDU from the PduMarshaler.
        /// </summary>
        /// <param name="marshaler">This is used to decode the fields of this PDU.</param>
        public override bool Decode(PduMarshaler marshaler)
        {
            try
            {
                if (!base.Decode(marshaler))
                {
                    return(false);
                }
                configurationHandle = marshaler.ReadUInt32();
                numInterfaces       = marshaler.ReadUInt32();

                if (numInterfaces == 0)
                {
                    interfaces = null;
                }
                else
                {
                    interfaces = new TS_USBD_INTERFACE_INFORMATION_RESULT[numInterfaces];
                    for (int i = 0; i < numInterfaces; i++)
                    {
                        interfaces[i] = new TS_USBD_INTERFACE_INFORMATION_RESULT();
                        if (!interfaces[i].Decode(marshaler))
                        {
                            return(false);
                        }
                    }
                }
            }
            catch (Exception)
            {
                return(false);
            }
            return(true);
        }
        /// <summary>
        /// Builds an interface-selection request.
        /// </summary>
        /// <param name="configuration">The result of configuration-selection.</param>
        /// <param name="index">The index of the interface to be selected.</param>
        /// <returns>The interface-selection request.</returns>
        public TS_URB_SELECT_INTERFACE BuildSelectionInterfaceRequest(TS_URB_SELECT_CONFIGURATION_RESULT configuration, int index)
        {
            if (null == configuration)
            {
                throw new ArgumentNullException("configuration");
            }
            if (index >= configuration.Interface.Length || null == configuration.Interface[index])
            {
                throw new ArgumentException("index specified interface doesn't exist.");
            }

            TS_URB_SELECT_INTERFACE urb = new TS_URB_SELECT_INTERFACE(this.requestId, this.noAck);

            urb.ConfigurationHandle = configuration.ConfigurationHandle;
            urb.Header.Size         = 8 + 4; // Header + ConfigurationHandle
            urb.TsUsbdIInfo         = new TS_USBD_INTERFACE_INFORMATION();
            TS_USBD_INTERFACE_INFORMATION_RESULT inf = configuration.Interface[index];

            if (inf.NumberOfPipes != inf.Pipes.Length)
            {
                throw new ArgumentException(String.Format(
                                                "The selecting interface count doesn't match. NumberOfPipes: {0}, Pipes count: {1}.",
                                                inf.NumberOfPipes,
                                                inf.Pipes.Length
                                                ));
            }

            urb.TsUsbdIInfo.Length = 2 + 2 + 1 + 1 + 2 + 4;
            urb.TsUsbdIInfo.NumberOfPipesExpected = (ushort)inf.NumberOfPipes;
            urb.TsUsbdIInfo.InterfaceNumber       = inf.InterfaceNumber;
            urb.TsUsbdIInfo.AlternateSetting      = inf.AlternateSetting;
            urb.TsUsbdIInfo.Padding       = PaddingGenerator.GeneratePadding();
            urb.TsUsbdIInfo.NumberOfPipes = inf.NumberOfPipes;

            urb.TsUsbdIInfo.Infomations = new TS_USBD_PIPE_INFORMATION[inf.NumberOfPipes];
            for (int i = 0; i < inf.NumberOfPipes; i++)
            {
                urb.TsUsbdIInfo.Length        += 2 + 2 + 4 + 4; // count Pipe sizes
                urb.TsUsbdIInfo.Infomations[i] = new TS_USBD_PIPE_INFORMATION();
                urb.TsUsbdIInfo.Infomations[i].MaximumPacketSize   = inf.Pipes[i].MaximumPacketSize;
                urb.TsUsbdIInfo.Infomations[i].Padding             = PaddingGenerator.GeneratePadding();
                urb.TsUsbdIInfo.Infomations[i].MaximumTransferSize = inf.Pipes[i].MaximumTransferSize;
                urb.TsUsbdIInfo.Infomations[i].PipeFlags           = inf.Pipes[i].PipeFlags;
            }

            urb.Header.Size += urb.TsUsbdIInfo.Length; // interface information size.
            return(urb);
        }
        /// <summary>
        /// Decode this PDU from the PduMarshaler.
        /// </summary>
        /// <param name="marshaler">This is used to decode the fields of this PDU.</param>
        public override bool Decode(PduMarshaler marshaler)
        {
            try
            {
                if (!base.Decode(marshaler))
                {
                    return false;
                }
                configurationHandle = marshaler.ReadUInt32();
                numInterfaces = marshaler.ReadUInt32();

                if (numInterfaces == 0)
                {
                    interfaces = null;
                }
                else
                {
                    interfaces = new TS_USBD_INTERFACE_INFORMATION_RESULT[numInterfaces];
                    for (int i = 0; i < numInterfaces; i++)
                    {
                        interfaces[i] = new TS_USBD_INTERFACE_INFORMATION_RESULT();
                        if (!interfaces[i].Decode(marshaler))
                        {
                            return false;
                        }
                    }
                }
            }
            catch (Exception)
            {
                return false;
            }
            return true;
        }
        public void S3_EUSB_OperateIo_SelectInterface()
        {
            LogComment("S3_EUSB_OperateIo_SelectInterface");

            LogComment("1. Creates the control virtual channel, exchanges capabilities then notifies that the channel is created.");
            context.ControlChannel =  CreateVirtualChannel();

            LogComment("2. Receives an add virtual channel request.");
            rdpeusbAdapter.ExpectAddVirtualChannel(context.ControlChannel);

            LogComment("3. Creates a new virtual channel for the device.");
            DynamicVirtualChannel channel =  CreateVirtualChannel();

            LogComment("4. Receives an add device request.");
            EusbDeviceContext device = rdpeusbAdapter.ExpectAddDevice(channel);

            LogComment("5. Registers a callback to provide the Request Completion Interface to the client.");
            uint interfaceId = IdGenerator.NewId();
            rdpeusbAdapter.RegisterCallback(device, 1, interfaceId);

            LogComment("6. Select the configuration with index 0.");
            SelectConfiguration(device, 0);

            Site.Assume.IsTrue(context.SelectedConfig.NumInterfaces > 0, "The configuration must contain at least 1 interface to be selected.");

            LogComment("7. Select the interface with index 0 by sending TS_URB_SELECT_INTERFACE request.");
            uint requestId = 0; // TDI, so set to 0
            TS_URB_SELECT_INTERFACE sel = new UrbBuilder(
                URB_FUNCTIONID.URB_FUNCTION_SELECT_INTERFACE,
                requestId,
                0).BuildSelectionInterfaceRequest(context.SelectedConfig, 0);
            rdpeusbAdapter.TransferInRequest(device, sel, 0);

            LogComment("8. Receives a completion message with the result for interface selection.");
            EusbPdu pdu = rdpeusbAdapter.ExpectCompletion(device.VirtualChannel);
            Site.Assert.IsInstanceOfType(
                pdu,
                typeof(EusbUrbCompletionNoDataPdu),
                "The result must be type of EusbUrbCompletionNoDataPdu.");
            EusbUrbCompletionNoDataPdu pduRes = (EusbUrbCompletionNoDataPdu)pdu;
            Site.Assert.IsSuccess((int)pduRes.HResult, "The EusbUrbCompletionNoDataPdu must indicate successful.");
            ReqCapturer.VerifyUrbCompletionNoData(pduRes, sel, true, interfaceId);

            TS_USBD_INTERFACE_INFORMATION_RESULT urb = new TS_USBD_INTERFACE_INFORMATION_RESULT();
            Site.Assert.IsTrue(
                PduMarshaler.Unmarshal(pduRes.TsUrbResult, urb),
                "The completion PDU must contain the result.");

            LogComment("The interface-selection result is {0}.", urb);

            LogComment("9. Sends retract device request and the channel for the device is expected to be closed.");
            rdpeusbAdapter.RetractDevice(device, USB_RETRACT_REASON.UsbRetractReason_BlockedByPolicy);
        }