mirror of
https://github.com/openjdk/jdk.git
synced 2026-07-28 11:53:09 +00:00
359 lines
15 KiB
C++
359 lines
15 KiB
C++
/*
|
|
* Copyright (c) 2005, 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.
|
|
*/
|
|
|
|
/*
|
|
* A class to track key JVM instance info from the AT WinAccessBridge
|
|
*/
|
|
|
|
#include "AccessBridgeDebug.h"
|
|
#include "AccessBridgeJavaVMInstance.h"
|
|
#include "AccessBridgeMessages.h"
|
|
#include "AccessBridgePackages.h"
|
|
#include "accessBridgeResource.h" // for debugging messages
|
|
|
|
#include <winbase.h>
|
|
#include <jni.h>
|
|
|
|
// The initialization must only be done one time and to provide for that the initialization
|
|
// is now done in WinAccessBridge and the CRITICAL_SECTION memory has been moved to there.
|
|
// send memory lock
|
|
//CRITICAL_SECTION sendMemoryIPCLock;
|
|
extern CRITICAL_SECTION sendMemoryIPCLock;
|
|
|
|
// protects the javaVMs chain while in use
|
|
extern bool isVMInstanceChainInUse;
|
|
|
|
DEBUG_CODE(extern HWND theDialogWindow);
|
|
extern "C" {
|
|
DEBUG_CODE(void AppendToCallInfo(const char *s));
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
*
|
|
*/
|
|
AccessBridgeJavaVMInstance::AccessBridgeJavaVMInstance(HWND ourABWindow,
|
|
HWND javaABWindow,
|
|
long javaVMID,
|
|
AccessBridgeJavaVMInstance *next) {
|
|
goingAway = FALSE;
|
|
// This should be called once. Moved to WinAccessBridge c'tor
|
|
//InitializeCriticalSection(&sendMemoryIPCLock);
|
|
ourAccessBridgeWindow = ourABWindow;
|
|
javaAccessBridgeWindow = javaABWindow;
|
|
vmID = javaVMID;
|
|
nextJVMInstance = next;
|
|
memoryMappedFileMapHandle = (HANDLE) 0;
|
|
memoryMappedView = (char *) 0;
|
|
sprintf(memoryMappedFileName, "AccessBridge-%p-%p.mmf",
|
|
ourAccessBridgeWindow, javaAccessBridgeWindow);
|
|
}
|
|
|
|
/**
|
|
*
|
|
*
|
|
*/
|
|
AccessBridgeJavaVMInstance::~AccessBridgeJavaVMInstance() {
|
|
DEBUG_CODE(char buffer[256]);
|
|
|
|
DEBUG_CODE(AppendToCallInfo("***** in AccessBridgeJavaVMInstance::~AccessBridgeJavaVMInstance\r\n"));
|
|
EnterCriticalSection(&sendMemoryIPCLock);
|
|
|
|
// if IPC memory mapped file view is valid, unmap it
|
|
goingAway = TRUE;
|
|
if (memoryMappedView != (char *) 0) {
|
|
DEBUG_CODE(sprintf(buffer, " unmapping memoryMappedView; view = %p\r\n", memoryMappedView));
|
|
DEBUG_CODE(AppendToCallInfo(buffer));
|
|
UnmapViewOfFile(memoryMappedView);
|
|
memoryMappedView = (char *) 0;
|
|
}
|
|
// if IPC memory mapped file handle map is open, close it
|
|
if (memoryMappedFileMapHandle != (HANDLE) 0) {
|
|
DEBUG_CODE(sprintf(buffer, " closing memoryMappedFileMapHandle; handle = %p\r\n", memoryMappedFileMapHandle));
|
|
DEBUG_CODE(AppendToCallInfo(buffer));
|
|
CloseHandle(memoryMappedFileMapHandle);
|
|
memoryMappedFileMapHandle = (HANDLE) 0;
|
|
}
|
|
LeaveCriticalSection(&sendMemoryIPCLock);
|
|
|
|
}
|
|
|
|
/**
|
|
* initiateIPC - sets up the memory-mapped file to do IPC messaging
|
|
* 1 file is created: to handle requests for information
|
|
* initiated from Windows AT. The package is placed into
|
|
* the memory-mapped file (char *memoryMappedView),
|
|
* and then a special SendMessage() is sent. When the
|
|
* JavaDLL returns from SendMessage() processing, the
|
|
* data will be in memoryMappedView. The SendMessage()
|
|
* return value tells us if all is right with the world.
|
|
*
|
|
* The set-up proces involves creating the memory-mapped
|
|
* file, and handshaking with the JavaDLL so it knows
|
|
* about it as well.
|
|
*
|
|
*/
|
|
LRESULT
|
|
AccessBridgeJavaVMInstance::initiateIPC() {
|
|
DEBUG_CODE(char debugBuf[256]);
|
|
DWORD errorCode;
|
|
|
|
DEBUG_CODE(AppendToCallInfo(" in AccessBridgeJavaVMInstance::initiateIPC()\r\n"));
|
|
|
|
// create Windows-initiated IPC file & map it to a ptr
|
|
memoryMappedFileMapHandle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
|
|
PAGE_READWRITE, 0,
|
|
// 8 bytes for return code
|
|
sizeof(WindowsInitiatedPackages) + 8,
|
|
memoryMappedFileName);
|
|
if (memoryMappedFileMapHandle == NULL) {
|
|
errorCode = GetLastError();
|
|
DEBUG_CODE(sprintf(debugBuf, " Failed to CreateFileMapping for %s, error: %X", memoryMappedFileName, errorCode));
|
|
DEBUG_CODE(AppendToCallInfo(debugBuf));
|
|
return errorCode;
|
|
} else {
|
|
DEBUG_CODE(sprintf(debugBuf, " CreateFileMapping worked - filename: %s\r\n", memoryMappedFileName));
|
|
DEBUG_CODE(AppendToCallInfo(debugBuf));
|
|
}
|
|
|
|
memoryMappedView = (char *) MapViewOfFile(memoryMappedFileMapHandle,
|
|
FILE_MAP_READ | FILE_MAP_WRITE,
|
|
0, 0, 0);
|
|
if (memoryMappedView == NULL) {
|
|
errorCode = GetLastError();
|
|
DEBUG_CODE(sprintf(debugBuf, " Failed to MapViewOfFile for %s, error: %X", memoryMappedFileName, errorCode));
|
|
DEBUG_CODE(AppendToCallInfo(debugBuf));
|
|
return errorCode;
|
|
} else {
|
|
DEBUG_CODE(sprintf(debugBuf, " MapViewOfFile worked - view: %p\r\n", memoryMappedView));
|
|
DEBUG_CODE(AppendToCallInfo(debugBuf));
|
|
}
|
|
|
|
|
|
// write some data to the memory mapped file
|
|
strcpy(memoryMappedView, AB_MEMORY_MAPPED_FILE_OK_QUERY);
|
|
|
|
|
|
// inform the JavaDLL that we've a memory mapped file ready for it
|
|
char buffer[sizeof(PackageType) + sizeof(MemoryMappedFileCreatedPackage)];
|
|
PackageType *type = (PackageType *) buffer;
|
|
MemoryMappedFileCreatedPackage *pkg = (MemoryMappedFileCreatedPackage *) (buffer + sizeof(PackageType));
|
|
*type = cMemoryMappedFileCreatedPackage;
|
|
pkg->bridgeWindow = ABHandleToLong(ourAccessBridgeWindow);
|
|
strncpy(pkg->filename, memoryMappedFileName, cMemoryMappedNameSize);
|
|
sendPackage(buffer, sizeof(buffer));
|
|
|
|
|
|
// look for the JavaDLL's answer to see if it could read the file
|
|
if (strcmp(memoryMappedView, AB_MEMORY_MAPPED_FILE_OK_ANSWER) != 0) {
|
|
DEBUG_CODE(sprintf(debugBuf, " JavaVM failed to deal with memory mapped file %s\r\n",
|
|
memoryMappedFileName));
|
|
DEBUG_CODE(AppendToCallInfo(debugBuf));
|
|
return -1;
|
|
} else {
|
|
DEBUG_CODE(sprintf(debugBuf, " Success! JavaVM accpeted our file\r\n"));
|
|
DEBUG_CODE(AppendToCallInfo(debugBuf));
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
// -----------------------
|
|
|
|
/**
|
|
* sendPackage - uses SendMessage(WM_COPYDATA) to do IPC messaging
|
|
* with the Java AccessBridge DLL
|
|
*
|
|
* NOTE: WM_COPYDATA is only for one-way IPC; there
|
|
* is no way to return parameters (especially big ones)
|
|
* Use sendMemoryPackage() to do that!
|
|
*/
|
|
LRESULT
|
|
AccessBridgeJavaVMInstance::sendPackage(char *buffer, long bufsize) {
|
|
COPYDATASTRUCT toCopy;
|
|
toCopy.dwData = 0; // 32-bits we could use for something...
|
|
toCopy.cbData = bufsize;
|
|
toCopy.lpData = buffer;
|
|
|
|
PrintDebugString("[INFO]: In AccessBridgeVMInstance::sendPackage");
|
|
PrintDebugString("[INFO]: javaAccessBridgeWindow: %p", javaAccessBridgeWindow);
|
|
/* This was SendMessage. Normally that is a blocking call. However, if
|
|
* SendMessage is sent to another process, e.g. another JVM and an incoming
|
|
* SendMessage is pending, control will be passed to the DialogProc to handle
|
|
* the incoming message. A bug occurred where this allowed an AB_DLL_GOING_AWAY
|
|
* message to be processed deleting an AccessBridgeJavaVMInstance object in
|
|
* the javaVMs chain. SendMessageTimeout with SMTO_BLOCK set will prevent the
|
|
* calling thread from processing other requests while waiting, i.e control
|
|
* will not be passed to the DialogProc. Also note that PostMessage or
|
|
* SendNotifyMessage can't be used. Although they don't allow transfer to
|
|
* the DialogProc they can't be used in cases where pointers are passed. This
|
|
* is because the referenced memory needs to be available when the other thread
|
|
* gets control.
|
|
*/
|
|
UINT flags = SMTO_BLOCK | SMTO_NOTIMEOUTIFNOTHUNG;
|
|
DWORD_PTR out; // not used
|
|
LRESULT lr = SendMessageTimeout( javaAccessBridgeWindow, WM_COPYDATA,
|
|
(WPARAM)ourAccessBridgeWindow, (LPARAM)&toCopy,
|
|
flags, 4000, &out );
|
|
return lr;
|
|
}
|
|
|
|
|
|
/**
|
|
* sendMemoryPackage - uses Memory-Mapped files to do IPC messaging
|
|
* with the Java AccessBridge DLL, informing the
|
|
* Java AccessBridge DLL via SendMessage that something
|
|
* is waiting for it in the shared file...
|
|
*
|
|
* In the SendMessage call, the third param (WPARAM) is
|
|
* the source HWND (ourAccessBridgeWindow in this case),
|
|
* and the fourth param (LPARAM) is the size in bytes of
|
|
* the package put into shared memory.
|
|
*
|
|
*/
|
|
BOOL
|
|
AccessBridgeJavaVMInstance::sendMemoryPackage(char *buffer, long bufsize) {
|
|
|
|
// Protect against race condition where the memory mapped file is
|
|
// deallocated before the memory package is being sent
|
|
if (goingAway) {
|
|
return FALSE;
|
|
}
|
|
BOOL retval = FALSE;
|
|
|
|
DEBUG_CODE(char outputBuf[256]);
|
|
DEBUG_CODE(sprintf(outputBuf, "AccessBridgeJavaVMInstance::sendMemoryPackage(, %d)", bufsize));
|
|
DEBUG_CODE(AppendToCallInfo(outputBuf));
|
|
|
|
DEBUG_CODE(PackageType *type = (PackageType *) buffer);
|
|
DEBUG_CODE(if (*type == cGetAccessibleTextRangePackage) {)
|
|
DEBUG_CODE(AppendToCallInfo(" 'buffer' contains:"));
|
|
DEBUG_CODE(GetAccessibleTextRangePackage *pkg = (GetAccessibleTextRangePackage *) (buffer + sizeof(PackageType)));
|
|
DEBUG_CODE(sprintf(outputBuf, " PackageType = %X", *type));
|
|
DEBUG_CODE(AppendToCallInfo(outputBuf));
|
|
DEBUG_CODE(sprintf(outputBuf, " GetAccessibleTextRange: start = %d, end = %d, rText = %ls",
|
|
pkg->start, pkg->end, pkg->rText));
|
|
DEBUG_CODE(AppendToCallInfo(outputBuf));
|
|
DEBUG_CODE(})
|
|
|
|
EnterCriticalSection(&sendMemoryIPCLock);
|
|
{
|
|
// copy the package into shared memory
|
|
if (!goingAway) {
|
|
memcpy(memoryMappedView, buffer, bufsize);
|
|
|
|
DEBUG_CODE(PackageType *type = (PackageType *) memoryMappedView);
|
|
DEBUG_CODE(if (*type == cGetAccessibleTextItemsPackage) {)
|
|
DEBUG_CODE(AppendToCallInfo(" 'memoryMappedView' now contains:"));
|
|
DEBUG_CODE(GetAccessibleTextItemsPackage *pkg = (GetAccessibleTextItemsPackage *) (buffer + sizeof(PackageType)));
|
|
DEBUG_CODE(sprintf(outputBuf, " PackageType = %X", *type));
|
|
DEBUG_CODE(AppendToCallInfo(outputBuf));
|
|
DEBUG_CODE(})
|
|
}
|
|
|
|
if (!goingAway) {
|
|
// Let the recipient know there is a package waiting for them. The unset byte
|
|
// at end of buffer which will only be set if message is properly received
|
|
char *done = &memoryMappedView[bufsize];
|
|
*done = 0;
|
|
|
|
PrintDebugString("[INFO]: javaAccessBridgeWindow: %p", javaAccessBridgeWindow);
|
|
// See the comment above the call to SendMessageTimeout in SendPackage method above.
|
|
UINT flags = SMTO_BLOCK | SMTO_NOTIMEOUTIFNOTHUNG;
|
|
DWORD_PTR out; // not used
|
|
SendMessageTimeout( javaAccessBridgeWindow, AB_MESSAGE_WAITING, (WPARAM)ourAccessBridgeWindow, (LPARAM)bufsize,
|
|
flags, 4000, &out );
|
|
|
|
// only succeed if message has been properly received
|
|
if(!goingAway) retval = (*done == 1);
|
|
}
|
|
|
|
// copy the package back from shared memory
|
|
if (!goingAway) {
|
|
memcpy(buffer, memoryMappedView, bufsize);
|
|
}
|
|
}
|
|
LeaveCriticalSection(&sendMemoryIPCLock);
|
|
return retval;
|
|
}
|
|
|
|
|
|
/**
|
|
* findAccessBridgeWindow - walk through linked list from where we are,
|
|
* return the HWND of the ABJavaVMInstance that
|
|
* matches the passed in vmID; no match: return 0
|
|
*
|
|
*/
|
|
HWND
|
|
AccessBridgeJavaVMInstance::findAccessBridgeWindow(long javaVMID) {
|
|
PrintDebugString("[INFO]: In findAccessBridgeWindow");
|
|
// no need to recurse really
|
|
if (vmID == javaVMID) {
|
|
return javaAccessBridgeWindow;
|
|
} else {
|
|
isVMInstanceChainInUse = true;
|
|
AccessBridgeJavaVMInstance *current = nextJVMInstance;
|
|
while (current != (AccessBridgeJavaVMInstance *) 0) {
|
|
if (current->vmID == javaVMID) {
|
|
isVMInstanceChainInUse = false;
|
|
return current->javaAccessBridgeWindow;
|
|
}
|
|
current = current->nextJVMInstance;
|
|
}
|
|
isVMInstanceChainInUse = false;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* findABJavaVMInstanceFromJavaHWND - walk through linked list from
|
|
* where we are. Return the
|
|
* AccessBridgeJavaVMInstance
|
|
* of the ABJavaVMInstance that
|
|
* matches the passed in vmID;
|
|
* no match: return 0
|
|
*/
|
|
AccessBridgeJavaVMInstance *
|
|
AccessBridgeJavaVMInstance::findABJavaVMInstanceFromJavaHWND(HWND window) {
|
|
PrintDebugString("[INFO]: In findABJavaInstanceFromJavaHWND");
|
|
// no need to recurse really
|
|
if (javaAccessBridgeWindow == window) {
|
|
return this;
|
|
} else {
|
|
isVMInstanceChainInUse = true;
|
|
AccessBridgeJavaVMInstance *current = nextJVMInstance;
|
|
while (current != (AccessBridgeJavaVMInstance *) 0) {
|
|
if (current->javaAccessBridgeWindow == window) {
|
|
isVMInstanceChainInUse = false;
|
|
return current;
|
|
}
|
|
current = current->nextJVMInstance;
|
|
}
|
|
}
|
|
isVMInstanceChainInUse = false;
|
|
return (AccessBridgeJavaVMInstance *) 0;
|
|
}
|