我正在使用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
。 一个更重要的信息:这是一个在cmd
运行的进程,没有窗口。 我只需要从我的相机事件,没有别的。
我注册callback函数的代码:
/** * 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产生睡眠。
所以如果在这个线程窗口的某个地方存在一个正常的消息泵(即GetMessage / DispatchMessage),那么你应该让这个泵执行大部分的工作,也许使用wMsgFilterMin,wMsgFilterMax来获取事件消息你需要; 或者在这种情况下更好使用PM_NOREMOVE peekmessage(那么你将需要你的睡眠呼叫,因为peekmessage立即返回)。
或者提供生成事件的窗口的hWnd以减少工作量。
使用spy ++来查看这个线程拥有的窗口以及正在产生什么消息。
要进一步回答这个问题,请给出答案:这个线程还在做什么,它拥有什么窗口? 也是这个消息泵只有一个,或者你打电话到SDK的API,它可能是泵信息呢?
有一个OpenSource项目用JNA封装了EDSDK,它的代码版本可能更好:
https://github.com/kritzikratzi/edsdk4j/blob/master/src/edsdk/api/CanonCamera.java#L436
不幸的是,这不是平台独立的,特别是在Windows上工作的方式。 我目前正在试图获得MacOS版本的工作: