0

我正在制作一个包含许多子表单的 mdi 应用程序,其中一个是显示报告的表单。在报表上,我使用 dll 文件来显示表单上的所有组件并在每个组件中查找值,我使用以下代码来执行此操作。

// this code i write in dll or bpl file
procedure getReportParams(Form : Tform); stdcall;
var
i : integer;
str, cbstr : string;
b : boolean;
begin

for i:=0 to Form.ComponentCount-1 do
  begin
  str:=str+Form.Components[i].Name+' - '+Form.Components[i].ClassName+', ';
      if (Form.Components[i] is TcxLookupComboBox) then
          begin
          showmessage('test 1');

          // if i uncomment the code below, the program get error Einvalidcast 
          // cbstr:=(Form.Components[i] as TcxDBLookupComboBox).Text;
          // if (Form.Components[i] as TcxDBLookUpCombobox).Parent=Form.FindComponent('pnledit') then
          //     showmessage((Form.Components[i] as TcxDBLookUpCombobox).Name);
          end;
  end;
showmessage(str);
// this showmessage work well in dll, bpl, or other unit
if b then
showmessage(cbstr+' true') else showmessage(cbstr+' false');
end;

简单的问题是如何cbstr:=(Form.Components[i] as TcxDBLookupComboBox).Text;使用 corecly 编写代码而不会出现 EInvalidCast 错误?

顺便说一句,如果我在其他单元中编写此代码,dll 和 bpl 程序会出错,但如果我在同一单元(单元报告)中编写该代码,则代码运行良好。感谢提前。

4

2 回答 2

3

您的问题是 DLL 中的类与可执行文件中的类不同。您有这些类的两个实例,即使它们是从相同的代码编译的。当编译器说对象不是您将其转换为的类时,它是准确的。您根本无法使用 DLL 共享 Delphi 类。

解决方案是:

  1. 将所有代码编译成一个可执行文件。
  2. 使用运行时包来共享类。

在您的场景中,将代码放在一个包中是不够的。问题是 devexpresses 类。您需要链接到使用运行时包的那些。因为您没有这样做,所以您有这些类的多个不同版本。

您注意到 is 运算符的结果似乎与 ClassName 函数不一致。嗯,那是因为类的所有不同版本都具有相同的名称。

我还注意到您遇到的问题与您之前的问题相同:如何将 TForm 作为参数传递给 DLL? 您在那里接受的答案的解释和建议在这里同样适用。

于 2013-03-09T18:14:56.287 回答
2

如果您已经使用了(Foo is TSomething)类型检查,那么您知道 foo 是 aTSomething并且您可以使用静态强制转换: TSomething(Foo)

如果您尝试将此代码链接到另一个可执行文件或 dll 中,则您可能没有包含正确的单元如果编译失败,并且如果它在运行时失败,则您没有打开 BPL 链接选项(使用运行时包,并确保包名称列表完整)。请记住,检查“某事是 TSomething”是在将一个类声明与另一个活动对象的类进行比较。类不是由字符串名称定义的。它实际上是链接到您的应用程序的类型信息。

当您链接一个 DLL(没有运行时包)时,您实际上可能已经链接TSomething到您的主 EXE 和您的 DLL,它们是具有相同名称的类的两个不同副本,并且名称并不重要。当您比较身份时,无法在运行时知道它们是同一件事。所以他们不是。

您以您在屏幕上看到代码的方式思考代码。当它运行时,它被编译成代码,类型只是exe或DLL中的数据。所以 TSomething-in-myexe.exe 与 TSomething-in-mydll.dll 不是同一个类。

如果您希望它们相同,请为您想要比较不同编译部分之间的类型信息的所有位置启用使用运行时包 (BPL)。特别是在未启用 bpl 的链接目标之间传递指针或对 VCL 类型的引用不会像您想象的那样工作。

您还应该确保运行时包列表包含定义您正在使用的类的包。(TcxSomething 可能是一个开发者快递组件,去查找它定义在什么包 BPL 中。)

于 2013-03-09T18:13:00.567 回答