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 AT instance info from the JavaAccessBridge
28 */
29
30#include "AccessBridgeDebug.h"
31#include "AccessBridgeATInstance.h"
32#include "AccessBridgeMessages.h"
33
34#include <windows.h>
35#include <winbase.h>
36
37
38/**
39 *  AccessBridgeATInstance constructor
40 */
41AccessBridgeATInstance::AccessBridgeATInstance(HWND ourABWindow, HWND winABWindow,
42                                               char *memoryFilename,
43                                               AccessBridgeATInstance *next) {
44    ourAccessBridgeWindow = ourABWindow;
45    winAccessBridgeWindow = winABWindow;
46    nextATInstance = next;
47    javaEventMask = 0;
48    accessibilityEventMask = 0;
49    strncpy(memoryMappedFileName, memoryFilename, cMemoryMappedNameSize);
50}
51
52/**
53 * AccessBridgeATInstance descructor
54 */
55AccessBridgeATInstance::~AccessBridgeATInstance() {
56    PrintDebugString("\r\nin AccessBridgeATInstance::~AccessBridgeATInstance");
57
58    // if IPC memory mapped file view is valid, unmap it
59    if (memoryMappedView != (char *) 0) {
60        PrintDebugString("  unmapping memoryMappedView; view = %p", memoryMappedView);
61        UnmapViewOfFile(memoryMappedView);
62        memoryMappedView = (char *) 0;
63    }
64    // if IPC memory mapped file handle map is open, close it
65    if (memoryMappedFileMapHandle != (HANDLE) 0) {
66        PrintDebugString("  closing memoryMappedFileMapHandle; handle = %p", memoryMappedFileMapHandle);
67        CloseHandle(memoryMappedFileMapHandle);
68        memoryMappedFileMapHandle = (HANDLE) 0;
69    }
70}
71
72/**
73 * Sets up the memory-mapped file to do IPC messaging
74 * 1 files is created: to handle requests for information
75 * initiated from Windows AT.  The package is placed into
76 * the memory-mapped file (char *memoryMappedView),
77 * and then a special SendMessage() is sent.  When the
78 * JavaDLL returns from SendMessage() processing, the
79 * data will be in memoryMappedView.  The SendMessage()
80 * return value tells us if all is right with the world.
81 *
82 * The set-up proces involves creating the memory-mapped
83 * file, and writing a special string to it so that the
84 * WindowsDLL so it knows about it as well.
85 */
86LRESULT
87AccessBridgeATInstance::initiateIPC() {
88    DWORD errorCode;
89
90    PrintDebugString("\r\nIn AccessBridgeATInstance::initiateIPC()");
91
92    // open Windows-initiated IPC filemap & map it to a ptr
93
94    memoryMappedFileMapHandle = OpenFileMapping(FILE_MAP_READ | FILE_MAP_WRITE,
95                                                FALSE, memoryMappedFileName);
96    if (memoryMappedFileMapHandle == NULL) {
97        errorCode = GetLastError();
98        PrintDebugString("  Failed to CreateFileMapping for %s, error: %X", memoryMappedFileName, errorCode);
99        return errorCode;
100    } else {
101        PrintDebugString("  CreateFileMapping worked - filename: %s", memoryMappedFileName);
102    }
103
104    memoryMappedView = (char *) MapViewOfFile(memoryMappedFileMapHandle,
105                                              FILE_MAP_READ | FILE_MAP_WRITE,
106                                              0, 0, 0);
107    if (memoryMappedView == NULL) {
108        errorCode = GetLastError();
109        PrintDebugString("  Failed to MapViewOfFile for %s, error: %X", memoryMappedFileName, errorCode);
110        return errorCode;
111    } else {
112        PrintDebugString("  MapViewOfFile worked - view: %p", memoryMappedView);
113    }
114
115
116    // look for the JavaDLL's answer to see if it could read the file
117    if (strcmp(memoryMappedView, AB_MEMORY_MAPPED_FILE_OK_QUERY) != 0) {
118        PrintDebugString("  JavaVM failed to write to memory mapped file %s",
119                         memoryMappedFileName);
120        return -1;
121    } else {
122        PrintDebugString("  JavaVM successfully wrote to file!");
123    }
124
125
126    // write some data to the memory mapped file for WindowsDLL to verify
127    strcpy(memoryMappedView, AB_MEMORY_MAPPED_FILE_OK_ANSWER);
128
129
130    return 0;
131}
132
133
134typedef struct EVENT_STRUCT
135{
136    char *buffer;
137    int bufsize;
138    ABHWND64 winAccessBridgeWindow;
139    ABHWND64 ourAccessBridgeWindow;
140}EVENT_STRUCT;
141
142
143#include <process.h>
144#define THREAD_PROC unsigned int __stdcall
145typedef unsigned int (__stdcall *THREAD_ROUTINE)(LPVOID lpThreadParameter);
146
147static HANDLE BeginThread(THREAD_ROUTINE thread_func,DWORD *id,DWORD param)
148{
149    HANDLE ret;
150    ret = (HANDLE) _beginthreadex(NULL,0,thread_func,(void *)param,0,(unsigned int *)id);
151    if(ret == INVALID_HANDLE_VALUE)
152        ret = NULL;
153    return(ret);
154}
155
156DWORD JavaBridgeThreadId = 0;
157
158static THREAD_PROC JavaBridgeThread(LPVOID param1)
159{
160    MSG msg;
161    DWORD rc = 0;
162    while (GetMessage(&msg,        // message structure
163                      NULL,                  // handle of window receiving the message
164                      0,                  // lowest message to examine
165                      0))                 // highest message to examine
166        {
167            if(msg.message == WM_USER)
168                {
169                    EVENT_STRUCT *event_struct = (EVENT_STRUCT *)msg.wParam;
170                    COPYDATASTRUCT toCopy;
171                    toCopy.dwData = 0;          // 32-bits we could use for something...
172                    toCopy.cbData = event_struct->bufsize;
173                    toCopy.lpData = event_struct->buffer;
174
175                    LRESULT ret = SendMessage((HWND)ABLongToHandle(event_struct->winAccessBridgeWindow), WM_COPYDATA,
176                                              (WPARAM)event_struct->ourAccessBridgeWindow, (LPARAM) &toCopy);
177                    delete event_struct->buffer;
178                    delete event_struct;
179                }
180            if(msg.message == (WM_USER+1))
181                PostQuitMessage(0);
182        }
183    JavaBridgeThreadId = 0;
184    return(0);
185}
186
187/*
188 * Handles one event
189 */
190static void do_event(char *buffer, int bufsize,HWND ourAccessBridgeWindow,HWND winAccessBridgeWindow)
191{
192    EVENT_STRUCT *event_struct = new EVENT_STRUCT;
193    event_struct->bufsize = bufsize;
194    event_struct->buffer = new char[bufsize];
195    memcpy(event_struct->buffer,buffer,bufsize);
196    event_struct->ourAccessBridgeWindow = ABHandleToLong(ourAccessBridgeWindow);
197    event_struct->winAccessBridgeWindow = ABHandleToLong(winAccessBridgeWindow);
198    if(!JavaBridgeThreadId)
199        {
200            HANDLE JavaBridgeThreadHandle = BeginThread(JavaBridgeThread,&JavaBridgeThreadId,(DWORD)event_struct);
201            CloseHandle(JavaBridgeThreadHandle);
202        }
203    PostThreadMessage(JavaBridgeThreadId,WM_USER,(WPARAM)event_struct,0);
204}
205
206
207/**
208 * sendJavaEventPackage - uses SendMessage(WM_COPYDATA) to do
209 *                        IPC messaging with the Java AccessBridge DLL
210 *                        to propogate events to those ATs that want 'em
211 *
212 */
213LRESULT
214AccessBridgeATInstance::sendJavaEventPackage(char *buffer, int bufsize, long eventID) {
215
216    PrintDebugString("AccessBridgeATInstance::sendJavaEventPackage() eventID = %X", eventID);
217    PrintDebugString("AccessBridgeATInstance::sendJavaEventPackage() (using PostMessage) eventID = %X", eventID);
218
219    if (eventID & javaEventMask) {
220        do_event(buffer,bufsize,ourAccessBridgeWindow,winAccessBridgeWindow);
221        return(0);
222    } else {
223        return -1;
224    }
225}
226
227
228/**
229 * uses SendMessage(WM_COPYDATA) to do
230 * IPC messaging with the Java AccessBridge DLL
231 * to propogate events to those ATs that want 'em
232 *
233 */
234LRESULT
235AccessBridgeATInstance::sendAccessibilityEventPackage(char *buffer, int bufsize, long eventID) {
236
237    PrintDebugString("AccessBridgeATInstance::sendAccessibilityEventPackage() eventID = %X", eventID);
238
239    if (eventID & accessibilityEventMask) {
240        do_event(buffer,bufsize,ourAccessBridgeWindow,winAccessBridgeWindow);
241        return(0);
242    } else {
243        return -1;
244    }
245}
246
247
248/**
249 * findABATInstanceFromATHWND - walk through linked list from
250 *                              where we are.  Return the
251 *                              AccessBridgeATInstance
252 *                              of the ABATInstance that
253 *                              matches the passed in vmID;
254 *                              no match: return 0
255 */
256AccessBridgeATInstance *
257AccessBridgeATInstance::findABATInstanceFromATHWND(HWND window) {
258    // no need to recurse really
259    if (winAccessBridgeWindow == window) {
260        return this;
261    } else {
262        AccessBridgeATInstance *current = nextATInstance;
263        while (current != (AccessBridgeATInstance *) 0) {
264            if (current->winAccessBridgeWindow == window) {
265                return current;
266            }
267            current = current->nextATInstance;
268        }
269    }
270    return (AccessBridgeATInstance *) 0;
271}
272