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,
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...
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.
"Herman Hofman" <h...@QNT.nl> schreef in bericht news:3c3c50da_2@dnews...
> | 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
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...
"Rick Francken" <ri...@steeldetails.com> wrote in message
news:3c3c7a7e_2@dnews...
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
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;
> 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.
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...
> 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.
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...
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.
> 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?
Cheers,
Rob
"Adam H." <ah...@NOSPAM.netconnect.com.au> wrote in message
news:3c3d021b_2@dnews...
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...
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...
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...
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...
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...
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.