简体   繁体   English

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

[英]Access windows forms controls from external DLLs in C#

This is my first Topic here and I didn't find any similar Topics so I try to describe my problem as good as I can: 这是我的第一个主题,但没有找到任何类似的主题,因此我尽力描述我的问题:

I was ordered by my Company to create a modular C# program to assist our Software Developers with Background tasks. 我的公司下令我创建一个模块化C#程序,以协助我们的软件开发人员执行后台任务。 The Programm is composed of a Windows Forms application with a User Interface that calls external DLLs that do the actual work. 该程序由一个Windows Forms应用程序组成,该应用程序具有一个用户界面,该用户界面调用执行实际工作的外部DLL。 All These DLLs are written by me aswell and follow certain rules to make them compatible to the Main App. 所有这些DLL也是由我编写的,并遵循某些规则以使其与Main App兼容。 That way I can easily add new funcions to the Programm just by putting the DLL into a predefined Folder. 这样,只需将DLL放入预定义的文件夹中,我就可以轻松地向Programm添加新功能。 So to say Plug-and-Run 可以说即插即用

The main program contains a ListBox that shows all available PlugIns and if one get's selected and the "start" button is clicked, the Main program calls the corresponding DLL and Invokes the method "program" that starts the DLLs actual function. 主程序包含一个显示所有可用插件的列表框,如果选择了“获取”并单击“开始”按钮,则主程序将调用相应的DLL,并调用方法“程序”来启动DLL的实际功能。 Furthermore the Main contains a method "Output" that is supposed to write the result of every PlugIn into a Tab of my TabControl. 此外,Main包含一个“输出”方法,该方法应该将每个插件的结果写入TabControl的Tab中。 That way the results of every PlugIn running in separate threads can be viewed independently. 这样,可以独立查看在单独线程中运行的每个PlugIn的结果。 The Access to the tab already has a delegate to make it threadsafe. 对选项卡的访问已经具有委托以使其具有线程安全性。 The Information is gathered by invoke from the PlugIn's own "returnOutput" method that simply Returns a List of strings containing the results to the Main. 该信息是通过从插件自己的“ returnOutput”方法中调用而收集的,该方法仅将包含结果的字符串列表返回给Main。

My Problem now is: How can i implement a Kind of a callback into my PlugIn DLLs so they can order the Main Program to gather the results at any time? 我现在的问题是:我如何在我的Plugin DLL中实现某种回调,以便它们可以命令主程序随时收集结果?

My first idea was to simply add the result as return values to the "program" method itself but that would make the Information only available at the end of the program and some of the Tasks require a "live update" during runtime. 我的第一个想法是简单地将结果作为返回值添加到“程序”方法本身,但这将使信息仅在程序末尾可用,并且某些“任务”在运行时需要“实时更新”。

My second idea was to use the delegate for the Control as Parameter and pass it to the PlugIn so the PlugIn DLL could Access the Control on it's own. 我的第二个想法是将控件的委托用作参数,并将其传递给插件,以便插件DLL可以自己访问控件。 This idea failed because the DLL doesn't "know" the Main program and can't Access it's Methods or the delegates instance so I am Always missing a reference. 这个想法失败了,因为DLL无法“知道”主程序,并且无法访问其“方法”或“委托”实例,因此我始终缺少引用。

Is there a way to solve my problem? 有办法解决我的问题吗? If necessary I can provide Code snippets but the program has already around 800 lines of Code and each PlugIn adds a few hundred more.. 如有必要,我可以提供代码段,但该程序已经有800行代码,每个插件增加了几百行。

Thanks in advance for every answer and sorry for my non-native english :D 预先感谢您的每一个回答,对于我的非母语英语:D感到抱歉

Best Regards 最好的祝福

Gerrit "Raketenmaulwurf" M. Gerrit“ Raketenmaulwurf” M.

Edit: I am using SharpDevelop 5.1 编辑:我正在使用SharpDevelop 5.1

Code Snippet for the DLL call: 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});

it basically Looks for a DLL file that has the same Name as the highlighted item in the ListBox 它基本上会寻找与ListBox中突出显示的项目具有相同名称的DLL文件

There are many different ways to do this. 有许多不同的方法可以做到这一点。 Some of the suggestions in the comments are really good and implementing them would make a robust and extendable solution. 评论中的某些建议确实很好,实施这些建议将成为一个健壮且可扩展的解决方案。

If you are looking for a quick and easy way to get messages from your plugins, though, then you can pass your callback directly to the plugin as an Action: 但是,如果您正在寻找一种快速简便的方法来从插件获取消息,则可以将回调作为Action直接传递给插件:

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

}

so you can use it like: 因此您可以像这样使用它:

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

then your plugin's Programm method writes its logs: 然后您插件的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
        });
    }

I must admit, that this is not the ideal way to deal with messaging. 我必须承认,这不是处理消息传递的理想方法。 There are far better (and, unfortunately, more complicated to implement) solutions out there. 那里有更好的解决方案(不幸的是,实现起来更复杂)。 This one is fairly simple though. 不过,这很简单。 Just don't forget that you receive your message on the same thread that have sent it and avoid deadlocks. 只是不要忘记您在发送消息的同一线程上接收到消息,并避免了死锁。

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

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