一段时间后无法接收消息

6

我正在使用JNA来访问User32函数(我认为这与Java无关,更多的是概念问题)。在我的应用程序中,我有一个Java进程与佳能SDK进行通信。为了分发任何消息,我使用以下函数:

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);
    }
}

以上,每当我收到相机事件时,就会将其添加到队列中,并在每次循环中检查队列以处理任何任务。还有一个重要的信息:这是在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

}

GetMessage() 不会返回,直到检索到消息;你可能想使用 PeekMessage()。也许阻塞调用正在干扰应用程序中的其他操作。 - HerrJoebob
它可能会引起哪些问题? - niting
GetMessage在出错时可能会返回-1 - 可以参考Raymond Chen的文章。也许就是这种情况?也许msg由于某些原因无效。 - Steve
为什么msg是一个参数,而不是一个本地变量?此外,典型的消息循环的行为稍有不同。不要睡眠(没有必要;GetMessage会阻塞 - 这也可能是您的应用程序变得“无法使用”的原因 - 是冻结了吗?崩溃了吗?请详细说明),检查是否为-1,而不是不相等。 - David
@DavidM @Steve 我从未在任何时候得到过-1。我已经尝试了一百多次,我没有看到“-1”的出现。关于循环,我将while循环放在方法外面。即peekMessage被重复调用(它检查它的窗口并调用peekMessage,否则调用Mac相应的方法)。不需要睡眠,我已经将其删除。 - Jatin
@DavidM 首先,上面的代码是应用程序(子集)的一部分,所以如果 GetMessage 被阻塞,它只会挂起相应的插件而不是整个应用程序。这里有一个奇怪的现象:有时候 GetMessage 确实会阻塞它,并且插件仍然处于冻结状态,但我可以看到从相机中派发出事件。有时候,即使没有从相机派发出事件,GetMessage 仍然会返回 1,也就是说,每次顺序地返回 1。最后关于 msg,我已经更新了帖子。 - Jatin
2个回答

1
您正在获取属于此线程的所有窗口的所有消息,包括所有鼠标移动、绘制等。如果您没有快速调用此函数,您的消息队列将会溢出并引起您所描述的行为。
您绝对不希望使用sleep,因为GetMessage会在没有消息等待时产生。
因此,如果存在一个正常的消息泵(即GetMessage/DispatchMessage)循环在这个线程的窗口中的某处,那么您应该让该泵完成大部分工作,也许使用wMsgFilterMin、wMsgFilterMax只获取您需要的事件消息;或者更好的方法是,在这种情况下使用peekmessage和PM_NOREMOVE(然后您将需要您的sleep调用,因为peekmessage立即返回)。
或者提供生成事件的窗口的hWnd以减少工作量。
使用spy++查看此线程拥有哪些窗口以及产生了哪些消息。
要进一步回答,请提供以下信息:此线程还在做什么以及它拥有哪些窗口;此消息泵是否是唯一的,或者您是否调用SDK API,其中它可能也在泵送消息?

1
同时,我授予您一份赏金,因为您帮助了我前进,但我不接受,因为解决方案尚未解决 :) - Jatin
也许阻塞正在破坏你的应用程序?如果你使用PeekMessage(msg, NULL, 0, 0, PM_REMOVE)和sleep会发生什么呢? - slonik
看起来 Spy++ 对控制台应用程序无效 :( 我不理解你如何使用回调和消息的解释,能否提供更多细节?所以你是从另一个应用程序向这个应用程序发送消息吗? - slonik
那么是哪个线程在回调你呢?你能否发布安装回调的代码以及您认为可能相关的任何其他SDK API调用。使用Spy++进行检查,也许SDK正在创建隐藏窗口来执行操作。 - slonik
1
让我们在聊天室中继续本次讨论 - slonik
显示剩余8条评论

0

1
我最终让它工作了。但佳能SDK经常崩溃,这是其他问题 :( - Jatin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接