Quantcast
Channel: Windows Virtual PC
Viewing all articles
Browse latest Browse all 24

USB Architecture in Windows Virtual PC

$
0
0

Some old legacy devices may not have driver support for newer operating systems (Windows® Vista and beyond). Windows® Virtual PC (WVPC) makes it possible to use these devices in Windows® 7, using Windows® XP Mode. Users can, at the same time, utilize the benefits of newer and secure features of Windows® 7. In this article, we will describe the USB architecture in WVPC. Typical USB devices used in a Virtual Machine (VM) are:

  • Printers
  • Flash memory sticks
  • External hard disks
  • Webcams and Digital cameras
  • Smartcards

Fig. 1

Figure 1a:  USB Menu on a Virtual Machine’s Tool Bar

Fig 2

Figure 1b:  Manage USB Devices for Virtual Applications

Details on using these devices with the VM can be found in an earlier post.

WVPC uses the Redirection Policy Manager (RPM) of the Windows to provide the USB redirection in a Virtual Machine. It loads an alternate driver in the lieu of the original driver to redirect the device to a Virtual machine. WVPC creates a virtualized host controller in the Virtual Machine that is being offered using a VPCBus Channel. For more details, please refer to earlier post.

USB Architecture

The overall USB architecture is shown in Figure 2.

Fig 3

Figure 2: USB Architecture showing a USB Device in VM

USB architecture consists of a server side component running in Host OS and a client side component running in Virtual Machine. The server side involves a Connector driver to manage USB devices and a Stub instance for every USB Device. The client side implements a VPCBus enumerated virtual host controller that supports the subset of the USB driver interfaces that are necessary for compatibility with the supported devices. The redirection process also triggers the connector driver to send commands to the guest to create the PDO for the redirected device. After this the Stub driver, Connector driver and the Virtual bus/hub driver work in unison to enable communication of commands, responses and data between physical USB device and the redirected USB device. Component details are described below:

Server Side (Host OS)

A channel is created by Virtual PC host process (VPC.exe) through the Connector Driver using VPCBus whenever a VM boots up. Also, a server side hub instance is created internally by the Connector with this channel for every VM. There are two drivers on the server side as below:

  • The Connector driver provides services regardless of the devices that are currently connected.
  • The USB Stub driver is the alternate driver loaded by the USB stack instead of the vendor supplied or system supplied driver for the device using RPM. Please refer Figure 2. The Stub driver just forwards requests from the Connector driver to the PDO created by the hub driver.

A total of up to 8 USB devices can be assigned to a VM at a time. HID and Hub Class Devices cannot be assigned to the VM. The USB devices in VM can be safely removed just like in Host OS whenever the USB device driver supports.

Client Side (Virtual Machine)

The virtual host controller is a VPCBus enumerated bus driver (USB Virtualization Bus Driver) that takes the place of normal host controller driver. It is exposed to the system as two devices – a host controller and a root-hub device.

The virtual hub (USB Virtualization Hub Driver) creates the PDOs that mirror virtualized devices in the parent partition. The PNP manager loads the Client USB device drivers (or stacks of drivers) for the device. The virtual hub driver handles the IOCTLs either locally or sends the same to the USB device using Connector Driver. Please refer Figure 3 showing the Device Manager of Guest and Host.

Fig 3B

Figure 3: A USB Device assigned to a Virtual Machine

Power State Changes of Host and Virtual Machine

USB Device assigned to a Virtual Machine reacts to the power state changes of the host OS as well as Virtual Machine. The changes are described below:

Virtual Machine Power State Changes

A USB device gets automatically assigned to host OS whenever a Virtual machine is shutdown, restarted, turned off or saved. The device remains within the VM whenever a VM is put to ‘Sleep’ state.

Host Power State Changes

USB Device gets assigned to host OS on host restart/shutdown/logoff. It remains within the VM on host sleep/hibernate.

Device Sharing vs. USB Device Redirection

Devices like printers, smart cards and USB external/flash drives are shared with Virtual Machine in Integration Features Enabled mode by the (Remote Desktop Protocol) RDP. These devices can be used with host OS as well as the Virtual Machine(s) at the same time. More details about this can be found in an earlier post.

