initializeAccessBridge

initializeAccessBridge

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

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

我正在Windows Vista上使用Java 6,update 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消息泵可以推送“hello”消息返回到该隐藏对话框,然后再使用。在简单的MFC对话框的情况下,这意味着在OnInitDialog中调用initializeAccessBridge,并调用枚举过程以响应按钮调用(例如)。如果希望枚举在对话框出现后立即出现,则可以在OnInitDialog完成后使用计时器触发(例如10ms)以允许处理初始化消息。

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

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

    干杯-达伦。

    哦。顺便说一句,我发现一个晦涩的Sun页面提到了有关AccessBridge的内容仅适用于基于awt的java应用程序(但考虑到Sun自2004年以来未更新任何文档,这可能已更改)。我不是Java程序员-为了进行测试,我获取了许多免费的Java应用程序(以及jdk附带的免费Java应用程序)并试用了我的测试应用程序。它适用于我尝试过的所有产品-YMMV。祝你好运!

    07-24 20:16