6

私はJNAを使用してUser32関数にアクセスしています(ここではJavaと関係があるとは思いませんが、概念の問題です)。私のアプリケーションには、Canon SDK と通信する Java プロセスがあります。メッセージをディスパッチするには、以下の関数を使用しています。

private void peekMessage(WinUser.MSG msg) throws InterruptedException {
    int hasMessage = lib.GetMessage(msg, null, 0, 0); 
    if (hasMessage != 0) {
        lib.TranslateMessage(msg);
        lib.DispatchMessage(msg);
    }
    Thread.sleep(1);
}

peekMessageループで呼び出され、すべてうまく機能します。画像がカメラから取得されるたびに、イベントを取得して残りを行います。

しかし、たとえば、カメラでのアクティビティが約 15 秒 (まったくない場合もあれば、開始時のみ) 後、写真を撮ってもダウンロード イベントが発生しないことを確認しました。その後、カメラからイベントを取得しないため、アプリケーション全体が使用できなくなります。

この理由は何ですか?他に必要な情報があればお知らせください。それぞれのコードを貼り付けることができます。

編集:

初期化:

Map<String, Integer> options = new HashMap<String, Integer>();
        lib = User32.INSTANCE;
        hMod = Kernel32.INSTANCE.GetModuleHandle("");
        options.put(Library.OPTION_CALLING_CONVENTION, StdCallLibrary.STDCALL_CONVENTION);
        this.EDSDK = (EdSdkLibrary) Native.loadLibrary("EDSDK/dll/EDSDK.dll", EdSdkLibrary.class, options);


 private void runNow() throws InterruptedException {

    while (!Thread.currentThread().isInterrupted()) {
        Task task = queue.poll();
        if (task != null) {
            int taskResult = task.call();
            switch (taskResult) {
                case (Task.INITIALIZE_STATE):
                    break;
                case (Task.PROCESS_STATE):
                    break;
                case (Task.TERMINATE_STATE): {
                    //queue.add(new InitializeTask());
                    Thread.currentThread().interrupt();
                    break;
                }
                default:
                    ;
            }
        }
        getOSEvents();
    }
}
WinUser.MSG msg = new WinUser.MSG();

private void getOSEvents() throws InterruptedException {
    if (isMac) {
        receiveEvents();
    } else {
        peekMessage(msg);
    }
}

上記では、カメラ イベントを取得するたびに に追加しqueue、各ループで をチェックしqueueて処理しますTask。もう 1 つの重要な情報: これは実行中のプロセスでcmdあり、ウィンドウはありません。カメラからのイベントだけが必要です。

コールバック関数を登録するコード:

/**
 * Adds handlers.
 */
private void addHandlers() {
    EdSdkLibrary.EdsVoid context = new EdSdkLibrary.EdsVoid(new Pointer(0));
    int result = EDSDK.EdsSetObjectEventHandler(edsCamera, new NativeLong(EdSdkLibrary.kEdsObjectEvent_All), new ObjectEventHandler(), context).intValue();
  //above ObjectEventHandler contains a function "apply" which is set as callback function

    context = new EdSdkLibrary.EdsVoid(new Pointer(0));
    result = EDSDK.EdsSetCameraStateEventHandler(edsCamera, new NativeLong(EdSdkLibrary.kEdsStateEvent_All), new StateEventHandler(), context).intValue();
   //above StateEventHandler contains a function "apply" which is set as callback function


    context = new EdSdkLibrary.EdsVoid(new Pointer(0));
    result = EDSDK.EdsSetPropertyEventHandler(edsCamera, new NativeLong(EdSdkLibrary.kEdsStateEvent_All), new PropertyEventHandler(), context).intValue();
 //above PropertyEventHandler contains a function "apply" which is set as callback function

}
4

2 に答える 2

1

このスレッドに属するすべてのウィンドウからすべてのメッセージを取得しています。これには、すべてのマウスの動き、ペイントなどが含まれます。この関数をすばやく呼び出さないと、メッセージ キューがオーバーフローし、説明した動作が発生します。

メッセージが待機していない場合に GetMessage が生成されるため、絶対に望ましくないスリープ。

したがって、このスレッド ウィンドウに対して通常のメッセージ ポンプ (つまり、GetMessage/DispatchMessage) ループが別の場所に存在する場合は、そのポンプにほとんどの作業を行わせる必要があります。おそらく、wMsgFilterMin、wMsgFilterMax を使用してイベント メッセージを取得します。あなたが必要とする; または、この場合はさらに良いことに、PM_NOREMOVE を指定して peekmessage を使用します (その後、peekmessage がすぐに戻るため、スリープ コールが必要になります)。

または、ワークロードを軽減するために、イベントを生成するウィンドウの hWnd を提供します。

spy++ を使用して、このスレッドが所有しているウィンドウと生成されているメッセージを調べます。

この回答をさらに進めるには、次の回答を提供してください。このスレッドは他に何をしていて、どのウィンドウを所有していますか。また、このメッセージ ポンプは唯一のものですか、それともメッセージをポンプしている可能性のある SDK API を呼び出しますか?

于 2013-05-29T21:46:32.750 に答える
0

JNA で EDSDK をラップする OpenSource プロジェクトがあり、おそらくより適切に機能するコードのバージョンがあります。

https://github.com/kritzikratzi/edsdk4j/blob/master/src/edsdk/api/CanonCamera.java#L436

残念ながら、これはプラットフォームに依存せず、具体的には Windows での動作方法ではありません。私は現在、次の場所で動作する MacOS バージョンを取得しようとしています。

https://github.com/WolfgangFahl/edsdk4j

于 2016-08-14T08:25:15.390 に答える