我正在制作一个包含许多子表单的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;
简单的问题是如何使用corecly编写代码cbstr:=(Form.Components[i] as TcxDBLookupComboBox).Text;
而不会出现EInvalidCast错误?
顺便说一句,如果我在其他单元中编写此代码,则dll和bpl程序会出错,但如果我将该代码写入同一单元(单元报告),则代码可以正常工作。谢谢你的进步。
答案 0 :(得分:3)
您的问题是DLL中的类与可执行文件中的类不同。你有两个这些类的实例,甚至认为它们是从相同的代码编译的。当编译器表示该对象不是您将其强制转换为的类时,编译器是准确的。你根本无法使用DLL共享Delphi类。
解决方案是:
在您的方案中,将代码放入包中是不够的。问题是devexpresses类。您需要链接到使用运行时包的那些。因为您没有这样做,所以您有这些类的多个不同版本。
您注意到is运算符的结果似乎与ClassName函数不一致。嗯,那是因为该类的所有不同版本都具有相同的名称。
我还注意到您遇到的问题与之前的问题相同:How can I pass TForm to a DLL as parameter?您在此处接受的答案的解释和建议同样适用于此。
答案 1 :(得分:2)
如果您已使用(Foo is TSomething)
类型检查,那么您知道foo是TSomething
并且您可以使用静态广播:TSomething(Foo)
如果您尝试将此代码链接到另一个可执行文件或dll中,则可能没有包含正确的单位,如果它在运行时失败,并且如果它在运行时失败,则您没有打开BPL链接选项(使用运行时PACKAGES,并确保包名称列表已完成)。请记住,检查“某事是TSomething”,您正在将类声明与另一个活动对象的类进行比较。字符串名称未定义类。它实际上是链接到您的应用程序中的类型信息。
当您链接DLL(没有运行时包)时,您实际上可能已将TSomething
链接到主EXE和DLL中,并且它们是具有相同名称且名称不重要的类的两个不同副本一点。当你比较身份时,没有办法在运行时知道它们是同一个东西。所以他们不是。
您可以按照您在屏幕上看到的方式来考虑代码。当它运行时,它被编译成代码,类型只是exe或DLL中的数据。所以TSomething-in-myexe.exe与TSomething-in-mydll.dll不是同一类。
如果希望它们相同,请为要在不同编译部分之间比较类型信息的所有位置启用“使用运行时包”(BPL)。特别是在非启用bpl的链接目标之间传递指针或对VCL类型的引用不会像你想象的那样工作。
您还应该确保运行时包列表包含定义您正在使用的类的包。 (TcxSomething可能是开发人员快速组件,请查找它所定义的BPL包。)