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 間の「hello」タイプのハンドシェイクのようです)。そのため、アプリケーションにアクティブなメッセージ ポンプがない場合、JavaVM からの戻りメッセージがアプリケーションで受信されることはありません。

このメッセージが受信されるまで、ブリッジは適切に初期化されず、「IsJavaWindow」へのすべての呼び出しが失敗するため、これは重要です (内部的には、メッセージが受信されると、ブリッジは内部構造を初期化します。そのため、アクティブなメッセージ ポンプはありません)。初期化しない)。これが、コールバック メッセージも受信しない理由だと思います。

それだけでなく、IsJavaWindow を呼び出す前に、メッセージ ポンプがメッセージを処理できる時点で initializeAccessBridge を呼び出す必要があります。

これが、JavaFerret と JavaMonkey が機能する理由です。これらは起動時に初期化され、ブリッジがメッセージ ポンプを介して初期化メッセージを受信したかなり後に、メニュー メッセージへの応答で列挙されます。

MFC ダイアログ アプリ (および MFC ベースのアプリケーション) でこれを解決できた方法は、組み込みの MFC メッセージ ポンプが「hello」をプッシュできるような時点で「initializeAccessBridge」を呼び出すようにすることです。使用する前に、この非表示のダイアログにメッセージを戻してください。単純な MFC ダイアログのケースでは、OnInitDialog で initializeAccessBridge を呼び出し、ボタン呼び出しに応答して enum プロシージャを呼び出すことを意味していました (たとえば)。ダイアログが表示されたらすぐに列挙型を発生させたい場合は、OnInitDialog の完了後にタイマーを使用して (たとえば 10ms)、初期化メッセージの処理を許可することができます。

これをコンソール アプリで使用する場合は、初期化メッセージを処理する独自のカスタム メッセージ ポンプを作成する必要があります。

とにかく、これが十分に明確であることを願っています!これが「正しい」方法であるかどうかを知る方法はありませんが (Sun のエンジニアにお金を払って教えてもらう以外に)、間違いなく私の問題は解決しました。

乾杯 -- ダレン。

おー。ところで、AccessBridge が awt ベースの Java アプリケーションでのみ機能することについて言及している、あいまいな Sun のページを見つけました (ただし、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 に答える