Matho
asked on
Dynamically created Objects from DLL's
G'Day,
I'm having problems with dynamically allocated Objects being distroyed once the DLL is freed.
I have a DLL which gets passed a TStringList as one of it's parameters. I dynamically create objects (of type TObject) and add these to the Object Property of the TStringList using TStringList.AddObject. I load in the DLL from the main application using LoadLibrary and free it using FreeLibrary. Once I return from the DLL and free it, I can not access the Objects of the TStringList. When I try to access the objects, I get an Access Violation. From this I assume that the objects are being freed along with the DLL.
I'm already using ShareMem in the DLL's Uses section and in my main application Uses section. From what I've read about this, it allocates memory from the Global Heap thus giving other modules access to it but this is not what appears to be happening.
What I need to know is if there is any way to create Objects in the DLL which the main application can gain access to after the DLL has been freed?
Note : It is not pratical to keep the DLL open until I exit the main application as I will have many DLL's loaded at the same time.
Please Help. Thanks.
I'm having problems with dynamically allocated Objects being distroyed once the DLL is freed.
I have a DLL which gets passed a TStringList as one of it's parameters. I dynamically create objects (of type TObject) and add these to the Object Property of the TStringList using TStringList.AddObject. I load in the DLL from the main application using LoadLibrary and free it using FreeLibrary. Once I return from the DLL and free it, I can not access the Objects of the TStringList. When I try to access the objects, I get an Access Violation. From this I assume that the objects are being freed along with the DLL.
I'm already using ShareMem in the DLL's Uses section and in my main application Uses section. From what I've read about this, it allocates memory from the Global Heap thus giving other modules access to it but this is not what appears to be happening.
What I need to know is if there is any way to create Objects in the DLL which the main application can gain access to after the DLL has been freed?
Note : It is not pratical to keep the DLL open until I exit the main application as I will have many DLL's loaded at the same time.
Please Help. Thanks.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
You are correct in your assumption, I'm using Delphi2.
I'll try and explain what I'm doing...
The TFBClass and TUserLabelClass, described below, are both created inside the DLL. The TStringList inside TFBClass is used to hold the TLabelClass. The TFBClass is held in a third Class which is passed to the DLL. The third CLass is a global variable of the main application and is created on the Main Applications OnCreate. The Class is of the following type.
type
TMainClass = class(TObject)
FBs : TStringList;
public
constructor Create;
end;
The DLL code is something like this.. (Cut down version)
unit DLLFile;
interface
uses
ShareMem, Windows, Messages, SysUtils, Classes, Graphics,
Controls, Forms, Dialogs, StdCtrls;
type
TMainClass = class(TObject)
FBs : TStringList; { TFBClass }
public
constructor Create;
end;
type
TFBClass = class(TObject)
Name : string;
Address : Integer;
UserLabels : TStringList; { TLabelClass }
public
constructor Create;
end;
type
TLabelClass = class(TObject)
Name : string;
Offset : Integer;
end;
type
TDLLForm = class(TForm)
DoneButton: TButton;
procedure DoneButtonClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
DLLForm: TDLLForm;
DeviceData : TMainClass;
FB : TFBClass;
function ExecuteDLL(AOwner : TControl; var PData : Pointer):Pointer; stdcall;
implementation
{$R *.DFM}
constructor TMainClass.Create;
begin
inherited Create;
FBs := TStringList.Create;
end;
constructor TFBClass.Create;
begin
inherited Create;
UserLabels := TStringList.Create;
end;
{ This function is exported out of the DLL and is called from the main Application. An explination of this is given after the DLL Code}
function ExecuteDLL(AOwner : TControl; var Data : TMainClass):Pointer; stdcall;
begin
DLLForm := TButtonForm.Create(AOwner)
DLLForm.SetBounds(AOwner.C
AOwner.ClientOrigin.Y,
AOwner.Width,
AOwner.Height); {Deffining the bounds of the form}
DeviceData := Data;
Result := ButtonForm;
end;
procedure TDLLForm.FormCreate(Sender
var
LabelName : TLabelClass;
begin
FB := TFBClass.Create;
FB.Name := 'Name';
FB.Address := 35;
LabelName := TLabelClass.Create;
LabelName.Name := 'Fred';
LabelName.Offset := 5;
FB.UserLabels.AddObject(La
{ This is not exact code but it shows you what I'm doing }
end;
procedure TDLLForm.DoneButtonClick(S
begin
DeviceData.FBs.AddObject(F
Close;
end;
end. //End of DLL Code
In the ExecuteDLL function, Data is the TMainClass to which the TFBClass is to be added. The pointer that gets returned is assigned to a Form in the main Application and allows me to destroy the DLL Form once I've finished with the DLL. i.e In the Main Application I have..
procedure AddStuff;
var
Child : TForm;
MyHandle : THandle;
ExecuteDLL : function(AOwner : TControl; var Data :
TMainClass):Pointer; stdcall;
begin
MyHandle := LoadLibrary(PChar(DLLName)
@ExecuteDLL := GetProcAddress(MyHandle, 'ExecuteDLL');
Child := ExecuteDLL(TControl(GroupB
Child.ShowModal;
Child.Free;
FreeLibrary(MyHandle);
end;
Data is a global variable of type TMainClass and has already been created. DLLName is the DLL Name.
I hope this explains things. As for Destructors for the objects,
I'm not really worried about freeing them up as yet. I can always
add these later when I have the program working. I'm more
interested in getting the Objects passed back to the Main
Application. Thanks again.