- Published on
Communicating with a USB Device Using WinUSB 3: Talking to the Device with the WinUSB API
- Authors

- Name
- Daisuke Kobayashi
- https://twitter.com
This time we will communicate with the target device using the WinUSB API.
Include or link the following files in your project.
winusb.h:WinDDK\BuildNumber\inc\ddkwinusbio.h:WinDDK\BuildNumber\inc\ddkusb.h:WinDDK\BuildNumber\inc\apiusb100.h:WinDDK\BuildNumber\inc\apiusb200.h:WinDDK\BuildNumber\inc\apisetupapi.lib:WinDDK\BuildNumber\lib\OSVersion\CPUArchwinusb.lib:WinDDK\BuildNumber\lib\OSVersion\CPUArch
Steps:
- Obtain a handle to the device using the device interface
GUID - Initialize WinUSB using that handle
- Configure the device through the WinUSB API
- Communicate with the endpoint through the WinUSB API
// winusb.h
#ifndef __WIN_USB_H__
#define __WIN_USB_H__
// Include Windows headers
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#include <strsafe.h>
#include <string>
// Include WinUSB headers
#include <winusb.h>
#include <usb100.h>
#include <setupapi.h>
const int WINUSB_BULK_IN_PIPE_BUFSIZE = 1024;
BOOL GetDevicePath(LPGUID interface_guid, LPTSTR device_path, size_t buf_len);
HANDLE OpenDevice(LPGUID interface_guid, BOOL sync);
class WinUSB {
public:
WinUSB(LPGUID interface_guid);
~WinUSB();
BOOL Send(const std::string& buf);
BOOL Recv(std::string& buf);
private:
LPGUID interface_guid_;
HANDLE device_handle_;
WINUSB_INTERFACE_HANDLE win_usb_handle_;
unsigned char bulk_in_pipe_;
unsigned char bulk_out_pipe_;
unsigned char interrupt_pipe_;
int device_speed_;
};
#endif
// winusb.cpp
#include "stdafx.h"
#include "win_usb.h"
BOOL GetDevicePath(LPGUID interface_guid, LPTSTR device_path, size_t buf_len)
{
BOOL result = FALSE;
HDEVINFO device_info;
SP_DEVICE_INTERFACE_DATA interface_data;
PSP_DEVICE_INTERFACE_DETAIL_DATA detail_data = NULL;
ULONG length;
ULONG required_length = 0;
HRESULT hr;
device_info = SetupDiGetClassDevs(interface_guid, NULL, NULL,
DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
interface_data.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
result = SetupDiEnumDeviceInterfaces(device_info, NULL, interface_guid, 0,
&interface_data);
SetupDiGetDeviceInterfaceDetail(device_info, &interface_data, NULL, 0,
&required_length, NULL);
detail_data = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LMEM_FIXED,
required_length);
if (detail_data == NULL) {
SetupDiDestroyDeviceInfoList(device_info);
return FALSE;
}
detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
length = required_length;
result = SetupDiGetDeviceInterfaceDetail(device_info, &interface_data,
detail_data, length,
&required_length, NULL);
if (result == FALSE) {
LocalFree(detail_data);
return FALSE;
}
hr = StringCchCopy(device_path, buf_len, detail_data->DevicePath);
if (FAILED(hr)) {
SetupDiDestroyDeviceInfoList(device_info);
LocalFree(detail_data);
}
LocalFree(detail_data);
return result;
}
HANDLE OpenDevice(LPGUID interface_guid, bool sync)
{
HANDLE device_handle = NULL;
char device_path[_MAX_PATH + 1];
BOOL retval = GetDevicePath(interface_guid, (LPTSTR)device_path,
sizeof(device_path) / sizeof(device_path[0]));
device_handle = CreateFile((LPTSTR)device_path,
GENERIC_WRITE | GENERIC_READ,
FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
NULL);
return device_handle;
}
WinUSB::WinUSB(LPGUID interface_guid)
{
BOOL result;
USB_INTERFACE_DESCRIPTOR iface_descriptor;
WINUSB_PIPE_INFORMATION pipe_info;
ULONG length;
device_handle_ = OpenDevice(interface_guid, true);
result = WinUsb_Initialize(device_handle_, &win_usb_handle_);
if (result) {
length = sizeof(unsigned char);
result = WinUsb_QueryDeviceInformation(win_usb_handle_, DEVICE_SPEED,
&length, &device_speed_);
}
if (result) {
result = WinUsb_QueryInterfaceSettings(win_usb_handle_, 0,
&iface_descriptor);
}
if (result) {
for (int i = 0; i < iface_descriptor.bNumEndpoints; i++) {
result = WinUsb_QueryPipe(win_usb_handle_, 0, (unsigned char)i,
&pipe_info);
if (pipe_info.PipeType == UsbdPipeTypeBulk &&
USB_ENDPOINT_DIRECTION_IN(pipe_info.PipeId)) {
bulk_in_pipe_ = pipe_info.PipeId;
} else if (pipe_info.PipeType == UsbdPipeTypeBulk &&
USB_ENDPOINT_DIRECTION_OUT(pipe_info.PipeId)) {
bulk_out_pipe_ = pipe_info.PipeId;
} else if (pipe_info.PipeType == UsbdPipeTypeInterrupt) {
interrupt_pipe_ = pipe_info.PipeId;
} else {
result = FALSE;
break;
}
}
}
}
WinUSB::~WinUSB()
{
WinUsb_Free(win_usb_handle_);
CloseHandle(device_handle_);
}
BOOL WinUSB::Send(const std::string& buf)
{
ULONG byte_written;
BOOL result = WinUsb_WritePipe(win_usb_handle_, bulk_out_pipe_,
(unsigned char*)buf.data(),
(ULONG)buf.size(), &byte_written, NULL);
return result;
}
BOOL WinUSB::Recv(std::string& buf)
{
ULONG bytes_read;
char recvbuf[WINUSB_BULK_IN_PIPE_BUFSIZE];
BOOL result;
std::string tempbuf;
while (1) {
::ZeroMemory(recvbuf, sizeof(recvbuf));
result = WinUsb_ReadPipe(win_usb_handle_, bulk_in_pipe_,
(unsigned char*)recvbuf, sizeof(recvbuf) - 1,
&bytes_read, NULL);
if (bytes_read) {
tempbuf += recvbuf;
} else {
break;
}
}
std::string(tempbuf.data(), tempbuf.size()).swap(buf);
return result;
}
After that, instantiate the WinUSB class by passing the GUID specified in the INF file from the previous post to the constructor. You can then communicate with WinSys through Send and Recv.