Identifying USB COM device using Windows APIs - c++11

I connect to Arduino Uno R3 via a WinAPI handle.
std::string name = "COM5";
this->handle = CreateFile(name.c_str(), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
How can I safely distinguish Arduino so I am not communicating with something different or at least get its name, preferably without third party libraries? After a research I found several APIs (QueryDosDevice and NtQueryObject), however I don't know how can I implement those in my code.
EDIT: I am now able to enumerate USB devices, however I have the exact opposite problem. I do not know how to CreateFile from these:
EXTERN_C const DEVPROPKEY DECLSPEC_SELECTANY DEVPKEY_Device_BusReportedDeviceDesc = { { 0x540b947e, 0x8b40, 0x45bc, { 0xa8, 0xa2, 0x6a, 0x0b, 0x89, 0x4c, 0xbd, 0xa2 } }, 4 };
typedef BOOL(WINAPI *FN_SetupDiGetDeviceProperty)(
__in HDEVINFO DeviceInfoSet,
__in PSP_DEVINFO_DATA DeviceInfoData,
__in const DEVPROPKEY *PropertyKey,
__out DEVPROPTYPE *PropertyType,
__out_opt PBYTE PropertyBuffer,
__in DWORD PropertyBufferSize,
__out_opt PDWORD RequiredSize,
__in DWORD Flags
);
std::vector<device> usbenumerator::ListDevices()
{
DWORD dwSize;
DEVPROPTYPE ulPropertyType;
CONFIGRET status;
HDEVINFO hDevInfo;
SP_DEVINFO_DATA DeviceInfoData;
char szDeviceInstanceID[MAX_DEVICE_ID_LEN];
WCHAR szBuffer[4096];
FN_SetupDiGetDeviceProperty GetDeviceProperty = (FN_SetupDiGetDeviceProperty)(GetProcAddress(GetModuleHandle("setupapi.dll"), "SetupDiGetDevicePropertyW"));
hDevInfo = SetupDiGetClassDevs(NULL, "USB", NULL, DIGCF_ALLCLASSES | DIGCF_PRESENT);
std::vector<device> output;
if (hDevInfo == INVALID_HANDLE_VALUE)
{
return output;
}
for (int i = 0; ; i++)
{
device dev;
DeviceInfoData.cbSize = sizeof(DeviceInfoData);
if (!SetupDiEnumDeviceInfo(hDevInfo, i, &DeviceInfoData))
{
break;
}
status = CM_Get_Device_ID(DeviceInfoData.DevInst, szDeviceInstanceID, MAX_PATH, 0);
if (status != CR_SUCCESS)
{
continue;
}
std::string deviceID = szDeviceInstanceID;
dev.id = deviceID;
if (GetDeviceProperty && GetDeviceProperty(hDevInfo, &DeviceInfoData, &DEVPKEY_Device_BusReportedDeviceDesc, &ulPropertyType, (BYTE*) szBuffer, sizeof(szBuffer), &dwSize, 0))
{
if (GetDeviceProperty(hDevInfo, &DeviceInfoData, &DEVPKEY_Device_BusReportedDeviceDesc, &ulPropertyType, (BYTE*)szBuffer, sizeof(szBuffer), &dwSize, 0))
{
_bstr_t b(szBuffer);
const char* cBusReportedDesc = b;
std::string busReportedDesc = cBusReportedDesc;
dev.busReportedDesc = busReportedDesc;
}
}
output.push_back(dev);
}
return output;
}

I think I got it: I am basically making my own copy of the SymbolicName key in the Windows registry (HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\**YOUR_DEVICE_ID**\Device Parameters, for example HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\VID_2341&PID_0001\75633313233351E0A1E1\Device Parameters)
// Error checking omitted
CM_Get_Device_ID(DeviceInfoData.DevInst, szDeviceInstanceID, MAX_PATH, 0);
std::string deviceID = szDeviceInstanceID;
std::string did = deviceID;
// Convert all backslashes to hash signs
std::replace(did.begin(), did.end(), '\\', '#');
// The GUID seems to stay the same: https://learn.microsoft.com/en-us/windows-hardware/drivers/install/guid-devinterface-usb-device
std::string rid = "\\??\\" + did + "#{a5dcbf10-6530-11d2-901f-00c04fb951ed}";
handle = CreateFile(rid, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);

Related

Why timeout param doesn't work in GetAddrInfoExW()?

When I try to call:
timeval timeout{ 0, 999 };
::GetAddrInfoExW(L"my_name", L"", NS_DNS, nullptr, nullptr, &pResult, &timeout, nullptr, nullptr, nullptr);
I got 10022 "Invalid params".
However, if I replace "&timeout" with "nullptr", I got 0 (OK).
Why the timeout causes EINVAL error?
UNICODE macro is defined, my system is Windows 10.
if timeout not 0, the lpOverlapped must be also not 0. the code can be next
#include <ws2tcpip.h>
struct QUERY_CONTEXT : OVERLAPPED
{
PADDRINFOEX _pResult;
ULONG _dwThreadId = GetCurrentThreadId();
~QUERY_CONTEXT()
{
if (PADDRINFOEX pResult = _pResult)
{
FreeAddrInfoEx(_pResult);
}
}
static void CALLBACK QueryCompleteCallback(
_In_ ULONG dwError,
_In_ ULONG /*dwBytes*/,
_In_ OVERLAPPED* lpOverlapped
)
{
static_cast<QUERY_CONTEXT*>(lpOverlapped)->OnComplete(dwError);
}
void OnComplete(_In_ ULONG dwError)
{
DbgPrint("OnComplete(%u)\n");
if (PADDRINFOEX pResult = _pResult)
{
do
{
WCHAR buf[64];
ULONG len = _countof(buf);
if (!WSAAddressToStringW(pResult->ai_addr, (ULONG)pResult->ai_addrlen, 0, buf, &len))
{
DbgPrint("%S\n", buf);
}
} while (pResult = pResult->ai_next);
}
PostThreadMessageW(_dwThreadId, WM_QUIT, dwError, 0);
delete this;
}
ULONG Query(_In_ PCWSTR pName, _In_opt_ timeval *timeout)
{
ULONG dwError = GetAddrInfoExW(pName, 0, NS_DNS, 0, 0,
&_pResult, timeout, this, QueryCompleteCallback, 0);
//
// If GetAddrInfoExW() returns WSA_IO_PENDING, GetAddrInfoExW will invoke
// the completion routine. If GetAddrInfoExW returned anything else we must
// invoke the completion directly.
//
if (dwError != WSA_IO_PENDING)
{
QueryCompleteCallback(dwError, 0, this);
}
return dwError;
}
};
///////////////////////////////////////
WSADATA wd;
if (NOERROR == WSAStartup(WINSOCK_VERSION, &wd))
{
if (QUERY_CONTEXT* pqc = new QUERY_CONTEXT {})
{
timeval timeout{ 1 };
pqc->Query(L"stackoverflow.com", &timeout);
}
MessageBoxW(0, 0, 0, 0);
WSACleanup();
}
also for dns query more efficient direct use DnsQueryEx function (GetAddrInfoExW internally call DnsQueryEx, but before this - alot of another code executed)

Create Named Pipe C++ Windows

I am trying to create a simple comunication between 2 processes in C++ ( Windows ) like FIFO in linux.
This is my server:
int main()
{
HANDLE pipe = CreateFile(TEXT("\\\\.\\pipe\\Pipe"), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
ConnectNamedPipe(pipe, NULL);
while(TRUE){
string data;
DWORD numRead =1 ;
ReadFile(pipe, &data, 1024, &numRead, NULL);
cout << data << endl;
}
CloseHandle(pipe);
return 0;
}
And this is my client:
int main()
{
HANDLE pipe = CreateFile(TEXT("\\\\.\\pipe\\Pipe"), GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
ConnectNamedPipe(pipe, NULL);
string message = "TEST";
DWORD numWritten;
WriteFile(pipe, message.c_str(), message.length(), &numWritten, NULL);
return 0;
}
The code does't work , how can i fixed it to like FIFO ?
You cannot create a named pipe by calling CreateFile(..).
Have a look at the pipe examples of the MSDN. Since these examples are quite complex I've quickly written a VERY simple named pipe server and client.
int main(void)
{
HANDLE hPipe;
char buffer[1024];
DWORD dwRead;
hPipe = CreateNamedPipe(TEXT("\\\\.\\pipe\\Pipe"),
PIPE_ACCESS_DUPLEX,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, // FILE_FLAG_FIRST_PIPE_INSTANCE is not needed but forces CreateNamedPipe(..) to fail if the pipe already exists...
1,
1024 * 16,
1024 * 16,
NMPWAIT_USE_DEFAULT_WAIT,
NULL);
while (hPipe != INVALID_HANDLE_VALUE)
{
if (ConnectNamedPipe(hPipe, NULL) != FALSE) // wait for someone to connect to the pipe
{
while (ReadFile(hPipe, buffer, sizeof(buffer) - 1, &dwRead, NULL) != FALSE)
{
/* add terminating zero */
buffer[dwRead] = '\0';
/* do something with data in buffer */
printf("%s", buffer);
}
}
DisconnectNamedPipe(hPipe);
}
return 0;
}
And here is the client code:
int main(void)
{
HANDLE hPipe;
DWORD dwWritten;
hPipe = CreateFile(TEXT("\\\\.\\pipe\\Pipe"),
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (hPipe != INVALID_HANDLE_VALUE)
{
WriteFile(hPipe,
"Hello Pipe\n",
12, // = length of string + terminating '\0' !!!
&dwWritten,
NULL);
CloseHandle(hPipe);
}
return (0);
}
You should replace the name of the pipe TEXT("\\\\.\\pipe\\Pipe") by a #define which is located in a commonly used header file.

BHO object won't load, probable registration trouble?

I can't get Internet Explorer or Windows Explorer to load this BHO. Sure there's no COM objects that can be created, but Explorer can't know that until it loads the DLL and checks, but LoadLibrary isn't getting called.
The message box shows when I run regsvr32.
Windows Version = 8.1
Internet Epxlorer Version = 11
Enhance Protected Mode on or off doesn't seem to make a difference.
#include <windows.h>
#include <olectl.h>
#include <stddef.h>
#include <string.h>
#define wstrlen wcslen
HINSTANCE me;
DWORD WINAPI M4(void *junk)
{
MessageBox(NULL, "Loaded", "bho", 0);
}
BOOL WINAPI DllMain(HINSTANCE hInstDll, DWORD fdwReason, LPVOID lpReserved)
{
wchar_t mainexe[1024];
if (fdwReason == DLL_PROCESS_ATTACH) {
me = hInstDll;
DisableThreadLibraryCalls(me);
/* GetModuleFileNameW(NULL, mainexe, 1024); */
/* len = wstrlen(mainexe); */
HANDLE th = CreateThread(NULL, 32768, M4, NULL, 0, NULL);
}
return TRUE;
}
STDAPI DllGetClassObject(REFIID rclsid,REFIID riid,LPVOID *ppv)
{
return CLASS_E_CLASSNOTAVAILABLE;
}
STDAPI DllCanUnloadNow()
{
return FALSE;
}
const char *CLSID_NAME = "CLSID\\{2D3E480A-0000-0000-0000-64756D796C6472}";
const char *CLSID_IPS32 = "CLSID\\{2D3E480A-0000-0000-0000-64756D796C6472}\\InProcServer32";
const char *BHO = "Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Browser Helper Objects\\{2D3E480A-0000-0000-0000-64756D796C6472}";
const wchar_t *name = L"Redacted BHO";
const char *apt = "Apartment";
STDAPI DllRegisterServer()
{
HKEY hk;
wchar_t dllpath[1024];
GetModuleFileNameW(me,dllpath,1024);
if (RegCreateKeyEx(HKEY_CLASSES_ROOT, CLSID_NAME, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hk, NULL) != ERROR_SUCCESS)
return SELFREG_E_CLASS;
RegSetValueExW(hk, NULL, 0, REG_SZ, (const BYTE *)(name), (wstrlen(name) + 1) << 1);
RegCloseKey(hk);
if (RegCreateKeyEx(HKEY_CLASSES_ROOT, CLSID_IPS32, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hk, NULL) != ERROR_SUCCESS)
return SELFREG_E_CLASS;
RegSetValueExW(hk, NULL, 0, REG_SZ, (const BYTE *)(dllpath), (wstrlen(dllpath) + 1) << 1);
RegSetValueEx(hk, "ThreadingModel", 0, REG_SZ, (const BYTE *)(apt), 10);
RegCloseKey(hk);
if (RegCreateKeyEx(HKEY_LOCAL_MACHINE, BHO, 0, NULL, 0, KEY_ALL_ACCESS, NULL, &hk, NULL) != ERROR_SUCCESS)
return SELFREG_E_CLASS;
RegCloseKey(hk);
return S_OK;
}
STDAPI DllUnregisterServer()
{
RegDeleteKey(HKEY_LOCAL_MACHINE, BHO);
RegDeleteKey(HKEY_CLASSES_ROOT, CLSID_IPS32);
RegDeleteKey(HKEY_CLASSES_ROOT, CLSID_NAME);
}
For IE11 in enhanced protected mode (EPM), the registry must be updated with:
HKEY_CLASSES_ROOT\CLSID\{your BHO CLSID}\Implemented
Categories\{59FB2056-D625-48D0-A944-1A85B5AB2640}

Getting the version of Renesas USB 3.0 Host Controller driver on Windows

Older versions of the Renesas USB 3.0 Host Controller have issues that may cause problems. To alert my customers of such problems, I need to detect outdated versions. To do this, I want to retrieve the running driver version same as the Renesas USB 3.0 Host Controller Utility does.
With OSR IrpTracker, I've determined the IOCTL and structure. Here's sample code that opens each Renesas USB Host Controller's device interface and queries the version number.
#include <initguid.h>
#include <windows.h>
#include <setupapi.h>
#include <stdlib.h>
#include <winioctl.h>
#include <pshpack1.h>
DEFINE_GUID(GUID_DEVINTERFACE_NUSB3XHC, 0xac051b02L, 0x603b, 0x4b3c, 0xb1, 0x4b, 0x95, 0xc9, 0x26, 0x8d, 0xe0, 0x81);
struct NUSB3XHC_DRIVER_VERSION
{
UCHAR Major;
UCHAR Minor;
UCHAR Build;
UCHAR Revision;
UCHAR Unknown[2]; // no idea what this is -- {0, 0} on my machine
};
struct NUSB3XHC_FIRMWARE_VERSION
{
USHORT BcdVersion; // UI displays this as BCD
};
#define IOCTL_NUSB3XHC_GET_DRIVER_VERSION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x800, METHOD_BUFFERED, FILE_ANY_ACCESS)
#define IOCTL_NUSB3XHC_GET_FIRMWARE_VERSION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x808, METHOD_BUFFERED, FILE_ANY_ACCESS)
#include <poppack.h>
BOOL GetVersion(LPCTSTR DevicePath, NUSB3XHC_DRIVER_VERSION* DriverVersion, NUSB3XHC_FIRMWARE_VERSION* FirmwareVersion)
{
HANDLE hDevice = CreateFile(DevicePath, GENERIC_ALL, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hDevice == NULL)
return FALSE;
BOOL success = FALSE;
DWORD returned;
if (DeviceIoControl(hDevice, IOCTL_NUSB3XHC_GET_DRIVER_VERSION, NULL, 0, DriverVersion, sizeof(NUSB3XHC_DRIVER_VERSION), &returned, NULL))
{
success = (returned == sizeof(NUSB3XHC_DRIVER_VERSION));
}
if (DeviceIoControl(hDevice, IOCTL_NUSB3XHC_GET_FIRMWARE_VERSION, NULL, 0, FirmwareVersion, sizeof(NUSB3XHC_FIRMWARE_VERSION), &returned, NULL))
{
success = success && (returned == sizeof(NUSB3XHC_FIRMWARE_VERSION));
}
CloseHandle(hDevice);
return success;
}
int _tmain(int argc, _TCHAR* argv[])
{
int crap = IOCTL_NUSB3XHC_GET_FIRMWARE_VERSION;
HDEVINFO hDevInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_NUSB3XHC, NULL, NULL, DIGCF_DEVICEINTERFACE | DIGCF_PRESENT);
if (hDevInfo != INVALID_HANDLE_VALUE)
{
SP_DEVICE_INTERFACE_DATA devIfaceData;
devIfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
DWORD Index = 0;
do
{
if (!SetupDiEnumDeviceInterfaces(hDevInfo, NULL, &GUID_DEVINTERFACE_NUSB3XHC, Index, &devIfaceData))
break; // hopefully ERROR_NO_MORE_ITEMS
DWORD requiredSize;
SetupDiGetDeviceInterfaceDetail(hDevInfo, &devIfaceData, NULL, NULL, &requiredSize, NULL);
// returns with ERROR_INSUFFICIENT_BUFFER
PSP_DEVICE_INTERFACE_DETAIL_DATA devIfaceDetailData =
(PSP_DEVICE_INTERFACE_DETAIL_DATA) malloc(requiredSize);
devIfaceDetailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
if (SetupDiGetDeviceInterfaceDetail(hDevInfo, &devIfaceData, devIfaceDetailData, requiredSize, NULL, NULL))
{
NUSB3XHC_DRIVER_VERSION driverVersion;
NUSB3XHC_FIRMWARE_VERSION firmwareVersion;
if (GetVersion(devIfaceDetailData->DevicePath, &driverVersion, &firmwareVersion))
{
_tprintf(_T("%s: driver version: %d.%d.%d.%d, firmware version: %x\n"), devIfaceDetailData->DevicePath,
driverVersion.Major,
driverVersion.Minor,
driverVersion.Build,
driverVersion.Revision,
firmwareVersion.BcdVersion);
}
else
{
_tprintf(_T("Failed getting version data from %s.\n"), devIfaceDetailData->DevicePath);
}
}
free(devIfaceDetailData);
++Index;
}
while(1);
}
return 0;
}

How to convert LPWSTR to LPBYTE

I found many informations how to convert LPBYTE to LPWSTR, but no info about reverse process. I have tried do it on my own and tested such methods:
// my_documents declaration:
WCHAR my_documents[MAX_PATH];
//1st
const int size = WideCharToMultiByte(CP_UTF8, 0, my_documents, -1, NULL, 0, 0, NULL);
char *path = (char *)malloc( size );
WideCharToMultiByte(CP_UTF8, 0, my_documents, -1, path, size, 0, NULL);
//2nd
size_t i;
char *pMBBuffer = (char *)malloc( MAX_PATH );
cstombs_s(&i, pMBBuffer, MAX_PATH, my_documents, MAX_PATH-1 );
But when I write them to registry they are unreadable. And this is how I write them to registry:
BOOL SetKeyData(HKEY hRootKey, WCHAR *subKey, DWORD dwType, WCHAR *value, LPBYTE data, DWORD cbData)
{
HKEY hKey;
if(RegCreateKeyW(hRootKey, subKey, &hKey) != ERROR_SUCCESS)
return FALSE;
LSTATUS status = RegSetValueExW(hKey, value, 0, dwType, data, cbData);
if(status != ERROR_SUCCESS)
{
RegCloseKey(hKey);
return FALSE;
}
RegCloseKey(hKey);
return TRUE;
}
SetKeyData(HKEY_CURRENT_USER, L"Software\\Microsoft\\Windows\\CurrentVersion\\Run", REG_SZ, L"My program", (LPBYTE)path, size)
There is no problem with conversion, but when I try to write this to registry I get some strange chars
When you are writing a string to the wide registry functions you should not convert but pass a normal WCHAR*, just cast to LPBYTE. Just remember to get the size correct. LPBYTE is really for when you write a binary blob, every other type has to be casted...

Resources