xxflip
asked on
Using multiple instances of the same DLL
I have a DLL that provides an interface to view data from a Database. This DLL is used by the mother app with no problem, but now I need to be able to call that same DLL from diferent programs.
Situation: I have 2 EXE files, named Interface1 and Interface2, that call the DLL as well as a batch file that uses rundll32 to call my DLL
Problem:
1. If I call the DLL from each interface (Interface1, Interface2 and Rundll32) one at a time (terminating it's use before I call it again) I have no problem.
2. If I call the DLL using 2 or more interfaces, including multiple instances of the same interface, I get an error on the interface when I close it, after the DLL_PROCESS_DETACH, on all open interfaces except the last one.
3. The error I get is
"Interface1.exe - Aplication error"
"The exception unknown software exception (0x0eedfade) occurred in the application at location 0x7c59ba9d."
and then I get
"Error"
"Runtime error 217 at 00E5088B"
My guess is that when I try to free the DLL, it somehow has a conflict with the other open instances.
// ------------- The exported functions are:
-InitCC - Opens the interface as a regular window
-InitCCMDI - Opens the interface as a MDI child
// ------------- Batch code:
rundll32.exe ccorrentes.dll,InitCC (I use full paths for both files)
// ------------- The Delphi code in Interface1 and Interface2 is:
DllHandle := LoadLibrary('ccorrentes.dl l');
if DllHandle <> 0 then @Child := GetProcAddress(DllHandle, 'InitCCMDI');
if @Child <> nil then Child(Application);
// ------------- The DLL dpr file is:
library ccorrentes;
uses
Forms,
Windows,
SysUtils,
Form_extracto_ccDll in 'Form_extracto_ccDll.pas' {F_extracto_cc};
{$R *.RES}
var
MyApp:TApplication;
procedure InitCC; export; stdcall;
begin
Application.CreateForm(Tf_ extracto_c c, f_extracto_cc);
f_extracto_cc.ParentWindow :=Applicat ion.Handle ;
f_extracto_cc.ShowModal;
f_extracto_cc.Free;
end;
procedure InitCCMDI(TApp:TApplicatio n); export; stdcall;
begin
Application:=TApp;
Application.CreateForm(Tf_ extracto_c c, f_extracto_cc);
f_extracto_cc.ParentWindow :=TApp.Han dle;
f_extracto_cc.FormStyle:=f sMDIChild;
f_extracto_cc.Show;
end;
procedure DLLEntryPoint(Reason: DWORD);
begin
if Reason = DLL_PROCESS_DETACH then Application:=MyApp;
end;
exports
InitCC,
InitCCMDI;
begin
MyApp:=Application;
DllProc := @DLLEntryPoint;
end.
Situation: I have 2 EXE files, named Interface1 and Interface2, that call the DLL as well as a batch file that uses rundll32 to call my DLL
Problem:
1. If I call the DLL from each interface (Interface1, Interface2 and Rundll32) one at a time (terminating it's use before I call it again) I have no problem.
2. If I call the DLL using 2 or more interfaces, including multiple instances of the same interface, I get an error on the interface when I close it, after the DLL_PROCESS_DETACH, on all open interfaces except the last one.
3. The error I get is
"Interface1.exe - Aplication error"
"The exception unknown software exception (0x0eedfade) occurred in the application at location 0x7c59ba9d."
and then I get
"Error"
"Runtime error 217 at 00E5088B"
My guess is that when I try to free the DLL, it somehow has a conflict with the other open instances.
// ------------- The exported functions are:
-InitCC - Opens the interface as a regular window
-InitCCMDI - Opens the interface as a MDI child
// ------------- Batch code:
rundll32.exe ccorrentes.dll,InitCC (I use full paths for both files)
// ------------- The Delphi code in Interface1 and Interface2 is:
DllHandle := LoadLibrary('ccorrentes.dl
if DllHandle <> 0 then @Child := GetProcAddress(DllHandle, 'InitCCMDI');
if @Child <> nil then Child(Application);
// ------------- The DLL dpr file is:
library ccorrentes;
uses
Forms,
Windows,
SysUtils,
Form_extracto_ccDll in 'Form_extracto_ccDll.pas' {F_extracto_cc};
{$R *.RES}
var
MyApp:TApplication;
procedure InitCC; export; stdcall;
begin
Application.CreateForm(Tf_
f_extracto_cc.ParentWindow
f_extracto_cc.ShowModal;
f_extracto_cc.Free;
end;
procedure InitCCMDI(TApp:TApplicatio
begin
Application:=TApp;
Application.CreateForm(Tf_
f_extracto_cc.ParentWindow
f_extracto_cc.FormStyle:=f
f_extracto_cc.Show;
end;
procedure DLLEntryPoint(Reason: DWORD);
begin
if Reason = DLL_PROCESS_DETACH then Application:=MyApp;
end;
exports
InitCC,
InitCCMDI;
begin
MyApp:=Application;
DllProc := @DLLEntryPoint;
end.
ASKER
That didn't work.
Passing just the handle causes more problems, I think that is because I'm using a form that is a MDI child when called by the Interface1 and Interface2 apps.
Also note that I only get an error with my solution, if another instance of the DLL is loaded by another interface.
Passing just the handle causes more problems, I think that is because I'm using a form that is a MDI child when called by the Interface1 and Interface2 apps.
Also note that I only get an error with my solution, if another instance of the DLL is loaded by another interface.
Hello
For MDI child, you need to pass the application and screen objects, see my comments in this paq
https://www.experts-exchange.com/questions/20653308/DLL-and-MDICHilds.html
For MDI child, you need to pass the application and screen objects, see my comments in this paq
https://www.experts-exchange.com/questions/20653308/DLL-and-MDICHilds.html
ASKER
I won't be back to the office until monday, but I will check that then, if it works the points are yours!
ASKER
I have passed the screen object alogn with the application, just like the example, but it once again created more problems (got some errors about not being able to assign a TFont to a TFont) that I think are due to some components I'm using.
But I did try something else I read in the linked post:
FreeLibraryAndExitThread(D llHandle, 0);
Having this in mind I then proceeded to using the windows API to terminate the thread on the OnDestroy event of the form, I used this instead of FreeLibraryAndExitThread inside the interface code, because I will not be able to control the interface, only the DLL.
TerminateThread(GetCurrent Thread,0);
Result: I get no errors regardless of how many symultaneous interfaces I open (Hurra) but the interfaces are not removed from the running process list (they are not using the processor but they are still loaded and using the DLL).
But I did try something else I read in the linked post:
FreeLibraryAndExitThread(D
Having this in mind I then proceeded to using the windows API to terminate the thread on the OnDestroy event of the form, I used this instead of FreeLibraryAndExitThread inside the interface code, because I will not be able to control the interface, only the DLL.
TerminateThread(GetCurrent
Result: I get no errors regardless of how many symultaneous interfaces I open (Hurra) but the interfaces are not removed from the running process list (they are not using the processor but they are still loaded and using the DLL).
ASKER
Update:
I changed the TerminateThread with ExitThread, and now I get no errors whatsoever, but there is still something I have to solve.
Let's say that I start 3 instances of each (interface1, interface2 and rundll) and then close them randomly. They all close with no errors BUT the last interface1 to be closed (which is the only one that loads the form as MDI) does not completly close.
What I mean is if I look at the processes it is still there (although I can't see it anymore on the screen/taskbar) and the DLL reports as still being used.
Any suggestions??
Here is the code for the DLL:
//----------------------- DLL
library ccorrentes;
uses
Forms,
Windows,
SysUtils,
Form_extracto_ccDll in 'Form_extracto_ccDll.pas' {F_extracto_cc};
{$R *.RES}
var
MyApp:TApplication;
procedure InitCC; export; stdcall;
begin
Application.CreateForm(Tf_ extracto_c c, f_extracto_cc);
f_extracto_cc.ParentWindow :=Applicat ion.Handle ;
f_extracto_cc.ShowModal;
end;
procedure InitCCMDI(TApp:TApplicatio n); export; stdcall;
begin
Application:=TApp;
Application.CreateForm(Tf_ extracto_c c, f_extracto_cc);
f_extracto_cc.ParentWindow :=TApp.Han dle;
f_extracto_cc.FormStyle:=f sMDIChild;
f_extracto_cc.Show;
end;
procedure CloseCCMDI; export; stdcall;
begin
if Assigned(f_extracto_cc) then f_extracto_cc.Free;
end;
procedure DLLEntryPoint(Reason: DWORD);
var ec:dWord;
begin
if Reason = DLL_PROCESS_DETACH then begin
Application:=MyApp;
ExitThread(0);
end;
end;
exports
InitCC,
InitCCMDI,
CloseCCMDI;
begin
MyApp:=Application;
DllProc := @DLLEntryPoint;
end.
I changed the TerminateThread with ExitThread, and now I get no errors whatsoever, but there is still something I have to solve.
Let's say that I start 3 instances of each (interface1, interface2 and rundll) and then close them randomly. They all close with no errors BUT the last interface1 to be closed (which is the only one that loads the form as MDI) does not completly close.
What I mean is if I look at the processes it is still there (although I can't see it anymore on the screen/taskbar) and the DLL reports as still being used.
Any suggestions??
Here is the code for the DLL:
//----------------------- DLL
library ccorrentes;
uses
Forms,
Windows,
SysUtils,
Form_extracto_ccDll in 'Form_extracto_ccDll.pas' {F_extracto_cc};
{$R *.RES}
var
MyApp:TApplication;
procedure InitCC; export; stdcall;
begin
Application.CreateForm(Tf_
f_extracto_cc.ParentWindow
f_extracto_cc.ShowModal;
end;
procedure InitCCMDI(TApp:TApplicatio
begin
Application:=TApp;
Application.CreateForm(Tf_
f_extracto_cc.ParentWindow
f_extracto_cc.FormStyle:=f
f_extracto_cc.Show;
end;
procedure CloseCCMDI; export; stdcall;
begin
if Assigned(f_extracto_cc) then f_extracto_cc.Free;
end;
procedure DLLEntryPoint(Reason: DWORD);
var ec:dWord;
begin
if Reason = DLL_PROCESS_DETACH then begin
Application:=MyApp;
ExitThread(0);
end;
end;
exports
InitCC,
InitCCMDI,
CloseCCMDI;
begin
MyApp:=Application;
DllProc := @DLLEntryPoint;
end.
ASKER
I have tried the previous code in other machines with the same OS, and the funny thing is I had no problems on them, so this is the solution I will be using.
Solution used:
I added a Close procedure to release forms, to make both situations clearer (MDI and non-MDI)
I added the line ExitThread(0); in the DLL_PROCESS_DETACH which eliminates the errors
Lee_Nover: Your suggestion was "instead of passing Application pass only it's handle"
mnasman: Your suggestion was "For MDI child, you need to pass the application and screen objects"
Since I used neither solution I will be asking for a refund of my points, but I would like to thank you both for the time you spend on this issue.
Solution used:
I added a Close procedure to release forms, to make both situations clearer (MDI and non-MDI)
I added the line ExitThread(0); in the DLL_PROCESS_DETACH which eliminates the errors
Lee_Nover: Your suggestion was "instead of passing Application pass only it's handle"
mnasman: Your suggestion was "For MDI child, you need to pass the application and screen objects"
Since I used neither solution I will be asking for a refund of my points, but I would like to thank you both for the time you spend on this issue.
Although they didnt find the exact answer, they still spent time helping you. I normally give delete this question and post others just saying "points for XXX" just 50pts but its nice to say thx for helping out.
My 2 pence worth.
smurff
My 2 pence worth.
smurff
ASKER
I agree with you, but I had read something about this not being a correct procedure.
I have investigated the matter further in the help pages and found the proper way to do so.
Reason for giving 50 points to mnasman:
Although I didn't get the answer for my question, it was through the link provided by mnasman that I got the information needed to solve it myself.
Points to question link: http://oldlook.experts-exchange.com/questions/20946203/Points-for-mnasman-Q-20941190.html
I have investigated the matter further in the help pages and found the proper way to do so.
Reason for giving 50 points to mnasman:
Although I didn't get the answer for my question, it was through the link provided by mnasman that I got the information needed to solve it myself.
Points to question link: http://oldlook.experts-exchange.com/questions/20946203/Points-for-mnasman-Q-20941190.html
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
procedure InitCCMDI(hApp: Cardinal); stdcall;
begin
if hApp > 0 then
Application.Handle:=hApp;
....
// ------------- Batch code:
rundll32.exe ccorrentes.dll,InitCC, 0 (I use full paths for both files)
// ------------- The Delphi code in Interface1 and Interface2 is:
DllHandle := LoadLibrary('ccorrentes.dl
if DllHandle <> 0 then @Child := GetProcAddress(DllHandle, 'InitCCMDI');
if @Child <> nil then Child(Application.Handle);