Assigning a USB Device to a VM removes the device from host OS. It is only visible to the Virtual machine it is attached to and an application running on the host OS cannot access the device.

Prevent Device Redirection using Group Policy

Group policy can be used to prevent the redirection of selected USB devices to a Virtual Machine, for security or compliance reasons for example. This can be done at per device/device-class level. Also, all USB devices can be prevented to be used inside a VM. These settings are helpful in an organization where users are not allowed to use these devices in the physical machine as well.

These Group policy settings can be found under Computer Configuration -> Administrative Templates -> System->Device Redirection -> Device Redirection Restrictions as shown below (Figure 4).

Fig 4

Figure 4: Group Policy Settings for USB Device restrictions

There are two group policy settings for the Device Redirection Restrictions as described below:

Preventing redirection of devices that match any of these Device IDs

Enabling this policy setting will prevent the redirection of specific USB devices on a machine that matches the criteria specified in the Value field. For example, to block all USB Audio class devices (USB Class Code 01) for the redirection, the policy needs to be configured with Class_01 as shown below (Figure 5).

Fig 5

Figure 5: Group Policy setting for redirection of specific USB devices restrictions

Preventing redirection of USB devices

Enabling this policy setting will prevent the redirection of all USB devices on a machine.

More details about these policy settings can be found on MSDN here.

Implementation and Code examples

WVPC provides COM support to manage USB devices. The APIs are documented on MSDN at http://msdn.microsoft.com/en-us/library/dd796758(VS.85).aspx. Let’s take a look few scenarios for using these APIs to manage USB devices. A user wants to assign a USB Device whenever a VM is started. Another scenario is that an IT admin wants to restrict the USB Device Redirection feature due to some piracy/security concerns. In these scenarios, a developer can write scripts in VB/powershell or a code in any COM capable language to achieve this. Some samples are provided below:

Assign a USB Device

