什么是“正常”如何用编译语言编写插件(C#/ C / C ++ / D)?我对语言无关的方法特别感兴趣,但语言特定并不是不可接受的。

目前,“编译时间”插入方法(只是包含代码或不包含所有代码)都是有效的,但是可以迁移到更加动态的方法是首选。

关于运行时类型,我对加载插件的机制比设计插件/ app界面更感兴趣

编辑:BTW插件将是奴隶而非主人。插件的基本动作是在给定情况下,它将被称为“做它的事情”。并获得一个环境对象,它应该用它来获得它需要操作的东西。

有帮助吗?

解决方案

对于编译语言(编译意味着程序作为本机可执行文件运行,没有任何类型的虚拟机),您几乎需要使用某种特定于平台的共享库方法。在Windows中,这意味着使用DLL。

您可以根据一组函数(具有特定的名称,参数和调用约定)来定义插件接口。然后,在共享库中加载函数的地址并转到城镇。在Windows中,这意味着使用 GetProcAddress() ,然后将返回值强制转换为C中相应类型的函数指针,或者您正在使用的语言中的等效项。

可能会或可能不会更合适的另一个选项是在本机应用程序中运行另一种语言的虚拟机,并使插件成为该语言的代码。例如,您可以使用CPython运行Python VM并动态加载Python模块。

其他提示

Mono.Addins 似乎是.NET的一个很好的解决方案。我相信它包含API,允许您从repo下载插件(或插件)并将其动态加载到正在运行的程序集中。

我发现插件的难点在于:找到它们,解决它们的依赖关系,以及处理版本问题。您和插件作者应该清楚如何处理这些问题。如果你把这些问题弄错了,就不会有痛苦的结局。我会看一下脚本语言和应用程序,这些语言和应用程序使用插件来提供有关哪些方面有效的建议。

静态构造函数通常是“聪明”的。在坏的意义上。因为你不得不一次加载(C / C ++:dlopen和Linux下的朋友)一个插件(在动态情况下),你可以明显地初始化它们。除此之外,这可能会让你有机会拒绝没有预期api的插件。

注意,您不必为插件使用动态加载库。也可以使用其他机制:共享内存,套接字等....

这实际上取决于你想做什么。在Emacs和Gimp中看到的常见Unix模式是编写一个程序,该程序由一个小的编译组件组成,该组件公开了解释组件用来执行所有操作的基本功能。提供可以在应用程序之上构建的新功能的插件很容易,但是您需要在为此提供的灵活性方面非常灵活。相反的极端想象一下可以保存多种格式的照片编辑器。您希望允许人们编写自己的文件格式处理程序。这需要使您的代码使用一组简单的原语,然后在运行时选择一个实现。在直接(Unix)C中使用dlopen,在C ++中使用extern C限制你可以做什么和dlopen。在Objective-C中,您有一个课程可以为您完成。在第一种情况下,你正在制作或重复使用口译员,所以你可以自由地统治你想做的事。

对于slave-type插件,其中每个插件封装了一组常用函数的不同实现,我只是将DLL存放在宿主应用程序已知的插件文件夹中(例如“c:\ program files \ myapp \”插件),然后通过Reflection从主机调用DLL。

可以在安装每个DLL时进行一些精心的注册过程,但我从来没有遇到过简单的插件一体文件夹方法的任何问题。

编辑:要在C#中执行此操作,只需向DLL添加一个公共类(名为“插件”或其他),并在那里实现所需的功能。然后,从主机中创建一个Plugin类型的对象并调用其方法(全部使用Reflection)。

与void Register(EventSource)的接口似乎运行良好 - 请参阅ASP.NET的 IHttpModule.Init(HttpApplication )的例子。

这允许应用程序作者(控制EventSource)根据需要添加事件,而无需扩展IPlugin接口(不可避免地导致IPluginEx,IPlugin2,IPlugin2Ex等)。

我使用的方法(在.NET中)是让主机初始调用插件(通过Reflection),启动插件并将引用传递给插件保存的主机。然后,插件会根据需要调用主机上的方法(也可以通过反射)。

我认为对于大多数插件,调用通常是在另一个方向进行的(即主机会根据需要调用插件)。就我而言,插件本身具有需要利用主机功能的UI元素。

低级模块实现问题(例如Windows DLL和实现问题),我使用的游戏引擎只在DLL中具有全局注册功能,并尝试在插件目录中的每个dll上查找和调用它。 registartion函数执行公开功能所需的任何簿记。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top