Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Freelibrary giving grief with DLL

490 views
Skip to first unread message

Adam H.

unread,
Jan 8, 2002, 8:03:55 PM1/8/02
to
Hi,

I'm having a problem with a DLL I've created. Whenever the code tries to
Free the library, I get an EInvalidPointer error "Invalid Pointer
operation." After this happens, my application locks up, and I must reset it
through delphi (if in debug mode).

I can't seem to find out what the problem is:

Can anyone please help. I'm new to DLL's - so please bear with me. <g>

Thanks & Regards

Adam Hair.

My DLL's code is:

-------------------------
library extrareports;

uses
SysUtils,
Windows,
Forms,
Classes,
dialogs,
wsdtypes,
sharemem;

{$R *.res}
Procedure test(database : string); stdcall;
Begin
showmessage('DLL is working on database "'+database+'"');
End;

exports
test ;
end.
-------------------------------

I call the DLL from the following code:

procedure TForm1.Button1Click(Sender: TObject);
begin
CallFromDLL('extrareports','test');
end;

procedure TForm1.CallFromDLL(dll_Name: String; Call_name: string);
type
TExtCall = Procedure (database : string); stdcall;
Var h : THandle;
ExtCall : TExtCall;
resset : TReportSettings;
Begin
h := LoadLibrary(pchar(dll_Name));
if h = 0 then
raise exception.create('Unable to find '+dll_name+' Dll Library!');
extcall := GetProcAddress(h, pchar(Call_Name));
if @extcall = nil then
Raise Exception.Create('Unable to locate call name '+call_name+' in
'+dll_name+' library');
// extcall(Application.Handle, 'testweighbridge',resset);
extcall( pchar('testweighbridge'));

FreeLibrary(h); //Unload Library **ERROR OCCURS HERE**

End;

Rick Betting

unread,
Jan 9, 2002, 6:22:05 AM1/9/02
to
At first ShareMem MUST be the first unit in the uses clause of your DLL!
And be sure that ShareMem is also in your application project file (.dpr)
also as the first unit!

--

Rick Betting,
Online Software.
ri...@ATonlinegroepDOT.nl
(Remove AT and DOT )

I don't like spammers so send your spam to
ab...@iname.com

"Adam H." <ah...@NOSPAM.netconnect.com.au> schreef in bericht
news:3c3b96fe_2@dnews...

Herman Hofman

unread,
Jan 9, 2002, 9:28:07 AM1/9/02
to
Adam,


I've got the same problem.
I don't believe it's (like Rick wrote) the Borland Memory Manager.
This is only nessasary for AnsiStrings.
I use only shortstrings or PChar between DLL's. (for Compatiblilty.)
I couldn't find a solution, so I'm keeping the Library open and have Windows Close it for me.
I know it's not the best solution, but it's affective.

I created some forms in the DLL assigning them to the main EXE Form.
I thought I did a poor job cleaning up untilI read your Thread.

So, Delphi users, Please help us!

Herman


"Adam H." <ah...@NOSPAM.netconnect.com.au> schreef in bericht news:3c3b96fe_2@dnews...

Herman Hofman

unread,
Jan 9, 2002, 9:37:23 AM1/9/02
to
I checked it again (With ShareMem used in both EXE and DLL).
Freeing the Library almost immediately afterwards generates an exception (after my main form has magically dissapeared?)
It generates an exception EAccessViolation in NotifyNonDelphiException (system.pas line 4263).
Call Stack: TObject.Free.
I'ts Quite impossible to trace. The error goes much to deep into code and is probably because an unnoticed error earlier
(overwritten memory). I just can't find the real error (and solution).

Herman.


"Herman Hofman" <h...@QNT.nl> schreef in bericht news:3c3c50da_2@dnews...

Colin Dawson

unread,
Jan 9, 2002, 9:32:35 AM1/9/02
to
Personally, I don't use Sharemem, and I don't see this problem either. Try
this variant of your program.

> | My DLL's code is:
> |
> | -------------------------
> | library extrareports;
> |
> | uses
> | SysUtils,
> | Windows,
> | Forms,
> | Classes,
> | dialogs,

> | wsdtypes; //sharemem removed
> |
> | {$R *.res}
> | Procedure test(database : PChar); stdcall; //Change String to PChar
> | Begin
> | showmessage('DLL is working on database "'+StrPas(database)+'"'); //Use
the StrPas to convert the PChar to a delphi String.


> | End;
> |
> | exports
> | test ;
> | end.
> | -------------------------------
> |
> | I call the DLL from the following code:
> |
> | procedure TForm1.Button1Click(Sender: TObject);
> | begin
> | CallFromDLL('extrareports','test');
> | end;
> |
> | procedure TForm1.CallFromDLL(dll_Name: String; Call_name: string);
> | type
> | TExtCall = Procedure (database : string); stdcall;
> | Var h : THandle;
> | ExtCall : TExtCall;
> | resset : TReportSettings;

DatebasePChar : PChar; //Added Variable


> | Begin
> | h := LoadLibrary(pchar(dll_Name));
> | if h = 0 then
> | raise exception.create('Unable to find '+dll_name+' Dll Library!');
> | extcall := GetProcAddress(h, pchar(Call_Name));
> | if @extcall = nil then
> | Raise Exception.Create('Unable to locate call name '+call_name+' in
> | '+dll_name+' library');
> | // extcall(Application.Handle, 'testweighbridge',resset);

//Complete change from here.
DatebasePChar := StrAlloc( Length( Call_Name ) + 1 ); //Get a memory
block for the string.
StrPCopy( DatebasePChar, Call_Name );
extcall( DatebasePChar );
StrDispose( DatebasePChar );


> |
> | FreeLibrary(h); //Unload Library **ERROR OCCURS HERE**
> |
> | End;
> |

Regards

Colin Dawson
ne...@cdawson.tele2.co.uk


Rick Francken

unread,
Jan 9, 2002, 12:17:06 PM1/9/02
to
That has to do with AnsiStrings most likely. Especially since you are
passing an AnsiString across DLL boundaries and have not put ShareMem.pas as
the FIRST unit in the uses clauses of both the program and the library.

One other solution you could use is to pass a shortstring instead of an
Ansistring in the exported function (assuming the database name does not
exceed 255 characters).

"Adam H." <ah...@NOSPAM.netconnect.com.au> wrote in message
news:3c3b96fe_2@dnews...

Robby Tanner

unread,
Jan 9, 2002, 2:18:32 PM1/9/02
to
...Or use PChar.


"Rick Francken" <ri...@steeldetails.com> wrote in message
news:3c3c7a7e_2@dnews...

Adam H.

unread,
Jan 9, 2002, 4:14:06 PM1/9/02
to
Hi Colin,

From your post, I guessing that you assume the problem has to do with the
pchar/string conversions?

I'm made the changes that you suggested to both modules (the dll, and exe)
but to no avail - still have the problem on freelibrary.

Best Regards

Adam Hair


Adam H.

unread,
Jan 9, 2002, 4:24:09 PM1/9/02
to
Hi Rick & Robby,

Thanks for your advise.

I've put sharemem as the *first* unit in the uses clause, and also changed
the database variable from a string to a shortstring and a Pchar in both
modules, but still no luck I'm afraid.

Infact - I've changed the script to the following (no variables passed
between exe and dll at all) - and it still doesn't work! (So I guess it
hasn't got anything to do with the parameter I was passwing?)

Thanks & Regards

Adam Hair.

{DLL}
Procedure test; stdcall;
Begin
showmessage('DLL is working!');
End;

{EXE}


procedure TForm1.CallFromDLL(dll_Name: String; Call_name: string);
type

TExtCall = Procedure ; stdcall;
<SNIP>
extcall;
FreeLibrary(h); //Unload Library
End;


Adam H.

unread,
Jan 9, 2002, 4:26:01 PM1/9/02
to
Hi Herman,

> I couldn't find a solution, so I'm keeping the Library open and have
Windows Close it for me.
> I know it's not the best solution, but it's affective.

I assume Windows closes the library when you exit the EXE application?

> I created some forms in the DLL assigning them to the main EXE Form.
> I thought I did a poor job cleaning up untilI read your Thread.

Do you find that it loads the DLL multiple times as you call it each
individual time? I agree that I don't like this solution, but I'm not sure
what other solutions are available at this time.

> So, Delphi users, Please help us!

Yes - Please!!! <g>

Adam.


Robby Tanner

unread,
Jan 9, 2002, 6:12:48 PM1/9/02
to
Do you load the library manually, or is it loaded as part of your function
declaration?

Maybe show the rest of your procedure CallFromDLL(dll_Name: String;
Call_name: string) procedure.
Since you are not passing strings between the DLL and the application, you
do not need to use ShareMem in either of them.

Rob

When you call


"Adam H." <ah...@NOSPAM.netconnect.com.au> wrote in message

news:3c3cb568_2@dnews...

Adam H.

unread,
Jan 9, 2002, 6:37:23 PM1/9/02
to
Hi Robby,

> Do you load the library manually, or is it loaded as part of your function
> declaration?

I load it manually.

> Maybe show the rest of your procedure CallFromDLL(dll_Name: String;
> Call_name: string) procedure.

Sorry - I thought I posted this in the original thread. If not here it is:

procedure TForm1.CallFromDLL(dll_Name: String; Call_name: string);
type

// TExtCall = Procedure (database : string); stdcall;
TExtCall = Procedure ; stdcall; //Changed to send no string.

Var h : THandle;
ExtCall : TExtCall;
resset : TReportSettings;
Begin
h := LoadLibrary(pchar(dll_Name));
if h = 0 then
raise exception.create('Unable to find '+dll_name+' Dll Library!');
extcall := GetProcAddress(h, pchar(Call_Name));
if @extcall = nil then
Raise Exception.Create('Unable to locate call name '+call_name+' in
'+dll_name+' library');

extcall;

FreeLibrary(h); //Unload Library **PROBLEM OCCURS HERE**

End;

> Since you are not passing strings between the DLL and the application, you
> do not need to use ShareMem in either of them.

I have removed the sharemem, but it still doesn't work. I don't think it has
anything to do with the parameters sent through. (If it had, I would assume
that the above script should work)...

Thanks & Regards

Adam.


Robby Tanner

unread,
Jan 9, 2002, 7:02:53 PM1/9/02
to
I used your code (more or less) and was able to accomplish what you wanted.
I now suspect it has something to do with your DLL. I have sent my sample
version to your email address.

If you like send me your DLL source code.

Regards,
Rob


"Adam H." <ah...@NOSPAM.netconnect.com.au> wrote in message

news:3c3cd432_1@dnews...

Adam H.

unread,
Jan 9, 2002, 7:50:14 PM1/9/02
to
Hi Robby,

I think I've found part of the problem thanks to your emails that you sent
through:

My dll contains an extra unit called sctrep. (Derived from AceReports from
sct-assocites).

As sson as I take away that file from my uses clause, everything behaves
fine. When I put that file in my uses clause it mis-behaves. What could
possibly be in a .pas file (that isn't called) that would cause a DLL to
remain open. (or not to be free'd).

From what I can see, that unit (or any of it's embedded units) don't call an
external procedure (dll) from within it's script, and I can't think of
anything else. I guess this is where the line ends. (I can't put the code up
here - I don't think Steve from SCT-Associates would appreciate it <g>)

I guess all I can do now is take it up with him and hope he's got some
understandings on DLL's.
(Unless anyone here knows of any settings in an external unit that would
possibly cause a DLL to remain open. The only thing I can think of is a unit
which opens another external dll).

Thanks for your help! It's greatly appreciated!

Adam. Hair.


Adam H.

unread,
Jan 9, 2002, 9:53:15 PM1/9/02
to
Correction:

> From what I can see, that unit (or any of it's embedded units) don't call
an
> external procedure (dll) from within it's script,

Some of his code does call external procedures statically. (As opposed to
dynamically).

Is there any other way of calling a DLL dynamically, (and freeing it!) in
which the DLL you're calling calls other DLL's statically?

HERMAN: (If you're still reading <g>)

My problem *appears* to be the fact that one of the units in my uses clause
refers to yet another unit that calls an external DLL statically. This may
also be the problem with your DLL?

Robby Tanner

unread,
Jan 10, 2002, 9:55:04 AM1/10/02
to
Check for code in the Initialization and Finalization sections as well.
As you mentioned, it will be tough for the rest of us to help without
looking at the code.
Good luck.

Cheers,
Rob

"Adam H." <ah...@NOSPAM.netconnect.com.au> wrote in message

news:3c3d021b_2@dnews...

Herman Hofman

unread,
Jan 11, 2002, 11:19:42 AM1/11/02
to
I was indeed offline for a while...

I'll have to check the units clause.
I've got D5 with some Turbopower components installed.
A lot of coropate code.

But my problem is slightly bigger than that.
When I said Windows cleans up, it looks like it does when the DLL doesn't claim resources (read: create any forms).
But this is my case:

In a class, I've got a handle to the library stored. This is what I do (simplified):

constructor
begin
MH := LoadLibrary( PChar(AlibName+#0) ); //I use shortstrings...
FShowForm := GetProcAddress(MH, 'ShowForm' );
FHideForm := GetProcAddress(MH, 'ShowForm' );
if Assigned(FHideForm) and Assigned(FShowForm) then
begin
FIForm {an interface to the form}:= FShowForm;
FIForm.Parent := Self;
end;
end;

destructor
begin
if Assigned(FIForm) then
FIForm := FHideForm;
FreeLibrary(MH);
end;


Now I thought Windows did clean up, but I must have done something wrong, because I got more and more errors.

I'm quite curious to the solution you found. until then I'm gonna check the FHideForm function and the finilisation code


Herman.


"Adam H." <ah...@NOSPAM.netconnect.com.au> schreef in bericht news:3c3d021b_2@dnews...

Robby Tanner

unread,
Jan 11, 2002, 11:16:00 AM1/11/02
to
First, FShowForm and FHideForm, according to the code below, refer to the
same address (whatever is returned by 'ShowForm').

What errors are you getting and where? What object are the
constuctor/destructor for? What types are the F....Form variables?

I'm coming in a little late and so please help bring me up to speed.

Regards,
Rob


"Herman Hofman" <h...@QNT.nl> wrote in message news:3c3f0c53_2@dnews...

Herman Hofman

unread,
Jan 14, 2002, 6:40:40 AM1/14/02
to
No, I just copied and pasted incorrectly to the newsgroup.
As I wrote, I simplyfied the code a bit during the way.
So, the ProcAddresses are OK.

Most errors are AccessViolation, and not all are linked to the code.
(That is, normally Delphi can find the piece of code the error occurred on, either right away of after Trace into (F7). No it's just
access Violation; as was the error in the IDE instead of My App.)

I've created some objects around my interfaces to simplify tasks for myself.
A lot of code is there and to structure several pieces of code. Like I've got per console DLL two forms to show (a list like the
Outlook-folderlist and the console itself (like OE-message))
I figured i could i could simplify/standarize to one object with parameterized constructor.

The IForm is a standard (of my own) inteface to a form. That means all my DLL-forms are derived from this interface
(TMyForm=class(TForm, IForm)). The FIForm is an instance of this type.
I've added some basic functions to this intercae like OKClick and so on.

No the problem was (I'm a bit embarised to say..) I first tried to destroy the Handle to the DLL and then the Forms created with
this DLL.
I only found out just today.

How did I descover that you say?
Well, I use a lot of debugging. This is the main Debug function, it can be called from just about everywhere.

procedure Debug(const S : AnsiString);
var
lS : AnsiString;
begin
lS := GetDebugHeaders + S;
//DebugString to Windows
OutputDebugString( pChar( lS + #0));

if Assigned( DebugCB) then
DebugCB( lS);
end;

I had GetDebugHeaders function return the ModuleName (from the "ServerExceptionHandler Example" in the D5 help). The Delphi Event
log stated (stripped a bit toshorten...):

...
ODS: ...EXE: Attempting to destroy TConsoleApp for library "....dll"
ODS: ...DLL: DoneAllUnits start
ODS: ...DLL: DoneAllUnits end
Module Unload: ...dll.
ODS: ...EXE: About to destroy the Interface
First chance exception at $040031FF . Exception class EAccessViolation with message 'Access violation at address 0404AEAA in module
'...EXE'. Read of address 02D61A40'.
ODS: ...EXE: Error Interface Release [EAccessViolation]: Access violation at address 0404AEAA in module '...EXE'. Read of address
02D61A40
...

Notice the first chance exception after the Module Unload.

My temporary solution was to hide the forms instead of destroying them, and let windows destroy on the end. I'll recheck if I can't
do it anyway. Having forms hidden asks more resources from Windows than recreating/destroying as needed. The forms are not that big,
so users shouldn't even notice a slight delay.
Next step: Turbopowers SleuthQA.

Thanks for your help, everybody

Herman.
Keep posting... someone might actually read it...

"Robby Tanner" <rta...@cls.usask.ca> schreef in bericht news:3c3f0fc1_2@dnews...

Herman Hofman

unread,
Jan 14, 2002, 6:59:42 AM1/14/02
to
You're using both ShortString and PChar (?)
Does that mean You are storing the DBName in Shortstring and communicating with PChar?
Here are some steps I'd take (again probably...).
- The function Loadlibrary gives back a Handle. Debug (OutputDebugString) that Handle. If the Returnvalue is 0, Debug the
GetLastError. (1157: Cannot find library...)
- Debug the same with GetProcAddress.
- From Within the Library, add code to the library source like this:
libary ....

uses
...
begin
Debug('Library loaded');
end;
You can change Debug into ShowMessage.
I had once during this project Error 1157. ShareMem.DLL was not found in the Path.

You should at least be able to load the library again before you can track the FreeLibrary Errors. <g>
I'll check this NG later...

Herman.

"Adam H." <ah...@NOSPAM.netconnect.com.au> schreef in bericht news:3c3cb4f8_1@dnews...

Adam H.

unread,
Jan 16, 2002, 12:42:53 AM1/16/02
to
Hi Herman,

Thanks for your reply. (Sorry 'bout the delay)...

I'll give this a go and get back to you...

Adam.

"Herman Hofman" <h...@QNT.nl> wrote in message news:3c42c2cd_2@dnews...

Adam H.

unread,
Jan 28, 2002, 7:50:51 PM1/28/02
to
Hi Herman,

I was having a problem with borlndmm.dll not in the path of certain
machines, (this was another problem I experienced), but freelibrary still
will not 'let go'. It still hangs if I try to call it after I've closed down
the dll.

Thanks for the suggestion...

Adam.

0 new messages