从 C# 中的外部 DLL 访问窗口窗体控件



这是我在这里的第一个主题,我没有找到任何类似的主题,所以我尝试尽可能好地描述我的问题:

我公司命令我创建一个模块化的C#程序,以帮助我们的软件开发人员完成后台任务。该程序由一个 Windows 窗体应用程序组成,该应用程序具有一个用户界面,该用户界面调用执行实际工作的外部 DLL。所有这些DLL也是由我编写的,并遵循某些规则以使它们与主应用程序兼容。这样,我可以轻松地将新功能添加到程序中,只需将DLL放入预定义的文件夹中即可。可以说即插即用

主程序包含一个列表框,显示所有可用的插件,如果选择一个插件并单击"开始"按钮,主程序将调用相应的DLL并调用启动DLL实际函数的方法"程序"。此外,Main 包含一个方法"输出",该方法应该将每个插件的结果写入我的 TabControl 的选项卡中。这样,可以独立查看在单独线程中运行的每个插件的结果。对选项卡的访问已具有一个委托,以使其线程安全。信息是通过调用插件自己的"returnOutput"方法收集的,该方法只是将包含结果的字符串列表返回给 Main。

我现在的问题是:如何在我的插件 DLL 中实现一种回调,以便它们可以命令主程序随时收集结果?

我的第一个想法是简单地将结果作为返回值添加到"程序"方法本身,但这将使信息仅在程序结束时可用,并且某些任务需要在运行时进行"实时更新"。

我的第二个想法是将控件的委托用作参数并将其传递给插件,以便插件 DLL 可以自行访问控件。这个想法失败了,因为 DLL 不"知道"主程序并且无法访问它的方法或委托实例,所以我总是缺少引用。

有没有办法解决我的问题?如有必要,我可以提供代码片段,但该程序已经有大约 800 行代码,每个插件都会添加几百行代码。

提前感谢每一个答案,对不起我的非英语母语:D

此致敬意

格里特"拉克滕莫尔武夫"M.

编辑:我正在使用夏普5.1

DLL 调用的代码段:

PlugIn = PlugIns.SelectedItem.ToString();
Assembly PlugInDLL = Assembly.LoadFile(@PlugInOrdner+"\"+PlugIn+".dll");
Object Objekt = PlugInDLL.CreateInstance("DLL.PlugIn");
MethodInfo Info1 = Objekt.GetType().GetMethod("Programm");
Info1.Invoke(Objekt, new Object[]{Projekt, TIAInstanz});

它基本上查找与列表框中突出显示的项具有相同名称的DLL文件

有许多不同的方法可以做到这一点。评论中的一些建议非常好,实施它们将成为一个强大且可扩展的解决方案。

但是,如果您正在寻找一种快速简便的方法来从插件获取消息,那么您可以将回调作为操作直接传递给插件:

public class PluginRunner
{
public class PluginMessageEventArgs
{
public string Text { get; set; }
}
public event EventHandler<PluginMessageEventArgs> PluginMessage;
public void Run( string pluginPath )
{
Assembly PlugInDLL = Assembly.LoadFile(pluginPath);
Object Objekt = PlugInDLL.CreateInstance("DLL.PlugIn");
MethodInfo Info1 = Objekt.GetType().GetMethod("Programm");
Info1.Invoke(Objekt, new Object[] { Projekt, TIAInstanz, new Action<string>(Log) });
}
private void Log(string s)
{
PluginMessage?.Invoke(this, new PluginMessageEventArgs { Text = s });
}
}

因此,您可以像以下方式使用它:

var path =
Path.Combine(
Path.GetDirectoryName(Assembly.GetEntryAssembly().Location),
"Plugins",
"MyAwesomePlugin.dll");
var pr = new PluginRunner();
// be aware that your event delegate might be invoked on a plugin's thread, not the application's UI thread!
pr.PluginMessage += (s,e) => Console.WriteLine("LOG: " + e.Text);
pr.Run(path);

然后你的插件的 Programm 方法写入它的日志:

public void Programm( ProjektClass p0, TIAClass p1, Action<string> log )
{
Task.Run(() =>
{
// do something
log.Invoke("here am I!");
// do something else
log.Invoke("here am I again!");
// do something more
});
}

我必须承认,这不是处理消息传递的理想方式。那里有更好的(不幸的是,实施起来更复杂(的解决方案。不过这个相当简单。只是不要忘记您在发送消息的同一线程上接收消息并避免死锁。

最新更新