JavaAccessBridge的使用


写在前面

工作中要通过自动化来操作java桌面程序,Windows的UIA只能识别顶层窗口,无法具体到内部的元素,所以无法使用,经过一番搜索,发现可以通过JavaAccessBridge来访问java中的ui组件。

相关文件

Java在某个版本后内置了JAB,可以在JDK安装目录\\include\\win32\\bridge下找到以下文件:

  1. AccessBridgeCallbacks.h (事件监听)
  2. AccessBridgeCalls.c (API)
  3. AccessBridgeCalls.h (API)
  4. AccessBridgePackages.h (数据结构)

可以在JDK安装目录\\include下找到以下文件:

  1. jni.h (数据类型)

可以在JRE安装目录\\include下找到以下文件:

  1. WindowsAccessBridge-64.dll (包含API具体实现的动态链接库)

文档

JavaAccessBridge指引
JavaAccessBridge介绍

在使用前,一定要通过命令行或控制面板启用jab。

C++调用

正常来说,只需要#include "AccessBridgeCalls.c"#include "AccessBridgeCalls.h"就可以轻松愉快的使用了,然而这样会存在一些问题,具体什么问题我忘了,反正编译无法通过。
AccessBridgeCalls.c稍作修改得到AccessBridgeCalls.cpp:

#include <jni.h>
#include <bridge/AccessBridgeCalls.h>

#define ACCESSBRIDGE_ARCH_64
#define error_code_offset 0x00007FF892C571C5 - 0x00007FF892C50000

// 某些版本的`WindowsAccessBridge-64.dll`存在bug,无法正常回调,所以要修改汇编指令
static unsigned char fix_asm_code[] = { 0x49,0x8B,0xF9 }; // mov rdi,r9
void fix_jab(HMODULE BaseAddr) {
    LONGLONG dwFixAddr = (LONGLONG)BaseAddr + error_code_offset;
    DWORD OldProtext = 0;
    VirtualProtect((LPVOID)dwFixAddr, 3, PAGE_EXECUTE_READWRITE, &OldProtext);
    memcpy((void*)dwFixAddr, fix_asm_code, 3);
    VirtualProtect((LPVOID)dwFixAddr, 5, OldProtext, &OldProtext);
}

