Thread & dll -> Exception [Résolu]

Messages postés
16
Date d'inscription
lundi 16 décembre 2002
Dernière intervention
27 octobre 2011
- 14 nov. 2008 à 11:43 - Dernière réponse :
Messages postés
3982
Date d'inscription
mardi 8 mars 2005
Dernière intervention
7 novembre 2014
- 18 nov. 2008 à 15:24
Bonjour à tous,

j'ai une dll qui contient un thread, tout ce passe bien le thread marche comme il faut mais cependant lors du dechargement de la dll par l'application, cela génère un exception. J'ai fait pas mal de tests dans tout les sens possible mais la je bloque. Donc je suis revenu au basse et j'ai créé un exe et une dll minimum permettant de reporduire le problème. Pourtant même avec ça, je ne vois pas d'ou viens cette fichue exception. Donc je viens ici avec l'immense espoir que quelqu'un puisse m'aider et me dire ce qui ne va pas. c'est surement pas grand chose mais la j'ai beau ouvrir les yeux, je ne vois rien.

Voici le code de l'appli:

unit uTest2;


interface


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


type
  TForm3 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  private
    { Déclarations privées }
  public
    { Déclarations publiques }
  end;


var
  Form3: TForm3;


implementation


{$R *.dfm}


procedure TForm3.Button1Click(Sender: TObject);
var
  libHwnd:                  HWnd;
begin
  libHwnd := LoadLibrary('InitDLL.dll');
  if libHwnd = 0 then
  begin
    memo1.Lines.Add('Could not find the dll file!');
    EXIT; {EXIT}
  end
  else
  begin
    memo1.Lines.Add('dll file find!');
  end;
  Sleep(1000);
  Application.ProcessMessages;


  freelibrary(libHwnd);


  memo1.Lines.add('Unload OK');
end;


end.

et celui de la dll :

unit myDLL2;


interface


uses
  Windows,
  SysUtils,
  Classes;




type TDllThread = class(TThread)
  private
  protected
    procedure Execute; override;
end;


var
  DllThread:  TDllThread = NIL;


implementation


procedure TDllThread.Execute();
{-----------------------------------------------------------------------------
  Procedure: Execute
  Date:      13-nov.-2008
  Arguments:
  Result:    None
  Comment:
  Comment
-----------------------------------------------------------------------------}
var
  i:                integer;
begin
  i:=0;
  {TRAITEMENT}
  while (Terminated=False) do
  begin
    Sleep(10);
    Inc(i);
  end;
  {VALEUR DE RETOUR}
  ReturnValue:=1;
end;


(************************************)
(*          INITIALIZATION          *)
(************************************)
initialization
  {Init thread}
  DllThread:=TDllThread.Create(TRUE);
  DllThread.FreeOnTerminate:=TRUE;
  {Execute thread}
  DllThread.Resume;


(************************************)
(*         FINALIZATION             *)
(************************************)
finalization
  Sleep(10)
end.

bon ben je crois qu'on peux pas faire plus simple comme code.
merci à tous pour votre aide.

WSTBoss!
Afficher la suite 

Votre réponse

5 réponses

Meilleure réponse
Messages postés
3982
Date d'inscription
mardi 8 mars 2005
Dernière intervention
7 novembre 2014
- 17 nov. 2008 à 15:02
3
Merci
Salut,

Heu !

Il y a un problème évident dans ton code...
1 Tu charges une dll.
2 Tu lances un thread qui fait une boucle infinie dans la dll.
3 Tu décharges la dll.

Ca plante. Logique. Comment veux-tu que le thread continue sa boucle infinie si tu décharges sont code ????

Il faut que tu demandes l'arrêt du thread avant de décharger la dll.

-> Ajout d'une fonction exportée par la dll.
-> Cette fonction demande l'arrêt du thread et attend son arrêt effectif.
-> Il faut que le thread soit libéré par cette fonction : le WaitFor ne fonctionne pas si le FreeOnTerminate est à true.
-> Le .exe doit appeler la fonction exportée par la dll avant de décharger celle-ci.

<hr size="2" width="100%" />unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Déclarations privées }
  public
    { Déclarations publiques }
  end;

type TStopThreadProc = procedure;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  libHwnd:                  HWnd;
  stopThreadProc: TStopThreadProc;
