Link to home
Start Free TrialLog in
Avatar of LEEJG
LEEJG

asked on

URGENT: Creating package containing objects, loading it and using the object...

First time using packages and I can't get objects passed to my apps.  Offering 500 points for VERY quick response:

Here is my code...

"User.dpk" package that contains "untUser.pas" + CREATE_PACKAGE defined:
TObject_User = class (TPersistent)
  procedure Execute(const sMode: String);
end;

{$ifdef CREATE_PACKAGE}
initialization
  RegisterClass(TObject_User);

finalization
  UnRegisterClass(TObject_User);
{$endif}

end.
========================================
Calling application that has:

uses untUser;

type TUserClass = class of TObject_Group_IBS;

procedure TForm1.Button1Click(Sender: TObject);
var
  hPackage: HModule;
  oClass: TPersistentClass;
begin
  hPackage:=LoadPackage('User.bpl');
  if hPackage=0 then raise Exception.Create('Cannot load pacakge');
  try
    oClass:=GetClass('TObject_User');
    if not assigned(oClass) then raise Exception.Create('Cannot find class');

    with TUserClass(oClass).Create() do begin
      try
        Execute('Add');
      finally
        Free;
      end;
    end;
  finally
    UnloadPackage(hPackage);
  end;
end;

Help help help!
Avatar of mocarts
mocarts

you must use runtime package which contains classes.pas unit (normally vcl.dcp) in both exe and bpl.
https://www.experts-exchange.com/questions/20548192/Registering-a-TFrame-class.html

wbr, mo.
Avatar of LEEJG

ASKER

So are you saying I need to base my object on something like a TComponent? I did try this and couldn't get it to work.
I have found lots of examples on the net but they all seem to be based on showing you how to use a TForm in a package and just use things like ShowModal (a standard method of TForm). I need to access properties and methods of MY class (like Execute) and not the standard ones of a TForm (like Top, ShowModal, etc).
no, problem is in fact, that RegisterClass and FindClass declared in classes.pas mantains private list of registered classes in unit and if you don't use runtime packages, then dynamically loaded library will have their own instance of classes.pas and respectively, registered classes list. you can see registered classes in package when calling IN package, but exe loaded that package will see only registered classes within that exe.

that's why you must use RUNTIME package, with classes.pas unit contained, for both - EXE and BPL. To achieve this:
- in exe project Options dialog in packages tab, check Build with runtime packages and type VCLxx (where xx is version of delfi. for Delphi 7 you must write without version - simply VCL) in the packages edit box (you don't need, at least at the moment, any other package)
- in bpl check whether your bpl haves vclxx.dcp in Requires treeview section, if not - add it with Add button.

build both projects and you must get all to work.

wbr, mo.
You may use TObject.MethodAddress procedure to obtain address of published method. So you need make all your methods you want to use outside the packgae published.
ok, that was about why you can't find class (if that was a problem too :) my missunderstood, likely :) but anyway you must use runtime packages to register classes..

I figured out two methods to call methods which passes parameters from dynamically loaded package:
1) by implementing interfaces in package classes and registering them (classes resp.) with RegisterClass:
unit MyInterface;  // compiles in both package and exe
interface
  type
    IMyInterface = interface
    ['{E648502D-F035-41B0-B53A-FCC3A02DF3A6}']
      procedure Execute(const aMode: string); stdcall;
    end;
implementation
end.

unit Component2; // in package
type
  TComponent2 = class(TComponent, IMyInterface)
  private
    procedure Execute(const aMode: string); stdcall;
  end;

implementation
procedure TComponent2.Execute(const aMode: string);
begin ...
end;

initialization
  RegisterClass(TComponent2);
finalization
  UnRegisterClass(TComponent2);
end.

and in exe:
...
implementation
uses MyInterface;

procedure TForm1.btnFindClassClick(Sender: TObject);
var
 hPackage: HModule;
 IMI: IMyInterface;
begin
 hPackage := LoadPackage('User.bpl');
 if hPackage = 0 then
   raise Exception.Create('Cannot load pacakge');
 try
   // findclass will rise exception we need
   with TComponentClass(FindClass('TComponent2')).Create(nil) do begin
     try
       if GetInterface(IMyInterface, IMI) then
         IMI.Execute('Add');
     finally
       // ensure reference count is set to 0
       IMI := nil;
       Free;
     end;
   end;
 finally
   UnloadPackage(hPackage);
 end;
end;

2) by using standard DLL function export routine (exports keyword) and in this case you don't need compile with runtime packages (but anyway it is better to compile if units overlaps)
unti Component2; // in package
uses..
  TObject2 = class(TObject)
    procedure Execute(const aMode: string);
  end;
  procedure Execute(const aMode: string); stdcall;

implementation

procedure Execute(const aMode: string); stdcall;
begin
  with TObject2.Create do
    try Execute(aMode);
      finally free; end;
end;
procedure TObject2.Execute(const aMode: string);
begin ..
end;

exports
  Execute;
end.

and calling from exe:
...
type TExecuteProc = procedure(const aMode: string); stdcall;

procedure TForm1.btnExportClick(Sender: TObject);
var
 hPackage: HModule;
 ep: TExecuteProc;
begin
 hPackage := LoadPackage('User.bpl');
 if hPackage = 0 then
   raise Exception.Create('Cannot load pacakge');
 try
   @ep := GetProcAddress(hPackage, 'Execute');
   if @ep = nil then
     raise Exception.Create('Package doesn''t exports Execute procedure');
   ep('Add');
 finally
   UnloadPackage(hPackage);
 end;
end;

I have placed full example project sources on:
http://www.grava.lv/files/pro/load_d5.zip

wbr, mo.
ASKER CERTIFIED SOLUTION
Avatar of mocarts
mocarts

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of LEEJG

ASKER

Thanks for all your help everyone, Not as easy as I thought it would be !! ... But anyway it now works great.

I am giving the points to mocarts.