没有从Java Access Bridge接收回调

时间:2009-07-21 19:11:41

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

我正在尝试使用Java Access Bridge从C ++应用程序中获取有关Swing组件的信息。但是,我注册的回调都没有被调用。我尝试在每个句柄上调用windows然后调用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;
   }
}

所有回调都是静态函数。

2 个答案:

答案 0 :(得分:10)

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

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

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

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

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

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

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

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

无论如何,我希望这很清楚!虽然没有办法知道这是否是“正确的”方式(除了支付太阳工程师告诉我们的费用),它肯定解决了我的问题。

干杯 - 达伦。

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

答案 1 :(得分:0)

你确定OnJavaShutdown()是静态的吗?我相信声明应该是

static oid JavaAccess::OnJavaShutdown( long vmID )