Making RTPkgs trivial plug-ins in delphi.



In general, I am sick and tired of how klunky the design is for Run-time
Package system is in Delphi. Things that should be real simple are real
hard and real frusturating.

In the thread entitled "RTTI for RT Packages", I was trying to figure out
how to surface an OnRegisterClass event handler that I could consume in my
application that would fire any time register class was call from a packaged
unit loaded via LoadPackage(). This functionality is essential to achieve a
basic plug-in design, which is of course what a run-time package is: A
Plug-in...

The solution is trivial.

For future versions of delphi the solution is:

1) Add a new event-handler to TApplication:

TClassRegisteredEvent = procedure(AClass: TPersistentClass) of object;

TApplication = class(...)
private
FOnClassRegistered:TClassRegisteredEvent;
public
property OnClassRegistered:TClassRegisteredEvent read FOnClassRegistered
write
FOnClassRegistered;
end;

2) create a wrapper for RegisterClass that calls an
TApplication.OnRegisterClass.

procedure RegisterClassEx(AClass: TPersistentClass);
begin
classes.registerClass(AClass);
if assigned(Application.OnClassRegistered) then
Application.OnClassRegistered(AClass);
end;

That's it CodeGear, you're done.


However, that doesn't help us out here in the trenches using current and
past version of Delphi on a daily basis.

So below is a solution should work for just about any version of Delphi.
I'll post the code here and a zip to attachments; and eventually I'll get it
up on my website of utilities...

//*********The Package
Code*******************************************************

unit uPkgTest;
//---------A Unit In a Run-time Pkg---------------------
interface

uses Windows, Messages, SysUtils, Variants, Classes, Forms,
Dialogs, StdCtrls, ExtCtrls, Controls;

type
TTest01 = class(TPersistent)
private
{ Private declarations }
public
{ Public declarations }
end;

implementation

procedure SendData(copyDataStruct: TCopyDataStruct) ;
var
receiverHandle : THandle;
recieverClassName, recieverName:string;
cbInt : integer;//callback value
begin
recieverName := application.mainform.Name;
recieverClassName:= application.mainform.ClassName;
showmessage('LoadPackage - '+#13#10+'Get the Application''s MainForm
Name: '+#13#10+
application.mainform.ClassName);
//application.MainForm.Handle;
receiverHandle :=
FindWindow(PChar(recieverClassName),PChar(recieverName)) ;
if receiverHandle = 0 then
begin
ShowMessage('CopyData Receiver NOT found!') ;
Exit;
end
else showmessage('MainForm''s Handle is: '+intToStr(receiverHandle));

cbInt := SendMessage(receiverHandle, WM_COPYDATA, 0,
Integer(@copyDataStruct));

if cbInt > 0 then ShowMessage(Format('Receiver has sent back this value:
%d !',[cbInt]));

end;

procedure SendString(s:string) ;
var
copyDataStruct : TCopyDataStruct;
begin

copyDataStruct.dwData := 0; //use it to identify the message contents
copyDataStruct.cbData := 1 + Length(s) ;
copyDataStruct.lpData := PChar(s) ;

SendData(copyDataStruct) ;
end;

procedure registerClassEx(AClass:TPersistentClass);
begin
registerClass(AClass);
sendString(AClass.ClassName);
//application should never be NIL...
if application = nil then showmessage('Application is nil');
end;

initialization
registerClassEx(TTest01);
finalization
unregisterClass(TTest01);

end.


//**********And below is code to drop into any MainForm ********************
//**** NOTE: Since we can't get an event handler in TApplication, **********
//***** TApplication.MainForm is our next best generic option...
**********


unit unit01;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;

type
TForm6 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
procedure WMCopyData(var Msg : TWMCopyData) ; message WM_COPYDATA;
procedure HandleCopyDataString(copyDataStruct: PCopyDataStruct);
public
{ Public declarations }
end;

var
Form6: TForm6;

implementation

{$R *.dfm}

procedure TForm6.Button1Click(Sender: TObject);
begin
if FileExists('Pkg01.bpl') then
begin
loadPackage('Pkg01.bpl') ;
end
else beep;
end;


procedure TForm6.HandleCopyDataString(copyDataStruct: PCopyDataStruct);
var
s : string;
begin
s := PChar(copyDataStruct.lpData);
showmessage('ClassName: '+s+' Recieved!');
end;

procedure TForm6.WMCopyData(var Msg: TWMCopyData);
begin
HandleCopyDataString(Msg.CopyDataStruct);
//Send something back
msg.Result := 1111111;
end;

end.





.