#ifdef __cplusplus
extern "C" {
#endif

    HINSTANCE theAccessBridgeInstance;
    AccessBridgeFPs theAccessBridge;

    BOOL theAccessBridgeInitializedFlag = FALSE;

#define LOAD_FP(result, type, name) \
    if ((theAccessBridge.result = \
        (type) GetProcAddress(theAccessBridgeInstance, name)) == (type) 0) { \
        return FALSE; \
    }

    BOOL initializeAccessBridge() {
// 这里看你使用的编码,如果是unicode,要在字符串前面加L,如果是ANSI则无需改动
#ifdef ACCESSBRIDGE_ARCH_32 // For 32bit AT new bridge
        theAccessBridgeInstance = LoadLibrary(L"WINDOWSACCESSBRIDGE-32");
#else
#ifdef ACCESSBRIDGE_ARCH_64 // For 64bit AT new bridge
        theAccessBridgeInstance = LoadLibrary(L"WINDOWSACCESSBRIDGE-64");
#else // legacy
        theAccessBridgeInstance = LoadLibrary(L"WINDOWSACCESSBRIDGE");
#endif
#endif
// 后面的跟AccessBridgeCalls.c完全一样,篇幅受限,就不写了
...

使用API

调用JAB的进程需要包含一个消息循环(消息循环必须在调用API之前创建完成),否则无法和Java虚拟机通信。

void PumbThread() {
    ChangeWindowMessageFilter(WM_COPYDATA, 1);
    for (int i = WM_USER + 0x1; i < 0xffff; i++) {
        if (!ChangeWindowMessageFilter(i, 1)) {
            cout << i << "error" << endl;
        }
    }
    INITCOMMONCONTROLSEX cc;
    cc.dwSize = sizeof(INITCOMMONCONTROLSEX);
    cc.dwICC = ICC_TREEVIEW_CLASSES;
    InitCommonControlsEx(&cc);
    // 初始化
    BOOL result = initializeAccessBridge();
    if (result != FALSE) {
        MSG msg = { 0 };
        int ret;
        while ((ret = GetMessage(&msg, 0, 0, 0)) != 0) {
            switch (msg.message) {
            case 0x401:
                break;
            }
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        // 卸载
        shutdownAccessBridge();
    }
}

一段简单的处理逻辑

#include <jni.h>
#include <bridge/AccessBridgeCalls.h>
#include <bridge/AccessBridgeCallbacks.h>

// 鼠标点击事件回调函数
void OnMouseClicked(long vmID, JOBJECT64 event, JOBJECT64 source) {
    AccessibleContextInfo aci = { 0 };
    printf("MouseClicked: vmID: 0x%08lX, event: 0x%016llX, source: 0x%016llX\n", vmID, event, source);
    if (GetAccessibleContextInfo(vmID, source, &aci)) {
        printf("role: %ws, name: %ws\n", aci.role, wcslen(aci.name) != 0 ? aci.name : L"null");
    }
    ReleaseJavaObject(vmID, source);
    ReleaseJavaObject(vmID, event);
}

void dealJavaWindow(HWND hwnd) {
    // 判断是否是java窗口
    if (IsJavaWindow(hwnd)) {
        long vmId = 0;
        AccessibleContext ac = { 0 };
        // 根据窗口句柄获取虚拟机ID和控件的AccessibleContext
        if (GetAccessibleContextFromHWND(hwnd, &vmId, &ac) == FALSE) {
            return;
        };
        // 获取Java版本信息
        AccessBridgeVersionInfo version = { 0 };
        GetVersionInfo(vmId, &version);
        wcout << version.bridgeWinDLLVersion << endl;
        AccessibleContextInfo aci = { 0 };
        // 获取可见子元素数量
        int length = getVisibleChildrenCount(vmId, ac);
        VisibleChildrenInfo vci = { 0 };
        // 获取可见子元素
        getVisibleChildren(vmId, ac, 0, &vci);
        for (int i = 0; i < vci.returnedChildrenCount; i++) {
            AccessibleContext* ac_temp = &vci.children[i];
            GetAccessibleContextInfo(vmId, *ac_temp, &aci);
            RECT ac_rect = { aci.x,aci.y,aci.x + aci.width,aci.y + aci.height };
        }
        wcout << (long long)hwnd << L" is a java window" << endl;
        SetMouseClicked(NULL);
        SetMouseClicked(OnMouseClicked);
        return;
    }
    else {
        wcout << (long long)hwnd << L" is not java window" << endl;
    }
}

int main() {
    DWORD threadid = 0;
    wcout.imbue(locale("chs"));
    HANDLE hThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PumbThread, NULL, NULL, &threadid);
    if (hThread)
    {
        // 等待消息循环创建完成
        while (!PostThreadMessage(threadid, 0x401, 0, 0)) {
            Sleep(55);
        }
        Sleep(55);
        // 查找目标窗口句柄
        HWND nWnd = FindWindow(L"SunAwtFrame", L"");
        dealJavaWindow(nWnd);
        PostThreadMessage(threadid, WM_QUIT, 0, 0);
        WaitForSingleObject(hThread,-1);
        CloseHandle(hThread);
    }
    return 0;
}

python调用

用编译语言写查找元素的工具比较合适,但用来执行操作,就显得过于麻烦了,用python这类脚本语言实现自动化流程更加合适。
python调用jab,也有现成的解决方案,可以参考pyjab这个库,也是在github上开源的。可以像操作selenium一样操作Java窗口。
如果想自己封装,那就要用到ctypes,加载WindowsAccessBridge-64.dll,还需要编写相关的结构体(这部分也可以从pyjab的代码里copy)
下面是我自己写的封装,消息循环的实现借鉴了pyjab,其他就纯手打了,累了个半死。希望对你有帮助:

# -*- coding: utf-8 -*-
import ctypes
import ctypes.wintypes
import win32event
import pythoncom
from collections import deque
from functools import wraps

ChangeWindowMessageFilter = ctypes.windll.user32.ChangeWindowMessageFilter
GetMessageW = ctypes.windll.user32.GetMessageW
TranslateMessage = ctypes.windll.user32.TranslateMessage
DispatchMessageW = ctypes.windll.user32.DispatchMessageW
PostThreadMessageW = ctypes.windll.user32.PostThreadMessageW
FindWindowW = ctypes.windll.user32.FindWindowW
FreeLibrary = ctypes.windll.kernel32.FreeLibrary

MAX_STRING_SIZE = 1024
SHORT_STRING_SIZE = 256
MAX_BUFFER_SIZE = 10240

MAX_RELATION_TARGETS = 25
MAX_RELATIONS = 5

MAX_HYPERLINKS = 64
MAX_ICON_INFO = 8
MAX_ACTIONS_TO_DO = 32
MAX_KEY_BINDINGS = 10
MAX_ACTION_INFO = 256

long = ctypes.c_long

jlong = ctypes.c_longlong
jint = long
jchar = ctypes.c_ushort
jboolean = ctypes.c_ubyte
jfloat = ctypes.c_float

JOBJECT64 = jlong
ABHWND64 = ctypes.c_long

AccessibleContext = JOBJECT64
AccessibleText = JOBJECT64
AccessibleValue = JOBJECT64
AccessibleSelection = JOBJECT64
PropertyChangeEvent = JOBJECT64
FocusEvent = JOBJECT64
CaretEvent = JOBJECT64
MouseEvent = JOBJECT64
MenuEvent = JOBJECT64
AccessibleTable = JOBJECT64
AccessibleHyperlink = JOBJECT64
AccessibleHypertext = JOBJECT64

Java_Object = JOBJECT64

BOOL = ctypes.wintypes.BOOL
c_void_p = ctypes.c_void_p
HWND = ctypes.wintypes.HWND
POINTER = ctypes.POINTER

AccessBridge_JavaShutdownFP = ctypes.CFUNCTYPE(None,
                                               ctypes.c_long)

AccessBridge_FocusGainedFP = ctypes.CFUNCTYPE(None,
                                              ctypes.c_long,
                                              JOBJECT64,
                                              JOBJECT64)
AccessBridge_FocusLostFP = ctypes.CFUNCTYPE(None,
                                            ctypes.c_long,
                                            JOBJECT64,
                                            JOBJECT64)

AccessBridge_CaretUpdateFP = ctypes.CFUNCTYPE(None,
                                              ctypes.c_long,
                                              JOBJECT64,
                                              JOBJECT64)

AccessBridge_MouseClickedFP = ctypes.CFUNCTYPE(None,
                                              ctypes.c_long,
                                              JOBJECT64,
                                              JOBJECT64)
AccessBridge_MouseEnteredFP = ctypes.CFUNCTYPE(None,
                                              ctypes.c_long,
                                              JOBJECT64,
                                              JOBJECT64)
AccessBridge_MouseExitedFP = ctypes.CFUNCTYPE(None,
                                              ctypes.c_long,
                                              JOBJECT64,
                                              JOBJECT64)
AccessBridge_MousePressedFP = ctypes.CFUNCTYPE(None,
                                              ctypes.c_long,
                                              JOBJECT64,
                                              JOBJECT64)
AccessBridge_MouseReleasedFP = ctypes.CFUNCTYPE(None,
                                              ctypes.c_long,
                                              JOBJECT64,
                                              JOBJECT64)

AccessBridge_MenuCanceledFP = ctypes.CFUNCTYPE(None,
                                              ctypes.c_long,
                                              JOBJECT64,
                                              JOBJECT64)
AccessBridge_MenuDeselectedFP = ctypes.CFUNCTYPE(None,
                                              ctypes.c_long,
                                              JOBJECT64,
                                              JOBJECT64)
AccessBridge_MenuSelectedFP = ctypes.CFUNCTYPE(None,
                                              ctypes.c_long,
                                              JOBJECT64,
                                              JOBJECT64)
AccessBridge_PopupMenuCanceledFP = ctypes.CFUNCTYPE(None,
                                                    ctypes.c_long,
                                                    JOBJECT64,
                                                    JOBJECT64)
AccessBridge_PopupMenuWillBecomeInvisibleFP = ctypes.CFUNCTYPE(None,
                                                               ctypes.c_long,
                                                               JOBJECT64,
                                                               JOBJECT64)
AccessBridge_PopupMenuWillBecomeVisibleFP = ctypes.CFUNCTYPE(None,
                                                             ctypes.c_long,
                                                             JOBJECT64,
                                                             JOBJECT64)

AccessBridge_PropertyNameChangeFP = ctypes.CFUNCTYPE(None,
                                                     ctypes.c_long,
                                                     JOBJECT64,
                                                     JOBJECT64,
                                                     ctypes.c_wchar_p,
                                                     ctypes.c_wchar_p)
AccessBridge_PropertyDescriptionChangeFP = ctypes.CFUNCTYPE(None,
                                                     ctypes.c_long,
                                                     JOBJECT64,
                                                     JOBJECT64,
                                                     ctypes.c_wchar_p,
                                                     ctypes.c_wchar_p)
AccessBridge_PropertyStateChangeFP = ctypes.CFUNCTYPE(None,
                                                     ctypes.c_long,
                                                     JOBJECT64,
                                                     JOBJECT64,
                                                     ctypes.c_wchar_p,
                                                     ctypes.c_wchar_p)
AccessBridge_PropertyValueChangeFP = ctypes.CFUNCTYPE(None,
                                                     ctypes.c_long,
                                                     JOBJECT64,
                                                     JOBJECT64,
                                                     ctypes.c_wchar_p,
                                                     ctypes.c_wchar_p)
AccessBridge_PropertySelectionChangeFP = ctypes.CFUNCTYPE(None,
                                                     ctypes.c_long,
                                                     JOBJECT64,
                                                     JOBJECT64,
                                                     ctypes.c_wchar_p,
                                                     ctypes.c_wchar_p)
AccessBridge_PropertyTextChangeFP = ctypes.CFUNCTYPE(None,
                                                     ctypes.c_long,
                                                     JOBJECT64,
                                                     JOBJECT64,
                                                     ctypes.c_wchar_p,
                                                     ctypes.c_wchar_p)
AccessBridge_PropertyCaretChangeFP = ctypes.CFUNCTYPE(None,
                                                     ctypes.c_long,
                                                     JOBJECT64,
                                                     JOBJECT64,
                                                     ctypes.c_wchar_p,
                                                     ctypes.c_wchar_p)
AccessBridge_PropertyVisibleDataChangeFP = ctypes.CFUNCTYPE(None,
                                                     ctypes.c_long,
                                                     JOBJECT64,
                                                     JOBJECT64,
                                                     ctypes.c_wchar_p,
                                                     ctypes.c_wchar_p)
AccessBridge_PropertyChildChangeFP = ctypes.CFUNCTYPE(None,
                                                     ctypes.c_long,
                                                     JOBJECT64,
                                                     JOBJECT64,
                                                     ctypes.c_wchar_p,
                                                     ctypes.c_wchar_p)
AccessBridge_PropertyActiveDescendentChangeFP = ctypes.CFUNCTYPE(None,
                                                                 ctypes.c_long,
                                                                 JOBJECT64,
                                                                 JOBJECT64,
                                                                 ctypes.c_wchar_p,
                                                                 ctypes.c_wchar_p)

AccessBridge_PropertyTableModelChangeFP = ctypes.CFUNCTYPE(None,
                                                           ctypes.c_long,
                                                           JOBJECT64,
                                                           JOBJECT64,
                                                           ctypes.c_wchar_p,
                                                           ctypes.c_wchar_p)


class AccessBridgeVersionInfo(ctypes.Structure):
    _fields_=[
        ('VMVersion',ctypes.c_wchar * SHORT_STRING_SIZE),
        ('bridgeJavaClassVersion',ctypes.c_wchar * SHORT_STRING_SIZE),
        ('bridgeJavaDLLVersion',ctypes.c_wchar * SHORT_STRING_SIZE),
        ('bridgeWinDLLVersion',ctypes.c_wchar * SHORT_STRING_SIZE)
    ]

class AccessibleContextInfo(ctypes.Structure):
    _fields_ = [
        ('name',ctypes.c_wchar * MAX_STRING_SIZE),
        ('description',ctypes.c_wchar * MAX_STRING_SIZE),
        ('role',ctypes.c_wchar * SHORT_STRING_SIZE),
        ('role_en_US',ctypes.c_wchar * SHORT_STRING_SIZE),
        ('states',ctypes.c_wchar * SHORT_STRING_SIZE),
        ('states_en_US',ctypes.c_wchar * SHORT_STRING_SIZE),
        ('indexInParent',jint),
        ('childrenCount',jint),
        ('x',jint),
        ('y',jint),
        ('width',jint),
        ('height',jint),
        ('accessibleComponent',BOOL),
        ('accessibleAction',BOOL),
        ('accessibleSelection',BOOL),
        ('accessibleText',BOOL),
        ('accessibleInterfaces',BOOL)
        ]

class VisibleChildrenInfo(ctypes.Structure):
    _fields_ = [
        ('returnedChildrenCount',ctypes.c_int),
        ('children',AccessibleContext * SHORT_STRING_SIZE)
        ]

class AccessibleTextInfo(ctypes.Structure):
    _fields_=[
        ('charCount',jint),
        ('caretIndex',jint),
        ('indexAtPoint',jint)
    ]

class AccessibleTextItemsInfo(ctypes.Structure):
    _fields_=[
        ('letter',ctypes.c_wchar),
        ('word',ctypes.c_wchar * SHORT_STRING_SIZE),
        ('sentence',ctypes.c_wchar * MAX_STRING_SIZE)
    ]

class AccessibleTextSelectionInfo(ctypes.Structure):
    _fields_=[
        ('selectionStartIndex',jint),
        ('selectionEndIndex',jint),
        ('selectedText',ctypes.c_wchar * MAX_STRING_SIZE)
    ]

class AccessibleTextRectInfo(ctypes.Structure):
    _fields_=[
        ('x',jint),
        ('y',jint),
        ('width',jint),
        ('height',jint)
    ]

class AccessibleTextAttributesInfo(ctypes.Structure):
    _fields_=[
        ('bold',BOOL),
        ('italic',BOOL),
        ('underline',BOOL),
        ('strikethrough',BOOL),
        ('superscript',BOOL),
        ('subscript',BOOL),
        ('backgroundColor',ctypes.c_wchar * SHORT_STRING_SIZE),
        ('foregroundColor',ctypes.c_wchar * SHORT_STRING_SIZE),
        ('fontFamily',ctypes.c_wchar * SHORT_STRING_SIZE),
        ('fontSize',jint),
        ('alignment',jint),
        ('bidiLevel',jint),
        ('firstLineIndent',jfloat),
        ('LeftIndent',jfloat),
        ('rightIndent',jfloat),
        ('lineSpacing',jfloat),
        ('spaceAbove',jfloat),
        ('spaceBelow',jfloat),
        ('fullAttributesString',ctypes.c_wchar * MAX_STRING_SIZE)
    ]

class AccessibleRelationInfo(ctypes.Structure):
    _fields_ = [
        ("key", ctypes.c_wchar * SHORT_STRING_SIZE),
        ("targetCount", jint),
        ("targets", JOBJECT64 * MAX_RELATION_TARGETS)
    ]

class AccessibleRelationSetInfo(ctypes.Structure):
    _fields_ = [
        ("relationCount", jint),
        ("relations", AccessibleRelationInfo * MAX_RELATIONS)
    ]

class AccessibleTableInfo(ctypes.Structure):
    _fields_ = [
        ('caption',JOBJECT64),
        ('summary',JOBJECT64),
        ('rowCount',jint),
        ('columnCount',jint),
        ('accessibleContext',JOBJECT64),
        ('accessibleTable',JOBJECT64)
        ]

class AccessibleTableCellInfo(ctypes.Structure):
    _fields_ = [
        ('accessibleContext',JOBJECT64),
        ('index',jint),
        ('row',jint),
        ('column',jint),
        ('rowExtent',jint),
        ('columnExtent',jint),
        ('isSelected',jboolean)
        ]

class AccessibleHyperlinkInfo(ctypes.Structure):
    _fields_ = [
        ('text',ctypes.c_wchar * SHORT_STRING_SIZE),
        ('startIndex',jint),
        ('endIndex',jint),
        ('accessibleHyperlink',JOBJECT64),
        ]

class AccessibleHypertextInfo(ctypes.Structure):
    _fields_ = [
        ('linkCount',jint),
        ('links',AccessibleHyperlinkInfo * MAX_HYPERLINKS),
        ('accessibleHypertext',JOBJECT64)
        ]

class AccessibleKeyBindingInfo(ctypes.Structure):
    _fields_ = [
        ('character',jchar),
        ('modifiers',jint)
        ]

class AccessibleKeyBindings(ctypes.Structure):
    _fields_ = [
        ('keyBindingsCount',jint),
        ('keyBindingInfo',AccessibleKeyBindingInfo * MAX_KEY_BINDINGS)
        ]

class AccessibleIconInfo(ctypes.Structure):
    _fields_ = [
        ('description',ctypes.c_wchar * SHORT_STRING_SIZE),
        ('height',jint),
        ('width',jint)
        ]

class AccessibleIcons(ctypes.Structure):
    _fields_ = [
        ('iconsCount',jint),
        ('iconInfo',AccessibleIconInfo * MAX_ICON_INFO)
        ]

class AccessibleActionInfo(ctypes.Structure):
    _fields_ = [
        ('name',ctypes.c_wchar * SHORT_STRING_SIZE)
        ]

class AccessibleActions(ctypes.Structure):
    _fields_ = [
        ('actionsCount',jint),
        ('actionInfo',AccessibleActionInfo * MAX_ACTION_INFO)
        ]

class AccessibleActionsToDo(ctypes.Structure):
    _fields_ = [
        ('actionsCount',jint),
        ('actions',AccessibleActionInfo * MAX_ACTIONS_TO_DO)
        ]

def singleton(cls):
    instances = {}

    @wraps(cls)
    def wrapper(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]

    return wrapper

def GetModuleFileName(handle):
    filepath = ctypes.create_unicode_buffer(260)
    ctypes.windll.kernel32.GetModuleFileNameW(ctypes.wintypes.HMODULE(handle),
                                              filepath,
                                              260)
    return filepath.value

@singleton
class JABUtils():
    stop_event = win32event.CreateEvent(None, 0, 0, None)
    other_event = win32event.CreateEvent(None, 0, 0, None)

    def setup_msg_pump(self):
        waitables = self.stop_event, self.other_event
        while True:
            rc = win32event.MsgWaitForMultipleObjects(
                waitables,
                0,
                200,
                win32event.QS_ALLEVENTS,
            )
            if rc == win32event.WAIT_OBJECT_0:
                break
            elif rc == win32event.WAIT_OBJECT_0 + 1:
                pass
            elif rc == win32event.WAIT_OBJECT_0 + len(waitables):
                if pythoncom.PumpWaitingMessages():
                    break
            elif rc == win32event.WAIT_TIMEOUT:
                pass
            else:
                raise RuntimeError("unexpected win32wait return value")
            try:
                yield
            finally:
                win32event.SetEvent(self.stop_event)

@singleton
class ActorScheduler:
    def __init__(self):
        self.actors = {}
        self.msg_queue = deque()

    def new_actor(self, name, actor):
        self.msg_queue.append((actor, None))
        self.actors[name] = actor

    def send(self, name, msg):
        actor = self.actors.get(name)
        if actor is not None:
            self.msg_queue.append((actor, msg))

    def run(self):
        while self.msg_queue:
            actor, msg = self.msg_queue.popleft()
            try:
                actor.send(msg)
            except StopIteration:
                pass

class JABFixedFunc(object):
    def __init__(self, bridge) -> None:
        self.bridge = bridge

    @staticmethod
    def _check_error(result, func, args):
        if not result:
            raise RuntimeError(f"Result {result}")
        return result

    def _fix_bridge_function(self, restype, name, *argtypes, **kwargs):
        try:
            func = getattr(self.bridge, name)
        except AttributeError:
            self.log.error(
                f"{name} not found in Java Access Bridge DLL"
            )
            return
        func.restype = restype
        func.argtypes = argtypes
        if kwargs.get("errorcheck"):
            func.errorcheck = self._check_error

    def _fix_bridge_functions(self):
        """Appropriately set the return and argument types of all the access bridge dll functions"""
        self._fix_bridge_function(None, "Windows_run")
        self._fix_bridge_function(None, "setFocusGainedFP", c_void_p)
        self._fix_bridge_function(None, "setPropertyNameChangeFP", c_void_p)
        self._fix_bridge_function(None, "setPropertyDescriptionChangeFP", c_void_p)
        self._fix_bridge_function(None, "setPropertyValueChangeFP", c_void_p)
        self._fix_bridge_function(None, "setPropertyStateChangeFP", c_void_p)
        self._fix_bridge_function(None, "setPropertyCaretChangeFP", c_void_p)
        self._fix_bridge_function(None, "setPropertyActiveDescendentChangeFP", c_void_p)
        self._fix_bridge_function(None, "releaseJavaObject", long, JOBJECT64)
        self._fix_bridge_function(
            BOOL,
            "getVersionInfo",
            long,
            ctypes.POINTER(AccessBridgeVersionInfo),
            errorcheck=True,
        )
        self._fix_bridge_function(BOOL, "isJavaWindow", HWND)
        self._fix_bridge_function(BOOL, "isSameObject", long, JOBJECT64, JOBJECT64)
        self._fix_bridge_function(
            BOOL,
            "getAccessibleContextFromHWND",
            HWND,
            POINTER(long),
            POINTER(JOBJECT64),
            errorcheck=True,
        )
        self._fix_bridge_function(
            HWND, "getHWNDFromAccessibleContext", long, JOBJECT64, errorcheck=True
        )
        self._fix_bridge_function(
            BOOL,
            "getAccessibleContextAt",
            long,
            JOBJECT64,
            jint,
            jint,
            POINTER(JOBJECT64),
            errorcheck=True,
        )
        self._fix_bridge_function(
            BOOL,
            "getAccessibleContextWithFocus",
            HWND,
            POINTER(long),
            POINTER(JOBJECT64),
            errorcheck=True,
        )
        self._fix_bridge_function(
            BOOL,
            "getAccessibleContextInfo",
            long,
            JOBJECT64,
            POINTER(AccessibleContextInfo),
            errorcheck=True,
        )
        self._fix_bridge_function(
            JOBJECT64,
            "getAccessibleChildFromContext",
            long,
            JOBJECT64,
            jint,
            errorcheck=True,
        )
        self._fix_bridge_function(
            JOBJECT64, "getAccessibleParentFromContext", long, JOBJECT64
        )
        self._fix_bridge_function(
            JOBJECT64, "getParentWithRole", long, JOBJECT64, POINTER(ctypes.c_wchar)
        )
        self._fix_bridge_function(
            BOOL,
            "getAccessibleRelationSet",
            long,
            JOBJECT64,
            POINTER(AccessibleRelationSetInfo),
            errorcheck=True,
        )
        self._fix_bridge_function(
            BOOL,
            "getAccessibleTextInfo",
            long,
            JOBJECT64,
            POINTER(AccessibleTextInfo),
            jint,
            jint,
            errorcheck=True,
        )
        self._fix_bridge_function(
            BOOL,
            "getAccessibleTextItems",
            long,
            JOBJECT64,
            POINTER(AccessibleTextItemsInfo),
            jint,
            errorcheck=True,
        )
        self._fix_bridge_function(
            BOOL,
            "getAccessibleTextSelectionInfo",
            long,
            JOBJECT64,
            POINTER(AccessibleTextSelectionInfo),
            errorcheck=True,
        )
        self._fix_bridge_function(
            BOOL,
            "getAccessibleTextAttributes",
            long,
            JOBJECT64,
            jint,
            POINTER(AccessibleTextAttributesInfo),
            errorcheck=True,
        )
        self._fix_bridge_function(
            BOOL,
            "getAccessibleTextRect",
            long,
            JOBJECT64,
            POINTER(AccessibleTextRectInfo),
            jint,
            errorcheck=True,
        )
        self._fix_bridge_function(
            BOOL,
            "getAccessibleTextLineBounds",
            long,
            JOBJECT64,
            jint,
            POINTER(jint),
            POINTER(jint),
            errorcheck=True,
        )
        self._fix_bridge_function(
            BOOL,
            "getAccessibleTextRange",
            long,
            JOBJECT64,
            jint,
            jint,
            POINTER(ctypes.c_wchar),
            ctypes.c_short,
            errorcheck=True,
        )
        self._fix_bridge_function(
            BOOL,
            "getCurrentAccessibleValueFromContext",
            long,
            JOBJECT64,
            POINTER(ctypes.c_wchar),
            ctypes.c_short,
            errorcheck=True,
        )
        self._fix_bridge_function(
            BOOL, "selectTextRange", long, JOBJECT64, jint, jint, errorcheck=True
        )
        self._fix_bridge_function(
            BOOL,
            "getTextAttributesInRange",
            long,
            JOBJECT64,
            jint,
            jint,
            POINTER(AccessibleTextAttributesInfo),
            POINTER(ctypes.c_short),
            errorcheck=True,
        )
        self._fix_bridge_function(
            JOBJECT64, "getTopLevelObject", long, JOBJECT64, errorcheck=True
        )
        self._fix_bridge_function(jint, "getObjectDepth", long, JOBJECT64)
        self._fix_bridge_function(JOBJECT64, "getActiveDescendent", long, JOBJECT64)
        self._fix_bridge_function(
            BOOL, "requestFocus", long, JOBJECT64, errorcheck=True
        )
        self._fix_bridge_function(
            BOOL, "setCaretPosition", long, JOBJECT64, jint, errorcheck=True
        )
        self._fix_bridge_function(
            BOOL,
            "getCaretLocation",
            long,
            JOBJECT64,
            POINTER(AccessibleTextRectInfo),
            jint,
            errorcheck=True,
        )
        self._fix_bridge_function(
            BOOL,
            "getAccessibleActions",
            long,
            JOBJECT64,
            POINTER(AccessibleActions),
            errorcheck=True,
        )
        self._fix_bridge_function(
            BOOL,
            "doAccessibleActions",
            long,
            JOBJECT64,
            POINTER(AccessibleActionsToDo),
            POINTER(jint),
            errorcheck=True,
        )
        self._fix_bridge_function(
            BOOL,
            "getAccessibleTableInfo",
            long,
            JOBJECT64,
            POINTER(AccessibleTableInfo),
        )
        self._fix_bridge_function(
            BOOL,
            "getAccessibleTableCellInfo",
            long,
            JOBJECT64,
            jint,
            jint,
            POINTER(AccessibleTableCellInfo),
            errorcheck=True,
        )
        self._fix_bridge_function(
            BOOL,
            "getAccessibleTableRowHeader",
            long,
            JOBJECT64,
            POINTER(AccessibleTableInfo),
        )
        self._fix_bridge_function(
            BOOL,
            "getAccessibleTableColumnHeader",
            long,
            JOBJECT64,
            POINTER(AccessibleTableInfo),
        )
        self._fix_bridge_function(
            JOBJECT64, "getAccessibleTableRowDescription", long, JOBJECT64, jint
        )
        self._fix_bridge_function(
            JOBJECT64, "getAccessibleTableColumnDescription", long, JOBJECT64, jint
        )
        self._fix_bridge_function(
            jint, "getAccessibleTableRow", long, JOBJECT64, jint
        )
        self._fix_bridge_function(
            jint, "getAccessibleTableColumn", long, JOBJECT64, jint
        )
        self._fix_bridge_function(
            jint, "getAccessibleTableIndex", long, JOBJECT64, jint, jint
        )
        self._fix_bridge_function(
            BOOL,
            "getAccessibleKeyBindings",
            long,
            JOBJECT64,
            POINTER(AccessibleKeyBindings),
            errorcheck=True,
        )
        self._fix_bridge_function(
            BOOL,
            "setTextContents",
            long,
            JOBJECT64,
            POINTER(ctypes.c_wchar),
            errorcheck=True,
        )
        self._fix_bridge_function(
            None, "clearAccessibleSelectionFromContext", long, JOBJECT64
        )
        self._fix_bridge_function(
            None, "addAccessibleSelectionFromContext", long, JOBJECT64, jint
        )
        self._fix_bridge_function(
            JOBJECT64, "getAccessibleSelectionFromContext", long, JOBJECT64, jint
        )
        self._fix_bridge_function(
            jint,
            "getVisibleChildrenCount",
            long,
            JOBJECT64,
        )
        self._fix_bridge_function(
            BOOL,
            "getVisibleChildren",
            long,
            JOBJECT64,
            jint,
            POINTER(VisibleChildrenInfo),
            errorcheck=True,
        )

@singleton
class AccessBridge():
    def __init__(self):
        self.module = None
        self.fixed_func = None
        self.jabUtils = JABUtils()
        self.initializeAccessBridge()

    def run_actor_sched(self):
        sched = ActorScheduler()
        sched.new_actor('海豚E工', self.jabUtils.setup_msg_pump())
        sched.run()

    def fix_jab(self):
        if self.module is None:
            return
        self.fixed_func = JABFixedFunc(self.module)
        self.fixed_func._fix_bridge_functions()
        error_code_offset = 0x00007FF892C571C5 - 0x00007FF892C50000
        # Modify `movsxd rdi,r9d` to `mov rdi,r9`
        fix_asm_code = (ctypes.c_ubyte * 3)(0x49,0x8B,0xF9)
        dwFixAddr = self.module._handle + error_code_offset
        OldProtext = ctypes.wintypes.DWORD(0)
        ctypes.windll.kernel32.VirtualProtect(ctypes.c_void_p(dwFixAddr),
                                              3,
                                              0x40,
                                              ctypes.byref(OldProtext))
        ctypes.cdll.msvcrt.memcpy(ctypes.c_void_p(dwFixAddr),
                                  ctypes.byref(fix_asm_code),
                                  3)
        ctypes.windll.kernel32.VirtualProtect(ctypes.c_void_p(dwFixAddr),
                                              3,
                                              OldProtext,
                                              ctypes.byref(OldProtext))


    def initializeAccessBridge(self):
        if self.module is not None:
            self.shutdownAccessBridge()
        self.module = ctypes.cdll.LoadLibrary('WindowsAccessBridge-64')
        self.fix_jab()
        self.Windows_run()
        self.run_actor_sched()
        return True

    def Windows_run(self):
        return self.module.Windows_run()

    def SetJavaShutdown(self,fp: 'AccessBridge_JavaShutdownFP') -> None:
        self.module.setJavaShutdownFP(fp)

    def SetFocusGained(self,fp: 'AccessBridge_FocusGainedFP') -> None:
        self.module.setFocusGainedFP(fp)

    def SetFocusLost(self,fp: 'AccessBridge_FocusLostFP') -> None:
        self.module.setFocusLostFP(fp)

    def SetCaretUpdate(self,fp: 'AccessBridge_CaretUpdateFP') -> None:
        self.module.setCaretUpdateFP(fp)

    def SetMouseClicked(self,fp: 'AccessBridge_MouseClickedFP') -> None:
        self.module.setMouseClickedFP(fp)

    def SetMouseEntered(self,fp: 'AccessBridge_MouseEnteredFP') -> None:
        self.module.setMouseEnteredFP(fp)

    def SetMouseExited(self,fp: 'AccessBridge_MouseExitedFP') -> None:
        self.module.setMouseExitedFP(fp)

    def SetMousePressed(self,fp: 'AccessBridge_MousePressedFP') -> None:
        self.module.setMousePressedFP(fp)

    def SetMouseReleased(self,fp: 'AccessBridge_MouseReleasedFP') -> None:
        self.module.setMouseReleasedFP(fp)

    def SetMenuCanceled(self,fp: 'AccessBridge_MenuCanceledFP') -> None:
        self.module.setMenuCanceledFP(fp)

    def SetMenuDeselected(self,fp: 'AccessBridge_MenuDeselectedFP') -> None:
        self.module.setMenuDeselectedFP(fp)

    def SetMenuSelected(self,fp: 'AccessBridge_MenuSelectedFP') -> None:
        self.module.setMenuSelectedFP(fp)

    def SetPopupMenuCanceled(self,fp: 'AccessBridge_PopupMenuCanceledFP') -> None:
        self.module.setPopupMenuCanceledFP(fp)

    def SetPopupMenuWillBecomeInvisible(self,fp: 'AccessBridge_PopupMenuWillBecomeInvisibleFP') -> None:
        self.module.setPopupMenuWillBecomeInvisibleFP(fp)

    def SetPopupMenuWillBecomeVisible(self,fp: 'AccessBridge_PopupMenuWillBecomeVisibleFP') -> None:
        self.module.setPopupMenuWillBecomeVisibleFP(fp)

    def SetPropertyNameChange(self,fp: 'AccessBridge_PropertyNameChangeFP') -> None:
        self.module.setPropertyNameChangeFP(fp)

    def SetPropertyDescriptionChange(self,fp: 'AccessBridge_PropertyDescriptionChangeFP') -> None:
        self.module.setPropertyDescriptionChangeFP(fp)

    def SetPropertyStateChange(self,fp: 'AccessBridge_PropertyStateChangeFP') -> None:
        self.module.setPropertyStateChangeFP(fp)

    def SetPropertyValueChange(self,fp: 'AccessBridge_PropertyValueChangeFP') -> None:
        self.module.setPropertyValueChangeFP(fp)

    def SetPropertySelectionChange(self,fp: 'AccessBridge_PropertySelectionChangeFP') -> None:
        self.module.setPropertySelectionChangeFP(fp)

    def SetPropertyTextChange(self,fp: 'AccessBridge_PropertyTextChangeFP') -> None:
        self.module.setPropertyTextChangeFP(fp)

    def SetPropertyCaretChange(self,fp: 'AccessBridge_PropertyCaretChangeFP') -> None:
        self.module.setPropertyCaretChangeFP(fp)

    def SetPropertyVisibleDataChange(self,fp: 'AccessBridge_PropertyVisibleDataChangeFP') -> None:
        self.module.setPropertyVisibleDataChangeFP(fp)

    def SetPropertyChildChange(self,fp: 'AccessBridge_PropertyChildChangeFP') -> None:
        self.module.setPropertyChildChangeFP(fp)

    def SetPropertyActiveDescendentChange(self,fp: 'AccessBridge_PropertyActiveDescendentChangeFP') -> None:
        self.module.setPropertyActiveDescendentChangeFP(fp)

    def SetPropertyTableModelChange(self,fp: 'AccessBridge_PropertyTableModelChangeFP') -> None:
        self.module.setPropertyTableModelChangeFP(fp)

    def ReleaseJavaObject(self,vmID,jobject):
        self.module.releaseJavaObject(long(vmID),
                                      Java_Object(jobject))

    def GetVersionInfo(self,vmID):
        info = AccessBridgeVersionInfo(0)
        status = self.module.getVersionInfo(long(vmID),
                                            ctypes.byref(info))
        return status,info

    def IsJavaWindow(self,window):
        return self.module.isJavaWindow(HWND(window))

    def IsSameObject(self,vmID,obj1,obj2):
        return self.module.isSameObject(long(vmID),
                                        JOBJECT64(obj1),
                                        JOBJECT64(obj2))

    def GetAccessibleContextFromHWND(self,target):
        vmID = long(0)
        ac = AccessibleContext(0)
        status = self.module.getAccessibleContextFromHWND(HWND(target), 
                                                          ctypes.byref(vmID),
                                                          ctypes.byref(ac))
        return status,vmID.value,ac.value

    def getHWNDFromAccessibleContext(self,vmID,ac):
        return self.module.getHWNDFromAccessibleContext(long(vmID),
                                                        AccessibleContext(ac))

    def GetAccessibleContextAt(self,vmID,acParent,x,y):
        ac = AccessibleContext(0)
        status = self.module.getAccessibleContextAt(long(vmID),
                                                    AccessibleContext(acParent),
                                                    jint(x),
                                                    jint(y),
                                                    ctypes.byref(ac))
        return status,ac.value

    def GetAccessibleContextWithFocus(self,window):
        vmID = long(0)
        ac = AccessibleContext(0)
        status = self.module.getAccessibleContextWithFocus(HWND(window),
                                                           ctypes.byref(vmID),
                                                           ctypes.byref(ac))
        return status,vmID.value,ac.value

    def GetAccessibleContextInfo(self,vmID,ac):
        info = AccessibleContextInfo()
        status = self.module.getAccessibleContextInfo(long(vmID),
                                                      AccessibleContext(ac),
                                                      ctypes.byref(info))
        return status,info

    def GetAccessibleChildFromContext(self,vmID,ac,index):
        return self.module.getAccessibleChildFromContext(long(vmID),
                                                         AccessibleContext(ac),
                                                         jint(index))

    def GetAccessibleParentFromContext(self,vmID,ac):
        return self.module.getAccessibleParentFromContext(long(vmID),
                                                         AccessibleContext(ac))

    def getAccessibleTableInfo(self,vmID,ac):
        tableinfo = AccessibleTableInfo()
        status = self.module.getAccessibleTableInfo(long(vmID),
                                                    AccessibleContext(ac),
                                                    ctypes.byref(tableinfo))
        return status,tableinfo

    def getAccessibleTableCellInfo(self,vmID,accessibleTable,row,column):
        tableCellInfo = AccessibleTableCellInfo()
        status = self.module.getAccessibleTableCellInfo(long(vmID),
                                                        AccessibleTable(accessibleTable),
                                                        jint(row),
                                                        jint(column),
                                                        ctypes.byref(tableCellInfo))
        return status,tableCellInfo

    def getAccessibleTableRowHeader(self,vmID,acParent):
        tableinfo = AccessibleTableInfo()
        status = self.module.getAccessibleTableRowHeader(long(vmID),
                                                         AccessibleContext(acParent),
                                                         ctypes.byref(tableinfo))
        return status,tableinfo

    def getAccessibleTableColumnHeader(self,vmID,acParent):
        tableinfo = AccessibleTableInfo()
        status = self.module.getAccessibleTableColumnHeader(long(vmID),
                                                            AccessibleContext(acParent),
                                                            ctypes.byref(tableinfo))
        return status,tableinfo

    def getAccessibleTableRowDescription(self,vmID,acParent,row):
        return self.module.module.getAccessibleTableRowDescription(long(vmID),
                                                            AccessibleContext(acParent),
                                                            jint(row))

    def getAccessibleTableColumnDescription(self,vmID,acParent,column):
        return self.module.getAccessibleTableColumnDescription(long(vmID),
                                                        AccessibleContext(acParent),
                                                        jint(column))

    def getAccessibleTableRowSelectionCount(self,vmID,table):
        return self.module.getAccessibleTableRowSelectionCount(long(vmID),
                                                               AccessibleTable(table))

    def isAccessibleTableRowSelected(self,vmID,table,row):
        return self.module.isAccessibleTableRowSelected(long(vmID),
                                                        AccessibleTable(table),
                                                        jint(row))

    def getAccessibleTableRowSelections(self,vmID,table,count):
        selections = (jint * count)(0)
        status = self.module.getAccessibleTableRowSelections(long(vmID),
                                                             AccessibleTable(table),
                                                             jint(count),
                                                             ctypes.byref(selections))
        return status,list(selections)

    def getAccessibleTableColumnSelectionCount(self,vmID,table):
        return self.module.getAccessibleTableColumnSelectionCount(long(vmID),
                                                                  AccessibleTable(table))

    def isAccessibleTableColumnSelected(self,vmID,table,column):
        return self.module.isAccessibleTableColumnSelected(long(vmID),
                                                        AccessibleTable(table),
                                                        jint(column))

    def getAccessibleTableColumnSelections(self,vmID,table,count):
        selections = (jint * count)(0)
        status = self.module.getAccessibleTableColumnSelections(long(vmID),
                                                                AccessibleTable(table),
                                                                jint(count),
                                                                ctypes.byref(selections))
        return status,list(selections)

    def getAccessibleTableRow(self,vmID,table,index):
        return self.module.getAccessibleTableRow(long(vmID),
                                                 AccessibleTable(table),
                                                 jint(index))

    def getAccessibleTableColumn(self,vmID,table,index):
        return self.module.getAccessibleTableColumn(long(vmID),
                                                    AccessibleTable(table),
                                                    jint(index))

    def getAccessibleTableIndex(self,vmID,table,row,column):
        return self.module.getAccessibleTableIndex(long(vmID),
                                                   AccessibleTable(table),
                                                   jint(row),
                                                   jint(column))

    def getAccessibleRelationSet(self,vmID,accessibleContext):
        relaitionSetInfo = AccessibleRelationSetInfo()
        status = self.module.getAccessibleRelationSet(long(vmID),
                                                      AccessibleContext(accessibleContext),
                                                      ctypes.byref(relaitionSetInfo))
        return status,relaitionSetInfo

    def getAccessibleHypertext(self,vmID,accessibleContext):
        hypertextInfo = AccessibleHypertextInfo()
        status = self.module.getAccessibleHypertext(long(vmID),
                                                    AccessibleContext(accessibleContext),
                                                    ctypes.byref(hypertextInfo))
        return status,hypertextInfo

    def activateAccessibleHyperlink(self,vmID,accessibleContext,accessibleHyperlink):
        return self.module.activateAccessibleHyperlink(long(vmID),
                                                       AccessibleContext(accessibleContext),
                                                       AccessibleHyperlink(accessibleHyperlink))

    def getAccessibleHyperlinkCount(self,vmID,hypertext):
        return self.module.getAccessibleHyperlinkCount(long(vmID),
                                                       AccessibleHypertext(hypertext))

    def getAccessibleHypertextExt(self,vmID,accessibleContext,nStartIndex):
        hypertextInfo = AccessibleHypertextInfo()
        status = self.module.getAccessibleHypertextExt(long(vmID),
                                                       AccessibleContext(accessibleContext),
                                                       jint(nStartIndex),
                                                       ctypes.byref(hypertextInfo))
        return status,hypertextInfo

    def getAccessibleHypertextLinkIndex(self,vmID,hypertext,nIndex):
        return self.module.getAccessibleHypertextLinkIndex(long(vmID),
                                                           AccessibleHypertext(hypertext),
                                                           jint(nIndex))

    def getAccessibleHyperlink(self,vmID,hypertext,nIndex):
        hyperlinkInfo = AccessibleHyperlinkInfo()
        status = self.module.getAccessibleHyperlink(long(vmID),
                                                    AccessibleHypertext(hypertext),
                                                    jint(nIndex),
                                                    ctypes.byref(hyperlinkInfo))
        return status,hyperlinkInfo

    def getAccessibleKeyBindings(self,vmID,accessibleContext):
        keyBindings = AccessibleKeyBindings()
        status = self.module.getAccessibleKeyBindings(long(vmID),
                                                      AccessibleContext(accessibleContext),
                                                      ctypes.byref(keyBindings))
        return status,keyBindings

    def getAccessibleIcons(self,vmID,accessibleContext):
        icons = AccessibleIcons()
        status = self.module.getAccessibleIcons(long(vmID),
                                                AccessibleContext(accessibleContext),
                                                ctypes.byref(icons))
        return status,icons

    def getAccessibleActions(self,vmID,accessibleContext):
        actions = AccessibleActions()
        status = self.module.getAccessibleActions(long(vmID),
                                                  AccessibleContext(accessibleContext),
                                                  ctypes.byref(actions))
        return status,actions

    def doAccessibleActions(self,vmID,accessibleContext,actionsToDo: 'AccessibleActionsToDo'):
        failure = jint(0)
        status = self.module.doAccessibleActions(long(vmID),
                                                 AccessibleContext(accessibleContext),
                                                 ctypes.byref(actionsToDo),
                                                 ctypes.byref(failure))
        return status,failure.value

    def GetAccessibleTextInfo(self,vmID, at,x, y):
        textInfo = AccessibleTextInfo()
        status = self.module.getAccessibleTextInfo(long(vmID),
                                                   AccessibleText(at),
                                                   ctypes.byref(textInfo),
                                                   jint(x),
                                                   jint(y))
        return status,textInfo

    def GetAccessibleTextItems(self,vmID,at,index):
        textItems = AccessibleTextItemsInfo()
        status = self.module.getAccessibleTextItems(long(vmID),
                                                    AccessibleText(at),
                                                    ctypes.byref(textItems),
                                                    jint(index))
        return status,textItems

    def GetAccessibleTextSelectionInfo(self,vmID,at):
        textSelection = AccessibleTextSelectionInfo()
        status = self.module.getAccessibleTextSelectionInfo(long(vmID),
                                                            AccessibleText(at),
                                                            ctypes.byref(textSelection))
        return status,textSelection

    def GetAccessibleTextAttributes(self,vmID, at,index):
        attributes = AccessibleTextAttributesInfo()
        status = self.module.getAccessibleTextAttributes(long(vmID),
                                                         AccessibleText(at),
                                                         jint(index),
                                                         ctypes.byref(attributes))
        return status,attributes

    def GetAccessibleTextRect(self,vmID, at,index):
        rectInfo = AccessibleTextRectInfo()
        status = self.module.getAccessibleTextRect(long(vmID),
                                                   AccessibleText(at),
                                                   ctypes.byref(rectInfo),
                                                   jint(index))
        return status,rectInfo

    def GetAccessibleTextLineBounds(self,vmID,at,index):
        startIndex = jint(0)
        endIndex = jint(0)
        status = self.module.getAccessibleTextLineBounds(long(vmID),
                                                         AccessibleText(at),
                                                         jint(index),
                                                         ctypes.byref(startIndex),
                                                         ctypes.byref(endIndex))
        return status,startIndex.value,endIndex.value

    def GetAccessibleTextRange(self,vmID,at,start,end,s_len):
        text = ctypes.create_unicode_buffer(s_len + 1)
        status = self.module.getAccessibleTextRange(long(vmID),
                                                    AccessibleText(at),
                                                    jint(start),
                                                    jint(end),
                                                    text,
                                                    ctypes.c_short(s_len))
        return status,text.value

    def GetCurrentAccessibleValueFromContext(self,vmID,av,s_len):
        value = ctypes.create_unicode_buffer(s_len + 1)
        status = self.module.getCurrentAccessibleValueFromContext(long(vmID),
                                                                  AccessibleValue(av),
                                                                  value,
                                                                  ctypes.c_short(s_len))
        return status,value.value

    def GetMaximumAccessibleValueFromContext(self,vmID,av,s_len):
        value = ctypes.create_unicode_buffer(s_len + 1)
        status = self.module.getMaximumAccessibleValueFromContext(long(vmID),
                                                                  AccessibleValue(av),
                                                                  value,
                                                                  ctypes.c_short(s_len))
        return status,value.value

    def GetMinimumAccessibleValueFromContext(self,vmID,av,s_len):
        value = ctypes.create_unicode_buffer(s_len + 1)
        status = self.module.getMinimumAccessibleValueFromContext(long(vmID),
                                                                  AccessibleValue(av),
                                                                  value,
                                                                  ctypes.c_short(s_len))
        return status,value.value

    def AddAccessibleSelectionFromContext(self,vmID,aS,i):
        return self.module.addAccessibleSelectionFromContext(long(vmID),
                                                             AccessibleSelection(aS),
                                                             ctypes.c_int(i))

    def ClearAccessibleSelectionFromContext(self,vmID,aS):
        return self.module.clearAccessibleSelectionFromContext(long(vmID),
                                                               AccessibleSelection(aS))

    def GetAccessibleSelectionFromContext(self,vmID,aS,i):
        return self.module.getAccessibleSelectionFromContext(long(vmID),
                                                             AccessibleSelection(aS),
                                                             ctypes.c_int(i))

    def GetAccessibleSelectionCountFromContext(self,vmID,aS):
        return self.module.getAccessibleSelectionCountFromContext(long(vmID),
                                                                  AccessibleSelection(aS))

    def IsAccessibleChildSelectedFromContext(self,vmID,aS,i):
        return self.module.isAccessibleChildSelectedFromContext(long(vmID),
                                                                AccessibleSelection(aS),
                                                                ctypes.c_int(i))

    def RemoveAccessibleSelectionFromContext(self,vmID,aS,i):
        return self.module.removeAccessibleSelectionFromContext(long(vmID),
                                                                AccessibleSelection(aS),
                                                                ctypes.c_int(i))

    def SelectAllAccessibleSelectionFromContext(self,vmID,aS):
        return self.module.selectAllAccessibleSelectionFromContext(long(vmID),
                                                                   AccessibleSelection(aS))

    def setTextContents(self,vmID,accessibleContext,text):
        return self.module.setTextContents(long(vmID),
                                           AccessibleContext(accessibleContext),
                                           ctypes.c_wchar_p(text))


    def getParentWithRole(self,vmID, accessibleContext,role):
        return self.module.getParentWithRole(long(vmID),
                                             AccessibleContext(accessibleContext),
                                             ctypes.c_wchar_p(role))

    def getTopLevelObject(self,vmID,accessibleContext):
        return self.module.getTopLevelObject(long(vmID),
                                             AccessibleContext(accessibleContext))

    def getParentWithRoleElseRoot(self,vmID,accessibleContext,role):
        return self.module.getParentWithRoleElseRoot(long(vmID),
                                             AccessibleContext(accessibleContext),
                                             ctypes.c_wchar_p(role))

    def getObjectDepth(self,vmID,accessibleContext):
        return self.module.getObjectDepth(long(vmID),
                                          AccessibleContext(accessibleContext))

    def getActiveDescendent(self,vmID,accessibleContext):
        return self.module.getActiveDescendent(long(vmID),
                                               AccessibleContext(accessibleContext))

    def getVirtualAccessibleName(self,vmID,accessibleContext,i_len):
        name = ctypes.create_unicode_buffer(i_len + 1)
        status = self.module.getVirtualAccessibleName(long(vmID),
                                                      AccessibleContext(accessibleContext),
                                                      name,
                                                      ctypes.c_int(i_len))
        return status,name.value

    def requestFocus(self,vmID,accessibleContext):
        return self.module.requestFocus(long(vmID),
                                        AccessibleContext(accessibleContext))

    def selectTextRange(self,vmID,accessibleContext,startIndex,endIndex):
        return self.module.selectTextRange(long(vmID),
                                           AccessibleContext(accessibleContext),
                                           ctypes.c_int(startIndex),
                                           ctypes.c_int(endIndex))

    def getTextAttributesInRange(self,vmID,accessibleContext,startIndex,endIndex):
        attributes = AccessibleTextAttributesInfo()
        s_len = ctypes.c_short(0)
        status = self.module.getTextAttributesInRange(long(vmID),
                                                      AccessibleContext(accessibleContext),
                                                      ctypes.c_int(startIndex),
                                                      ctypes.c_int(endIndex),
                                                      ctypes.byref(attributes),
                                                      ctypes.byref(s_len))
        return status,attributes,s_len.value

    def getVisibleChildrenCount(self,vmID,accessibleContext):
        return self.module.getVisibleChildrenCount(long(vmID),
                                                   AccessibleContext(accessibleContext))

    def getVisibleChildren(self,vmID,accessibleContext,startindex):
        info = VisibleChildrenInfo()
        status = self.module.getVisibleChildren(long(vmID),
                                                AccessibleContext(accessibleContext),
                                                ctypes.c_int(startindex),
                                                ctypes.byref(info))
        return status,info

    def setCaretPosition(self,vmID,accessibleContext,position):
        return self.module.setCaretPosition(long(vmID),
                                            AccessibleContext(accessibleContext),
                                            ctypes.c_int(position))

    def getCaretLocation(self,vmID,ac,index):
        rectInfo = AccessibleTextRectInfo()
        status = self.module.getCaretLocation(long(vmID),
                                              AccessibleContext(ac),
                                              ctypes.byref(rectInfo),
                                              jint(index))
        return status,rectInfo

    def getEventsWaiting(self):
        return self.module.getEventsWaiting()

    def shutdownAccessBridge(self):
        if self.module:
            FreeLibrary(ctypes.wintypes.HMODULE(self.module._handle))
        self.module = None

    def __del__(self):
        self.shutdownAccessBridge()

写在后面

虽然WindowsAccessBridge中提供了很多接口,但用起来还是会有诸多问题,如果要十分精确的访问java元素,可能还是要用java编写jar包,然后注入到目标程序,实现事件监听。