【问题标题】:Not receiving callbacks from the Java Access Bridge未收到来自 Java Access Bridge 的回调
【发布时间】:2017-10-18 02:27:26
【问题描述】:

我正在尝试使用 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;
   }
}

所有的回调都是静态函数。

【问题讨论】:

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


    【解决方案1】:

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

    • 对“initializeAccessBridge”的调用要求您拥有一个活动的 Windows 消息泵。

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

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

    不仅如此,在调用 IsJavaWindow 之前,您必须在消息泵可以处理消息的位置调用 initializeAccessBridge。

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

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

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

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

    干杯——达伦。

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

    【讨论】:

    • 我开始怀疑它需要一个消息泵,我喜欢你的解释。我刚刚修改了我的测试,它现在可以工作了。这里有一些赏金!
    • 感谢关于消息循环的要点。回复:控制台应用程序。在 C# 中,您可以使用 Application.Run() 和无参数来创建一个简单的主消息循环。如果您想对 dll 进行任何调用,请从另一个线程执行此操作。对于 C++,Java Access Bridge download 包含具有标准 GetMessage、TranslateMessage、DispatchMessage 循环的 JavaMonkey.cpp 源代码。
    • 这是有史以来最晦涩难懂的答案。你能显示任何代码吗?
    【解决方案2】:

    您确定 OnJavaShutdown() 是静态的吗?我认为声明应该是

    static oid JavaAccess::OnJavaShutdown( long vmID )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-10-04
      • 2017-10-16
      • 2015-10-27
      • 2019-11-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多