7

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

所有回调都是静态函数。

4

2 回答 2

11

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

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

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

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

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

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

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

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

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

干杯——达伦。

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

于 2009-07-28T12:02:10.470 回答
0

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

static oid JavaAccess::OnJavaShutdown( long vmID )
于 2009-07-28T12:01:02.830 回答