blob: e3f398b94c9b011a8edce0ce82263e752940a52c [file] [log] [blame]
/*
* Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <Windows.h>
#include <tchar.h>
// This is the default buffer size used for RegQueryValue values.
#define DEFAULT_ALLOC MAX_PATH
// only allocate a buffer as big as MAX_ALLOC for RegQueryValue values.
#define MAX_ALLOC 262144
static LPCTSTR ACCESSIBILITY_USER_KEY =
_T("Software\\Microsoft\\Windows NT\\CurrentVersion\\Accessibility");
static LPCTSTR ACCESSIBILITY_SYSTEM_KEY =
_T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Accessibility\\Session");
static LPCTSTR ACCESSIBILITY_CONFIG =
_T("Configuration");
static LPCTSTR STR_ACCESSBRIDGE =
_T("oracle_javaaccessbridge");
// Note: There are senarios where more than one extension can be specified on the
// asssistive_technologies=
// line but this code only deals with the case of
// assistive_technologies=com.sun.java.accessibility.AccessBridge
// assuming that if additional extensions are desired the user knows how edit the file.
FILE* origFile;
FILE* tempFile;
bool isXP()
{
static bool isXPFlag = false;
OSVERSIONINFO osvi;
// Initialize the OSVERSIONINFO structure.
ZeroMemory( &osvi, sizeof( osvi ) );
osvi.dwOSVersionInfoSize = sizeof( osvi );
GetVersionEx( &osvi );
if ( osvi.dwMajorVersion == 5 ) // For Windows XP and Windows 2000
isXPFlag = true;
return isXPFlag ;
}
void enableJAB() {
// Copy lines from orig to temp modifying the line containing
// assistive_technologies=
// There are various scenarios:
// 1) If the line exists exactly as
// #assistive_technologies=com.sun.java.accessibility.AccessBridge
// replace it with
// assistive_technologies=com.sun.java.accessibility.AccessBridge
// 2) else if the line exists exactly as
// assistive_technologies=com.sun.java.accessibility.AccessBridge
// use it as is
// 3) else if a line containing "assistive_technologies" exits
// a) if it's already commented out, us it as is (jab will be enabled in step 4)
// b) else if it's not commented out, comment it out and add a new line with
// assistive_technologies=com.sun.java.accessibility.AccessBridge
// 4) If the line doesn't exist (or case 3a), add
// assistive_technologies=com.sun.java.accessibility.AccessBridge
// Do the same for screen_magnifier_present=
char line[512];
char commentLine[512] = "#";
char jabLine[] = "assistive_technologies=com.sun.java.accessibility.AccessBridge\n";
char magLine[] = "screen_magnifier_present=true\n";
bool foundJabLine = false;
bool foundMagLine = false;
while (!feof(origFile)) {
if (fgets(line, 512, origFile) != NULL) {
if (_stricmp(line, "#assistive_technologies=com.sun.java.accessibility.AccessBridge\n") == 0) {
fputs(jabLine, tempFile);
foundJabLine = true;
} else if (_stricmp(line, jabLine) == 0) {
fputs(line, tempFile);
foundJabLine = true;
} else if (strstr(line, "assistive_technologies") != NULL) {
char* context;
char* firstNonSpaceChar = strtok_s(line, " ", &context);
if (*firstNonSpaceChar == '#') {
fputs(line, tempFile);
} else {
strcat_s(commentLine, line);
fputs(commentLine, tempFile);
fputs(jabLine, tempFile);
foundJabLine = true;
}
} else if (_stricmp(line, "#screen_magnifier_present=true\n") == 0) {
fputs(magLine, tempFile);
foundMagLine = true;
} else if (_stricmp(line, magLine) == 0) {
fputs(line, tempFile);
foundMagLine = true;
} else if (strstr(line, "screen_magnifier_present") != NULL) {
char* context;
char* firstNonSpaceChar = strtok_s(line, " ", &context);
if (*firstNonSpaceChar == '#') {
fputs(line, tempFile);
} else {
strcat_s(commentLine, line);
fputs(commentLine, tempFile);
fputs(magLine, tempFile);
foundMagLine = true;
}
} else {
fputs(line, tempFile);
}
}
}
if (!foundJabLine) {
fputs(jabLine, tempFile);
}
if (!foundMagLine) {
fputs(magLine, tempFile);
}
}
void disableJAB() {
// Copy lines from orig to temp modifying the line containing
// assistive_technologies=
// There are various scenarios:
// 1) If the uncommented line exists, comment it out
// 2) If the line exists but is preceeded by a #, nothing to do
// 3) If the line doesn't exist, nothing to do
// Do the same for screen_magnifier_present=
char line[512];
char commentLine[512];
while (!feof(origFile)) {
if (fgets(line, 512, origFile) != NULL) {
if (strstr(line, "assistive_technologies") != NULL) {
char* context;
char* firstNonSpaceChar = strtok_s(line, " ", &context);
if (*firstNonSpaceChar != '#') {
strcpy_s(commentLine, "#");
strcat_s(commentLine, line);
fputs(commentLine, tempFile);
} else {
fputs(line, tempFile);
}
} else if (strstr(line, "screen_magnifier_present") != NULL) {
char* context;
char* firstNonSpaceChar = strtok_s(line, " ", &context);
if (*firstNonSpaceChar != '#') {
strcpy_s(commentLine, "#");
strcat_s(commentLine, line);
fputs(commentLine, tempFile);
} else {
fputs(line, tempFile);
}
} else {
fputs(line, tempFile);
}
}
}
}
int modify(bool enable) {
errno_t error = 0;
char path[_MAX_PATH];
char tempPath[_MAX_PATH];
// Get the path for %USERPROFILE%
char *profilePath;
size_t len;
error = _dupenv_s(&profilePath, &len, "USERPROFILE" );
if (error) {
printf("Error fetching USERPROFILE.\n");
perror("Error");
return error;
}
const char acc_props1[] = "\\.accessibility.properties";
const char acc_props2[] = "\\.acce$$ibility.properties";
// len must be 234 or less (233 characters)
// sizeof(path) is 260 (room for 259 characters)
// sizeof(acc_props1) is 27 (26 characters)
// path will hold 233 path characters plus 26 file characters plus 1 null character)
// if len - 1 > 233 then error
if ( len - 1 > sizeof(path) - sizeof(acc_props1) ||
len - 1 > sizeof(tempPath) - sizeof(acc_props2) ) {
printf("The USERPROFILE environment variable is too long.\n");
printf("It must be no longer than 233 characters.\n");
free(profilePath);
return 123;
}
path[0] = 0;
strcat_s(path, _MAX_PATH, profilePath);
strcat_s(path, acc_props1);
tempPath[0] = 0;
strcat_s(tempPath, _MAX_PATH, profilePath);
strcat_s(tempPath, acc_props2);
free(profilePath);
profilePath = 0;
// Open the original file. If it doesn't exist and this is an enable request then create it.
error = fopen_s(&origFile, path, "r");
if (error) {
if (enable) {
error = fopen_s(&origFile, path, "w");
if (error) {
printf("Couldn't create file: %s\n", path);
perror("Error");
} else {
char str[100] = "assistive_technologies=com.sun.java.accessibility.AccessBridge\n";
strcat_s(str, "screen_magnifier_present=true\n");
fprintf(origFile, str);
fclose(origFile);
}
} else {
// It's OK if the file isn't there for a -disable
error = 0;
}
} else {
// open a temp file
error = fopen_s(&tempFile, tempPath, "w");
if (error) {
printf("Couldn't open temp file: %s\n", tempPath);
perror("Error");
return error;
}
if (enable) {
enableJAB();
} else {
disableJAB();
}
fclose(origFile);
fclose(tempFile);
// delete the orig file and rename the temp file
if (remove(path) != 0) {
printf("Couldn't remove file: %s\n", path);
perror("Error");
return errno;
}
if (rename(tempPath, path) != 0) {
printf("Couldn't rename %s to %s.\n", tempPath, path);
perror("Error");
return errno;
}
}
return error;
}
void printUsage() {
printf("\njabswitch [/enable | /disable | /version | /?]\n\n");
printf("Description:\n");
printf(" jabswitch enables or disables the Java Access Bridge.\n\n");
printf("Parameters:\n");
printf(" /enable Enable the Java Accessibility Bridge.\n");
printf(" /disable Disable the Java Accessibility Bridge.\n");
printf(" /version Display the version.\n");
printf(" /? Display this usage information.\n");
printf("\nNote:\n");
printf(" The Java Access Bridge can also be enabled with the\n");
printf(" Windows Ease of Access control panel (which can be\n");
printf(" activated by pressing Windows + U). The Ease of Access\n");
printf(" control panel has a Java Access Bridge checkbox. Please\n");
printf(" be aware that unchecking the checkbox has no effect and\n");
printf(" in order to disable the Java Access Bridge you must run\n");
printf(" jabswitch.exe from the command line.\n");
}
void printVersion() {
TCHAR executableFileName[_MAX_PATH];
if (!GetModuleFileName(0, executableFileName, _MAX_PATH)) {
printf("Unable to get executable file name.\n");
return;
}
DWORD nParam;
DWORD nVersionSize = GetFileVersionInfoSize(executableFileName, &nParam);
if (!nVersionSize) {
printf("Unable to get version info size.\n");
return;
}
char* pVersionData = new char[nVersionSize];
if (!GetFileVersionInfo(executableFileName, 0, nVersionSize, pVersionData)) {
printf("Unable to get version info.\n");
return;
}
LPVOID pVersionInfo;
UINT nSize;
if (!VerQueryValue(pVersionData, _T("\\"), &pVersionInfo, &nSize)) {
printf("Unable to query version value.\n");
return;
}
VS_FIXEDFILEINFO *pVSInfo = (VS_FIXEDFILEINFO *)pVersionInfo;
char versionString[100];
sprintf_s( versionString, "version %i.%i.%i.%i",
pVSInfo->dwProductVersionMS >> 16,
pVSInfo->dwProductVersionMS & 0xFFFF,
pVSInfo->dwProductVersionLS >> 16,
pVSInfo->dwProductVersionLS & 0xFFFF );
char outputString[100];
strcpy_s(outputString, "jabswitch ");
strcat_s(outputString, versionString);
strcat_s(outputString, "\njabswitch enables or disables the Java Access Bridge.\n");
printf(outputString);
}
int regEnable() {
HKEY hKey;
DWORD retval = -1;
LSTATUS err;
err = RegOpenKeyEx(HKEY_CURRENT_USER, ACCESSIBILITY_USER_KEY, NULL, KEY_READ|KEY_WRITE, &hKey);
if (err == ERROR_SUCCESS) {
DWORD dataType = REG_SZ;
DWORD dataLength = DEFAULT_ALLOC;
TCHAR dataBuffer[DEFAULT_ALLOC];
TCHAR *data = dataBuffer;
bool freeData = false;
err = RegQueryValueEx(hKey, ACCESSIBILITY_CONFIG, 0, &dataType, (BYTE *)data, &dataLength);
if (err == ERROR_MORE_DATA) {
if (dataLength > 0 && dataLength < MAX_ALLOC) {
data = new TCHAR[dataLength];
err = RegQueryValueEx(hKey, ACCESSIBILITY_CONFIG, 0, &dataType, (BYTE *)data, &dataLength);
}
}
if (err == ERROR_SUCCESS) {
err = _tcslwr_s(dataBuffer, DEFAULT_ALLOC);
if (err) {
return -1;
}
if (_tcsstr(dataBuffer, STR_ACCESSBRIDGE) != NULL) {
return 0; // This is OK, e.g. ran enable twice and the value is there.
} else {
// add oracle_javaaccessbridge to Config key for HKCU
dataLength = dataLength + (_tcslen(STR_ACCESSBRIDGE) + 1) * sizeof(TCHAR);
TCHAR *newStr = new TCHAR[dataLength];
if (newStr != NULL) {
wsprintf(newStr, L"%s,%s", dataBuffer, STR_ACCESSBRIDGE);
RegSetValueEx(hKey, ACCESSIBILITY_CONFIG, 0, REG_SZ, (BYTE *)newStr, dataLength);
}
}
}
RegCloseKey(hKey);
}
return err;
}
int regDeleteValue(HKEY hFamilyKey, LPCWSTR lpSubKey)
{
HKEY hKey;
DWORD retval = -1;
LSTATUS err;
err = RegOpenKeyEx(hFamilyKey, lpSubKey, NULL, KEY_READ|KEY_WRITE|KEY_WOW64_64KEY, &hKey);
if (err != ERROR_SUCCESS)
err = RegOpenKeyEx(hFamilyKey, lpSubKey, NULL, KEY_READ|KEY_WRITE, &hKey);
if (err == ERROR_SUCCESS) {
DWORD dataType = REG_SZ;
DWORD dataLength = DEFAULT_ALLOC;
TCHAR dataBuffer[DEFAULT_ALLOC];
TCHAR searchBuffer[DEFAULT_ALLOC];
TCHAR *data = dataBuffer;
bool freeData = false;
err = RegQueryValueEx(hKey, ACCESSIBILITY_CONFIG, 0, &dataType, (BYTE *)data, &dataLength);
if (err == ERROR_MORE_DATA) {
if (dataLength > 0 && dataLength < MAX_ALLOC) {
data = new TCHAR[dataLength];
err = RegQueryValueEx(hKey, ACCESSIBILITY_CONFIG, 0, &dataType, (BYTE *)data, &dataLength);
}
}
if (err == ERROR_SUCCESS) {
err = _tcslwr_s(dataBuffer, DEFAULT_ALLOC);
if (err) {
return -1;
}
if (_tcsstr(dataBuffer, STR_ACCESSBRIDGE) == NULL) {
return 0; // This is OK, e.g. ran disable twice and the value is not there.
} else {
// remove oracle_javaaccessbridge from Config key
TCHAR *newStr = new TCHAR[dataLength];
TCHAR *nextToken;
LPTSTR tok, beg1 = dataBuffer;
bool first = true;
_tcscpy_s(newStr, dataLength, L"");
tok = _tcstok_s(beg1, L",", &nextToken);
while (tok != NULL) {
_tcscpy_s(searchBuffer, DEFAULT_ALLOC, tok);
err = _tcslwr_s(searchBuffer, DEFAULT_ALLOC);
if (err) {
return -1;
}
if (_tcsstr(searchBuffer, STR_ACCESSBRIDGE) == NULL) {
if (!first) {
_tcscat_s(newStr, dataLength, L",");
}
first = false;
_tcscat_s(newStr, dataLength, tok);
}
tok = _tcstok_s(NULL, L",", &nextToken);
}
dataLength = (_tcslen(newStr) + 1) * sizeof(TCHAR);
RegSetValueEx(hKey, ACCESSIBILITY_CONFIG, 0, REG_SZ, (BYTE *)newStr, dataLength);
}
}
RegCloseKey(hKey);
}
return err;
}
int regDisable()
{
LSTATUS err;
// Update value for HKCU
err=regDeleteValue(HKEY_CURRENT_USER, ACCESSIBILITY_USER_KEY);
// Update value for HKLM for Session
TCHAR dataBuffer[DEFAULT_ALLOC];
DWORD dwSessionId ;
ProcessIdToSessionId(GetCurrentProcessId(),&dwSessionId ) ;
if( dwSessionId >= 0 )
{
wsprintf(dataBuffer, L"%s%d", ACCESSIBILITY_SYSTEM_KEY, dwSessionId);
err=regDeleteValue(HKEY_LOCAL_MACHINE, dataBuffer);
}
return err;
}
void main(int argc, char* argv[]) {
bool enableWasRequested = false;
bool disableWasRequested = false;
bool badParams = true;
int error = 0;
if (argc == 2) {
if (_stricmp(argv[1], "-?") == 0 || _stricmp(argv[1], "/?") == 0) {
printUsage();
badParams = false;
} else if (_stricmp(argv[1], "-version") == 0 || _stricmp(argv[1], "/version") == 0) {
printVersion();
badParams = false;
} else {
if (_stricmp(argv[1], "-enable") == 0 || _stricmp(argv[1], "/enable") == 0) {
badParams = false;
enableWasRequested = true;
error = modify(true);
if (error == 0) {
if( !isXP() )
regEnable();
}
} else if (_stricmp(argv[1], "-disable") == 0 || _stricmp(argv[1], "/disable") == 0) {
badParams = false;
disableWasRequested = true;
error = modify(false);
if (error == 0) {
if( !isXP() )
regDisable();
}
}
}
}
if (badParams) {
printUsage();
} else if (enableWasRequested || disableWasRequested) {
if (error != 0) {
printf("There was an error.\n\n");
}
printf("The Java Access Bridge has ");
if (error != 0) {
printf("not ");
}
printf("been ");
if (enableWasRequested) {
printf("enabled.\n");
} else {
printf("disabled.\n");
}
// Use exit so test case can sense for error.
if (error != 0) {
exit(error);
}
}
}