代码之家  ›  专栏  ›  技术社区  ›  James

不接收Java访问桥的回调

  •  7
  • James  · 技术社区  · 16 年前

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

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

    我使用Java 6,在Windows Vista上更新13,我认为Access桥的版本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 回复  |  直到 7 年前
        1
  •  9
  •   Darren Ford    16 年前

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

    • 调用“InitializeAccessBridge”需要有一个活动的Windows消息泵。

    在“InitializeAccessBridge”中,它(最终)创建一个隐藏的对话框窗口(使用CreatedDialog)。创建对话框后,它将使用已注册的消息执行后期消息。Access桥的JavaVM侧响应此消息,并将另一条消息回传到创建的对话框(它看起来是您的应用程序与Java VM之间的“hello”类型握手)。因此,如果您的应用程序没有活动消息泵,那么来自javavm的返回消息将永远不会被您的应用程序接收。

    这一点很重要,因为在收到此消息之前,网桥从未正确初始化,因此对“isjavaWindow”的所有调用都失败(在内部,网桥在收到消息后初始化内部结构——例如,没有活动的消息泵,没有初始化)。我猜这就是为什么你从来没有收到回拨消息的原因。

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

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

    我在MFC对话应用程序(以及我们基于MFC的应用程序)中解决这个问题的方法是,确保您在调用“InitializeAccessBridge”时,内置的MFC消息泵可以将“Hello”消息推回到隐藏的对话中,然后再使用它。在简单的MFC对话框中,这意味着在OnInitDialog中调用InitializeAccessBridge,并调用枚举过程以响应按钮调用(例如)。如果希望枚举在对话框出现时立即出现,则可以在OnInitDialog完成后使用计时器启动(例如10毫秒),以允许处理初始化消息。

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

    不管怎样,我希望这足够清楚!虽然没有办法知道这是不是“正确”的方法(除了支付给太阳工程师告诉我们),但它确实解决了我的问题。

    干杯——达伦。

    哦。顺便说一句,我发现了一个晦涩的Sun页面,它提到了Access桥的一些东西,只适用于基于AWT的Java应用程序(但鉴于Sun自2004以来就没有更新过任何文档,这一点可能已经改变)。我不是Java程序员——为了测试,我抓取了一些免费的Java应用程序(以及那些附带JDK的应用程序),并试用了我的测试应用程序。它适用于所有我尝试过的——YMMV。祝你好运!

        2
  •  0
  •   David Rabinowitz    16 年前

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

    static oid JavaAccess::OnJavaShutdown( long vmID )
    
    推荐文章