1/* 2 * Copyright (c) 2012, 2015, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26#include <stdio.h> 27#include <string.h> 28#include <stdlib.h> 29#include <ctype.h> 30#include <Windows.h> 31#include <tchar.h> 32 33// This is the default buffer size used for RegQueryValue values. 34#define DEFAULT_ALLOC MAX_PATH 35// only allocate a buffer as big as MAX_ALLOC for RegQueryValue values. 36#define MAX_ALLOC 262144 37 38static LPCTSTR ACCESSIBILITY_USER_KEY = 39 _T("Software\\Microsoft\\Windows NT\\CurrentVersion\\Accessibility"); 40static LPCTSTR ACCESSIBILITY_SYSTEM_KEY = 41 _T("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Accessibility\\Session"); 42static LPCTSTR ACCESSIBILITY_CONFIG = 43 _T("Configuration"); 44static LPCTSTR STR_ACCESSBRIDGE = 45 _T("oracle_javaaccessbridge"); 46 47// Note: There are senarios where more than one extension can be specified on the 48// asssistive_technologies= 49// line but this code only deals with the case of 50// assistive_technologies=com.sun.java.accessibility.AccessBridge 51// assuming that if additional extensions are desired the user knows how edit the file. 52 53FILE* origFile; 54FILE* tempFile; 55 56bool isXP() 57{ 58 static bool isXPFlag = false; 59 OSVERSIONINFO osvi; 60 61 // Initialize the OSVERSIONINFO structure. 62 ZeroMemory( &osvi, sizeof( osvi ) ); 63 osvi.dwOSVersionInfoSize = sizeof( osvi ); 64 65 GetVersionEx( &osvi ); 66 67 if ( osvi.dwMajorVersion == 5 ) // For Windows XP and Windows 2000 68 isXPFlag = true; 69 70 return isXPFlag ; 71} 72 73void enableJAB() { 74 // Copy lines from orig to temp modifying the line containing 75 // assistive_technologies= 76 // There are various scenarios: 77 // 1) If the line exists exactly as 78 // #assistive_technologies=com.sun.java.accessibility.AccessBridge 79 // replace it with 80 // assistive_technologies=com.sun.java.accessibility.AccessBridge 81 // 2) else if the line exists exactly as 82 // assistive_technologies=com.sun.java.accessibility.AccessBridge 83 // use it as is 84 // 3) else if a line containing "assistive_technologies" exits 85 // a) if it's already commented out, us it as is (jab will be enabled in step 4) 86 // b) else if it's not commented out, comment it out and add a new line with 87 // assistive_technologies=com.sun.java.accessibility.AccessBridge 88 // 4) If the line doesn't exist (or case 3a), add 89 // assistive_technologies=com.sun.java.accessibility.AccessBridge 90 // Do the same for screen_magnifier_present= 91 char line[512]; 92 char commentLine[512] = "#"; 93 char jabLine[] = "assistive_technologies=com.sun.java.accessibility.AccessBridge\n"; 94 char magLine[] = "screen_magnifier_present=true\n"; 95 bool foundJabLine = false; 96 bool foundMagLine = false; 97 while (!feof(origFile)) { 98 if (fgets(line, 512, origFile) != NULL) { 99 if (_stricmp(line, "#assistive_technologies=com.sun.java.accessibility.AccessBridge\n") == 0) { 100 fputs(jabLine, tempFile); 101 foundJabLine = true; 102 } else if (_stricmp(line, jabLine) == 0) { 103 fputs(line, tempFile); 104 foundJabLine = true; 105 } else if (strstr(line, "assistive_technologies") != NULL) { 106 char* context; 107 char* firstNonSpaceChar = strtok_s(line, " ", &context); 108 if (*firstNonSpaceChar == '#') { 109 fputs(line, tempFile); 110 } else { 111 strcat_s(commentLine, line); 112 fputs(commentLine, tempFile); 113 fputs(jabLine, tempFile); 114 foundJabLine = true; 115 } 116 } else if (_stricmp(line, "#screen_magnifier_present=true\n") == 0) { 117 fputs(magLine, tempFile); 118 foundMagLine = true; 119 } else if (_stricmp(line, magLine) == 0) { 120 fputs(line, tempFile); 121 foundMagLine = true; 122 } else if (strstr(line, "screen_magnifier_present") != NULL) { 123 char* context; 124 char* firstNonSpaceChar = strtok_s(line, " ", &context); 125 if (*firstNonSpaceChar == '#') { 126 fputs(line, tempFile); 127 } else { 128 strcat_s(commentLine, line); 129 fputs(commentLine, tempFile); 130 fputs(magLine, tempFile); 131 foundMagLine = true; 132 } 133 } else { 134 fputs(line, tempFile); 135 } 136 } 137 } 138 if (!foundJabLine) { 139 fputs(jabLine, tempFile); 140 } 141 if (!foundMagLine) { 142 fputs(magLine, tempFile); 143 } 144} 145 146void disableJAB() { 147 // Copy lines from orig to temp modifying the line containing 148 // assistive_technologies= 149 // There are various scenarios: 150 // 1) If the uncommented line exists, comment it out 151 // 2) If the line exists but is preceeded by a #, nothing to do 152 // 3) If the line doesn't exist, nothing to do 153 // Do the same for screen_magnifier_present= 154 char line[512]; 155 char commentLine[512]; 156 while (!feof(origFile)) { 157 if (fgets(line, 512, origFile) != NULL) { 158 if (strstr(line, "assistive_technologies") != NULL) { 159 char* context; 160 char* firstNonSpaceChar = strtok_s(line, " ", &context); 161 if (*firstNonSpaceChar != '#') { 162 strcpy_s(commentLine, "#"); 163 strcat_s(commentLine, line); 164 fputs(commentLine, tempFile); 165 } else { 166 fputs(line, tempFile); 167 } 168 } else if (strstr(line, "screen_magnifier_present") != NULL) { 169 char* context; 170 char* firstNonSpaceChar = strtok_s(line, " ", &context); 171 if (*firstNonSpaceChar != '#') { 172 strcpy_s(commentLine, "#"); 173 strcat_s(commentLine, line); 174 fputs(commentLine, tempFile); 175 } else { 176 fputs(line, tempFile); 177 } 178 } else { 179 fputs(line, tempFile); 180 } 181 } 182 } 183} 184 185int modify(bool enable) { 186 errno_t error = 0; 187 char path[_MAX_PATH]; 188 char tempPath[_MAX_PATH]; 189 // Get the path for %USERPROFILE% 190 char *profilePath; 191 size_t len; 192 error = _dupenv_s(&profilePath, &len, "USERPROFILE" ); 193 if (error) { 194 printf("Error fetching USERPROFILE.\n"); 195 perror("Error"); 196 return error; 197 } 198 const char acc_props1[] = "\\.accessibility.properties"; 199 const char acc_props2[] = "\\.acce$$ibility.properties"; 200 // len must be 234 or less (233 characters) 201 // sizeof(path) is 260 (room for 259 characters) 202 // sizeof(acc_props1) is 27 (26 characters) 203 // path will hold 233 path characters plus 26 file characters plus 1 null character) 204 // if len - 1 > 233 then error 205 if ( len - 1 > sizeof(path) - sizeof(acc_props1) || 206 len - 1 > sizeof(tempPath) - sizeof(acc_props2) ) { 207 printf("The USERPROFILE environment variable is too long.\n"); 208 printf("It must be no longer than 233 characters.\n"); 209 return 123; 210 } 211 path[0] = 0; 212 strcat_s(path, _MAX_PATH, profilePath); 213 strcat_s(path, acc_props1); 214 tempPath[0] = 0; 215 strcat_s(tempPath, _MAX_PATH, profilePath); 216 strcat_s(tempPath, acc_props2); 217 free(profilePath); 218 profilePath = 0; 219 // Open the original file. If it doesn't exist and this is an enable request then create it. 220 error = fopen_s(&origFile, path, "r"); 221 if (error) { 222 if (enable) { 223 error = fopen_s(&origFile, path, "w"); 224 if (error) { 225 printf("Couldn't create file: %s\n", path); 226 perror("Error"); 227 } else { 228 char str[100] = "assistive_technologies=com.sun.java.accessibility.AccessBridge\n"; 229 strcat_s(str, "screen_magnifier_present=true\n"); 230 fprintf(origFile, str); 231 fclose(origFile); 232 } 233 } else { 234 // It's OK if the file isn't there for a -disable 235 error = 0; 236 } 237 } else { 238 // open a temp file 239 error = fopen_s(&tempFile, tempPath, "w"); 240 if (error) { 241 printf("Couldn't open temp file: %s\n", tempPath); 242 perror("Error"); 243 return error; 244 } 245 if (enable) { 246 enableJAB(); 247 } else { 248 disableJAB(); 249 } 250 fclose(origFile); 251 fclose(tempFile); 252 // delete the orig file and rename the temp file 253 if (remove(path) != 0) { 254 printf("Couldn't remove file: %s\n", path); 255 perror("Error"); 256 return errno; 257 } 258 if (rename(tempPath, path) != 0) { 259 printf("Couldn't rename %s to %s.\n", tempPath, path); 260 perror("Error"); 261 return errno; 262 } 263 } 264 return error; 265} 266 267void printUsage() { 268 printf("\njabswitch [/enable | /disable | /version | /?]\n\n"); 269 printf("Description:\n"); 270 printf(" jabswitch enables or disables the Java Access Bridge.\n\n"); 271 printf("Parameters:\n"); 272 printf(" /enable Enable the Java Accessibility Bridge.\n"); 273 printf(" /disable Disable the Java Accessibility Bridge.\n"); 274 printf(" /version Display the version.\n"); 275 printf(" /? Display this usage information.\n"); 276 printf("\nNote:\n"); 277 printf(" The Java Access Bridge can also be enabled with the\n"); 278 printf(" Windows Ease of Access control panel (which can be\n"); 279 printf(" activated by pressing Windows + U). The Ease of Access\n"); 280 printf(" control panel has a Java Access Bridge checkbox. Please\n"); 281 printf(" be aware that unchecking the checkbox has no effect and\n"); 282 printf(" in order to disable the Java Access Bridge you must run\n"); 283 printf(" jabswitch.exe from the command line.\n"); 284} 285 286void printVersion() { 287 TCHAR executableFileName[_MAX_PATH]; 288 if (!GetModuleFileName(0, executableFileName, _MAX_PATH)) { 289 printf("Unable to get executable file name.\n"); 290 return; 291 } 292 DWORD nParam; 293 DWORD nVersionSize = GetFileVersionInfoSize(executableFileName, &nParam); 294 if (!nVersionSize) { 295 printf("Unable to get version info size.\n"); 296 return; 297 } 298 char* pVersionData = new char[nVersionSize]; 299 if (!GetFileVersionInfo(executableFileName, 0, nVersionSize, pVersionData)) { 300 printf("Unable to get version info.\n"); 301 return; 302 } 303 LPVOID pVersionInfo; 304 UINT nSize; 305 if (!VerQueryValue(pVersionData, _T("\\"), &pVersionInfo, &nSize)) { 306 printf("Unable to query version value.\n"); 307 return; 308 } 309 VS_FIXEDFILEINFO *pVSInfo = (VS_FIXEDFILEINFO *)pVersionInfo; 310 char versionString[100]; 311 sprintf_s( versionString, "version %i.%i.%i.%i", 312 pVSInfo->dwProductVersionMS >> 16, 313 pVSInfo->dwProductVersionMS & 0xFFFF, 314 pVSInfo->dwProductVersionLS >> 16, 315 pVSInfo->dwProductVersionLS & 0xFFFF ); 316 char outputString[100]; 317 strcpy_s(outputString, "jabswitch "); 318 strcat_s(outputString, versionString); 319 strcat_s(outputString, "\njabswitch enables or disables the Java Access Bridge.\n"); 320 printf(outputString); 321} 322 323int regEnable() { 324 HKEY hKey; 325 DWORD retval = -1; 326 LSTATUS err; 327 err = RegOpenKeyEx(HKEY_CURRENT_USER, ACCESSIBILITY_USER_KEY, NULL, KEY_READ|KEY_WRITE, &hKey); 328 if (err == ERROR_SUCCESS) { 329 DWORD dataType = REG_SZ; 330 DWORD dataLength = DEFAULT_ALLOC; 331 TCHAR dataBuffer[DEFAULT_ALLOC]; 332 TCHAR *data = dataBuffer; 333 bool freeData = false; 334 err = RegQueryValueEx(hKey, ACCESSIBILITY_CONFIG, 0, &dataType, (BYTE *)data, &dataLength); 335 if (err == ERROR_MORE_DATA) { 336 if (dataLength > 0 && dataLength < MAX_ALLOC) { 337 data = new TCHAR[dataLength]; 338 err = RegQueryValueEx(hKey, ACCESSIBILITY_CONFIG, 0, &dataType, (BYTE *)data, &dataLength); 339 } 340 } 341 if (err == ERROR_SUCCESS) { 342 err = _tcslwr_s(dataBuffer, DEFAULT_ALLOC); 343 if (err) { 344 return -1; 345 } 346 if (_tcsstr(dataBuffer, STR_ACCESSBRIDGE) != NULL) { 347 return 0; // This is OK, e.g. ran enable twice and the value is there. 348 } else { 349 // add oracle_javaaccessbridge to Config key for HKCU 350 dataLength = dataLength + (_tcslen(STR_ACCESSBRIDGE) + 1) * sizeof(TCHAR); 351 TCHAR *newStr = new TCHAR[dataLength]; 352 if (newStr != NULL) { 353 wsprintf(newStr, L"%s,%s", dataBuffer, STR_ACCESSBRIDGE); 354 RegSetValueEx(hKey, ACCESSIBILITY_CONFIG, 0, REG_SZ, (BYTE *)newStr, dataLength); 355 } 356 } 357 } 358 RegCloseKey(hKey); 359 } 360 return err; 361} 362 363int regDeleteValue(HKEY hFamilyKey, LPCWSTR lpSubKey) 364{ 365 HKEY hKey; 366 DWORD retval = -1; 367 LSTATUS err; 368 err = RegOpenKeyEx(hFamilyKey, lpSubKey, NULL, KEY_READ|KEY_WRITE|KEY_WOW64_64KEY, &hKey); 369 if (err != ERROR_SUCCESS) 370 err = RegOpenKeyEx(hFamilyKey, lpSubKey, NULL, KEY_READ|KEY_WRITE, &hKey); 371 372 if (err == ERROR_SUCCESS) { 373 DWORD dataType = REG_SZ; 374 DWORD dataLength = DEFAULT_ALLOC; 375 TCHAR dataBuffer[DEFAULT_ALLOC]; 376 TCHAR searchBuffer[DEFAULT_ALLOC]; 377 TCHAR *data = dataBuffer; 378 bool freeData = false; 379 err = RegQueryValueEx(hKey, ACCESSIBILITY_CONFIG, 0, &dataType, (BYTE *)data, &dataLength); 380 if (err == ERROR_MORE_DATA) { 381 if (dataLength > 0 && dataLength < MAX_ALLOC) { 382 data = new TCHAR[dataLength]; 383 err = RegQueryValueEx(hKey, ACCESSIBILITY_CONFIG, 0, &dataType, (BYTE *)data, &dataLength); 384 } 385 } 386 if (err == ERROR_SUCCESS) { 387 err = _tcslwr_s(dataBuffer, DEFAULT_ALLOC); 388 if (err) { 389 return -1; 390 } 391 if (_tcsstr(dataBuffer, STR_ACCESSBRIDGE) == NULL) { 392 return 0; // This is OK, e.g. ran disable twice and the value is not there. 393 } else { 394 // remove oracle_javaaccessbridge from Config key 395 TCHAR *newStr = new TCHAR[dataLength]; 396 TCHAR *nextToken; 397 LPTSTR tok, beg1 = dataBuffer; 398 bool first = true; 399 _tcscpy_s(newStr, dataLength, L""); 400 tok = _tcstok_s(beg1, L",", &nextToken); 401 while (tok != NULL) { 402 _tcscpy_s(searchBuffer, DEFAULT_ALLOC, tok); 403 err = _tcslwr_s(searchBuffer, DEFAULT_ALLOC); 404 if (err) { 405 return -1; 406 } 407 if (_tcsstr(searchBuffer, STR_ACCESSBRIDGE) == NULL) { 408 if (!first) { 409 _tcscat_s(newStr, dataLength, L","); 410 } 411 first = false; 412 _tcscat_s(newStr, dataLength, tok); 413 } 414 tok = _tcstok_s(NULL, L",", &nextToken); 415 } 416 dataLength = (_tcslen(newStr) + 1) * sizeof(TCHAR); 417 RegSetValueEx(hKey, ACCESSIBILITY_CONFIG, 0, REG_SZ, (BYTE *)newStr, dataLength); 418 } 419 } 420 RegCloseKey(hKey); 421 } 422 return err; 423} 424 425int regDisable() 426{ 427 LSTATUS err; 428 // Update value for HKCU 429 err=regDeleteValue(HKEY_CURRENT_USER, ACCESSIBILITY_USER_KEY); 430 // Update value for HKLM for Session 431 TCHAR dataBuffer[DEFAULT_ALLOC]; 432 DWORD dwSessionId ; 433 ProcessIdToSessionId(GetCurrentProcessId(),&dwSessionId ) ; 434 if( dwSessionId >= 0 ) 435 { 436 wsprintf(dataBuffer, L"%s%d", ACCESSIBILITY_SYSTEM_KEY, dwSessionId); 437 err=regDeleteValue(HKEY_LOCAL_MACHINE, dataBuffer); 438 } 439 return err; 440} 441 442void main(int argc, char* argv[]) { 443 bool enableWasRequested = false; 444 bool disableWasRequested = false; 445 bool badParams = true; 446 int error = 0; 447 if (argc == 2) { 448 if (_stricmp(argv[1], "-?") == 0 || _stricmp(argv[1], "/?") == 0) { 449 printUsage(); 450 badParams = false; 451 } else if (_stricmp(argv[1], "-version") == 0 || _stricmp(argv[1], "/version") == 0) { 452 printVersion(); 453 badParams = false; 454 } else { 455 if (_stricmp(argv[1], "-enable") == 0 || _stricmp(argv[1], "/enable") == 0) { 456 badParams = false; 457 enableWasRequested = true; 458 error = modify(true); 459 if (error == 0) { 460 if( !isXP() ) 461 regEnable(); 462 } 463 } else if (_stricmp(argv[1], "-disable") == 0 || _stricmp(argv[1], "/disable") == 0) { 464 badParams = false; 465 disableWasRequested = true; 466 error = modify(false); 467 if (error == 0) { 468 if( !isXP() ) 469 regDisable(); 470 } 471 } 472 } 473 } 474 if (badParams) { 475 printUsage(); 476 } else if (enableWasRequested || disableWasRequested) { 477 if (error != 0) { 478 printf("There was an error.\n\n"); 479 } 480 printf("The Java Access Bridge has "); 481 if (error != 0) { 482 printf("not "); 483 } 484 printf("been "); 485 if (enableWasRequested) { 486 printf("enabled.\n"); 487 } else { 488 printf("disabled.\n"); 489 } 490 // Use exit so test case can sense for error. 491 if (error != 0) { 492 exit(error); 493 } 494 } 495} 496