Do not use FTDI driver to fetch COM name, and search for MODEM devices
This commit is contained in:
parent
ba48714bcb
commit
d0aab972b6
|
@ -2,7 +2,7 @@
|
|||
* SerialPort_Windows.c
|
||||
*
|
||||
* Created on: Feb 25, 2012
|
||||
* Last Updated on: Jan 20, 2022
|
||||
* Last Updated on: Jan 21, 2022
|
||||
* Author: Will Hedgecock
|
||||
*
|
||||
* Copyright (C) 2012-2022 Fazecast, Inc.
|
||||
|
@ -32,10 +32,11 @@
|
|||
#include <windows.h>
|
||||
#include <delayimp.h>
|
||||
#include <direct.h>
|
||||
#include <ntddmodm.h>
|
||||
#include <ntddser.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <setupapi.h>
|
||||
#include <shellapi.h>
|
||||
#include <devpkey.h>
|
||||
#include <devguid.h>
|
||||
#include "ftdi/ftd2xx.h"
|
||||
|
@ -75,9 +76,6 @@ jfieldID eventFlagsField;
|
|||
// Runtime-loadable DLL functions
|
||||
typedef int (__stdcall *FT_CreateDeviceInfoListFunction)(LPDWORD);
|
||||
typedef int (__stdcall *FT_GetDeviceInfoListFunction)(FT_DEVICE_LIST_INFO_NODE*, LPDWORD);
|
||||
typedef int (__stdcall *FT_GetComPortNumberFunction)(FT_HANDLE, LPLONG);
|
||||
typedef int (__stdcall *FT_OpenFunction)(int, FT_HANDLE*);
|
||||
typedef int (__stdcall *FT_CloseFunction)(FT_HANDLE);
|
||||
|
||||
// List of available serial ports
|
||||
serialPortVector serialPorts = { NULL, 0, 0 };
|
||||
|
@ -107,139 +105,149 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
|
|||
|
||||
// Enumerate all serial ports present on the current system
|
||||
wchar_t comPort[128];
|
||||
HDEVINFO devList = SetupDiGetClassDevsW(&GUID_DEVCLASS_PORTS, NULL, NULL, DIGCF_PRESENT);
|
||||
if (devList != INVALID_HANDLE_VALUE)
|
||||
const struct { GUID guid; DWORD flags; } setupClasses[] = {
|
||||
{ .guid = GUID_DEVCLASS_PORTS, .flags = DIGCF_PRESENT },
|
||||
{ .guid = GUID_DEVCLASS_MODEM, .flags = DIGCF_PRESENT },
|
||||
{ .guid = GUID_DEVCLASS_MULTIPORTSERIAL, .flags = DIGCF_PRESENT },
|
||||
{ .guid = GUID_DEVINTERFACE_COMPORT, .flags = DIGCF_PRESENT | DIGCF_DEVICEINTERFACE },
|
||||
{ .guid = GUID_DEVINTERFACE_MODEM, .flags = DIGCF_PRESENT | DIGCF_DEVICEINTERFACE }
|
||||
};
|
||||
for (int i = 0; i < (sizeof(setupClasses) / sizeof(setupClasses[0])); ++i)
|
||||
{
|
||||
// Iterate through all devices
|
||||
DWORD devInterfaceIndex = 0;
|
||||
DEVPROPTYPE devInfoPropType;
|
||||
SP_DEVINFO_DATA devInfoData;
|
||||
devInfoData.cbSize = sizeof(devInfoData);
|
||||
while (SetupDiEnumDeviceInfo(devList, devInterfaceIndex++, &devInfoData))
|
||||
HDEVINFO devList = SetupDiGetClassDevsW(&setupClasses[i].guid, NULL, NULL, setupClasses[i].flags);
|
||||
if (devList != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
// Fetch the corresponding COM port for this device
|
||||
wchar_t *comPortString = NULL;
|
||||
DWORD comPortLength = sizeof(comPort) / sizeof(wchar_t);
|
||||
HKEY key = SetupDiOpenDevRegKey(devList, &devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
|
||||
if ((key != INVALID_HANDLE_VALUE) && (RegQueryValueExW(key, L"PortName", NULL, NULL, (BYTE*)comPort, &comPortLength) == ERROR_SUCCESS))
|
||||
comPortString = (comPort[0] == L'\\') ? (wcsrchr(comPort, L'\\') + 1) : comPort;
|
||||
if (key != INVALID_HANDLE_VALUE)
|
||||
RegCloseKey(key);
|
||||
if (!comPortString)
|
||||
continue;
|
||||
// Iterate through all devices
|
||||
DWORD devInterfaceIndex = 0;
|
||||
DEVPROPTYPE devInfoPropType;
|
||||
SP_DEVINFO_DATA devInfoData;
|
||||
devInfoData.cbSize = sizeof(devInfoData);
|
||||
while (SetupDiEnumDeviceInfo(devList, devInterfaceIndex++, &devInfoData))
|
||||
{
|
||||
// Fetch the corresponding COM port for this device
|
||||
wchar_t *comPortString = NULL;
|
||||
DWORD comPortLength = sizeof(comPort) / sizeof(wchar_t);
|
||||
HKEY key = SetupDiOpenDevRegKey(devList, &devInfoData, DICS_FLAG_GLOBAL, 0, DIREG_DEV, KEY_QUERY_VALUE);
|
||||
if ((key != INVALID_HANDLE_VALUE) && (RegQueryValueExW(key, L"PortName", NULL, NULL, (BYTE*)comPort, &comPortLength) == ERROR_SUCCESS))
|
||||
comPortString = (comPort[0] == L'\\') ? (wcsrchr(comPort, L'\\') + 1) : comPort;
|
||||
if (key != INVALID_HANDLE_VALUE)
|
||||
RegCloseKey(key);
|
||||
if (!comPortString)
|
||||
continue;
|
||||
|
||||
// Fetch the friendly name for this device
|
||||
DWORD friendlyNameLength = 0;
|
||||
wchar_t *friendlyNameString = NULL;
|
||||
SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_FriendlyName, &devInfoPropType, NULL, 0, &friendlyNameLength, 0);
|
||||
if (!friendlyNameLength)
|
||||
SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_FRIENDLYNAME, NULL, NULL, 0, &friendlyNameLength);
|
||||
if (friendlyNameLength)
|
||||
{
|
||||
friendlyNameString = (wchar_t*)malloc(friendlyNameLength);
|
||||
if (!SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_FriendlyName, &devInfoPropType, (BYTE*)friendlyNameString, friendlyNameLength, NULL, 0) &&
|
||||
!SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_FRIENDLYNAME, NULL, (BYTE*)friendlyNameString, friendlyNameLength, NULL))
|
||||
// Fetch the friendly name for this device
|
||||
DWORD friendlyNameLength = 0;
|
||||
wchar_t *friendlyNameString = NULL;
|
||||
SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_FriendlyName, &devInfoPropType, NULL, 0, &friendlyNameLength, 0);
|
||||
if (!friendlyNameLength)
|
||||
SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_FRIENDLYNAME, NULL, NULL, 0, &friendlyNameLength);
|
||||
if (friendlyNameLength)
|
||||
{
|
||||
friendlyNameLength = comPortLength;
|
||||
friendlyNameString = (wchar_t*)realloc(friendlyNameString, comPortLength);
|
||||
wcscpy_s(friendlyNameString, comPortLength / sizeof(wchar_t), comPortString);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
friendlyNameLength = comPortLength;
|
||||
friendlyNameString = (wchar_t*)malloc(comPortLength);
|
||||
wcscpy_s(friendlyNameString, comPortLength / sizeof(wchar_t), comPortString);
|
||||
}
|
||||
|
||||
// Fetch the bus-reported device description
|
||||
DWORD portDescriptionLength = 0;
|
||||
wchar_t *portDescriptionString = NULL;
|
||||
SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_BusReportedDeviceDesc, &devInfoPropType, NULL, 0, &portDescriptionLength, 0);
|
||||
if (portDescriptionLength)
|
||||
{
|
||||
portDescriptionString = (wchar_t*)malloc(portDescriptionLength);
|
||||
if (!SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_BusReportedDeviceDesc, &devInfoPropType, (BYTE*)portDescriptionString, portDescriptionLength, NULL, 0))
|
||||
{
|
||||
portDescriptionString = (wchar_t*)realloc(portDescriptionString, friendlyNameLength);
|
||||
wcscpy_s(portDescriptionString, friendlyNameLength / sizeof(wchar_t), friendlyNameString);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
portDescriptionString = (wchar_t*)malloc(friendlyNameLength);
|
||||
wcscpy_s(portDescriptionString, friendlyNameLength / sizeof(wchar_t), friendlyNameString);
|
||||
}
|
||||
|
||||
// Fetch the physical location for this device
|
||||
wchar_t *locationString = NULL;
|
||||
DWORD locationLength = 0, busNumber = -1, hubNumber = -1, portNumber = -1;
|
||||
if (!SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_BusNumber, &devInfoPropType, (BYTE*)&busNumber, sizeof(busNumber), NULL, 0) &&
|
||||
!SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_BUSNUMBER, NULL, (BYTE*)&busNumber, sizeof(busNumber), NULL))
|
||||
busNumber = -1;
|
||||
if (!SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_Address, &devInfoPropType, (BYTE*)&portNumber, sizeof(portNumber), NULL, 0) &&
|
||||
!SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_ADDRESS, NULL, (BYTE*)&portNumber, sizeof(portNumber), NULL))
|
||||
portNumber = -1;
|
||||
SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_LocationInfo, &devInfoPropType, NULL, 0, &locationLength, 0);
|
||||
if (!locationLength)
|
||||
SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_LOCATION_INFORMATION, NULL, NULL, 0, &locationLength);
|
||||
if (locationLength)
|
||||
{
|
||||
locationString = (wchar_t*)malloc(locationLength);
|
||||
if (SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_LocationInfo, &devInfoPropType, (BYTE*)locationString, locationLength, NULL, 0) ||
|
||||
SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_LOCATION_INFORMATION, NULL, (BYTE*)locationString, locationLength, NULL))
|
||||
{
|
||||
if (wcsstr(locationString, L"Hub"))
|
||||
hubNumber = _wtoi(wcschr(wcsstr(locationString, L"Hub"), L'#') + 1);
|
||||
if ((portNumber == -1) && wcsstr(locationString, L"Port"))
|
||||
friendlyNameString = (wchar_t*)malloc(friendlyNameLength);
|
||||
if (!SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_FriendlyName, &devInfoPropType, (BYTE*)friendlyNameString, friendlyNameLength, NULL, 0) &&
|
||||
!SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_FRIENDLYNAME, NULL, (BYTE*)friendlyNameString, friendlyNameLength, NULL))
|
||||
{
|
||||
wchar_t *portString = wcschr(wcsstr(locationString, L"Port"), L'#') + 1;
|
||||
if (portString)
|
||||
{
|
||||
wchar_t *end = wcschr(portString, L'.');
|
||||
if (end)
|
||||
*end = L'\0';
|
||||
}
|
||||
portNumber = _wtoi(portString);
|
||||
friendlyNameLength = comPortLength;
|
||||
friendlyNameString = (wchar_t*)realloc(friendlyNameString, comPortLength);
|
||||
wcscpy_s(friendlyNameString, comPortLength / sizeof(wchar_t), comPortString);
|
||||
}
|
||||
}
|
||||
free(locationString);
|
||||
}
|
||||
if (busNumber == -1)
|
||||
busNumber = 0;
|
||||
if (hubNumber == -1)
|
||||
hubNumber = 0;
|
||||
if (portNumber == -1)
|
||||
portNumber = 0;
|
||||
locationString = (wchar_t*)malloc(32*sizeof(wchar_t));
|
||||
_snwprintf_s(locationString, 32, 32, L"%d-%d.%d", busNumber, hubNumber, portNumber);
|
||||
|
||||
// Check if port is already enumerated
|
||||
serialPort *port = fetchPort(&serialPorts, comPortString);
|
||||
if (port)
|
||||
{
|
||||
// See if device has changed locations
|
||||
port->enumerated = 1;
|
||||
int oldLength = wcslen(port->portLocation);
|
||||
int newLength = wcslen(locationString);
|
||||
if (oldLength != newLength)
|
||||
else
|
||||
{
|
||||
port->portLocation = (wchar_t*)realloc(port->portLocation, (1 + newLength) * sizeof(wchar_t));
|
||||
wcscpy_s(port->portLocation, 32, locationString);
|
||||
friendlyNameLength = comPortLength;
|
||||
friendlyNameString = (wchar_t*)malloc(comPortLength);
|
||||
wcscpy_s(friendlyNameString, comPortLength / sizeof(wchar_t), comPortString);
|
||||
}
|
||||
else if (wcscmp(port->portLocation, locationString))
|
||||
wcscpy_s(port->portLocation, 32, locationString);
|
||||
}
|
||||
else
|
||||
pushBack(&serialPorts, comPortString, friendlyNameString, portDescriptionString, locationString);
|
||||
|
||||
// Clean up memory and reset device info structure
|
||||
free(locationString);
|
||||
free(portDescriptionString);
|
||||
free(friendlyNameString);
|
||||
devInfoData.cbSize = sizeof(devInfoData);
|
||||
// Fetch the bus-reported device description
|
||||
DWORD portDescriptionLength = 0;
|
||||
wchar_t *portDescriptionString = NULL;
|
||||
SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_BusReportedDeviceDesc, &devInfoPropType, NULL, 0, &portDescriptionLength, 0);
|
||||
if (portDescriptionLength)
|
||||
{
|
||||
portDescriptionString = (wchar_t*)malloc(portDescriptionLength);
|
||||
if (!SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_BusReportedDeviceDesc, &devInfoPropType, (BYTE*)portDescriptionString, portDescriptionLength, NULL, 0))
|
||||
{
|
||||
portDescriptionString = (wchar_t*)realloc(portDescriptionString, friendlyNameLength);
|
||||
wcscpy_s(portDescriptionString, friendlyNameLength / sizeof(wchar_t), friendlyNameString);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
portDescriptionString = (wchar_t*)malloc(friendlyNameLength);
|
||||
wcscpy_s(portDescriptionString, friendlyNameLength / sizeof(wchar_t), friendlyNameString);
|
||||
}
|
||||
|
||||
// Fetch the physical location for this device
|
||||
wchar_t *locationString = NULL;
|
||||
DWORD locationLength = 0, busNumber = -1, hubNumber = -1, portNumber = -1;
|
||||
if (!SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_BusNumber, &devInfoPropType, (BYTE*)&busNumber, sizeof(busNumber), NULL, 0) &&
|
||||
!SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_BUSNUMBER, NULL, (BYTE*)&busNumber, sizeof(busNumber), NULL))
|
||||
busNumber = -1;
|
||||
if (!SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_Address, &devInfoPropType, (BYTE*)&portNumber, sizeof(portNumber), NULL, 0) &&
|
||||
!SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_ADDRESS, NULL, (BYTE*)&portNumber, sizeof(portNumber), NULL))
|
||||
portNumber = -1;
|
||||
SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_LocationInfo, &devInfoPropType, NULL, 0, &locationLength, 0);
|
||||
if (!locationLength)
|
||||
SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_LOCATION_INFORMATION, NULL, NULL, 0, &locationLength);
|
||||
if (locationLength)
|
||||
{
|
||||
locationString = (wchar_t*)malloc(locationLength);
|
||||
if (SetupDiGetDevicePropertyW(devList, &devInfoData, &DEVPKEY_Device_LocationInfo, &devInfoPropType, (BYTE*)locationString, locationLength, NULL, 0) ||
|
||||
SetupDiGetDeviceRegistryPropertyW(devList, &devInfoData, SPDRP_LOCATION_INFORMATION, NULL, (BYTE*)locationString, locationLength, NULL))
|
||||
{
|
||||
if (wcsstr(locationString, L"Hub"))
|
||||
hubNumber = _wtoi(wcschr(wcsstr(locationString, L"Hub"), L'#') + 1);
|
||||
if ((portNumber == -1) && wcsstr(locationString, L"Port"))
|
||||
{
|
||||
wchar_t *portString = wcschr(wcsstr(locationString, L"Port"), L'#') + 1;
|
||||
if (portString)
|
||||
{
|
||||
wchar_t *end = wcschr(portString, L'.');
|
||||
if (end)
|
||||
*end = L'\0';
|
||||
}
|
||||
portNumber = _wtoi(portString);
|
||||
}
|
||||
}
|
||||
free(locationString);
|
||||
}
|
||||
if (busNumber == -1)
|
||||
busNumber = 0;
|
||||
if (hubNumber == -1)
|
||||
hubNumber = 0;
|
||||
if (portNumber == -1)
|
||||
portNumber = 0;
|
||||
locationString = (wchar_t*)malloc(32*sizeof(wchar_t));
|
||||
_snwprintf_s(locationString, 32, 32, L"%d-%d.%d", busNumber, hubNumber, portNumber);
|
||||
|
||||
// Check if port is already enumerated
|
||||
serialPort *port = fetchPort(&serialPorts, comPortString);
|
||||
if (port)
|
||||
{
|
||||
// See if device has changed locations
|
||||
port->enumerated = 1;
|
||||
int oldLength = wcslen(port->portLocation);
|
||||
int newLength = wcslen(locationString);
|
||||
if (oldLength != newLength)
|
||||
{
|
||||
port->portLocation = (wchar_t*)realloc(port->portLocation, (1 + newLength) * sizeof(wchar_t));
|
||||
wcscpy_s(port->portLocation, 32, locationString);
|
||||
}
|
||||
else if (wcscmp(port->portLocation, locationString))
|
||||
wcscpy_s(port->portLocation, 32, locationString);
|
||||
}
|
||||
else
|
||||
pushBack(&serialPorts, comPortString, friendlyNameString, portDescriptionString, locationString);
|
||||
|
||||
// Clean up memory and reset device info structure
|
||||
free(locationString);
|
||||
free(portDescriptionString);
|
||||
free(friendlyNameString);
|
||||
devInfoData.cbSize = sizeof(devInfoData);
|
||||
}
|
||||
SetupDiDestroyDeviceInfoList(devList);
|
||||
}
|
||||
SetupDiDestroyDeviceInfoList(devList);
|
||||
}
|
||||
|
||||
// Attempt to locate any FTDI-specified port descriptions
|
||||
|
@ -248,10 +256,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
|
|||
{
|
||||
FT_CreateDeviceInfoListFunction FT_CreateDeviceInfoList = (FT_CreateDeviceInfoListFunction)GetProcAddress(ftdiLibInstance, "FT_CreateDeviceInfoList");
|
||||
FT_GetDeviceInfoListFunction FT_GetDeviceInfoList = (FT_GetDeviceInfoListFunction)GetProcAddress(ftdiLibInstance, "FT_GetDeviceInfoList");
|
||||
FT_GetComPortNumberFunction FT_GetComPortNumber = (FT_GetComPortNumberFunction)GetProcAddress(ftdiLibInstance, "FT_GetComPortNumber");
|
||||
FT_OpenFunction FT_Open = (FT_OpenFunction)GetProcAddress(ftdiLibInstance, "FT_Open");
|
||||
FT_CloseFunction FT_Close = (FT_CloseFunction)GetProcAddress(ftdiLibInstance, "FT_Close");
|
||||
if (FT_CreateDeviceInfoList && FT_GetDeviceInfoList && FT_GetComPortNumber && FT_Open && FT_Close)
|
||||
if (FT_CreateDeviceInfoList && FT_GetDeviceInfoList)
|
||||
{
|
||||
DWORD numDevs;
|
||||
if ((FT_CreateDeviceInfoList(&numDevs) == FT_OK) && (numDevs > 0))
|
||||
|
@ -273,30 +278,24 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
|
|||
}
|
||||
|
||||
// Update the port description if not already open
|
||||
if (!isOpen)
|
||||
if (!isOpen && getPortPathFromSerial(comPort, devInfo[i].SerialNumber))
|
||||
{
|
||||
LONG comPortNumber = 0;
|
||||
if ((FT_Open(i, &devInfo[i].ftHandle) == FT_OK) && (FT_GetComPortNumber(devInfo[i].ftHandle, &comPortNumber) == FT_OK))
|
||||
{
|
||||
// Close port and check if actually connected and present in the port list
|
||||
FT_Close(devInfo[i].ftHandle);
|
||||
swprintf(comPort, sizeof(comPort) / sizeof(wchar_t), L"COM%ld", comPortNumber);
|
||||
for (int j = 0; j < serialPorts.length; ++j)
|
||||
if (wcscmp(serialPorts.ports[j]->portPath, comPort) == 0)
|
||||
// Check if actually connected and present in the port list
|
||||
for (int j = 0; j < serialPorts.length; ++j)
|
||||
if (wcscmp(serialPorts.ports[j]->portPath, comPort) == 0)
|
||||
{
|
||||
// Update the port description
|
||||
serialPorts.ports[j]->enumerated = 1;
|
||||
size_t descLength = 8 + strlen(devInfo[i].Description);
|
||||
wchar_t *newMemory = (wchar_t*)realloc(serialPorts.ports[j]->portDescription, descLength*sizeof(wchar_t));
|
||||
if (newMemory)
|
||||
{
|
||||
// Update the port description
|
||||
serialPorts.ports[j]->enumerated = 1;
|
||||
size_t descLength = 8+strlen(devInfo[i].Description);
|
||||
wchar_t *newMemory = (wchar_t*)realloc(serialPorts.ports[j]->portDescription, descLength*sizeof(wchar_t));
|
||||
if (newMemory)
|
||||
{
|
||||
serialPorts.ports[j]->portDescription = newMemory;
|
||||
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, devInfo[i].Description, -1, serialPorts.ports[j]->portDescription, descLength);
|
||||
}
|
||||
memcpy(serialPorts.ports[j]->serialNumber, devInfo[i].SerialNumber, sizeof(serialPorts.ports[j]->serialNumber));
|
||||
break;
|
||||
serialPorts.ports[j]->portDescription = newMemory;
|
||||
MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, devInfo[i].Description, -1, serialPorts.ports[j]->portDescription, descLength);
|
||||
}
|
||||
}
|
||||
memcpy(serialPorts.ports[j]->serialNumber, devInfo[i].SerialNumber, sizeof(serialPorts.ports[j]->serialNumber));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -444,85 +443,8 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Reduce the port's latency timer to minimum value of 2
|
||||
HKEY key, paramKey = 0;
|
||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Enum\\FTDIBUS", 0, KEY_READ, &key) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD index = 0, subkeySize = 255, portNameSize = 16;
|
||||
wchar_t *subkey = (wchar_t*)malloc(subkeySize*sizeof(wchar_t)), *regPortName = (wchar_t*)malloc(portNameSize*sizeof(wchar_t));
|
||||
while (RegEnumKeyExW(key, index++, subkey, &subkeySize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD latency = 2, oldLatency = 2, oldLatencySize = sizeof(DWORD);
|
||||
char *subkeyString = (char*)malloc(subkeySize + 2);
|
||||
memset(subkeyString, 0, subkeySize + 2);
|
||||
wcstombs(subkeyString, subkey, subkeySize + 1);
|
||||
subkeySize = 255;
|
||||
portNameSize = 16;
|
||||
memset(regPortName, 0, portNameSize * sizeof(wchar_t));
|
||||
wcscat_s(subkey, subkeySize, L"\\0000\\Device Parameters");
|
||||
if (RegOpenKeyExW(key, subkey, 0, KEY_QUERY_VALUE, ¶mKey) == ERROR_SUCCESS)
|
||||
{
|
||||
if ((RegQueryValueExW(paramKey, L"PortName", NULL, NULL, (LPBYTE)regPortName, &portNameSize) == ERROR_SUCCESS) && (wcscmp(port->portPath + 4, regPortName) == 0))
|
||||
RegQueryValueExW(paramKey, L"LatencyTimer", NULL, NULL, (LPBYTE)&oldLatency, &oldLatencySize);
|
||||
RegCloseKey(paramKey);
|
||||
}
|
||||
if (oldLatency > latency)
|
||||
{
|
||||
if (RegOpenKeyExW(key, subkey, 0, KEY_SET_VALUE, ¶mKey) == ERROR_SUCCESS)
|
||||
{
|
||||
RegSetValueExW(paramKey, L"LatencyTimer", 0, REG_DWORD, (LPBYTE)&latency, sizeof(latency));
|
||||
RegCloseKey(paramKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create registry update file
|
||||
char *workingDirectory = _getcwd(NULL, 0);
|
||||
wchar_t *workingDirectoryWide = _wgetcwd(NULL, 0);
|
||||
int workingDirectoryLength = strlen(workingDirectory) + 1;
|
||||
char *registryFileName = (char*)malloc(workingDirectoryLength + 8);
|
||||
wchar_t *paramsString = (wchar_t*)malloc((workingDirectoryLength + 11) * sizeof(wchar_t));
|
||||
sprintf(registryFileName, "%s\\del.reg", workingDirectory);
|
||||
swprintf(paramsString, workingDirectoryLength + 11, L"/s %s\\del.reg", workingDirectoryWide);
|
||||
FILE *registryFile = fopen(registryFileName, "wb");
|
||||
if (registryFile)
|
||||
{
|
||||
fprintf(registryFile, "Windows Registry Editor Version 5.00\n\n");
|
||||
fprintf(registryFile, "[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Enum\\FTDIBUS\\%s\\0000\\Device Parameters]\n", subkeyString);
|
||||
fprintf(registryFile, "\"LatencyTimer\"=dword:00000002\n\n");
|
||||
fclose(registryFile);
|
||||
}
|
||||
|
||||
// Launch a new administrative process to update the registry value
|
||||
SHELLEXECUTEINFOW shExInfo = { 0 };
|
||||
shExInfo.cbSize = sizeof(shExInfo);
|
||||
shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
|
||||
shExInfo.hwnd = NULL;
|
||||
shExInfo.lpVerb = L"runas";
|
||||
shExInfo.lpFile = L"C:\\Windows\\regedit.exe";
|
||||
shExInfo.lpParameters = paramsString;
|
||||
shExInfo.lpDirectory = NULL;
|
||||
shExInfo.nShow = SW_SHOW;
|
||||
shExInfo.hInstApp = 0;
|
||||
if (ShellExecuteExW(&shExInfo))
|
||||
{
|
||||
WaitForSingleObject(shExInfo.hProcess, INFINITE);
|
||||
CloseHandle(shExInfo.hProcess);
|
||||
}
|
||||
|
||||
// Delete the registry update file
|
||||
remove(registryFileName);
|
||||
free(workingDirectoryWide);
|
||||
free(workingDirectory);
|
||||
free(registryFileName);
|
||||
free(paramsString);
|
||||
}
|
||||
}
|
||||
free(subkeyString);
|
||||
}
|
||||
RegCloseKey(key);
|
||||
free(regPortName);
|
||||
free(subkey);
|
||||
}
|
||||
// Reduce the port's latency to its minimum value
|
||||
reduceLatencyToMinimum(port->portPath + 4);
|
||||
|
||||
// Try to open the serial port with read/write access
|
||||
if ((port->handle = CreateFileW(portName, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH | FILE_FLAG_OVERLAPPED, NULL)) != INVALID_HANDLE_VALUE)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* WindowsHelperFunctions.c
|
||||
*
|
||||
* Created on: May 05, 2015
|
||||
* Last Updated on: Jan 06, 2022
|
||||
* Last Updated on: Jan 22, 2022
|
||||
* Author: Will Hedgecock
|
||||
*
|
||||
* Copyright (C) 2012-2022 Fazecast, Inc.
|
||||
|
@ -24,6 +24,13 @@
|
|||
*/
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WINVER _WIN32_WINNT_VISTA
|
||||
#define _WIN32_WINNT _WIN32_WINNT_VISTA
|
||||
#define NTDDI_VERSION NTDDI_VISTA
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <direct.h>
|
||||
#include <shellapi.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "WindowsHelperFunctions.h"
|
||||
|
@ -100,4 +107,124 @@ void removePort(serialPortVector* vector, serialPort* port)
|
|||
free(port);
|
||||
}
|
||||
|
||||
// Windows-specific functionality
|
||||
void reduceLatencyToMinimum(const wchar_t* portName)
|
||||
{
|
||||
// Search for this port in all FTDI enumerated ports
|
||||
HKEY key, paramKey = 0;
|
||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Enum\\FTDIBUS", 0, KEY_READ, &key) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD index = 0, subkeySize = 255, portNameSize = 16;
|
||||
wchar_t *subkey = (wchar_t*)malloc(subkeySize*sizeof(wchar_t)), *regPortName = (wchar_t*)malloc(portNameSize*sizeof(wchar_t));
|
||||
while (RegEnumKeyExW(key, index++, subkey, &subkeySize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD latency = 2, oldLatency = 2, oldLatencySize = sizeof(DWORD);
|
||||
char *subkeyString = (char*)malloc(subkeySize + 2);
|
||||
memset(subkeyString, 0, subkeySize + 2);
|
||||
wcstombs(subkeyString, subkey, subkeySize + 1);
|
||||
subkeySize = 255;
|
||||
portNameSize = 16;
|
||||
memset(regPortName, 0, portNameSize * sizeof(wchar_t));
|
||||
wcscat_s(subkey, subkeySize, L"\\0000\\Device Parameters");
|
||||
if (RegOpenKeyExW(key, subkey, 0, KEY_QUERY_VALUE, ¶mKey) == ERROR_SUCCESS)
|
||||
{
|
||||
if ((RegQueryValueExW(paramKey, L"PortName", NULL, NULL, (LPBYTE)regPortName, &portNameSize) == ERROR_SUCCESS) && (wcscmp(portName, regPortName) == 0))
|
||||
RegQueryValueExW(paramKey, L"LatencyTimer", NULL, NULL, (LPBYTE)&oldLatency, &oldLatencySize);
|
||||
RegCloseKey(paramKey);
|
||||
}
|
||||
if (oldLatency > latency)
|
||||
{
|
||||
if (RegOpenKeyExW(key, subkey, 0, KEY_SET_VALUE, ¶mKey) == ERROR_SUCCESS)
|
||||
{
|
||||
RegSetValueExW(paramKey, L"LatencyTimer", 0, REG_DWORD, (LPBYTE)&latency, sizeof(latency));
|
||||
RegCloseKey(paramKey);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create registry update file
|
||||
char *workingDirectory = _getcwd(NULL, 0);
|
||||
wchar_t *workingDirectoryWide = _wgetcwd(NULL, 0);
|
||||
int workingDirectoryLength = strlen(workingDirectory) + 1;
|
||||
char *registryFileName = (char*)malloc(workingDirectoryLength + 8);
|
||||
wchar_t *paramsString = (wchar_t*)malloc((workingDirectoryLength + 11) * sizeof(wchar_t));
|
||||
sprintf(registryFileName, "%s\\del.reg", workingDirectory);
|
||||
swprintf(paramsString, workingDirectoryLength + 11, L"/s %s\\del.reg", workingDirectoryWide);
|
||||
FILE *registryFile = fopen(registryFileName, "wb");
|
||||
if (registryFile)
|
||||
{
|
||||
fprintf(registryFile, "Windows Registry Editor Version 5.00\n\n");
|
||||
fprintf(registryFile, "[HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Enum\\FTDIBUS\\%s\\0000\\Device Parameters]\n", subkeyString);
|
||||
fprintf(registryFile, "\"LatencyTimer\"=dword:00000002\n\n");
|
||||
fclose(registryFile);
|
||||
}
|
||||
|
||||
// Launch a new administrative process to update the registry value
|
||||
SHELLEXECUTEINFOW shExInfo = { 0 };
|
||||
shExInfo.cbSize = sizeof(shExInfo);
|
||||
shExInfo.fMask = SEE_MASK_NOCLOSEPROCESS;
|
||||
shExInfo.hwnd = NULL;
|
||||
shExInfo.lpVerb = L"runas";
|
||||
shExInfo.lpFile = L"C:\\Windows\\regedit.exe";
|
||||
shExInfo.lpParameters = paramsString;
|
||||
shExInfo.lpDirectory = NULL;
|
||||
shExInfo.nShow = SW_SHOW;
|
||||
shExInfo.hInstApp = 0;
|
||||
if (ShellExecuteExW(&shExInfo))
|
||||
{
|
||||
WaitForSingleObject(shExInfo.hProcess, INFINITE);
|
||||
CloseHandle(shExInfo.hProcess);
|
||||
}
|
||||
|
||||
// Delete the registry update file
|
||||
remove(registryFileName);
|
||||
free(workingDirectoryWide);
|
||||
free(workingDirectory);
|
||||
free(registryFileName);
|
||||
free(paramsString);
|
||||
}
|
||||
}
|
||||
free(subkeyString);
|
||||
}
|
||||
RegCloseKey(key);
|
||||
free(regPortName);
|
||||
free(subkey);
|
||||
}
|
||||
}
|
||||
|
||||
int getPortPathFromSerial(wchar_t* portPath, const char* serialNumber)
|
||||
{
|
||||
// Search for this port in all FTDI enumerated ports
|
||||
int found = 0;
|
||||
HKEY key, paramKey = 0;
|
||||
if (RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SYSTEM\\CurrentControlSet\\Enum\\FTDIBUS", 0, KEY_READ, &key) == ERROR_SUCCESS)
|
||||
{
|
||||
DWORD index = 0, subkeySize = 255, portNameSize = 16;
|
||||
wchar_t *subkey = (wchar_t*)malloc(subkeySize * sizeof(wchar_t));
|
||||
while (RegEnumKeyExW(key, index++, subkey, &subkeySize, NULL, NULL, NULL, NULL) == ERROR_SUCCESS)
|
||||
{
|
||||
// Determine if this device matches the specified serial number
|
||||
char *subkeyString = (char*)malloc(subkeySize + 2);
|
||||
memset(subkeyString, 0, subkeySize + 2);
|
||||
wcstombs(subkeyString, subkey, subkeySize + 1);
|
||||
subkeySize = 255;
|
||||
if (strstr(subkeyString, serialNumber))
|
||||
{
|
||||
portNameSize = 16;
|
||||
memset(portPath, 0, portNameSize * sizeof(wchar_t));
|
||||
wcscat_s(subkey, subkeySize, L"\\0000\\Device Parameters");
|
||||
if (RegOpenKeyExW(key, subkey, 0, KEY_QUERY_VALUE, ¶mKey) == ERROR_SUCCESS)
|
||||
{
|
||||
if (RegQueryValueExW(paramKey, L"PortName", NULL, NULL, (LPBYTE)portPath, &portNameSize) == ERROR_SUCCESS)
|
||||
found = 1;
|
||||
RegCloseKey(paramKey);
|
||||
}
|
||||
}
|
||||
free(subkeyString);
|
||||
}
|
||||
RegCloseKey(key);
|
||||
free(subkey);
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,10 +2,10 @@
|
|||
* WindowsHelperFunctions.h
|
||||
*
|
||||
* Created on: May 05, 2015
|
||||
* Last Updated on: Dec 16, 2021
|
||||
* Last Updated on: Jan 21, 2022
|
||||
* Author: Will Hedgecock
|
||||
*
|
||||
* Copyright (C) 2012-2021 Fazecast, Inc.
|
||||
* Copyright (C) 2012-2022 Fazecast, Inc.
|
||||
*
|
||||
* This file is part of jSerialComm.
|
||||
*
|
||||
|
@ -50,4 +50,8 @@ serialPort* pushBack(serialPortVector* vector, const wchar_t* key, const wchar_t
|
|||
serialPort* fetchPort(serialPortVector* vector, const wchar_t* key);
|
||||
void removePort(serialPortVector* vector, serialPort* port);
|
||||
|
||||
// Windows-specific functionality
|
||||
void reduceLatencyToMinimum(const wchar_t* portName);
|
||||
int getPortPathFromSerial(wchar_t* portPath, const char* serialNumber);
|
||||
|
||||
#endif // #ifndef __WINDOWS_HELPER_FUNCTIONS_HEADER_H__
|
||||
|
|
|
@ -561,6 +561,11 @@ public final class SerialPort
|
|||
* <p>
|
||||
* All serial port parameters or timeouts can be changed at any time before or after the port has been opened.
|
||||
* <p>
|
||||
* Note on Windows using an FTDI device: The first time this method is called, you may be prompted to allow elevated privileges
|
||||
* so that the driver latency can be correctly specified. This should only be necessary the first time you use a new FTDI device.
|
||||
* Declining the elevated privileges will not affect the ability of the serial port to be accessed; however, read/write timing
|
||||
* may not be as expected.
|
||||
* <p>
|
||||
* Note that calling this method on an already opened port will simply reconfigure the port parameters.
|
||||
*
|
||||
* @param safetySleepTime The number of milliseconds to sleep before opening the port in case of frequent closing/openings.
|
||||
|
@ -631,6 +636,11 @@ public final class SerialPort
|
|||
* <p>
|
||||
* All serial port parameters or timeouts can be changed at any time before or after the port has been opened.
|
||||
* <p>
|
||||
* Note on Windows using an FTDI device: The first time this method is called, you may be prompted to allow elevated privileges
|
||||
* so that the driver latency can be correctly specified. This should only be necessary the first time you use a new FTDI device.
|
||||
* Declining the elevated privileges will not affect the ability of the serial port to be accessed; however, read/write timing
|
||||
* may not be as expected.
|
||||
* <p>
|
||||
* Note that calling this method on an already opened port will simply reconfigure the port parameters.
|
||||
*
|
||||
* @param safetySleepTime The number of milliseconds to sleep before opening the port in case of frequent closing/openings.
|
||||
|
@ -645,6 +655,11 @@ public final class SerialPort
|
|||
* <p>
|
||||
* All serial port parameters or timeouts can be changed at any time before or after the port has been opened.
|
||||
* <p>
|
||||
* Note on Windows using an FTDI device: The first time this method is called, you may be prompted to allow elevated privileges
|
||||
* so that the driver latency can be correctly specified. This should only be necessary the first time you use a new FTDI device.
|
||||
* Declining the elevated privileges will not affect the ability of the serial port to be accessed; however, read/write timing
|
||||
* may not be as expected.
|
||||
* <p>
|
||||
* Note that calling this method on an already opened port will simply reconfigure the port parameters.
|
||||
*
|
||||
* @return Whether the port was successfully opened with a valid configuration.
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue