来自 C DLL 回调的 C# 跨线程 UI 操作
C# cross thread UI operation from C DLL callback
我有 C 风格的 Dll,我必须在 C# 中使用它。我为图书馆创建了一个 Pinvoke 包装器。一切正常,但其中一个 C 函数接受函数指针(回调)。因此,在我的 static class 的 C# 包装器中,我添加了以下代码:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void CallbackType(uint status);
/* To prevent garbage collection of delegate, need to keep a reference */
static CallbackType privCallback;
[DllImport(DLL_FILE_NAME, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
public static extern int SetCallback(uint handle, CallbackType callback);
public static int SetMyCallback(uint handle, CallbackType callback)
{
return SetCallback(handle, callback);
}
现在,在我的 C# 表单中 class,
private void RefreshCallback(uint status)
{
this.statusLabel.Text = "Status Code: "+ status.toString();
}
private void myBtn_Click(object sender, EventArgs e)
{
int status, handle = 0;
...
status = MyDllWrapper.SetMyCallback(handle, RefreshCallback);
...
}
调用我的回调时,出现错误:
Cross-thread operation not valid
我希望 UI 线程中的 运行 回调函数。我应该在包装器中进行哪些更改才能实现此目的。
我想保持表单 class 干净并使包装器 class 易于最终用户使用。因此,如果需要复杂的代码来处理这种情况,我想在包装器中处理它,以便最终用户可以轻松使用我的 dll。
此外,我的静态包装器中委托的静态实例是否会阻止垃圾回收。
您可以(大部分)检测回调是否转到 GUI 代码,并从与 UI 代码关联的线程自动执行它。
public static int SetMyCallback(uint handle, CallbackType callback)
{
var callbackB = callback;
var syncTarget = callback.Target as System.Windows.Forms.Control;
if (syncTarget != null)
callbackB = (v) => syncTarget.Invoke(callback, new object[] { v });
return SetCallback(handle, callbackB);
}
另一种选择是根据用于调用 SetMyCallback
的线程创建一个 SynchronizationContext
,然后使用该上下文进行调用。
我有 C 风格的 Dll,我必须在 C# 中使用它。我为图书馆创建了一个 Pinvoke 包装器。一切正常,但其中一个 C 函数接受函数指针(回调)。因此,在我的 static class 的 C# 包装器中,我添加了以下代码:
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate void CallbackType(uint status);
/* To prevent garbage collection of delegate, need to keep a reference */
static CallbackType privCallback;
[DllImport(DLL_FILE_NAME, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.Cdecl)]
public static extern int SetCallback(uint handle, CallbackType callback);
public static int SetMyCallback(uint handle, CallbackType callback)
{
return SetCallback(handle, callback);
}
现在,在我的 C# 表单中 class,
private void RefreshCallback(uint status)
{
this.statusLabel.Text = "Status Code: "+ status.toString();
}
private void myBtn_Click(object sender, EventArgs e)
{
int status, handle = 0;
...
status = MyDllWrapper.SetMyCallback(handle, RefreshCallback);
...
}
调用我的回调时,出现错误:
Cross-thread operation not valid
我希望 UI 线程中的 运行 回调函数。我应该在包装器中进行哪些更改才能实现此目的。
我想保持表单 class 干净并使包装器 class 易于最终用户使用。因此,如果需要复杂的代码来处理这种情况,我想在包装器中处理它,以便最终用户可以轻松使用我的 dll。
此外,我的静态包装器中委托的静态实例是否会阻止垃圾回收。
您可以(大部分)检测回调是否转到 GUI 代码,并从与 UI 代码关联的线程自动执行它。
public static int SetMyCallback(uint handle, CallbackType callback)
{
var callbackB = callback;
var syncTarget = callback.Target as System.Windows.Forms.Control;
if (syncTarget != null)
callbackB = (v) => syncTarget.Invoke(callback, new object[] { v });
return SetCallback(handle, callbackB);
}
另一种选择是根据用于调用 SetMyCallback
的线程创建一个 SynchronizationContext
,然后使用该上下文进行调用。