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
|
||||
*
|
||||
* Created on: Feb 25, 2012
|
||||
* Last Updated on: Jan 25, 2022
|
||||
* Last Updated on: Jan 28, 2022
|
||||
* Author: Will Hedgecock
|
||||
*
|
||||
* Copyright (C) 2012-2022 Fazecast, Inc.
|
||||
|
@ -63,6 +63,7 @@ jfieldID parityField;
|
|||
jfieldID flowControlField;
|
||||
jfieldID sendDeviceQueueSizeField;
|
||||
jfieldID receiveDeviceQueueSizeField;
|
||||
jfieldID requestElevatedPermissionsField;
|
||||
jfieldID rs485ModeField;
|
||||
jfieldID rs485DelayBeforeField;
|
||||
jfieldID rs485DelayAfterField;
|
||||
|
@ -269,7 +270,7 @@ static void enumeratePorts(void)
|
|||
for (int i = 0; i < numDevs; ++i)
|
||||
{
|
||||
// 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)
|
||||
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))
|
||||
|
@ -284,7 +285,7 @@ static void enumeratePorts(void)
|
|||
{
|
||||
// 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)
|
||||
if ((wcscmp(serialPorts.ports[j]->portPath + 4, comPort) == 0) && strlen(devInfo[i].Description))
|
||||
{
|
||||
// Update the port description
|
||||
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
|
||||
jobject serialCommObject = (*env)->NewObject(env, serialCommClass, serialCommConstructor);
|
||||
if (checkJniError(env, __LINE__ - 1)) return arrayObject;
|
||||
wcscpy_s(comPort, sizeof(comPort) / sizeof(wchar_t), L"\\\\.\\");
|
||||
wcscat_s(comPort, sizeof(comPort) / sizeof(wchar_t), serialPorts.ports[i]->portPath);
|
||||
(*env)->SetObjectField(env, serialCommObject, comPortField, (*env)->NewString(env, (jchar*)comPort, wcslen(comPort)));
|
||||
(*env)->SetObjectField(env, serialCommObject, comPortField, (*env)->NewString(env, (jchar*)serialPorts.ports[i]->portPath, wcslen(serialPorts.ports[i]->portPath)));
|
||||
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)));
|
||||
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;
|
||||
receiveDeviceQueueSizeField = (*env)->GetFieldID(env, serialCommClass, "receiveDeviceQueueSize", "I");
|
||||
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");
|
||||
if (checkJniError(env, __LINE__ - 1)) return;
|
||||
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;
|
||||
const wchar_t *portName = (wchar_t*)(*env)->GetStringChars(env, portNameJString, NULL);
|
||||
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);
|
||||
if (checkJniError(env, __LINE__ - 1)) return 0;
|
||||
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
|
||||
reduceLatencyToMinimum(port->portPath + 4);
|
||||
reduceLatencyToMinimum(portName + 4, requestElevatedPermissions);
|
||||
|
||||
// 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 25, 2022
|
||||
* Last Updated on: Jan 28, 2022
|
||||
* Author: Will Hedgecock
|
||||
*
|
||||
* 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)
|
||||
{
|
||||
// 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)
|
||||
{
|
||||
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));
|
||||
port->handle = (void*)-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->friendlyName = (wchar_t*)malloc((wcslen(friendlyName)+1)*sizeof(wchar_t));
|
||||
port->portDescription = (wchar_t*)malloc((wcslen(description)+1)*sizeof(wchar_t));
|
||||
|
||||
// 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->friendlyName, wcslen(friendlyName)+1, friendlyName);
|
||||
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)
|
||||
{
|
||||
// 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
|
||||
int keyOffset = ((key[0] == L'\\') && (key[1] == L'\\') && (key[2] == L'.') && (key[3] == L'\\')) ? 0 : 4;
|
||||
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 NULL;
|
||||
}
|
||||
|
@ -113,7 +117,7 @@ void removePort(serialPortVector* vector, serialPort* port)
|
|||
}
|
||||
|
||||
// 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
|
||||
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));
|
||||
RegCloseKey(paramKey);
|
||||
}
|
||||
else
|
||||
else if (requestElevatedPermissions)
|
||||
{
|
||||
// Create registry update file
|
||||
char *workingDirectory = _getcwd(NULL, 0);
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
* WindowsHelperFunctions.h
|
||||
*
|
||||
* Created on: May 05, 2015
|
||||
* Last Updated on: Jan 21, 2022
|
||||
* Last Updated on: Jan 28, 2022
|
||||
* Author: Will Hedgecock
|
||||
*
|
||||
* Copyright (C) 2012-2022 Fazecast, Inc.
|
||||
|
@ -51,7 +51,7 @@ serialPort* fetchPort(serialPortVector* vector, const wchar_t* key);
|
|||
void removePort(serialPortVector* vector, serialPort* port);
|
||||
|
||||
// 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);
|
||||
|
||||
#endif // #ifndef __WINDOWS_HELPER_FUNCTIONS_HEADER_H__
|
||||
|
|
|
@ -719,6 +719,29 @@ public final class SerialPort
|
|||
*/
|
||||
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
|
||||
* 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
|
||||
*
|
||||
* Created on: Feb 27, 2015
|
||||
* Last Updated on: Nov 29, 2021
|
||||
* Last Updated on: Jan 28, 2022
|
||||
* Author: Will Hedgecock
|
||||
*
|
||||
* Copyright (C) 2012-2021 Fazecast, Inc.
|
||||
* Copyright (C) 2012-2022 Fazecast, Inc.
|
||||
*
|
||||
* This file is part of jSerialComm.
|
||||
*
|
||||
|
@ -87,13 +87,13 @@ public class SerialPortTest
|
|||
SerialPort[] ports = SerialPort.getCommPorts();
|
||||
System.out.println("\nAvailable Ports:\n");
|
||||
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");
|
||||
try { Thread.sleep(2000); } catch (Exception e) {}
|
||||
ports = SerialPort.getCommPorts();
|
||||
System.out.println("Available Ports:\n");
|
||||
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;
|
||||
System.out.print("\nChoose your desired serial port or enter -1 to specify a port directly: ");
|
||||
int serialPortChoice = 0;
|
||||
|
@ -113,6 +113,7 @@ public class SerialPortTest
|
|||
}
|
||||
else
|
||||
ubxPort = ports[serialPortChoice];
|
||||
ubxPort.allowElevatedPermissionsRequest();
|
||||
byte[] readBuffer = new byte[2048];
|
||||
System.out.println("\nPre-setting RTS: " + (ubxPort.setRTS() ? "Success" : "Failure"));
|
||||
boolean openedSuccessfully = ubxPort.openPort(0);
|
||||
|
|
Loading…
Reference in New Issue