A developer can use AttachUSBDevice method of IVMVirtualMachine interface to assign a USB device to the VM. A sample C++ code is shown below:

   1:// Steps to Assign a Device
   2:// Step 1: Get the Virtual PC object
   3:// Step 2: Get the Virtual Machine Object
   4:// Step 3: Start the Virtual Machine if it's not running
   5:// Step 3: Get the USB Device Collection
   6:// Step 4: Get the USB Device Object to be assigned based on Device String
   7:// Step 5: Assign the Device
   8:  
   9:  
  10:#define CHECK_NULL_RELEASE(obj) if(obj) \
  11:                     {\
  12:                     obj->Release();\
  13:                     obj = NULL;\
  14:                     }
  15:  
  16:int __cdecl main(int , char* )
  17: {
  18:     IVMVirtualMachine*      pVM                     = NULL;
  19:     IVMVirtualPC*           pIVPC                   = NULL;
  20:     HRESULT                 hr                      = S_OK;
  21:     BSTR                    bName                   = NULL;
  22:     VMVMState               vmState                 = vmVMState_Invalid;
  23:     IVMTask*                pIVMTask                = NULL;
  24:     IVMUSBDeviceCollection* pUSBDeviceCollection    = NULL;
  25:long                    usbDeviceCount          = 0;
  26:     IVMUSBDevice*           pUsbDevice              = NULL;
  27:long                    index                   = 0;
  28:     BSTR                    bDeviceString           = NULL;
  29:bool                    bDeviceFound            = FALSE;
  30:  
  31:// Change the VM name as needed 
  32:     LPWSTR                  lVMNameToBeAssigned     = L"Windows XP Mode";
  33:  
  34:// Change the Device String as needed 
  35:     LPWSTR                  lUsbDeviceString        = L"Cruzer Micro"; //L"Mass Storage Device";
  36:  
  37:// Initialize VPC COM interfaces.
  38:     hr = InitVPCComInterfaces(&pIVPC);
  39:if (hr != S_OK)
  40:     {
  41:goto Cleanup;
  42:     }
  43:  
  44:// Allocate the Memory for the Virtual Machine Name
  45:// on which Device needs to be assigned.
  46:     bName = SysAllocString(lVMNameToBeAssigned);
  47:if (bName == NULL) // Unable to allocate the Memory for VM Name String
  48:     {
  49:         hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
  50:goto Cleanup;
  51:     }
  52:  
  53:// Get the Virtual Machine object of the provided VMNAME
  54:     hr = pIVPC->FindVirtualMachine(bName, &pVM);
  55:if (hr != S_OK)
  56:     {
  57:goto Cleanup;
  58:     }
  59:  
  60:// Start the Virtual Machine if it's not running
  61:     hr = pVM->get_State(&vmState);
  62:if (hr != S_OK)
  63:     {
  64:goto Cleanup;
  65:     }
  66:  
  67:if(vmState == vmVMState_Running)
  68:     {
  69:// VM is already Running
  70:     }
  71:else
  72:     {
  73:         hr = pVM->Startup(&pIVMTask);
  74:if (hr !=S_OK)
  75:         {
  76:goto Cleanup;
  77:         }
  78:  
  79:// Wait till the VM boots up
  80:         hr = pIVMTask->WaitForCompletion(-1);
  81:if (hr != S_OK)
  82:         {
  83:goto Cleanup;
  84:         }        
  85:     }
  86:  
  87:// Get the USB Device Collection
  88:     hr = pIVPC->get_USBDeviceCollection(&pUSBDeviceCollection);
  89:if (hr != S_OK)
  90:     {
  91:goto Cleanup;
  92:     }
  93:  
  94:// Get the USB Device Collection Count
  95:     hr = pUSBDeviceCollection->get_Count(&usbDeviceCount);
  96:if (hr != S_OK)
  97:     {
  98:goto Cleanup;
  99:     }
 100:  
 101:if (usbDeviceCount == 0)
 102:goto Cleanup;
 103:  
 104:// Iterate through the USB Device Collection for the Device to be Assigned
 105:for ( index = 1; index <= usbDeviceCount; index++)
 106:     {
 107:         hr = pUSBDeviceCollection->get_Item(index, &pUsbDevice);
 108:if (hr != S_OK)
 109:goto Cleanup;
 110:
 111:// Get the Device Name or Manufacturer String 
 112:         hr = pUsbDevice->get_DeviceString(&bDeviceString); 
 113:if (hr != S_OK)
 114:goto Cleanup;
 115:  
 116:// Check the Device String for the Match
 117:if (_wcsicmp(bDeviceString, lUsbDeviceString) == 0 )
 118:         {
 119:// Device is Found
 120:             bDeviceFound = TRUE;
 121:break;
 122:         }
 123:     }
 124:  
 125:if (bDeviceFound == TRUE)
 126:     {
 127:// Device was found above.
 128:// Assign the Device to the VM
 129:         hr = pVM->AttachUSBDevice(pUsbDevice);
 130:if (hr != S_OK)
 131:goto Cleanup;
 132:     }
 133:  
 134: Cleanup:
 135:     CHECK_NULL_RELEASE(pIVPC);
 136:     CHECK_NULL_RELEASE(pVM);
 137:     CHECK_NULL_RELEASE(pUSBDeviceCollection); 
 138:     CHECK_NULL_RELEASE(pUsbDevice); 
 139:     CHECK_NULL_RELEASE(pIVMTask);
 140:     SysFreeString(bName);
 141:     SysFreeString(bDeviceString);
 142:  
 143:return 0;
 144: }
 145:  
 146: HRESULT 
 147: InitVPCComInterfaces(
 148:             __inout IVMVirtualPC** ppIVPC
 149:     )
 150: {
 151:     HRESULT     hr      = S_OK;
 152:     BSTR        bVer    = NULL;
 153:
 154:// Initialize COM
 155:  
 156:     hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
 157:if (hr !=  S_OK) 
 158:return hr;
 159:  
 160:     REFCLSID classID = _uuidof(VMVirtualPC);
 161:  
 162:// Get the VPC object
 163:     hr = CoCreateInstance(classID, 
 164:                           NULL, 
 165:                           CLSCTX_ALL, 
 166:                           IID_IVMVirtualPC, 
 167:                           (LPVOID*)ppIVPC);
 168:  
 169:if (SUCCEEDED(hr) && (*ppIVPC != NULL))
 170:     {       
 171:// Make a call to the VPC interface and see if it works.
 172:         hr = (*ppIVPC)->get_Version(&bVer);
 173:     }
 174:  
 175:     SysFreeString(bVer);
 176:return hr;
 177: }

