Qt DLL向C#程序传递事件异常求助:需调用Application.doEvents()
Qt DLL向C#发送事件需手动调用
Application.DoEvents()才能接收的解决方法 问题场景
我用Qt编写的DLL向C#程序发送事件,已确认事件正常发出,但C#端必须手动调用Application.DoEvents()才能捕获到事件。
C#端回调捕获代码
public byte OnKpeDllEvent(int category, IntPtr pInfo) { KPE_EVENT_INFO Info = new KPE_EVENT_INFO(); if (pInfo != IntPtr.Zero) { m_hInstance = pInfo; object struttura = Marshal.PtrToStructure(pInfo, typeof(KPE_EVENT_INFO)); if (struttura != null) Info = (KPE_EVENT_INFO)struttura; } }
Qt DLL发送事件代码(已验证功能正常)
void KpeQTLibrary::onConnected() { KPE_EVENT_INFO einfo{}; einfo.nLine = -1; einfo.nSize = sizeof(KPE_EVENT_INFO); if (m_pCallbackProc != NULL) m_pCallbackProc(KPE_EVENT::CONNECTED, &einfo); qDebug() << KPE_EVENT::CONNECTED; }
核心原因
这种情况通常是Qt DLL的事件回调在非UI线程触发,而C#的回调方法默认绑定到UI线程上下文,导致回调请求被挂在UI线程的消息队列中,只有手动调用DoEvents()才会强制处理队列里的消息。
解决方案
方案1:C#端异步切换到UI线程处理
如果事件处理需要更新UI,可在回调中主动切换到UI线程执行逻辑,避免依赖DoEvents():
public byte OnKpeDllEvent(int category, IntPtr pInfo) { // 判断当前是否处于UI线程 var mainForm = Application.OpenForms.Cast<Form>().FirstOrDefault(); if (mainForm != null) { if (!mainForm.InvokeRequired) { ProcessEvent(category, pInfo); } else { // 通过Invoke切换到UI线程执行 mainForm.Invoke(new Action<int, IntPtr>(ProcessEvent), category, pInfo); } } return 0; } // 抽离事件处理逻辑 private void ProcessEvent(int category, IntPtr pInfo) { KPE_EVENT_INFO Info = new KPE_EVENT_INFO(); if (pInfo != IntPtr.Zero) { m_hInstance = pInfo; object struttura = Marshal.PtrToStructure(pInfo, typeof(KPE_EVENT_INFO)); if (struttura != null) Info = (KPE_EVENT_INFO)struttura; } // 这里添加具体的事件处理逻辑 }
方案2:Qt端切换到主线程触发回调
如果Qt的事件是在后台线程中产生的,可通过Qt的信号槽机制将回调调用转发到Qt主线程,确保回调触发线程与C# UI线程兼容:
void KpeQTLibrary::onConnected() { // 使用Qt::QueuedConnection将逻辑切换到主线程执行 QMetaObject::invokeMethod(this, [this](){ KPE_EVENT_INFO einfo{}; einfo.nLine = -1; einfo.nSize = sizeof(KPE_EVENT_INFO); if (m_pCallbackProc != NULL) m_pCallbackProc(KPE_EVENT::CONNECTED, &einfo); qDebug() << KPE_EVENT::CONNECTED; }, Qt::QueuedConnection); }
方案3:利用C#同步上下文处理
在UI初始化时保存同步上下文,回调中通过上下文发送消息,自动适配UI线程:
private SynchronizationContext _uiSyncContext; // 程序初始化时(比如主窗体构造函数)保存UI线程的同步上下文 public void InitSyncContext() { _uiSyncContext = SynchronizationContext.Current; } public byte OnKpeDllEvent(int category, IntPtr pInfo) { // 通过同步上下文将事件处理投递到UI线程 _uiSyncContext.Post(state => { var args = (Tuple<int, IntPtr>)state; ProcessEvent(args.Item1, args.Item2); }, Tuple.Create(category, pInfo)); return 0; } private void ProcessEvent(int category, IntPtr pInfo) { // 事件处理逻辑同方案1 }
内容的提问来源于stack exchange,提问作者Nicolò Pietro Oggiano
相关产品推荐
相关产品推荐

