在运行时调用多线程DLL

时间:2013-05-09 09:59:10

标签: winforms dll task-parallel-library async-await c#-5.0

所有,我在运行时从WinForm C#应用程序调用包含WinForm的.NET DLL。为此,我使用以下内容:

DLL = Assembly.LoadFrom(strDllPath);
classType = DLL.GetType(String.Format("{0}.{1}", strNamespaceName, strClassName));
if (classType != null)
{
    if (bDllIsWinForm)
    {
        classInst = Activator.CreateInstance(classType);
        Form dllWinForm = (Form)classInst;
        dllWinForm.Show();

        // Invoke required method.
        MethodInfo methodInfo = classType.GetMethod(strMethodName);
        if (methodInfo != null)
        {
            object result = null;
            result = methodInfo.Invoke(classInst, new object[] { dllParams });
            return result == null ? String.Empty : result.ToString();
        }
    }
}

这是调用WinForm DLL和DLL中的串行方法所需的方法。但是,我现在正在调用一个多线程DLL,并调用以下方法:

public async void ExecuteTest(object[] args)
{
    Result result = new Result();
    if (!BuildParameterObjects(args[0].ToString(), args[1].ToString()))
        return;
    IProgress<ProgressInfo> progressIndicator = new Progress<ProgressInfo>(ReportProgress);
    List<Enum> enumList = new List<Enum>()
    {
        Method.TestSqlConnection, 
        Method.ImportReferenceTables
    };
    Task task = Task.Factory.StartNew(() =>
    {
        foreach (Method method in enumList)
        {
            result = Process.ProcessStrategyFactory.Execute(Parameters.Instance, progressIndicator,
            Process.ProcessStrategyFactory.GetProcessType(method));
            if (!result.Succeeded)
            {
                // Display error.
                return;
            }
        }
    });
    await task;
    Utilities.InfoMsg("VCDC run executed successfully.");
}

但由于await(预期),这会立即将控制权交还给来电者。但是,返回会导致调用方法退出,从而关闭DLL WinForm。

保持DLL WinForm活动/打开的最佳方法是什么?

感谢您的时间。


编辑。根据Stephen的建议,我决定将我的DLL intery方法类型转换为Task<object>并设置如下的继续

if (classType != null)
{
    if (bDllIsWinForm)
    {   
        // To pass object array to constructor use the following.
        // classInst = Activator.CreateInstance(classType, new object[] {dllParams});
        classInst = Activator.CreateInstance(classType);
        dllWinForm = (Form)classInst;
        dllWinForm.Show();

        // Invoke required method.
        MethodInfo methodInfo = classType.GetMethod(strMethodName);
        if (methodInfo != null)
        {
            object result = null;
            result = methodInfo.Invoke(classInst, new object[] { dllParams });
            if (result != null)
            {
                if (result.GetType() == typeof(Task<object>))
                {
                    Task<object> task = (Task<object>)result;
                    task.ContinueWith(ant =>
                        {
                            object innerResult = task.Result;
                            return innerResult == null ? String.Empty : innerResult.ToString();
                        });
                }
                return result.ToString();
            }
            return String.Empty;
        }
    }
}

我决定成立的延续,而不是await,以避免将与await的关键字发生链 - 即正在调用方法(即呼叫类型的DLL Task<String>等调用堆栈。

DLL入口方法现在变为:

public Task<object> ExecuteTest(object[] args)
{
    Task<object> task = null;
    Result result = new Result();
    if (!BuildParameterObjects(args[0].ToString(), args[1].ToString()))
        return task;
    IProgress<ProgressInfo> progressIndicator = new Progress<ProgressInfo>(ReportProgress);
    List<Enum> enumList = new List<Enum>()
    {
        Method.TestSqlConnection, 
        Method.ImportReferenceTables
    };
    task = Task.Factory.StartNew<object>(() =>
    {
        foreach (Method method in enumList)
        {
            result = Process.ProcessStrategyFactory.Execute(Parameters.Instance, progressIndicator,
            Process.ProcessStrategyFactory.GetProcessType(method));
            if (!result.Succeeded)
            {
                // Display error.
            }
            task.Wait(5000); // Wait to prevent the method returning too quickly for testing only.
        }
        return null;
    });
    return task;
}

但是这会导致DLL WinForm显示一瞬间然后消失。我甚至试图使Form dllWinForm全局保持对对象的引用活动,但这也没有奏效。我想要注意到对DLL的调用( N.B。调用方法已经在后台线程池线程上运行)。

感谢任何进一步的帮助。

2 个答案:

答案 0 :(得分:4)

Execute的返回类型更改为Taskawait

答案 1 :(得分:1)

很难猜出你在dll中有什么,但最终你的dll代码+暴露在你的问题中:

dllWinForm.Show();  

最终应该并列:

new Thread
      (   
         () => new Form().ShowDialog()
       )
       .Start();  

您可能应该dllWinForm.Show();更改dllWinForm.ShowDialog().Start();

ShowDialog(),与Show()starts its own message pumping and returns only when explicitly closed形成鲜明对比。

更新(以回复评论):
从UI启动表单并非绝对必要 由于您使用的是.NET 4.5,因此使用WPF(而不是Windows Form)形式可能更简单 以下是the code for WPF form,为了调整Windows表单,您应该通过初始化WindowsFormsSynchronizationContext来更改Dispatcher部分

虽然,IMO,WinForms代码会复杂得多。