begin
  libHwnd := LoadLibrary('Project2.dll');
  if libHwnd = 0 then
  begin
    memo1.Lines.Add('Could not find the dll file!');
    EXIT; {EXIT}
  end
  else
  begin
    memo1.Lines.Add('dll file find!');
  end;
  Sleep(1000);
  Application.ProcessMessages;

  @stopThreadProc:= GetProcAddress(libHwnd, 'StopThread');
  if not Assigned(stopThreadProc) then
  begin
    memo1.Lines.Add('Could not find StopThread in the dll!');
    EXIT; {EXIT}
  end;
 
  stopThreadProc();

  freelibrary(libHwnd);

  memo1.Lines.add('Unload OK');
end;

end.
<hr size="2" width="100%" />unit Unit2;

interface

uses
  Windows,
  SysUtils,
  Classes,
  Dialogs;

type TDllThread = class(TThread)
  private
  protected
    procedure Execute; override;
end;

var
  DllThread:  TDllThread = NIL;

procedure StopThread;

implementation

procedure StopThread;
begin
ShowMessage('Fin du thread');
  DllThread.Terminate;
  // On attend la fin du thread
  DllThread.WaitFor;
  DllThread.Free;
end;

procedure TDllThread.Execute();
{-----------------------------------------------------------------------------
  Procedure: Execute
  Date:      13-nov.-2008
  Arguments:
  Result:    None
  Comment:
  Comment
-----------------------------------------------------------------------------}
var
  i:                integer;
begin
  i:=0;
  {TRAITEMENT}
  while (Terminated=False) do
  begin
    Sleep(10);
    Inc(i);
  end;
  {VALEUR DE RETOUR}
  ReturnValue:=1;
end;

(************************************)
(*          INITIALIZATION          *)
(************************************)
initialization
  {Init thread}
  DllThread:=TDllThread.Create(TRUE);
  DllThread.FreeOnTerminate:=FALSE;
  {Execute thread}
  DllThread.Resume;

(************************************)
(*         FINALIZATION             *)
(************************************)
finalization
  Sleep(10)
end.

Merci cs_rt15 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 88 internautes ce mois-ci

Commenter la réponse de cs_rt15
Meilleure réponse
Messages postés
3982
Date d'inscription
mardi 8 mars 2005
Dernière intervention
7 novembre 2014
- 18 nov. 2008 à 15:24
3
Merci
Non non ça devrait aller.

Windows ferme tous les handles et décharge les modules quand les processus se terminent, que l'arrêt soit violent ou non.

Les cas où la dll reste en mémoire sont bien plus tordus que ça.

Mais bon ça ne t'exempte pas de libérer proprement ta dll.

Merci cs_rt15 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 88 internautes ce mois-ci

Commenter la réponse de cs_rt15
Messages postés
16
Date d'inscription
lundi 16 décembre 2002
Dernière intervention
27 octobre 2011
- 17 nov. 2008 à 15:41
0
Merci
Salut rt15,

merci pour ta réponse, effectivement, je viens de voir ma boulette. En fait, j'ai tellement fait de test que je me suis mélangé les pinceaux. En plus j'ai essayé de faire un code minimal afin de reproduire le bug et du coup, j'ai du supprimer un peux trop vite la ligne dans la section Finalization qui disait DllThread.Terminate;
Du coup, j'ai généré un autre bug que celui que je traquais. Y'a plus qu'a retourner à la pêche...

Sinon, j'avais une question, vaut il mieux utiliser une fonction exporté qui permet d'arréter le thread (comme tu l'as fait) ou mon DllThread.Terminate dans la section Finalization est suffisant ?

merci pour ton aide précieuse. Je retourne chercher le bug qui m'intéresse...

WSTBoss!
Commenter la réponse de WSTBoss
Messages postés
3982
Date d'inscription
mardi 8 mars 2005
Dernière intervention
7 novembre 2014
- 17 nov. 2008 à 17:54
0
Merci
Oki pour le terminate dans la finalization, mais avec un WaitFor.

Sinon terminate va revenir avant que le thread se termine (Terminate ne fait que mettre terminated à true) -> Plantage.
Commenter la réponse de cs_rt15
Messages postés
16
Date d'inscription
lundi 16 décembre 2002
Dernière intervention
27 octobre 2011
- 18 nov. 2008 à 14:49
0
Merci
Salut,

Pour info, si l'on met le terminate et le waitfor dans la section finalization, c'est déjà un peu trop tard pour terminer le thread. cela génère une exception ou le programme ne se ferme pas.
Je prends donc ta méthode d'appeler une fonction d'arrêt du thread avant de décharger la dll.
Cependant que se passe t'il si le programme principal plante et qu'il n'appelle pas la fonction StopThread ?
la dll reste t'elle en mémoire avec le thread qui tourne ?

merci

WSTBoss!
Commenter la réponse de WSTBoss

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.