关于delphi:运行时包加载vs静态链接

Run-time package load vs static linking

所以,我有一个自己编写的运行时包。如果包是静态链接的,则使用的项目可以完全访问导出的数据,因为编译器完全了解从中导入的内容,对吗?但也可以通过 LoadPackage() 动态加载包。但是,如何处理导入的复杂数据结构,比如类呢?除了使用 FindClass(\\'TSomeClass\\') 构造复杂表达式并调用 RTTI 对导入类的实例进行操作之外,我找不到可行的方法。


编译器完全了解包中的内容,因为 DCU 和 DCP 文件告诉它那里有什么。

IDE 知道包中的内容,因为它知道如何在所有单元中找到 Register 过程,并且该过程会告诉 IDE 可用的类。

在大多数情况下,程序知道包中的内容是因为程序使用了该包中的单元,并且编译器确保在这些单元中提及事物的名称将在运行时解析为 BPL 文件中的相应事物.这包括在程序的导入表中提及 BPL 文件,因此操作系统会自动加载 BPL。

如果您希望加载的 BPL 列表只能在运行时确定,那么您不能使用这些包中的任何单元。您必须动态加载包。

仍然是如何使用这些包中的内容的问题。您可以尝试使用 RTTI 发现全部内容。不过,那不是野餐。相反,定义一个所有相关模块都将使用的中间包。

为所有包类定义一个接口或一个公共基类。将该类的定义放在一个单元中,该单元位于它自己的包中,我们将其称为 Shared.bpl。将该包包含在所有其他包和 EXE 的"需要"列表中。现在,一切都可以引用共享单元和公共基类。

这正是 Delphi 本身所做的。共享包称为 RTL 和 VCL。那里已经定义了几个常见的基类,包括 TComponent。在您的情况下,听起来您需要一些超出 TComponent 的通用定义。


简答:

您需要的是编译器/链接器来设置您并使用 DCP 进行所有类型的链接等。

然后您应该在自定义代码中延迟/完成 BPL 的加载。

不幸的是,Delphi 不允许这样做,可能是出于政治原因,您可以尝试破解它,请参阅下面的更全面的答案。

长答案:

显然 DCP 向编译器/链接器/Delphi yadayadayada 描述了这些包/DLL/BPL 中的类型。

这些 DCP 可以被认为是这些 DLL/BPL 的接口,这些 DCP 可能以某种方式编译成可执行文件。

那么 BPL 可能包含"实现"。

现在问题就从这里开始了。这些 BPL 是"自动加载的",正如其他人已经提到的"导入表"。

您可以尝试"nuking"/更改导入表,以便不再自动加载这些 BPL。

然后您可以尝试手动加载这些 BPL。

我不确定它是否与执行"加载包"操作一样简单。

也许加载更像是获取指向例程/方法/类的指针,不确定它是如何工作的。

但是,也许该代码可以重复使用,所以您需要做的就是"破解"导入表并破解"加载 bpl"并禁用它。

然后你应该能够用你自己的自定义加载代码替换它,也许最后"重新修补"到其他导入例程中......比如调用 getprocaddress 的例程等,如果需要,不确定最后一部分.

无论如何,这对于 Delphi 开发人员来说是非常草率的,因为没有功能可以自己执行这个小"导入表"/"加载步骤"。

虽然这是政治因素,但没有技术原因不能延迟,由您自定义,然后在必要时调用其余部分。

出于某种原因,他们不希望您手动加载这些 BPL。他们可能希望您继续以这种方式使用 IDE。

如果您能够手动加载这些东西,那么 IDE 可能就不再需要了。

目前需要 IDE 指定从哪里加载这些东西,没有 IDE 会变得很困难。尽管在某处可能还有一些编译器选项可以指定相同的内容,但很少有人会使用它。

所以对我来说,这个产品似乎有一些非常奇怪的"搭配",老实说,我必须承认它非常他妈的迟钝。

他们对 winsock 做了同样的事情,例如它有两个不同的版本,很容易自己手动加载,所以你可以选择使用哪个版本而不是总是 v1 或 v2。为了方便他们延迟这些 getprocs 等,但他们没有......

如果他们这样做了,Delphi 将更加向后兼容 Windows 95/98,目前 Delphi exe 不再适用于那些旧操作系统,虽然没有真正的技术原因它不能工作,但它基本上必须这样做加载哪些 DLL,只需几行代码就可以很容易地使其工作。

这可能又是为了让 Delphi 只支持最新的 Windows 版本,这是 Delphi 创建者和 Microsoft 之间达成的协议。

与 Windows 10 相同,它明显检测到较旧的处理器,然后拒绝在它们上运行,删除/破解这几行代码/指令将使 Windows 10 在较旧的处理器上运行。惊喜 ! =D