1 /* 2 * Copyright (c) 2005, 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 /* 27 * A class to track key JVM instance info from the AT WinAccessBridge 28 */ 29 30 #include "AccessBridgeDebug.h" 31 #include "AccessBridgeJavaVMInstance.h" 32 #include "AccessBridgeMessages.h" 33 #include "AccessBridgePackages.h" 34 #include "accessBridgeResource.h" // for debugging messages 35 36 #include <winbase.h> 37 #include <jni.h> 38 39 // The initialization must only be done one time and to provide for that the initialization 40 // is now done in WinAccessBridge and the CRITICAL_SECTION memory has been moved to there. 41 // send memory lock 42 //CRITICAL_SECTION sendMemoryIPCLock; 43 extern CRITICAL_SECTION sendMemoryIPCLock; 44 45 // protects the javaVMs chain while in use 46 extern bool isVMInstanceChainInUse; 47 48 DEBUG_CODE(extern HWND theDialogWindow); 49 extern "C" { 50 DEBUG_CODE(void AppendToCallInfo(char *s)); 51 } 52 53 54 /** 55 * 56 * 57 */ 58 AccessBridgeJavaVMInstance::AccessBridgeJavaVMInstance(HWND ourABWindow, 59 HWND javaABWindow, 60 long javaVMID, 61 AccessBridgeJavaVMInstance *next) { 62 goingAway = FALSE; 63 // This should be called once. Moved to WinAccessBridge c'tor 64 //InitializeCriticalSection(&sendMemoryIPCLock); 65 ourAccessBridgeWindow = ourABWindow; 66 javaAccessBridgeWindow = javaABWindow; 67 vmID = javaVMID; 68 nextJVMInstance = next; 69 memoryMappedFileMapHandle = (HANDLE) 0; 70 memoryMappedView = (char *) 0; 71 sprintf(memoryMappedFileName, "AccessBridge-%p-%p.mmf", 72 ourAccessBridgeWindow, javaAccessBridgeWindow); 73 } 74 75 /** 76 * 77 * 78 */ 79 AccessBridgeJavaVMInstance::~AccessBridgeJavaVMInstance() { 80 DEBUG_CODE(char buffer[256]); 81 82 DEBUG_CODE(AppendToCallInfo("***** in AccessBridgeJavaVMInstance::~AccessBridgeJavaVMInstance\r\n")); 83 EnterCriticalSection(&sendMemoryIPCLock); 84 85 // if IPC memory mapped file view is valid, unmap it 86 goingAway = TRUE; 87 if (memoryMappedView != (char *) 0) { 88 DEBUG_CODE(sprintf(buffer, " unmapping memoryMappedView; view = %p\r\n", memoryMappedView)); 89 DEBUG_CODE(AppendToCallInfo(buffer)); 90 UnmapViewOfFile(memoryMappedView); 91 memoryMappedView = (char *) 0; 92 } 93 // if IPC memory mapped file handle map is open, close it 94 if (memoryMappedFileMapHandle != (HANDLE) 0) { 95 DEBUG_CODE(sprintf(buffer, " closing memoryMappedFileMapHandle; handle = %p\r\n", memoryMappedFileMapHandle)); 96 DEBUG_CODE(AppendToCallInfo(buffer)); 97 CloseHandle(memoryMappedFileMapHandle); 98 memoryMappedFileMapHandle = (HANDLE) 0; 99 } 100 LeaveCriticalSection(&sendMemoryIPCLock); 101 102 } 103 104 /** 105 * initiateIPC - sets up the memory-mapped file to do IPC messaging 106 * 1 file is created: to handle requests for information 107 * initiated from Windows AT. The package is placed into 108 * the memory-mapped file (char *memoryMappedView), 109 * and then a special SendMessage() is sent. When the 110 * JavaDLL returns from SendMessage() processing, the 111 * data will be in memoryMappedView. The SendMessage() 112 * return value tells us if all is right with the world. 113 * 114 * The set-up proces involves creating the memory-mapped 115 * file, and handshaking with the JavaDLL so it knows 116 * about it as well. 117 * 118 */ 119 LRESULT 120 AccessBridgeJavaVMInstance::initiateIPC() { 121 DEBUG_CODE(char debugBuf[256]); 122 DWORD errorCode; 123 124 DEBUG_CODE(AppendToCallInfo(" in AccessBridgeJavaVMInstance::initiateIPC()\r\n")); 125 126 // create Windows-initiated IPC file & map it to a ptr 127 memoryMappedFileMapHandle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, 128 PAGE_READWRITE, 0, 129 // 8 bytes for return code 130 sizeof(WindowsInitiatedPackages) + 8, 131 memoryMappedFileName); 132 if (memoryMappedFileMapHandle == NULL) { 133 errorCode = GetLastError(); 134 DEBUG_CODE(sprintf(debugBuf, " Failed to CreateFileMapping for %s, error: %X", memoryMappedFileName, errorCode)); 135 DEBUG_CODE(AppendToCallInfo(debugBuf)); 136 return errorCode; 137 } else { 138 DEBUG_CODE(sprintf(debugBuf, " CreateFileMapping worked - filename: %s\r\n", memoryMappedFileName)); 139 DEBUG_CODE(AppendToCallInfo(debugBuf)); 140 } 141 142 memoryMappedView = (char *) MapViewOfFile(memoryMappedFileMapHandle, 143 FILE_MAP_READ | FILE_MAP_WRITE, 144 0, 0, 0); 145 if (memoryMappedView == NULL) { 146 errorCode = GetLastError(); 147 DEBUG_CODE(sprintf(debugBuf, " Failed to MapViewOfFile for %s, error: %X", memoryMappedFileName, errorCode)); 148 DEBUG_CODE(AppendToCallInfo(debugBuf)); 149 return errorCode; 150 } else { 151 DEBUG_CODE(sprintf(debugBuf, " MapViewOfFile worked - view: %p\r\n", memoryMappedView)); 152 DEBUG_CODE(AppendToCallInfo(debugBuf)); 153 } 154 155 156 // write some data to the memory mapped file 157 strcpy(memoryMappedView, AB_MEMORY_MAPPED_FILE_OK_QUERY); 158 159 160 // inform the JavaDLL that we've a memory mapped file ready for it 161 char buffer[sizeof(PackageType) + sizeof(MemoryMappedFileCreatedPackage)]; 162 PackageType *type = (PackageType *) buffer; 163 MemoryMappedFileCreatedPackage *pkg = (MemoryMappedFileCreatedPackage *) (buffer + sizeof(PackageType)); 164 *type = cMemoryMappedFileCreatedPackage; 165 pkg->bridgeWindow = ABHandleToLong(ourAccessBridgeWindow); 166 strncpy(pkg->filename, memoryMappedFileName, cMemoryMappedNameSize); 167 sendPackage(buffer, sizeof(buffer)); 168 169 170 // look for the JavaDLL's answer to see if it could read the file 171 if (strcmp(memoryMappedView, AB_MEMORY_MAPPED_FILE_OK_ANSWER) != 0) { 172 DEBUG_CODE(sprintf(debugBuf, " JavaVM failed to deal with memory mapped file %s\r\n", 173 memoryMappedFileName)); 174 DEBUG_CODE(AppendToCallInfo(debugBuf)); 175 return -1; 176 } else { 177 DEBUG_CODE(sprintf(debugBuf, " Success! JavaVM accpeted our file\r\n")); 178 DEBUG_CODE(AppendToCallInfo(debugBuf)); 179 } 180 181 return 0; 182 } 183 184 // ----------------------- 185 186 /** 187 * sendPackage - uses SendMessage(WM_COPYDATA) to do IPC messaging 188 * with the Java AccessBridge DLL 189 * 190 * NOTE: WM_COPYDATA is only for one-way IPC; there 191 * is no way to return parameters (especially big ones) 192 * Use sendMemoryPackage() to do that! 193 */ 194 LRESULT 195 AccessBridgeJavaVMInstance::sendPackage(char *buffer, long bufsize) { 196 COPYDATASTRUCT toCopy; 197 toCopy.dwData = 0; // 32-bits we could use for something... 198 toCopy.cbData = bufsize; 199 toCopy.lpData = buffer; 200 201 PrintDebugString("In AccessBridgeVMInstance::sendPackage"); 202 PrintDebugString(" javaAccessBridgeWindow: %p", javaAccessBridgeWindow); 203 /* This was SendMessage. Normally that is a blocking call. However, if 204 * SendMessage is sent to another process, e.g. another JVM and an incoming 205 * SendMessage is pending, control will be passed to the DialogProc to handle 206 * the incoming message. A bug occurred where this allowed an AB_DLL_GOING_AWAY 207 * message to be processed deleting an AccessBridgeJavaVMInstance object in 208 * the javaVMs chain. SendMessageTimeout with SMTO_BLOCK set will prevent the 209 * calling thread from processing other requests while waiting, i.e control 210 * will not be passed to the DialogProc. Also note that PostMessage or 211 * SendNotifyMessage can't be used. Although they don't allow transfer to 212 * the DialogProc they can't be used in cases where pointers are passed. This 213 * is because the referenced memory needs to be available when the other thread 214 * gets control. 215 */ 216 UINT flags = SMTO_BLOCK | SMTO_NOTIMEOUTIFNOTHUNG; 217 DWORD_PTR out; // not used 218 LRESULT lr = SendMessageTimeout( javaAccessBridgeWindow, WM_COPYDATA, 219 (WPARAM)ourAccessBridgeWindow, (LPARAM)&toCopy, 220 flags, 4000, &out ); 221 return lr; 222 } 223 224 225 /** 226 * sendMemoryPackage - uses Memory-Mapped files to do IPC messaging 227 * with the Java AccessBridge DLL, informing the 228 * Java AccessBridge DLL via SendMessage that something 229 * is waiting for it in the shared file... 230 * 231 * In the SendMessage call, the third param (WPARAM) is 232 * the source HWND (ourAccessBridgeWindow in this case), 233 * and the fourth param (LPARAM) is the size in bytes of 234 * the package put into shared memory. 235 * 236 */ 237 BOOL 238 AccessBridgeJavaVMInstance::sendMemoryPackage(char *buffer, long bufsize) { 239 240 // Protect against race condition where the memory mapped file is 241 // deallocated before the memory package is being sent 242 if (goingAway) { 243 return FALSE; 244 } 245 BOOL retval = FALSE; 246 247 DEBUG_CODE(char outputBuf[256]); 248 DEBUG_CODE(sprintf(outputBuf, "AccessBridgeJavaVMInstance::sendMemoryPackage(, %d)", bufsize)); 249 DEBUG_CODE(AppendToCallInfo(outputBuf)); 250 251 DEBUG_CODE(PackageType *type = (PackageType *) buffer); 252 DEBUG_CODE(if (*type == cGetAccessibleTextRangePackage) {) 253 DEBUG_CODE(AppendToCallInfo(" 'buffer' contains:")); 254 DEBUG_CODE(GetAccessibleTextRangePackage *pkg = (GetAccessibleTextRangePackage *) (buffer + sizeof(PackageType))); 255 DEBUG_CODE(sprintf(outputBuf, " PackageType = %X", *type)); 256 DEBUG_CODE(AppendToCallInfo(outputBuf)); 257 DEBUG_CODE(sprintf(outputBuf, " GetAccessibleTextRange: start = %d, end = %d, rText = %ls", 258 pkg->start, pkg->end, pkg->rText)); 259 DEBUG_CODE(AppendToCallInfo(outputBuf)); 260 DEBUG_CODE(}) 261 262 EnterCriticalSection(&sendMemoryIPCLock); 263 { 264 // copy the package into shared memory 265 if (!goingAway) { 266 memcpy(memoryMappedView, buffer, bufsize); 267 268 DEBUG_CODE(PackageType *type = (PackageType *) memoryMappedView); 269 DEBUG_CODE(if (*type == cGetAccessibleTextItemsPackage) {) 270 DEBUG_CODE(AppendToCallInfo(" 'memoryMappedView' now contains:")); 271 DEBUG_CODE(GetAccessibleTextItemsPackage *pkg = (GetAccessibleTextItemsPackage *) (buffer + sizeof(PackageType))); 272 DEBUG_CODE(sprintf(outputBuf, " PackageType = %X", *type)); 273 DEBUG_CODE(AppendToCallInfo(outputBuf)); 274 DEBUG_CODE(}) 275 } 276 277 if (!goingAway) { 278 // Let the recipient know there is a package waiting for them. The unset byte 279 // at end of buffer which will only be set if message is properly received 280 char *done = &memoryMappedView[bufsize]; 281 *done = 0; 282 283 PrintDebugString(" javaAccessBridgeWindow: %p", javaAccessBridgeWindow); 284 // See the comment above the call to SendMessageTimeout in SendPackage method above. 285 UINT flags = SMTO_BLOCK | SMTO_NOTIMEOUTIFNOTHUNG; 286 DWORD_PTR out; // not used 287 SendMessageTimeout( javaAccessBridgeWindow, AB_MESSAGE_WAITING, (WPARAM)ourAccessBridgeWindow, (LPARAM)bufsize, 288 flags, 4000, &out ); 289 290 // only succeed if message has been properly received 291 if(!goingAway) retval = (*done == 1); 292 } 293 294 // copy the package back from shared memory 295 if (!goingAway) { 296 memcpy(buffer, memoryMappedView, bufsize); 297 } 298 } 299 LeaveCriticalSection(&sendMemoryIPCLock); 300 return retval; 301 } 302 303 304 /** 305 * findAccessBridgeWindow - walk through linked list from where we are, 306 * return the HWND of the ABJavaVMInstance that 307 * matches the passed in vmID; no match: return 0 308 * 309 */ 310 HWND 311 AccessBridgeJavaVMInstance::findAccessBridgeWindow(long javaVMID) { 312 PrintDebugString("In findAccessBridgeWindow"); 313 // no need to recurse really 314 if (vmID == javaVMID) { 315 return javaAccessBridgeWindow; 316 } else { 317 isVMInstanceChainInUse = true; 318 AccessBridgeJavaVMInstance *current = nextJVMInstance; 319 while (current != (AccessBridgeJavaVMInstance *) 0) { 320 if (current->vmID == javaVMID) { 321 isVMInstanceChainInUse = false; 322 return current->javaAccessBridgeWindow; 323 } 324 current = current->nextJVMInstance; 325 } 326 isVMInstanceChainInUse = false; 327 } 328 return 0; 329 } 330 331 /** 332 * findABJavaVMInstanceFromJavaHWND - walk through linked list from 333 * where we are. Return the 334 * AccessBridgeJavaVMInstance 335 * of the ABJavaVMInstance that 336 * matches the passed in vmID; 337 * no match: return 0 338 */ 339 AccessBridgeJavaVMInstance * 340 AccessBridgeJavaVMInstance::findABJavaVMInstanceFromJavaHWND(HWND window) { 341 PrintDebugString("In findABJavaInstanceFromJavaHWND"); 342 // no need to recurse really 343 if (javaAccessBridgeWindow == window) { 344 return this; 345 } else { 346 isVMInstanceChainInUse = true; 347 AccessBridgeJavaVMInstance *current = nextJVMInstance; 348 while (current != (AccessBridgeJavaVMInstance *) 0) { 349 if (current->javaAccessBridgeWindow == window) { 350 isVMInstanceChainInUse = false; 351 return current; 352 } 353 current = current->nextJVMInstance; 354 } 355 } 356 isVMInstanceChainInUse = false; 357 return (AccessBridgeJavaVMInstance *) 0; 358 }