java - 未收到来自 Java Access Bridge 的回调

标签 java c++ accessibility java-access-bridge

我正在尝试使用 Java Access Bridge 从 C++ 应用程序内部获取有关 Swing 组件的信息。但是,我注册的回调都没有被调用过。我尝试枚举窗口,然后在每个句柄上调用 IsJavaWindow(),但它总是返回 false。关于为什么它显然不起作用的任何想法?

我认为这是我的应用程序而不是网桥安装的问题,因为演示 Monkey 和 Ferret 程序可以运行,initializeAccessBridge() 返回 true,并且调试器显示 WindowsAccessBridge dll 已加载。

我在 Windows Vista 上使用 Java 6 更新 13,我认为访问桥的版本为 2.0.1。

JavaAccess::JavaAccess(void)
{
   using namespace std;

   BOOL isInitialized = initializeAccessBridge();
   if(isInitialized)
   {
      cout << "Bridge Initialized!" << endl;
   }
   else
   {
      cout << "Initialization failed!" << endl;
      return;
   }

   EnumWindows((WNDENUMPROC)EnumWndProc, NULL);

   SetJavaShutdown(OnJavaShutdown);
   SetFocusGained(OnFocusGained);
   SetMouseClicked(OnMouseClicked);
}

JavaAccess::~JavaAccess(void)
{
   shutdownAccessBridge();
}

void JavaAccess::OnJavaShutdown( long vmID )
{
   using namespace std;
   cout << "Java shutdown!" << endl;
}

void JavaAccess::OnFocusGained( long vmID, FocusEvent event, AccessibleContext context )
{
   using namespace std;
   cout << "Focus Gained!" << endl;

   ReleaseJavaObject(vmID, event);
   ReleaseJavaObject(vmID, context);
}

void JavaAccess::OnMouseClicked( long vmID, jobject event, jobject source )
{
   std::cout << "Mouse clicked!" << std::endl;

   ReleaseJavaObject(vmID, event);
   ReleaseJavaObject(vmID, source);
}

BOOL CALLBACK JavaAccess::EnumWndProc( HWND hwnd, LPARAM lparam )
{
   if (IsJavaWindow(hwnd))
   {
      std::cout << "Found Java Window!" << std::endl;
      return FALSE;
   }
   else
   {
      std::cout << "Still looking" << std::endl;
      return TRUE;
   }
}

所有回调都是静态函数。

最佳答案

我也一直在与这个问题作斗争,并且刚刚找到了一个真正有意义的解决方案。我最终不得不构建 WindowsAccessBridge.dll 的调试版本,并使用调试器进入它以观察发生了什么。

  • 调用“initializeAccessBridge”需要您有一个 Activity 的 Windows 消息泵。

在“initializeAccessBridge”中,它(最终)创建了一个隐藏的对话窗口(使用 CreateDialog)。创建对话框后,它会执行带有已注册消息的 PostMessage。访问桥的 JavaVM 端响应此消息,并将另一条消息回发到已创建的对话框(它似乎是您的应用程序和 Java VM 之间的“hello”类型握手)。因此,如果您的应用程序没有 Activity 的消息泵,则您的应用程序永远不会收到来自 JavaVM 的返回消息。

这很重要,因为在收到此消息之前,桥永远不会正确初始化,因此所有对“IsJavaWindow”的调用都会失败(在内部,一旦收到消息,桥就会初始化一个内部结构——因此,没有 Activity 的消息泵,没有初始化)。我猜这就是为什么您也永远不会收到回调消息的原因。

不仅如此,您还必须在消息泵可以处理消息的位置调用 initializeAccessBridge,然后才能调用 IsJavaWindow。

这就是 JavaFerret 和 JavaMonkey 工作的原因——它们在启动时初始化,然后在桥通过消息泵接收到初始化消息之后枚举对菜单消息的响应。

我能够在我的 MFC 对话框应用程序(以及我们基于 MFC 的应用程序)中解决这个问题的方法是确保您在某个点调用“initializeAccessBridge”,以便内置 MFC 消息泵可以推送在使用它之前,将“你好”消息返回到这个隐藏的对话框。在简单的 MFC 对话框情况下,这意味着调用 OnInitDialog 中的 initializeAccessBridge,并调用枚举过程以响应按钮调用(例如)。如果您希望枚举在对话框出现时立即发生,您可以使用计时器在 OnInitDialog 完成后触发(例如 10 毫秒)以允许处理初始化消息。

如果您打算在控制台应用程序中使用它,您将需要编写自己的自定义消息泵来处理初始化消息。

无论如何,我希望这已经足够清楚了!虽然没有办法知道这是否是“正确”的方法(除了花钱请 Sun 工程师告诉我们),但它确实解决了我的问题。

干杯——达伦。

哦。顺便说一句,我发现了一个不起眼的 Sun 页面,其中提到了一些关于 AccessBridge 仅适用于基于 awt 的 java 应用程序的内容(但鉴于 Sun 自 2004 年以来没有更新任何文档,这可能已经改变)。我不是 Java 程序员——为了测试,我获取了一些免费的 Java 应用程序(以及 jdk 附带的应用程序)并试用了我的测试应用程序。它适用于所有我尝试过的——YMMV。祝你好运!

关于java - 未收到来自 Java Access Bridge 的回调,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1161142/

相关文章:

Java,不同对象的重复逻辑 block ,清理代码

c++ - 调试核心转储时的源代码行

c++ - 为什么我必须通过this指针访问模板基类成员?

c++ - Qt Creator 项目不会在 Windows 上构建(链接器错误)

ios - 如何为 tableview 上的 webview 内容启用 VoiceOver

objective-c - 通过 OSX 辅助功能 API 获取窗口编号

java - 我应该解析以下 XML 输出的常用库是什么?

java - 使用 Google Translate Java 库,具有特殊字符的语言返回问号

java - 我可以对 JList 进行分页吗

javascript - 实际上,渐进增强和优雅降级是一回事吗?