Bonjour,
Citation Envoyé par KlausGunther Voir le message
Je clos cette discussion. Je n'ai pas trouvé de solution à ce problème, et j'ai choisi de procéder entièrement différemment, dans l'application. Le handle du canvas ne peut pas être transmis valablement à une DLL et utilisé à cet endroit. Tant pis. En tout cas, merci de votre aide.
Vieille discussion qui est exhumée là...
Cela dit, c'est assez confus et je ne suis pas sur d'avoir tout compris sur les spécifications et les responsabilités de l'application et de la dll...

Pour résumer, actuellement, l'application transmet un Handle de windows (fenêtre) au sens Windows du terme (système d'exploitation) et un certain nombre de fonctions de la dll doivent dessiner sur cette fenêtre en utilisant que des appels directs aux API et aucun mécanisme de Delphi (dont TCanvas qui encapsule les DeviceContext).

AMHA, cette approche n'est pas la bonne sur la répartition des responsabilités : Comme l'a dit Paul TOTH, l'application doit se charger de l'affichage et votre dll doit se limiter au dessin. Pour ce faire, l'application doit transmettre à chaque fonction appelée dans la dll le device context du moment, la fonction réalise son dessin et rend la main. L'avantage est que vous pouvez alors utiliser dans votre dll les mécanismes et les encapsulations propres à Delphi, en l'occurrence un TCanvas !

Comment ? C'est simple, vous allez créer un TCanvas dans votre fonction, lui affecter le device context reçu en paramètre, faire votre dessin, puis supprimer le Canvas avant de rendre la main.
La seule complication est côté application appelante : elle doit fournir un device context et le gérer....

Voici un extrait de code tiré d'un petit exemple que j'ai écrit à partir du code que vous aviez fourni : une application Lazarus qui appelle une dll Delphi...
Côté dll Delphi
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
function Cadre(HDC: HWND): Integer;
var
  Canvas: TCanvas;
begin
  Canvas := TCanvas.Create;
  try
    Canvas.Handle := HDC;
    Canvas.Font.Name := 'Arial';
    Canvas.Font.Size := 12;
    Canvas.Pen.Color := clBlack;
    Canvas.TextOut(0,0,format('Page %d',[1]));
    Canvas.Rectangle(100, 100, 400, 400);
    Canvas.TextOut(50, 50, 'Ligne 2');
    Canvas.TextOut(75, 75, 'Ligne 3');
    Canvas.TextOut(50,100,'Ligne 4');
  finally
    Canvas.Free;
  end;
end;
 
function Lines(HDC: HWND): Integer;
var
  Canvas: TCanvas;
begin
  Canvas := TCanvas.Create;
  try
    Canvas.Handle := HDC;
    Canvas.Pen.Color := clRed;
    Canvas.MoveTo(20, 20);
    Canvas.LineTo(480, 20);
    Canvas.MoveTo(20, 28);
    Canvas.LineTo(480, 28);
    Canvas.MoveTo(20, 36);
    Canvas.LineTo(480, 36);
  finally
    Canvas.Free;
  end;
end;
Côté application Lazarus
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
procedure TForm1.BtnCreateWinClick(Sender: TObject);
begin
  CreateWindows;
end;
 
procedure TForm1.CreateWindows;
var
  Frm: TForm;
  Img: TImage;
begin
  Frm := TForm.Create(nil);
  Frm.Left := Self.Left + Self.Width + 8;
  Frm.Top := Self.Top;
  Frm.Width := 500;
  Frm.Height := 500;
  Frm.Caption := 'Fenêtre Test';
  Frm.OnClose := @DynFormClose; // Lazarus contrairement à Delphi demande que l'adresse de la fonction soit préfixée par @
 
  BtnCreateWin.Enabled := False;
 
  //
  Img := TImage.Create(Frm);
  Img.Parent := Frm;
  Img.Left := 0;
  Img.Top := 0;
  Img.Width := Frm.ClientWidth;
  Img.Height := Frm.ClientHeight;
  Img.Canvas.FloodFill(0, 0, clWhite, fsBorder);
 
  ShowMessage('Handle 1 : ' + IntToStr(Img.Canvas.Handle)); // Les ShowMessage n'affectent pas le résultat !
  Cadre(Img.Canvas.Handle);
  ShowMessage('Handle 2 : ' + IntToStr(Img.Canvas.Handle));
  Lines(Img.Canvas.Handle);
  ShowMessage('Handle 3 : ' + IntToStr(Img.Canvas.Handle));
  Img.Repaint;
  Frm.Show;
end;
 
procedure TForm1.DynFormClose(Sender: TObject; var CloseAction: TCloseAction);
begin
  BtnCreateWin.Enabled := True;
end;