简体   繁体   English

来自C DLL回调的C#跨线程UI操作

[英]C# cross thread UI operation from C DLL callback

I have C style Dll, which I have to use in C#. 我有C风格的Dll,必须在C#中使用。 I have created a Pinvoke wrapper for the library. 我为该库创建了一个Pinvoke包装器。 Everything is working fine, but one of the C functions accepts a function pointer (Callback). 一切工作正常,但是C函数之一接受一个函数指针(回调)。 So, in my C# wrapper which is a static class I added following code: 因此,在我的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);
}

Now, in my C# Form class, 现在,在我的C#Form类中,

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

The moment my callback is invoked, i get an error: 调用回调函数后,出现错误:

Cross-thread operation not valid

I want the Callback function to run in the UI thread. 我希望回调函数在UI线程中运行。 What changes should I make in my wrapper to achieve this. 我应该在包装器中进行哪些更改以实现此目的。

I want to keep the Form class clean and wrapper class easy to use for end users. 我想让Form类保持干净,包装类便于最终用户使用。 So, if complex code is required to handle this situation I would like to handle that in the wrapper so that end user can easily use my dll. 因此,如果需要复杂的代码来处理这种情况,我想在包装器中进行处理,以便最终用户可以轻松使用我的dll。

Also, will the static instance of delegate inside my static wrapper keep it from garbage collection. 另外,我的静态包装器中的委托的静态实例是否会将其从垃圾回收中保留下来。

You can (mostly) detect whether the callback is going to GUI code, and automatically perform it from the thread associated with the UI code. 您可以(大部分)检测回调是否将转到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);
}

Another option would be to create a SynchronizationContext based on the thread used to call SetMyCallback , and then make the call using that context. 另一个选择是基于用于调用SetMyCallback的线程创建SynchronizationContext ,然后使用该上下文进行调用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM