diff --git a/node_modules/@serialport/bindings-cpp/src/serialport_win.cpp b/node_modules/@serialport/bindings-cpp/src/serialport_win.cpp index b11c07f..910023e 100644 --- a/node_modules/@serialport/bindings-cpp/src/serialport_win.cpp +++ b/node_modules/@serialport/bindings-cpp/src/serialport_win.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #pragma comment(lib, "setupapi.lib") #define ARRAY_SIZE(arr) (sizeof(arr)/sizeof(arr[0])) @@ -25,6 +26,29 @@ typedef BOOL (WINAPI *CancelIoExType)(HANDLE hFile, LPOVERLAPPED lpOverlapped); std::list g_closingHandles; +void ErrorCodeToString(const wchar_t* prefix, int errorCode, wchar_t *errorStr) { + switch (errorCode) { + case ERROR_FILE_NOT_FOUND: + _snwprintf_s(errorStr, ERROR_STRING_SIZE, _TRUNCATE, L"%ls: File not found", prefix); + break; + case ERROR_INVALID_HANDLE: + _snwprintf_s(errorStr, ERROR_STRING_SIZE, _TRUNCATE, L"%ls: Invalid handle", prefix); + break; + case ERROR_ACCESS_DENIED: + _snwprintf_s(errorStr, ERROR_STRING_SIZE, _TRUNCATE, L"%ls: Access denied", prefix); + break; + case ERROR_OPERATION_ABORTED: + _snwprintf_s(errorStr, ERROR_STRING_SIZE, _TRUNCATE, L"%ls: Operation aborted", prefix); + break; + case ERROR_INVALID_PARAMETER: + _snwprintf_s(errorStr, ERROR_STRING_SIZE, _TRUNCATE, L"%ls: The parameter is incorrect %d", prefix, errorCode); + break; + default: + _snwprintf_s(errorStr, ERROR_STRING_SIZE, _TRUNCATE, L"%ls: Unknown error code %d", prefix, errorCode); + break; + } +} + void ErrorCodeToString(const char* prefix, int errorCode, char *errorStr) { switch (errorCode) { case ERROR_FILE_NOT_FOUND: @@ -608,9 +632,9 @@ void CloseBaton::Execute() { } } -char *copySubstring(char *someString, int n) { - char *new_ = reinterpret_cast(malloc(sizeof(char)*n + 1)); - strncpy_s(new_, n + 1, someString, n); +wchar_t *copySubstring(wchar_t *someString, int n) { + wchar_t *new_ = reinterpret_cast(malloc(sizeof(wchar_t)*n + 1)); + wcsncpy_s(new_, n + 1, someString, n); new_[n] = '\0'; return new_; } @@ -625,7 +649,7 @@ Napi::Value List(const Napi::CallbackInfo& info) { Napi::Function callback = info[0].As(); ListBaton* baton = new ListBaton(callback); - snprintf(baton->errorString, sizeof(baton->errorString), ""); + _snwprintf(baton->errorString, sizeof(baton->errorString), L""); baton->Queue(); return env.Undefined(); @@ -633,20 +657,20 @@ Napi::Value List(const Napi::CallbackInfo& info) { // It's possible that the s/n is a construct and not the s/n of the parent USB // composite device. This performs some convoluted registry lookups to fetch the USB s/n. -void getSerialNumber(const char *vid, - const char *pid, +void getSerialNumber(const wchar_t *vid, + const wchar_t *pid, const HDEVINFO hDevInfo, SP_DEVINFO_DATA deviceInfoData, const unsigned int maxSerialNumberLength, - char* serialNumber) { - _snprintf_s(serialNumber, maxSerialNumberLength, _TRUNCATE, ""); + wchar_t* serialNumber) { + _snwprintf_s(serialNumber, maxSerialNumberLength, _TRUNCATE, L""); if (vid == NULL || pid == NULL) { return; } DWORD dwSize; WCHAR szWUuidBuffer[MAX_BUFFER_SIZE]; - WCHAR containerUuid[MAX_BUFFER_SIZE]; + WCHAR wantedUuid[MAX_BUFFER_SIZE]; // Fetch the "Container ID" for this device node. In USB context, this "Container @@ -683,7 +707,7 @@ void getSerialNumber(const char *vid, // Given the UUID bytes, build up a (widechar) string from it. There's some mangling // going on. - StringFromGUID2((REFGUID)szWUuidBuffer, containerUuid, ARRAY_SIZE(containerUuid)); + StringFromGUID2((REFGUID)szWUuidBuffer, wantedUuid, ARRAY_SIZE(wantedUuid)); } else { // Container UUID could not be fetched, return empty serial number. return; @@ -693,21 +717,15 @@ void getSerialNumber(const char *vid, // This means they're non-removable, and are not handled (yet). // Maybe they should inherit the s/n from somewhere else. - // Sanitize input - for whatever reason, StringFromGUID2() returns a WCHAR* but - // the comparisons later need a plain old char*, in lowercase ASCII. - char wantedUuid[MAX_BUFFER_SIZE]; - _snprintf_s(wantedUuid, MAX_BUFFER_SIZE, _TRUNCATE, "%ws", containerUuid); - strlwr(wantedUuid); - // Iterate through all the USB devices with the given VendorID/ProductID HKEY vendorProductHKey; DWORD retCode; - char hkeyPath[MAX_BUFFER_SIZE]; + wchar_t hkeyPath[MAX_BUFFER_SIZE]; - _snprintf_s(hkeyPath, MAX_BUFFER_SIZE, _TRUNCATE, "SYSTEM\\CurrentControlSet\\Enum\\USB\\VID_%s&PID_%s", vid, pid); + _snwprintf_s(hkeyPath, MAX_BUFFER_SIZE, _TRUNCATE, L"SYSTEM\\CurrentControlSet\\Enum\\USB\\VID_%s&PID_%s", vid, pid); - retCode = RegOpenKeyEx( + retCode = RegOpenKeyExW( HKEY_LOCAL_MACHINE, hkeyPath, 0, @@ -739,9 +757,9 @@ void getSerialNumber(const char *vid, // Each of the subkeys here is the serial number of a USB device with the // given VendorId/ProductId. Now fetch the string for the S/N. DWORD serialNumberLength = maxSerialNumberLength; - retCode = RegEnumKeyEx(vendorProductHKey, + retCode = RegEnumKeyExW(vendorProductHKey, i, - serialNumber, + reinterpret_cast(serialNumber), &serialNumberLength, NULL, NULL, @@ -751,21 +769,21 @@ void getSerialNumber(const char *vid, if (retCode == ERROR_SUCCESS) { // Lookup info for VID_(vendorId)&PID_(productId)\(serialnumber) - _snprintf_s(hkeyPath, MAX_BUFFER_SIZE, _TRUNCATE, - "SYSTEM\\CurrentControlSet\\Enum\\USB\\VID_%s&PID_%s\\%s", + _snwprintf_s(hkeyPath, MAX_BUFFER_SIZE, _TRUNCATE, + L"SYSTEM\\CurrentControlSet\\Enum\\USB\\VID_%ls&PID_%ls\\%ls", vid, pid, serialNumber); HKEY deviceHKey; - if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, hkeyPath, 0, KEY_READ, &deviceHKey) == ERROR_SUCCESS) { - char readUuid[MAX_BUFFER_SIZE]; + if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, hkeyPath, 0, KEY_READ, &deviceHKey) == ERROR_SUCCESS) { + wchar_t readUuid[MAX_BUFFER_SIZE]; DWORD readSize = sizeof(readUuid); // Query VID_(vendorId)&PID_(productId)\(serialnumber)\ContainerID - retCode = RegQueryValueEx(deviceHKey, "ContainerID", NULL, NULL, (LPBYTE)&readUuid, &readSize); + retCode = RegQueryValueExW(deviceHKey, L"ContainerID", NULL, NULL, (LPBYTE)&readUuid, &readSize); if (retCode == ERROR_SUCCESS) { readUuid[readSize] = '\0'; - if (strcmp(wantedUuid, readUuid) == 0) { + if (wcscmp(wantedUuid, readUuid) == 0) { // The ContainerID UUIDs match, return now that serialNumber has // the right value. RegCloseKey(deviceHKey); @@ -783,7 +801,7 @@ void getSerialNumber(const char *vid, RegCloseKey(vendorProductHKey); } - _snprintf_s(serialNumber, maxSerialNumberLength, _TRUNCATE, ""); + _snwprintf_s(serialNumber, maxSerialNumberLength, _TRUNCATE, L""); return; } @@ -795,15 +813,15 @@ void ListBaton::Execute() { int memberIndex = 0; DWORD dwSize, dwPropertyRegDataType; - char szBuffer[MAX_BUFFER_SIZE]; - char *pnpId; - char *vendorId; - char *productId; - char *name; - char *manufacturer; - char *locationId; - char *friendlyName; - char serialNumber[MAX_REGISTRY_KEY_SIZE]; + wchar_t szBuffer[MAX_BUFFER_SIZE]; + wchar_t *pnpId; + wchar_t *vendorId; + wchar_t *productId; + wchar_t *name; + wchar_t *manufacturer; + wchar_t *locationId; + wchar_t *friendlyName; + wchar_t serialNumber[MAX_REGISTRY_KEY_SIZE]; bool isCom; while (true) { isCom = false; @@ -814,7 +832,6 @@ void ListBaton::Execute() { manufacturer = NULL; locationId = NULL; friendlyName = NULL; - isCom = false; ZeroMemory(&deviceInfoData, sizeof(SP_DEVINFO_DATA)); deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA); @@ -826,16 +843,16 @@ void ListBaton::Execute() { } dwSize = sizeof(szBuffer); - SetupDiGetDeviceInstanceId(hDevInfo, &deviceInfoData, szBuffer, dwSize, &dwSize); + SetupDiGetDeviceInstanceIdW(hDevInfo, &deviceInfoData, reinterpret_cast(szBuffer), dwSize, &dwSize); szBuffer[dwSize] = '\0'; - pnpId = strdup(szBuffer); + pnpId = wcsdup(szBuffer); - vendorId = strstr(szBuffer, "VID_"); + vendorId = wcsstr(szBuffer, L"VID_"); if (vendorId) { vendorId += 4; vendorId = copySubstring(vendorId, 4); } - productId = strstr(szBuffer, "PID_"); + productId = wcsstr(szBuffer, L"PID_"); if (productId) { productId += 4; productId = copySubstring(productId, 4); @@ -843,32 +860,29 @@ void ListBaton::Execute() { getSerialNumber(vendorId, productId, hDevInfo, deviceInfoData, MAX_REGISTRY_KEY_SIZE, serialNumber); - if (SetupDiGetDeviceRegistryProperty(hDevInfo, &deviceInfoData, + if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, &deviceInfoData, SPDRP_LOCATION_INFORMATION, &dwPropertyRegDataType, - reinterpret_cast(szBuffer), - sizeof(szBuffer), &dwSize)) { - locationId = strdup(szBuffer); + reinterpret_cast(szBuffer), sizeof(szBuffer), &dwSize)) { + locationId = wcsdup(szBuffer); } - if (SetupDiGetDeviceRegistryProperty(hDevInfo, &deviceInfoData, + if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, &deviceInfoData, SPDRP_FRIENDLYNAME, &dwPropertyRegDataType, - reinterpret_cast(szBuffer), - sizeof(szBuffer), &dwSize)) { - friendlyName = strdup(szBuffer); + reinterpret_cast(szBuffer), sizeof(szBuffer), &dwSize)) { + friendlyName = wcsdup(szBuffer); } - if (SetupDiGetDeviceRegistryProperty(hDevInfo, &deviceInfoData, + if (SetupDiGetDeviceRegistryPropertyW(hDevInfo, &deviceInfoData, SPDRP_MFG, &dwPropertyRegDataType, - reinterpret_cast(szBuffer), - sizeof(szBuffer), &dwSize)) { - manufacturer = strdup(szBuffer); + reinterpret_cast(szBuffer), sizeof(szBuffer), &dwSize)) { + manufacturer = wcsdup(szBuffer); } HKEY hkey = SetupDiOpenDevRegKey(hDevInfo, &deviceInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_READ); if (hkey != INVALID_HANDLE_VALUE) { dwSize = sizeof(szBuffer); - if (RegQueryValueEx(hkey, "PortName", NULL, NULL, (LPBYTE)&szBuffer, &dwSize) == ERROR_SUCCESS) { + if (RegQueryValueExW(hkey, L"PortName", NULL, NULL, (LPBYTE)&szBuffer, &dwSize) == ERROR_SUCCESS) { + name = wcsdup(szBuffer); szBuffer[dwSize] = '\0'; - name = strdup(szBuffer); - isCom = strstr(szBuffer, "COM") != NULL; + isCom = wcsstr(szBuffer, L"COM") != NULL; } } if (isCom) { @@ -916,6 +930,16 @@ void setIfNotEmpty(Napi::Object item, std::string key, const char *value) { } } +void setIfNotEmpty(Napi::Object item, std::string key, const wchar_t *value) { + Napi::Env env = item.Env(); + Napi::String v8key = Napi::String::New(env, key); + if (wcslen(value) > 0) { + (item).Set(v8key, Napi::String::New(env, (const char16_t*) value)); + } else { + (item).Set(v8key, env.Undefined()); + } +} + void FlushBaton::Execute() { DWORD purge_all = PURGE_RXCLEAR | PURGE_TXABORT | PURGE_TXCLEAR; if (!PurgeComm(int2handle(fd), purge_all)) { diff --git a/node_modules/@serialport/bindings-cpp/src/serialport_win.h b/node_modules/@serialport/bindings-cpp/src/serialport_win.h index f3e3c32..739b5dd 100644 --- a/node_modules/@serialport/bindings-cpp/src/serialport_win.h +++ b/node_modules/@serialport/bindings-cpp/src/serialport_win.h @@ -47,23 +47,24 @@ Napi::Value Read(const Napi::CallbackInfo& info); Napi::Value List(const Napi::CallbackInfo& info); void setIfNotEmpty(Napi::Object item, std::string key, const char *value); +void setIfNotEmpty(Napi::Object item, std::string key, const wchar_t *value); struct ListResultItem { - std::string path; - std::string manufacturer; - std::string serialNumber; - std::string pnpId; - std::string locationId; - std::string friendlyName; - std::string vendorId; - std::string productId; + std::wstring path; + std::wstring manufacturer; + std::wstring serialNumber; + std::wstring pnpId; + std::wstring locationId; + std::wstring friendlyName; + std::wstring vendorId; + std::wstring productId; }; struct ListBaton : public Napi::AsyncWorker { ListBaton(Napi::Function& callback) : Napi::AsyncWorker(callback, "node-serialport:ListBaton"), errorString() {} std::list results; - char errorString[ERROR_STRING_SIZE]; + wchar_t errorString[ERROR_STRING_SIZE]; void Execute() override; void OnOK() override {