在运行时调用多线程DLL [英] Invoking a Multi-Threaded DLL at Run-Time

查看:143
本文介绍了在运行时调用多线程DLL的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好,我调用包含一个WinForm C#应用程序在运行时一个WinForm的.NET的DLL。要做到这一点,我使用以下命令:

All, I call a .NET DLL containing a WinForm at run-time from a WinForm C# application. To do this I use the following:

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

这是调用DLL的WinForm和在DLL中的串行方法所需的方法很好。不过,我现在调用一个多线程的DLL,并调用下面的方法:

This is invoking the WinForm DLL and the required method fine for serial methods within the DLL. However, I am now invoking a multi-threaded DLL, and calling the following method:

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 (预计)控制返回给调用者的时候了。然而,回报会导致调用的方法来退出该关闭的WinForm DLL

But this is returning control to the caller right away due to the await (which is expected). However, the return causes the calling method to exit which closes the DLL WinForm.

什么是保持DLL的WinForm活跃的最好方法/开?

感谢您的时间。

编辑。继斯蒂芬的建议之下,我决定把我的DLL intery方法类型为任务&LT;对象&gt; ,并成立了延续如下:

Edit. Following the suggestion by Stephen below I have decided to turn my DLL intery method type to Task<object> and set up a continuation as follows

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 关键词 - 即拍即调用方法(即调用类任务&LT的DLL;串&GT; 等调用堆栈

I decided to set up the continuation instead of the await to avoid the chaining that would occur with the await keyword - that is making the calling method (that calling the DLL of type Task<String> etc. up the call stack.

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是显示的一瞬间,然后disapear。我甚至企图使表格dllWinForm 全球保持在基准对象主动,但是这也没有奏效。我想指出,在调用DLL( N.B。调用方法已经在后台线程池中的线程运行)。

But this causes the DLL WinForm to be show for a split second and then disapear. i even attempted to make the Form dllWinForm global to keep the refernce to the object active, but this also has not worked. I want to note that the call to the DLL (N.B. the calling method is already running on a background thread-pool thread).

任何进一步的帮助是AP preciated。

推荐答案

这是很难猜测你在DLL中,但最终你的DLL code +暴露了你的问题:

It's difficult to guess what you have in dll but eventually your dll code + exposed in your question:

dllWinForm.Show();  

最终应该是并列后:

should eventually have been after juxtaposing:

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

或许,你应该改变 dllWinForm.Show(); dllWinForm.ShowDialog()启动() ;

的ShowDialog(),符合显示()相比之下,的开始自己的消息抽水,并返回只有明确封闭

ShowDialog(), in contrast with Show(), starts its own message pumping and returns only when explicitly closed.

更新(在respnse评论):结果
这不是绝对必要推出从用户界面的形式。结果
既然你是在.NET 4.5,它可能是更容易使用(而不是Windows窗体)WPF的形​​式。结果
这里是的code代表WPF表单,其中,以调整Windows窗体,你应该初始化<一改调度部分href=\"http://msdn.microsoft.com/en-us/library/system.windows.forms.windowsformssynchronizationcontext.aspx\"相对=nofollow> WindowsFormsSynchronizationContext

Update (in respnse to comment):
It is not absolutely necessary to launch a form from UI.
Since you are on .NET 4.5, it is probably simpler to use WPF (instead of Windows Form) form.
Here is the code for WPF form which, in order to adjust for Windows Form, you should change Dispatcher parts by initializing WindowsFormsSynchronizationContext

不过,国际海事组织,WinForms的code将变得更加复杂。

Though, IMO, WinForms code will be much more complex.

这篇关于在运行时调用多线程DLL的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