0

I'm making a mdi application with many child forms, one of which is the form to display the report. on the report form I use dll files to display all the components on the form and look for value in each component, I use the following code to do that.

// 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;

simple question is how to write code cbstr:=(Form.Components[i] as TcxDBLookupComboBox).Text; with corecly without get EInvalidCast error?

Btw if i write this code in other unit, dll and bpl program get error but if i write that code in same unit (unit report) the code work well. thank for advance.

AsepRoro
  • 353
  • 2
  • 6
  • 19

2 Answers2

3

Your problem is that the classes in your DLL are different from the classes in your executable. You have two instances of these classes, even thought they are compiled from the same code. The compiler is accurate when it says that the object is not the class that you cast it to. You simply cannot share Delphi classes using DLLs.

The solution is either:

  1. Compile all your code into a single executable.
  2. Use runtime packages to share classes.

In your scenario it's not enough that you put your code in a package. The problem are the devexpresses classes. You need to link to those using runtime packages. Because you are not doing so you have multiple different versions of those classes.

You note that the results of the is operator appear to be at odds with the ClassName function. Well, that's because all the different versions of the class have the same name.

I also note that the issue you are encountering is the same as in your earlier question: How can I pass TForm to a DLL as parameter? The explanation and advice from the answer you accepted there apply equally here.

Community
  • 1
  • 1
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Then you need to use packages – David Heffernan Mar 09 '13 at 18:20
  • i haved to used package to, but i get the same result – AsepRoro Mar 09 '13 at 18:21
  • What is the list of packages in your runtime packages options? Does it contain all the developer express package bpls you're referencing? – Warren P Mar 09 '13 at 18:24
  • It's not enough to use a couple of packages. You need all shared code to be in packages. – David Heffernan Mar 09 '13 at 18:26
  • @David Heffernan As i remember interfaces also can help. – Abelisto Mar 09 '13 at 18:41
  • @Abelisto just to hide the code there is no need to switch to interfaces. Just have a look to component libraries without the source. You'll get only the dcu files – Sir Rufo Mar 10 '13 at 01:36
  • @Abelisto Interfaces can only help if the classes expose interfaces. These classes don't. – David Heffernan Mar 10 '13 at 08:33
  • @Roro Are you still needing help understanding this issue? – David Heffernan Mar 11 '13 at 08:07
  • sory i'am still confusing about that. and the last i get your first solution – AsepRoro Mar 11 '13 at 08:34
  • Do you understand what I mean when I say that you have two different versions of the class? One in the EXE and one in the DLL. Conceptually it's just the same as writing `TMyClass = class(TObject);` in two different units. Then you have two different classes, both named `'TMyClass'`. But none the less different classes. The bottom line is that DLLs are fine for simple types, integer, double, records, PChar. But to share Delphi classes, managed types etc. between modules you have to use runtime packages. – David Heffernan Mar 11 '13 at 09:02
  • is posible to run application without runtime packages? because is need all of support unit to include with application just like devexpress bpl, vcl, rttl etc. i tried to do that but files size to large, but i will try with your last comment. – AsepRoro Mar 11 '13 at 13:19
  • You don't need runtime packages. You just compile all the code into a single executable. But you can't use DLLs if you intend to pass Delphi classes across the module boundary. Why is file size a problem? – David Heffernan Mar 11 '13 at 13:20
  • my exe has 20mb :D, its to large for me for chasier application, sory i'm not real delphi programmer he he he, but your submission increase my delphi knowledge thanks – AsepRoro Mar 11 '13 at 13:31
  • I don't know what chasier application means. Using DLLs won't reduce the total size. If anything it will make it bigger. Plus it doesn't work as already discussed. Packages will also require more total file size. Try the tips from my answer to this Q: http://stackoverflow.com/questions/7398580/reduce-exe-file – David Heffernan Mar 11 '13 at 13:34
  • OK, but why is 20MB too large? You should be aware that Delphi does produce very fat executables. If you stopped using devexpress then you'd likely save something, but I do wonder why a 20MB exe is a problem. – David Heffernan Mar 11 '13 at 13:40
  • first i use devexpress because i like then skin in there. and yes it is a problem for me, because if there is an error in the future I have to re-send the exe and hate doing it because my internet connection is slow. Therefore I want to create applications in a modular – AsepRoro Mar 11 '13 at 13:48
  • Then use packages. Your options are listed in full in my answer. One or the other. That's it. – David Heffernan Mar 11 '13 at 13:49
2

If you already used a (Foo is TSomething) type check, then you know that foo is a TSomething and you can use a static cast: TSomething(Foo)

If you are trying to link this code in another Executable or dll, you probably have not included the correct units IF IT FAILS TO COMPILE, AND IF it fails at runtime, you didn't turn the BPL link option on (Use Runtime PACKAGES, and make sure the list of package names is complete). Remember that checking "something is TSomething" you are comparing a class declaration with another live object's class. A class is not defined by the string name. It's actually type information linked into your application.

When you link a DLL (without runtime packages) you actually may have linked TSomething into your main EXE and into your DLL, and they are TWO DIFFERENT copies of the class with the same name and the name matters not one bit. When you compare for identity, there's no way to know at runtime that they were the same thing. SO they aren't.

You think about code the way you see it written on the screen. When it runs, it's been compiled into code, and the types are simply data in the exe or DLL. So TSomething-in-myexe.exe is not the same class as TSomething-in-mydll.dll.

If you want them to be the same, turn on Use Runtime Packages (BPLs) for all places where you want to compare type information between different compiled parts. In particular passing pointers or references to VCL types between non-bpl-enabled linked targets is not going to work the way you thought it would.

You should also make sure that the list of runtime packages contains the package that defines that class you're using. (TcxSomething is probably a developer express component, go find what package BPL it is defined in.)

Warren P
  • 65,725
  • 40
  • 181
  • 316
  • i haved do that because if i write (foo is Tsomething) the result always false but strangely when I call (form.component [i]. classname) would result according to the type of components I expected – AsepRoro Mar 09 '13 at 18:19
  • It's failing to notice what it IS because you didn't understand all I wrote. Read it again. – Warren P Mar 09 '13 at 18:20