Release a USB Device

Similarly, a developer can use DetachUSBDevice method of IVMVirtualMachine interface to release a USB device from the VM. A sample C++ code is shown below:

   1:// Steps to Release a Device
   2:// Step 1: Get the Virtual PC object
   3:// Step 2: Get the Virtual Machine Object
   4:// Step 3: Get the USB Device Collection
   5:// Step 4: Get the USB Device Object to be assigned based on Device String
   6:// Step 5: Verify the Device is attached to the VM
   7:// Step 6: Release the USB Device
   8:  
   9:#define SAFE_RELEASE(obj) if(obj) \
  10:                     {\
  11:                     obj->Release();\
  12:                     obj = NULL;\
  13:                     }
  14:  
  15:int __cdecl main(int , char* )
  16: {
  17:     IVMVirtualMachine*      pVM                     = NULL;
  18:     IVMVirtualPC*           pIVPC                   = NULL;
  19:     HRESULT                 hr                      = S_OK;
  20:     BSTR                    bName                   = NULL;
  21:     BSTR                    bVmNameAttachedTo       = NULL;
  22:     VMVMState               vmState                 = vmVMState_Invalid;
  23:     IVMUSBDeviceCollection* pUSBDeviceCollection    = NULL;
  24:long                    usbDeviceCount          = 0;
  25:     IVMUSBDevice*           pUsbDevice              = NULL;
  26:long                    index                   = 0;
  27:     BSTR                    bDeviceString           = NULL;
  28:bool                    bDeviceFound            = FALSE;
  29:  
  30:// Change the VM name as needed 
  31:     LPWSTR                  lVMNameToBeAssigned     = L"Windows XP Mode";
  32:  
  33:// Change the Device String as needed 
  34:     LPWSTR                  lUsbDeviceString        = L"Mass Storage Device";
  35:  
  36:// Initialize VPC COM interfaces.
  37:     hr = InitVPCComInterfaces(&pIVPC);
  38:if (hr != S_OK)
  39:     {
  40:goto Cleanup;
  41:     }
  42:  
  43:// Allocate the Memory for the Virtual Machine Name
  44:// on which Device needs to be assigned.
  45:     bName = SysAllocString(lVMNameToBeAssigned);
  46:if (bName == NULL) // Unable to allocate the Memory for VM Name String
  47:     {
  48:         hr = HRESULT_FROM_WIN32(ERROR_OUTOFMEMORY);
  49:goto Cleanup;
  50:     }
  51:  
  52:// Get the Virtual Machine object of the provided VMNAME
  53:     hr = pIVPC->FindVirtualMachine(bName, &pVM);
  54:if (hr != S_OK)
  55:     {
  56:goto Cleanup;
  57:     }
  58:  
  59:// Check the Virtual Machine State for Running
  60:     hr = pVM->get_State(&vmState);
  61:if (hr != S_OK)
  62:     {
  63:goto Cleanup;
  64:     }
  65:  
  66:if(vmState == vmVMState_Running)
  67:     {
  68:// VM is Running
  69:     }
  70:else
  71:     {
  72:// VM is not Running
  73:goto Cleanup;
  74:     }
  75:  
  76:// Get the USB Device Collection
  77:     hr = pIVPC->get_USBDeviceCollection(&pUSBDeviceCollection);
  78:if (hr != S_OK)
  79:     {
  80:goto Cleanup;
  81:     }
  82:  
  83:// Get the USB Device Collection Count
  84:     hr = pUSBDeviceCollection->get_Count(&usbDeviceCount);
  85:if (hr != S_OK)
  86:     {
  87:goto Cleanup;
  88:     }
  89:  
  90:if (usbDeviceCount == 0) // No USB Devices Connected to the Machine
  91:goto Cleanup;
  92:
  93:// Iterate through the USB Device Collection for the Device to be Assigned
  94:for ( index = 1; index <= usbDeviceCount; index++)
  95:     {
  96:         hr = pUSBDeviceCollection->get_Item(index, &pUsbDevice);
  97:if (hr != S_OK)
  98:goto Cleanup;
  99:
 100:// Get the Device Name or Manufacturer String 
 101:         hr = pUsbDevice->get_DeviceString(&bDeviceString); 
 102:if (hr != S_OK)
 103:goto Cleanup;
 104:  
 105:// Check the Device String for the Match
 106:if (_wcsicmp(bDeviceString, lUsbDeviceString) == 0 )
 107:         {
 108:// Verify that the Device is attached to this VM
 109:             hr = pUsbDevice->get_AttachedToVM(&bVmNameAttachedTo); 
 110:if (hr != S_OK)
 111:goto Cleanup;
 112:  
 113:if (_wcsicmp(bVmNameAttachedTo, bName) == 0 )
 114:             {
 115:// Device is Found attached to this VM
 116:                 bDeviceFound = TRUE;
 117:break;
 118:             }
 119:         }
 120:     }
 121:  
 122:if (bDeviceFound == TRUE)
 123:     {
 124:// Device was found above.
 125:// Assign the Device to the VM
 126:         hr = pVM->DetachUSBDevice(pUsbDevice);
 127:if (hr != S_OK)
 128:goto Cleanup;
 129:     }
 130:  
 131: Cleanup:
 132:     SAFE_RELEASE(pIVPC);
 133:     SAFE_RELEASE(pVM);
 134:     SAFE_RELEASE(pUSBDeviceCollection); 
 135:     SAFE_RELEASE(pUsbDevice); 
 136:     SysFreeString(bName);
 137:     SysFreeString(bDeviceString);
 138:     SysFreeString(bVmNameAttachedTo);
 139:
 140:return 0;
 141: }
 142:  
 143: HRESULT 
 144: InitVPCComInterfaces(
 145:             __inout IVMVirtualPC** ppIVPC
 146:     )
 147: {
 148:     HRESULT     hr      = S_OK;
 149:     BSTR        bVer    = NULL;
 150:
 151:// Initialize COM
 152:  
 153:     hr = CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
 154:if (hr !=  S_OK) 
 155:return hr;
 156:  
 157:     REFCLSID classID = _uuidof(VMVirtualPC);    
 158:  
 159:// Get the VPC object
 160:     hr = CoCreateInstance(classID, 
 161:                           NULL, 
 162:                           CLSCTX_ALL, 
 163:                           IID_IVMVirtualPC, 
 164:                           (LPVOID*)ppIVPC);
 165:  
 166:if (SUCCEEDED(hr) && (*ppIVPC != NULL))
 167:     {       
 168:// Make a call to the VPC interface and see if it works.
 169:         hr = (*ppIVPC)->get_Version(&bVer);
 170:     }
 171:  
 172:     SysFreeString(bVer);
 173:return hr;
 174: }

Using Group Policy Objects to restrict USB Devices

In Windows 7, GP objects can be managed using Powershell or using COM scripts. These can be extended to restrict USB Devices in Virtual Machines.

Create own applications on top of these APIs

A device gets assigned to host OS whenever the VM is hibernated, shutdown/restarted. WVPC doesn’t provide a direct option to assign a USB device automatically in these scenarios. However, a developer can create their own applications using the above APIs.

Conclusion

Managing USB devices of Windows XP Mode and WVPC is very simple and straightforward. USB devices can be shared or even assigned to a VM. COM APIs can be used to assign-release devices or even creating applications for their own customized scenarios. We hope this information is useful to you.

Rahul Rajwanshi

SDET

Microsoft Virtualization Team


Viewing all articles
Browse latest Browse all 24

Latest Images

Trending Articles





Latest Images