private USB_STRING_DESCRIPTOR ParseStringDescriptor(EusbPdu pdu)
        {
            if (pdu is EusbUrbCompletionNoDataPdu)
            {
                Site.Log.Add(
                    LogEntryKind.Debug,
                    "Unexpectedly received an EusbUrbCompletionNoDataPdu message: {0}",
                    pdu
                    );
                return(null);
            }

            Site.Assert.IsInstanceOfType(
                pdu,
                typeof(EusbUrbCompletionPdu),
                "Must receive an EusbUrbCompletionPdu message."
                );

            EusbUrbCompletionPdu completionPdu = (EusbUrbCompletionPdu)pdu;

            Site.Assert.IsSuccess(
                (int)completionPdu.HResult,
                "the HResult member of the EusbUrbCompletionPdu must be a successful code."
                );

            USB_STRING_DESCRIPTOR res = UsbStructParser.Parse <USB_STRING_DESCRIPTOR>(completionPdu);

            Site.Assert.IsNotNull(res, "USB_STRING_DESCRIPTOR cannot be parsed from EusbUrbCompletionPdu");
            return(res);
        }
        private bool SelectConfiguration(EusbDeviceContext device, byte configIndex)
        {
            // 6. Sends TS_URB_CONTROL_DESCRIPTOR_REQUEST with the descriptor type of USB_DEVICE_DESCRIPTOR_TYPE.
            uint requestId = IdGenerator.NewId();
            TS_URB_CONTROL_DESCRIPTOR_REQUEST des = new UrbBuilder(
                URB_FUNCTIONID.URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE,
                requestId,
                0).BuildDeviceDescriptorRequest();

            rdpeusbAdapter.TransferInRequest(device, des, USB_DEVICE_DESCRIPTOR.DefaultSize);

            // 7. Receives a completion message with the result for USB_DEVICE_DESCRIPTOR.");
            EusbUrbCompletionPdu pdu = (EusbUrbCompletionPdu)rdpeusbAdapter.ExpectCompletion(device.VirtualChannel);

            if (null == pdu || pdu.HResult != (uint)HRESULT_FROM_WIN32.ERROR_SUCCESS)
            {
                return(false);
            }
            USB_DEVICE_DESCRIPTOR desDevice = UsbStructParser.Parse <USB_DEVICE_DESCRIPTOR>(pdu);

            // 8. Sends TS_URB_CONTROL_DESCRIPTOR_REQUEST to retrieve the total length of the configuration.
            requestId = IdGenerator.NewId();
            des       = new UrbBuilder(
                URB_FUNCTIONID.URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE,
                requestId,
                0).BuildConfigurationDescriptorRequest(configIndex);
            rdpeusbAdapter.TransferInRequest(device, des, USB_CONFIGURATION_DESCRIPTOR.DefaultSize);

            // 9. Receives a completion message with the result for USB_CONFIGURATION_DESCRIPTOR.");
            pdu = (EusbUrbCompletionPdu)rdpeusbAdapter.ExpectCompletion(device.VirtualChannel);
            if (null == pdu || pdu.HResult != (uint)HRESULT_FROM_WIN32.ERROR_SUCCESS)
            {
                return(false);
            }
            USB_CONFIGURATION_DESCRIPTOR desConfig = UsbStructParser.Parse <USB_CONFIGURATION_DESCRIPTOR>(pdu);

            // 10. Sends TS_URB_CONTROL_DESCRIPTOR_REQUEST with the actual length of USB_CONFIGURATION_DESCRIPTOR result.
            requestId = IdGenerator.NewId();
            des       = new UrbBuilder(
                URB_FUNCTIONID.URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE,
                requestId,
                0).BuildConfigurationDescriptorRequest(configIndex);
            rdpeusbAdapter.TransferInRequest(device, des, desConfig.wTotalLength);

            // 11. Receives a completion message with the complete result for USB_CONFIGURATION_DESCRIPTOR.");
            pdu = (EusbUrbCompletionPdu)rdpeusbAdapter.ExpectCompletion(device.VirtualChannel);

            // 12. Sends TS_URB_SELECT_CONFIGURATION URB request.
            UsbConfigurationParser configParser = new UsbConfigurationParser();

            configParser.ParseAll(pdu);
            requestId = IdGenerator.NewId();
            TS_URB_SELECT_CONFIGURATION sel = new UrbBuilder(
                URB_FUNCTIONID.URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE,
                requestId,
                0).BuildSelectConfigRequest(configParser.Interfaces, configParser.configDescriptor);

            rdpeusbAdapter.TransferInRequest(device, sel, 0);

            // 13. Receives a completion message with the result for configuration selection.");
            EusbUrbCompletionNoDataPdu pduRes = (EusbUrbCompletionNoDataPdu)rdpeusbAdapter.ExpectCompletion(device.VirtualChannel);

            if (null == pduRes || pduRes.HResult != (uint)HRESULT_FROM_WIN32.ERROR_SUCCESS)
            {
                return(false);
            }

            TS_URB_SELECT_CONFIGURATION_RESULT urb = new TS_URB_SELECT_CONFIGURATION_RESULT();

            if (!PduMarshaler.Unmarshal(pduRes.TsUrbResult, urb))
            {
                return(false);
            }

            context.SelectedConfig = urb;
            return(true);
        }