Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 动态加载的BPL';s共享代码/传递对象_Delphi_Bpl - Fatal编程技术网

Delphi 动态加载的BPL';s共享代码/传递对象

Delphi 动态加载的BPL';s共享代码/传递对象,delphi,bpl,Delphi,Bpl,我一直在玩弄使用动态加载BPL并将对象实例从主应用程序传递到BPL中的方法的想法。这在应用程序使用的单元和BPL使用的单元之间造成了问题 我写了一个小的原型来实现这一点,我很好奇Delphi如何在内部管理应用程序和BPL中定义的类之间的差异 例如,假设一个基本的小部件类,如: TmyWidget = class private fId:Integer; fDescription:String; public procedure DoSomething1(); end; 现在,应用程

我一直在玩弄使用动态加载BPL并将对象实例从主应用程序传递到BPL中的方法的想法。这在应用程序使用的单元和BPL使用的单元之间造成了问题

我写了一个小的原型来实现这一点,我很好奇Delphi如何在内部管理应用程序和BPL中定义的类之间的差异

例如,假设一个基本的小部件类,如:

TmyWidget = class
private
  fId:Integer;
  fDescription:String;
public
  procedure DoSomething1();
end;
现在,应用程序和BPL是使用包含TmyWidget类的单元构建的。后来,TMyWidget中发生了一些变化,应用程序被重建,但BPL没有(反之亦然)。我添加了另一个方法DoSomething2(),在应用程序中创建了一个TMyWidget实例,并将其传递给BPL进行处理,在基本示例中,它起到了作用。但它显然充满了潜在的问题

如果另一个动态加载的BPL也使用TmyWidget,那么事情会变得更加有趣。这似乎有效,但感觉绝对不理想

主要问题是-通常如何向主应用程序和DLL或BPL传递对象?我以前从未尝试过,可能是出于一个很好的理由,但我有一个想法,适合这种方法

我认为最好的方法是序列化对象,传递这些字节,并在DLL/BPL中对其进行反序列化,这个过程要注意主机和动态加载模块之间可能存在的版本差异,但我希望新的SimpleSharedMem选项可能会带来这一新功能,而不会带来序列化,但它似乎不是很有用,除非您严格要求在任何共享代码更改上重新生成应用程序和dll…但是在这个原型中,应用程序将保持相当稳定,动态加载的模块将随着功能添加到TmyWidget而频繁更改。(服务器应用程序充当基于客户端请求构建TmyWidget的工厂,应用程序将实例传递给各个模块进行处理。)

…很好奇Delphi如何在内部管理应用程序和BPL中定义的类之间的差异

Delphi通过不允许它来管理这一点。您不能同时在多个软件包中使用相同名称的设备:如果这样做,您会收到一条错误消息,提示类似于
的东西,软件包XYZ已经包含ABC
(很久没有看到过了…)。由于类型名称包括单元名称,因此在两个不同的包中不能有相同的类型。除非它是一个由GUID定义的接口,但这是另一回事

。。。通常如何向主应用程序和DLL或BPL传递对象

不将对象传递给DLL,这不是一个好主意。当需要将对象传递给BPL时,请确保将该BPL的基类定义为第三个BPL

例如。您的
TmyWidget
的多态行为可能是使用一些虚拟方法定义的。确保您有一个定义所有这些虚拟方法的
TmyWidgetBase
类,从该基类派生所有
TmyWidget
,并传递类型为
TmyWidgetBase
的对象。确保
TmyWidgetBase
类位于它自己的包中


当我尝试这样做时,我得到了一个很小的“bootstrap”exe和很多BPL。基本上所有的逻辑都在BPL中,以便于传递对象。

我参与的一个项目已经成功地使用了大量运行时软件包十多年了,因此我将分享一些处理软件包的经验

正如Cosmin指出的,不同的包不能包含相同的单元。如果使用隐式链接,通过将包添加到另一个包的requires子句,或通过将包添加到项目选项中的Runtime packages列表,编译器将为您完成工作并报告以下错误消息之一:

E2199:包“%s”和“%s”都包含单元“%s”
(如果您的编译项目依赖于包含相同单元的两个包)

E2200:包“%s”已包含单元“%s”
(如果您编译的包中包含单元,则该单元已包含在它所依赖的某个包中)

如果您使用的是显式链接,使用LoadPackage,则通常会在运行时尝试进行检查(尽管可以避免),并引发:

EPackageError:无法加载包 “%s”。它包含单元“%s”,它是 也包含在包“%s”中

解决这些错误其实并不那么困难

如果您有两个包都需要使用一个单元,只需让其中一个包含该单元,另一个需要第一个。

如果您有两个包需要使用彼此包含的单元,那么您必须将这些单元移动到一个新的包中,这两个包都可以依赖。

隐式链接的包的优点是,您可以直接访问类定义,就像它们是静态链接的一样。只需在需要使用的单元的uses子句中添加一个单元。编译器和运行时环境负责解决所有问题


显式链接的包需要依赖于初始化部分中的类注册。

正确的解决方案当然是每个单元只有一个实例。为什么同一个单元有两次?难道你不能像自然所希望的那样组织代码以避免这种情况吗?是的,它可以(应该)被重新组织-它是通过玩弄一种想法开始的,这种想法转变为加载BPL,而这些BPL最初是DLL,带有一些共享代码,没有被分割,出于某种原因它工作了,我有点想知道为什么。注意-我没有得到答案“包已包含xx”错误,两个动态加载的BPL在每个BPL中包含相同的TmyWidget单元(在runt时使用LoadPackage动态加载)