2

すべて、実行時に 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 をアクティブ/オープンにしておく最善の方法は何ですか?

御時間ありがとうございます。


編集。以下のスティーブンの提案に従って、DLLのインターリーメソッドタイプを次のように変更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-つまり、呼び出しメソッドを作成します(型のDLLTask<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 への呼び出しに注意してください (注: 呼び出し元のメソッドは既にバックグラウンド スレッド プール スレッドで実行されています)。

さらに助けていただければ幸いです。

4

2 に答える 2

1

あなたがdllに何を持っているかを推測するのは難しいですが、最終的にあなたのdllコード+あなたの質問で公開されています:

dllWinForm.Show();  

最終的には並置した後だったはずです:

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

おそらく、次のように変更する必要がありdllWinForm.Show();ますdllWinForm.ShowDialog().Start()

ShowDialog()は、 とは対照的にShow()独自のメッセージ ポンピングを開始し、明示的に閉じられた場合にのみ戻ります

更新 (コメントへの返信):
UI からフォームを起動する必要はありません。
.NET 4.5 を使用しているため、(Windows フォームではなく) WPF フォームを使用する方がおそらく簡単です。 これは、Windows フォームに合わせて調整するために、WindowsFormsSynchronizationContext を初期化してパーツを変更する必要がある
WPFフォームコードです。Dispatcher

ただし、IMO、WinForms コードははるかに複雑になります。

于 2013-05-14T20:11:53.437 に答える