Create method to allow elevated permission requests on Windows
This commit is contained in:
parent
a742cad114
commit
28c21ec4eb
|
@ -2,7 +2,7 @@
|
||||||
* SerialPort_Windows.c
|
* SerialPort_Windows.c
|
||||||
*
|
*
|
||||||
* Created on: Feb 25, 2012
|
* Created on: Feb 25, 2012
|
||||||
* Last Updated on: Jan 25, 2022
|
* Last Updated on: Jan 28, 2022
|
||||||
* Author: Will Hedgecock
|
* Author: Will Hedgecock
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-2022 Fazecast, Inc.
|
* Copyright (C) 2012-2022 Fazecast, Inc.
|
||||||
|
@ -63,6 +63,7 @@ jfieldID parityField;
|
||||||
jfieldID flowControlField;
|
jfieldID flowControlField;
|
||||||
jfieldID sendDeviceQueueSizeField;
|
jfieldID sendDeviceQueueSizeField;
|
||||||
jfieldID receiveDeviceQueueSizeField;
|
jfieldID receiveDeviceQueueSizeField;
|
||||||
|
jfieldID requestElevatedPermissionsField;
|
||||||
jfieldID rs485ModeField;
|
jfieldID rs485ModeField;
|
||||||
jfieldID rs485DelayBeforeField;
|
jfieldID rs485DelayBeforeField;
|
||||||
jfieldID rs485DelayAfterField;
|
jfieldID rs485DelayAfterField;
|
||||||
|
@ -269,7 +270,7 @@ static void enumeratePorts(void)
|
||||||
for (int i = 0; i < numDevs; ++i)
|
for (int i = 0; i < numDevs; ++i)
|
||||||
{
|
{
|
||||||
// Determine if the port is currently enumerated and already open
|
// Determine if the port is currently enumerated and already open
|
||||||
char isOpen = (devInfo[i].Flags & FT_FLAGS_OPENED) ? 1 : 0;
|
char isOpen = ((devInfo[i].Flags & FT_FLAGS_OPENED) || !strlen(devInfo[i].SerialNumber)) ? 1 : 0;
|
||||||
if (!isOpen)
|
if (!isOpen)
|
||||||
for (int j = 0; j < serialPorts.length; ++j)
|
for (int j = 0; j < serialPorts.length; ++j)
|
||||||
if ((memcmp(serialPorts.ports[j]->serialNumber, devInfo[i].SerialNumber, sizeof(serialPorts.ports[j]->serialNumber)) == 0) && (serialPorts.ports[j]->handle != INVALID_HANDLE_VALUE))
|
if ((memcmp(serialPorts.ports[j]->serialNumber, devInfo[i].SerialNumber, sizeof(serialPorts.ports[j]->serialNumber)) == 0) && (serialPorts.ports[j]->handle != INVALID_HANDLE_VALUE))
|
||||||
|
@ -284,7 +285,7 @@ static void enumeratePorts(void)
|
||||||
{
|
{
|
||||||
// Check if actually connected and present in the port list
|
// Check if actually connected and present in the port list
|
||||||
for (int j = 0; j < serialPorts.length; ++j)
|
for (int j = 0; j < serialPorts.length; ++j)
|
||||||
if (wcscmp(serialPorts.ports[j]->portPath, comPort) == 0)
|
if ((wcscmp(serialPorts.ports[j]->portPath + 4, comPort) == 0) && strlen(devInfo[i].Description))
|
||||||
{
|
{
|
||||||
// Update the port description
|
// Update the port description
|
||||||
serialPorts.ports[j]->enumerated = 1;
|
serialPorts.ports[j]->enumerated = 1;
|
||||||
|
@ -331,9 +332,7 @@ JNIEXPORT jobjectArray JNICALL Java_com_fazecast_jSerialComm_SerialPort_getCommP
|
||||||
// Create new SerialComm object containing the enumerated values
|
// Create new SerialComm object containing the enumerated values
|
||||||
jobject serialCommObject = (*env)->NewObject(env, serialCommClass, serialCommConstructor);
|
jobject serialCommObject = (*env)->NewObject(env, serialCommClass, serialCommConstructor);
|
||||||
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
|
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
|
||||||
wcscpy_s(comPort, sizeof(comPort) / sizeof(wchar_t), L"\\\\.\\");
|
(*env)->SetObjectField(env, serialCommObject, comPortField, (*env)->NewString(env, (jchar*)serialPorts.ports[i]->portPath, wcslen(serialPorts.ports[i]->portPath)));
|
||||||
wcscat_s(comPort, sizeof(comPort) / sizeof(wchar_t), serialPorts.ports[i]->portPath);
|
|
||||||
(*env)->SetObjectField(env, serialCommObject, comPortField, (*env)->NewString(env, (jchar*)comPort, wcslen(comPort)));
|
|
||||||
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
|
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
|
||||||
(*env)->SetObjectField(env, serialCommObject, friendlyNameField, (*env)->NewString(env, (jchar*)serialPorts.ports[i]->friendlyName, wcslen(serialPorts.ports[i]->friendlyName)));
|
(*env)->SetObjectField(env, serialCommObject, friendlyNameField, (*env)->NewString(env, (jchar*)serialPorts.ports[i]->friendlyName, wcslen(serialPorts.ports[i]->friendlyName)));
|
||||||
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
|
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
|
||||||
|
@ -393,6 +392,8 @@ JNIEXPORT void JNICALL Java_com_fazecast_jSerialComm_SerialPort_initializeLibrar
|
||||||
if (checkJniError(env, __LINE__ - 1)) return;
|
if (checkJniError(env, __LINE__ - 1)) return;
|
||||||
receiveDeviceQueueSizeField = (*env)->GetFieldID(env, serialCommClass, "receiveDeviceQueueSize", "I");
|
receiveDeviceQueueSizeField = (*env)->GetFieldID(env, serialCommClass, "receiveDeviceQueueSize", "I");
|
||||||
if (checkJniError(env, __LINE__ - 1)) return;
|
if (checkJniError(env, __LINE__ - 1)) return;
|
||||||
|
requestElevatedPermissionsField = (*env)->GetFieldID(env, serialCommClass, "requestElevatedPermissions", "Z");
|
||||||
|
if (checkJniError(env, __LINE__ - 1)) return;
|
||||||
rs485ModeField = (*env)->GetFieldID(env, serialCommClass, "rs485Mode", "Z");
|
rs485ModeField = (*env)->GetFieldID(env, serialCommClass, "rs485Mode", "Z");
|
||||||
if (checkJniError(env, __LINE__ - 1)) return;
|
if (checkJniError(env, __LINE__ - 1)) return;
|
||||||
rs485DelayBeforeField = (*env)->GetFieldID(env, serialCommClass, "rs485DelayBefore", "I");
|
rs485DelayBeforeField = (*env)->GetFieldID(env, serialCommClass, "rs485DelayBefore", "I");
|
||||||
|
@ -464,6 +465,8 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
|
||||||
if (checkJniError(env, __LINE__ - 1)) return 0;
|
if (checkJniError(env, __LINE__ - 1)) return 0;
|
||||||
const wchar_t *portName = (wchar_t*)(*env)->GetStringChars(env, portNameJString, NULL);
|
const wchar_t *portName = (wchar_t*)(*env)->GetStringChars(env, portNameJString, NULL);
|
||||||
if (checkJniError(env, __LINE__ - 1)) return 0;
|
if (checkJniError(env, __LINE__ - 1)) return 0;
|
||||||
|
unsigned char requestElevatedPermissions = (*env)->GetBooleanField(env, obj, requestElevatedPermissionsField);
|
||||||
|
if (checkJniError(env, __LINE__ - 1)) return 0;
|
||||||
unsigned char disableAutoConfig = (*env)->GetBooleanField(env, obj, disableConfigField);
|
unsigned char disableAutoConfig = (*env)->GetBooleanField(env, obj, disableConfigField);
|
||||||
if (checkJniError(env, __LINE__ - 1)) return 0;
|
if (checkJniError(env, __LINE__ - 1)) return 0;
|
||||||
unsigned char autoFlushIOBuffers = (*env)->GetBooleanField(env, obj, autoFlushIOBuffersField);
|
unsigned char autoFlushIOBuffers = (*env)->GetBooleanField(env, obj, autoFlushIOBuffersField);
|
||||||
|
@ -486,7 +489,7 @@ JNIEXPORT jlong JNICALL Java_com_fazecast_jSerialComm_SerialPort_openPortNative(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reduce the port's latency to its minimum value
|
// Reduce the port's latency to its minimum value
|
||||||
reduceLatencyToMinimum(port->portPath + 4);
|
reduceLatencyToMinimum(portName + 4, requestElevatedPermissions);
|
||||||
|
|
||||||
// Try to open the serial port with read/write access
|
// 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)
|
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
|
* WindowsHelperFunctions.c
|
||||||
*
|
*
|
||||||
* Created on: May 05, 2015
|
* Created on: May 05, 2015
|
||||||
* Last Updated on: Jan 25, 2022
|
* Last Updated on: Jan 28, 2022
|
||||||
* Author: Will Hedgecock
|
* Author: Will Hedgecock
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-2022 Fazecast, Inc.
|
* Copyright (C) 2012-2022 Fazecast, Inc.
|
||||||
|
@ -39,6 +39,7 @@
|
||||||
serialPort* pushBack(serialPortVector* vector, const wchar_t* key, const wchar_t* friendlyName, const wchar_t* description, const wchar_t* location)
|
serialPort* pushBack(serialPortVector* vector, const wchar_t* key, const wchar_t* friendlyName, const wchar_t* description, const wchar_t* location)
|
||||||
{
|
{
|
||||||
// Allocate memory for the new SerialPort storage structure
|
// Allocate memory for the new SerialPort storage structure
|
||||||
|
unsigned char containsSlashes = ((key[0] == L'\\') && (key[1] == L'\\') && (key[2] == L'.') && (key[3] == L'\\'));
|
||||||
if (vector->capacity == vector->length)
|
if (vector->capacity == vector->length)
|
||||||
{
|
{
|
||||||
serialPort** newArray = (serialPort**)realloc(vector->ports, ++vector->capacity * sizeof(serialPort*));
|
serialPort** newArray = (serialPort**)realloc(vector->ports, ++vector->capacity * sizeof(serialPort*));
|
||||||
|
@ -60,13 +61,19 @@ serialPort* pushBack(serialPortVector* vector, const wchar_t* key, const wchar_t
|
||||||
memset(port, 0, sizeof(serialPort));
|
memset(port, 0, sizeof(serialPort));
|
||||||
port->handle = (void*)-1;
|
port->handle = (void*)-1;
|
||||||
port->enumerated = 1;
|
port->enumerated = 1;
|
||||||
port->portPath = (wchar_t*)malloc((wcslen(key)+1)*sizeof(wchar_t));
|
port->portPath = (wchar_t*)malloc((wcslen(key)+(containsSlashes ? 1 : 5))*sizeof(wchar_t));
|
||||||
port->portLocation = (wchar_t*)malloc((wcslen(location)+1)*sizeof(wchar_t));
|
port->portLocation = (wchar_t*)malloc((wcslen(location)+1)*sizeof(wchar_t));
|
||||||
port->friendlyName = (wchar_t*)malloc((wcslen(friendlyName)+1)*sizeof(wchar_t));
|
port->friendlyName = (wchar_t*)malloc((wcslen(friendlyName)+1)*sizeof(wchar_t));
|
||||||
port->portDescription = (wchar_t*)malloc((wcslen(description)+1)*sizeof(wchar_t));
|
port->portDescription = (wchar_t*)malloc((wcslen(description)+1)*sizeof(wchar_t));
|
||||||
|
|
||||||
// Store port strings
|
// Store port strings
|
||||||
wcscpy_s(port->portPath, wcslen(key)+1, key);
|
if (containsSlashes)
|
||||||
|
wcscpy_s(port->portPath, wcslen(key)+1, key);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wcscpy_s(port->portPath, wcslen(key)+5, L"\\\\.\\");
|
||||||
|
wcscat_s(port->portPath, wcslen(key)+5, key);
|
||||||
|
}
|
||||||
wcscpy_s(port->portLocation, wcslen(location)+1, location);
|
wcscpy_s(port->portLocation, wcslen(location)+1, location);
|
||||||
wcscpy_s(port->friendlyName, wcslen(friendlyName)+1, friendlyName);
|
wcscpy_s(port->friendlyName, wcslen(friendlyName)+1, friendlyName);
|
||||||
wcscpy_s(port->portDescription, wcslen(description)+1, description);
|
wcscpy_s(port->portDescription, wcslen(description)+1, description);
|
||||||
|
@ -77,13 +84,10 @@ serialPort* pushBack(serialPortVector* vector, const wchar_t* key, const wchar_t
|
||||||
|
|
||||||
serialPort* fetchPort(serialPortVector* vector, const wchar_t* key)
|
serialPort* fetchPort(serialPortVector* vector, const wchar_t* key)
|
||||||
{
|
{
|
||||||
// Move past any opening slashes
|
|
||||||
if ((key[0] == L'\\') && (key[1] == L'\\') && (key[2] == L'.') && (key[3] == L'\\'))
|
|
||||||
key += 4;
|
|
||||||
|
|
||||||
// Retrieve the serial port specified by the passed-in key
|
// Retrieve the serial port specified by the passed-in key
|
||||||
|
int keyOffset = ((key[0] == L'\\') && (key[1] == L'\\') && (key[2] == L'.') && (key[3] == L'\\')) ? 0 : 4;
|
||||||
for (int i = 0; i < vector->length; ++i)
|
for (int i = 0; i < vector->length; ++i)
|
||||||
if (wcscmp(key, vector->ports[i]->portPath) == 0)
|
if (wcscmp(key, vector->ports[i]->portPath + keyOffset) == 0)
|
||||||
return vector->ports[i];
|
return vector->ports[i];
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -113,7 +117,7 @@ void removePort(serialPortVector* vector, serialPort* port)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Windows-specific functionality
|
// Windows-specific functionality
|
||||||
void reduceLatencyToMinimum(const wchar_t* portName)
|
void reduceLatencyToMinimum(const wchar_t* portName, unsigned char requestElevatedPermissions)
|
||||||
{
|
{
|
||||||
// Search for this port in all FTDI enumerated ports
|
// Search for this port in all FTDI enumerated ports
|
||||||
HKEY key, paramKey = 0;
|
HKEY key, paramKey = 0;
|
||||||
|
@ -144,7 +148,7 @@ void reduceLatencyToMinimum(const wchar_t* portName)
|
||||||
RegSetValueExW(paramKey, L"LatencyTimer", 0, REG_DWORD, (LPBYTE)&latency, sizeof(latency));
|
RegSetValueExW(paramKey, L"LatencyTimer", 0, REG_DWORD, (LPBYTE)&latency, sizeof(latency));
|
||||||
RegCloseKey(paramKey);
|
RegCloseKey(paramKey);
|
||||||
}
|
}
|
||||||
else
|
else if (requestElevatedPermissions)
|
||||||
{
|
{
|
||||||
// Create registry update file
|
// Create registry update file
|
||||||
char *workingDirectory = _getcwd(NULL, 0);
|
char *workingDirectory = _getcwd(NULL, 0);
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* WindowsHelperFunctions.h
|
* WindowsHelperFunctions.h
|
||||||
*
|
*
|
||||||
* Created on: May 05, 2015
|
* Created on: May 05, 2015
|
||||||
* Last Updated on: Jan 21, 2022
|
* Last Updated on: Jan 28, 2022
|
||||||
* Author: Will Hedgecock
|
* Author: Will Hedgecock
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-2022 Fazecast, Inc.
|
* Copyright (C) 2012-2022 Fazecast, Inc.
|
||||||
|
@ -51,7 +51,7 @@ serialPort* fetchPort(serialPortVector* vector, const wchar_t* key);
|
||||||
void removePort(serialPortVector* vector, serialPort* port);
|
void removePort(serialPortVector* vector, serialPort* port);
|
||||||
|
|
||||||
// Windows-specific functionality
|
// Windows-specific functionality
|
||||||
void reduceLatencyToMinimum(const wchar_t* portName);
|
void reduceLatencyToMinimum(const wchar_t* portName, unsigned char requestElevatedPermissions);
|
||||||
int getPortPathFromSerial(wchar_t* portPath, const char* serialNumber);
|
int getPortPathFromSerial(wchar_t* portPath, const char* serialNumber);
|
||||||
|
|
||||||
#endif // #ifndef __WINDOWS_HELPER_FUNCTIONS_HEADER_H__
|
#endif // #ifndef __WINDOWS_HELPER_FUNCTIONS_HEADER_H__
|
||||||
|
|
|
@ -719,6 +719,29 @@ public final class SerialPort
|
||||||
*/
|
*/
|
||||||
public final synchronized void disableExclusiveLock() { disableExclusiveLock = true; }
|
public final synchronized void disableExclusiveLock() { disableExclusiveLock = true; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows the library to request elevation of the current user's permissions for use in making certain
|
||||||
|
* system-specific changes regarding this serial port.
|
||||||
|
* <p>
|
||||||
|
* Examples of such changes include reducing the default latency for FTDI-type devices using
|
||||||
|
* the Windows registry, or adding the current Linux user to the same OS group to which the serial
|
||||||
|
* port belongs so that they can access the port without having to make these changes manually.
|
||||||
|
* <p>
|
||||||
|
* On Windows, if elevated permissions are required, a User Access Control (UAC) dialog box will
|
||||||
|
* appear, requesting authorization to carry out the privileged operation.
|
||||||
|
* On a non-Windows system, elevated permissions will be requested as if you had used the 'sudo' command
|
||||||
|
* in a terminal. As such, this function should not be used if your application does not contain or use
|
||||||
|
* a console.
|
||||||
|
* <p>
|
||||||
|
* Care should be taken when choosing to use this function as it <i>may</i> cause a prompt to appear
|
||||||
|
* during runtime of your final application requesting permission to make these elevated changes which
|
||||||
|
* may detract from the user experience of your application. When possible, making any system changes
|
||||||
|
* related to serial port usage should be done manually before attempting to use such ports, but in some
|
||||||
|
* situations, this function may make it easier for your application to automatically apply these
|
||||||
|
* necessary changes.
|
||||||
|
*/
|
||||||
|
public final synchronized void allowElevatedPermissionsRequest() { requestElevatedPermissions = true; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the source code line location of the latest error encountered during execution of
|
* Returns the source code line location of the latest error encountered during execution of
|
||||||
* the native code for this port.
|
* the native code for this port.
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -2,10 +2,10 @@
|
||||||
* SerialPortTest.java
|
* SerialPortTest.java
|
||||||
*
|
*
|
||||||
* Created on: Feb 27, 2015
|
* Created on: Feb 27, 2015
|
||||||
* Last Updated on: Nov 29, 2021
|
* Last Updated on: Jan 28, 2022
|
||||||
* Author: Will Hedgecock
|
* Author: Will Hedgecock
|
||||||
*
|
*
|
||||||
* Copyright (C) 2012-2021 Fazecast, Inc.
|
* Copyright (C) 2012-2022 Fazecast, Inc.
|
||||||
*
|
*
|
||||||
* This file is part of jSerialComm.
|
* This file is part of jSerialComm.
|
||||||
*
|
*
|
||||||
|
@ -87,13 +87,13 @@ public class SerialPortTest
|
||||||
SerialPort[] ports = SerialPort.getCommPorts();
|
SerialPort[] ports = SerialPort.getCommPorts();
|
||||||
System.out.println("\nAvailable Ports:\n");
|
System.out.println("\nAvailable Ports:\n");
|
||||||
for (int i = 0; i < ports.length; ++i)
|
for (int i = 0; i < ports.length; ++i)
|
||||||
System.out.println(" [" + i + "] " + ports[i].getSystemPortName() + ": " + ports[i].getDescriptivePortName() + " - " + ports[i].getPortDescription() + " @ " + ports[i].getPortLocation());
|
System.out.println(" [" + i + "] " + ports[i].getSystemPortName() + " (" + ports[i].getSystemPortPath() + "): " + ports[i].getDescriptivePortName() + " - " + ports[i].getPortDescription() + " @ " + ports[i].getPortLocation());
|
||||||
System.out.println("\nRe-enumerating ports again in 2 seconds...\n");
|
System.out.println("\nRe-enumerating ports again in 2 seconds...\n");
|
||||||
try { Thread.sleep(2000); } catch (Exception e) {}
|
try { Thread.sleep(2000); } catch (Exception e) {}
|
||||||
ports = SerialPort.getCommPorts();
|
ports = SerialPort.getCommPorts();
|
||||||
System.out.println("Available Ports:\n");
|
System.out.println("Available Ports:\n");
|
||||||
for (int i = 0; i < ports.length; ++i)
|
for (int i = 0; i < ports.length; ++i)
|
||||||
System.out.println(" [" + i + "] " + ports[i].getSystemPortName() + ": " + ports[i].getDescriptivePortName() + " - " + ports[i].getPortDescription() + " @ " + ports[i].getPortLocation());
|
System.out.println(" [" + i + "] " + ports[i].getSystemPortName() + " (" + ports[i].getSystemPortPath() + "): " + ports[i].getDescriptivePortName() + " - " + ports[i].getPortDescription() + " @ " + ports[i].getPortLocation());
|
||||||
SerialPort ubxPort;
|
SerialPort ubxPort;
|
||||||
System.out.print("\nChoose your desired serial port or enter -1 to specify a port directly: ");
|
System.out.print("\nChoose your desired serial port or enter -1 to specify a port directly: ");
|
||||||
int serialPortChoice = 0;
|
int serialPortChoice = 0;
|
||||||
|
@ -113,6 +113,7 @@ public class SerialPortTest
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
ubxPort = ports[serialPortChoice];
|
ubxPort = ports[serialPortChoice];
|
||||||
|
ubxPort.allowElevatedPermissionsRequest();
|
||||||
byte[] readBuffer = new byte[2048];
|
byte[] readBuffer = new byte[2048];
|
||||||
System.out.println("\nPre-setting RTS: " + (ubxPort.setRTS() ? "Success" : "Failure"));
|
System.out.println("\nPre-setting RTS: " + (ubxPort.setRTS() ? "Success" : "Failure"));
|
||||||
boolean openedSuccessfully = ubxPort.openPort(0);
|
boolean openedSuccessfully = ubxPort.openPort(0);
|
||||||
|
|
Loading…
Reference in New Issue