D'abord, petite remarque concernant les règles d'utilisation du forum :
(je l'ai rajouté pour toi)
Après cette parenthèse, voici une réponse :
La première chose, c'est que lorsque tu crées un objet (quel qu'il soit) :
Image := Timage.Create(Self);
Il faut penser à le détruire quelque part (sinon il reste en mémoire et windows fini par ne pas être content du tout !).
Juste avant le End de ton "device Context" par exemple, c'est bien.
De plus, quand tu libères un objet graphique, le "Device Context" que tu lui as assigné est lui aussi libéré, donc tu n'as plus besoin du release :
1 2 3 4 5 6 7 8 9 10 11 12
| function NbPoint(n : integer):integer; stdcall;
var DC : HDC;
Image: TImage;
begin
Image := Timage.Create(Self);
DC := getdc(n);
Image.Canvas.Handle := DC;
Result := Image.Width;
Image.Free; //<-- Libération de l'objet créé
end; |
Le premier problème provient du fait que tu utilises un TImage.
A la place, il faudrait que tu utilises un TBitmap (et encore...).
TImage, ne représente en RIEN une image, c'est un composant visuel qui peut contenir une image. Bref, en résumé, un TImage n'est pas une image.
C'est bien pour afficher une image sur une fiche, mais pas terrible pour travailler sur une image !
Par contre un TBitmap (Le TImage contient un TBitmap), oui, ça représente une image que l'on peut manipuler.
Donc, pour l'instant, voici ton nouveau code :
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
| library Ma;
uses
SysUtils,Controls,Windows,Graphics,ExtCtrls,
Classes;
{$R *.res}
function NbPoint(n : integer):integer; stdcall;
var DC : HDC;
Image: TBitmap;
begin
Image := TBitmap.Create;
DC := getdc(n);
Image .Canvas.Handle := DC;
Result := Image.Width;
Image.Free;
end;
exports
NbPoint;
begin
end. |
Mais ce n'est pas fini !
Comme tu l'as remarqué, le Handle du "Device Context", en delphi, est toujours une propriété de TCanvas. C'est normal, un "Device Context" ne te donnes pas accès à une image bitmap, mais à une "surface de dessin".
Ainsi, pour dessiner sur une Image (un TBitmap), on passe par sa "surface de dessin" (représentée par TCanvas).
Mais il n'y a pas que les Images qui proposent une surface de dessin, une fenètre (TForm) en propose une, un TPanel en propose une aussi, ainsi que TButton, TMemo, le bureau et l'écran (accessibles via la variable Screen), l'imprimante (printer), etc...
Donc, quand tu accèdes à un objet Windows via son "Device Context", tu accèdes en fait à sa "surface de dessin", tu es donc en présence, ni plus ni moins, d'un TCanvas, mais pas forcément d'une image.
Ce que tu dois retenir
"Device Context" (Windows) est équivalent à "TCanvas" (Delphi)
Donc on va remplacer TBitmap par TCanvas...
Mais en faisant ceci, il ne faut pas oublier que TCanvas ne libère pas le "Device Context" qu'on lui assigne (comme le faisait TBitmap ou TImage), on a donc le retour de Release...
De là ton nouveau code :
1 2 3 4 5 6 7 8 9 10 11
| function NbPoint(n : integer):integer; stdcall;
var DC : HDC;
Image: TCanvas;
begin
Image := TCanvas.Create;
DC := getdc(n);
Image.Handle := DC;
Result := Image.Width; //<--là, ça va coincer...
Image.Free;
ReleaseDC(n,DC); //<--on l'a remis...
end; |
Là, tu es coincé... : Un TCanvas ça n'a ni largeur ni hauteur ! ça s'étend de "moins l'infini" à "plus l'infini" (en théorie) aussi bien en X qu'en Y.
Celà te permet de dessiner en dehors de la vue (pour dessiner une portion de cercle sur le bord d'une fiche ou d'une image par exemple).
Mais, TCanvas possède une propriété ClipRect, qui représente les limites du rectangles où le dessin peut s'effectuer. Par defaut, si cette valeur n'a pas été modifiée pour restreindre la zone où le dessin peut s'effectuer, elle contient implicitement la hauteur et la largeur de ton "image", voici ton nouveau code :
1 2 3 4 5 6 7 8 9 10 11 12 13
| function NbPoint(n : integer):integer; stdcall;
var DC : HDC;
Image: TCanvas;
Largeur:integer;
begin
Image := TCanvas.Create;
DC := getdc(n);
Image.Handle := DC;
Largeur:=Image.ClipRect.Right-Image.ClipRect.Left;
Result := Largeur;
Image.Free;
ReleaseDC(n,DC);
end; |
Mais ce n'est pas fini ! Il y a encore un problème avec
- ça :
- ça :
- et ça :

Envoyé par
CMOINI
...dont je ne connais que le Device context.
Bref, dans ta fonction NBPoint, si j'ai bien compris, tu passes en paramètre un "Device Context" :
- tu as déjà un Device Context, pas la peine d'en demander un à windows.
- corriges ta déclaration de fonction (on va y revenir dans le nouveau code)
- si tu vas voir dans l'aide "SDK Windows", tu verras que GetDC attend un HWnd (c'est un handle de fenètre, par un "Device Condext" : même si l'un et l'autre sont des entiers, ce n'est pas pareil).
Un handle de fenètre c'est l'ID (un identifiant unique) d'une fenètre (TForm en Delphi), du bureau (égale à zéro), d'un contrôle fenètré (TPanel par exemple et tout les descendants de TWinControl)
Rappel : une fenètre (ou un contrôle fenétré), est un objet qui peut lui même contenir des fenètres (ou des contrôles fenétrés), ainsi que des contrôles qui eux, ne sont pas fenétrés (TGaphicControl).
Donc, il ne faut pas confondre Form1.Handle (HWNd) et Canvas.Handle (HDC)...
Pour un même Handle de fenètre (HWnd) tu peux obtenir de windows autant de "Device Context" (HDC) que tu veux ! (mais faut pas en abuser
) :
1 2 3
| DC_Fiche1:=GetDC(Form1.Handle);
DC_Fiche2:=GetDC(Form1.Handle);
... |
Et puis du coup, on a plus besoin du Release... 
Bref, voici ton nouveau code :
1 2 3 4 5 6 7 8 9 10
| function NbPoint(DC : HDC):integer; stdcall;
var Image: TCanvas;
Largeur:integer;
begin
Image := TCanvas.Create;
Image.Handle := DC;
Largeur:=Image.ClipRect.Right-Image.ClipRect.Left;
Result := Largeur;
Image.Free;
end; |
Bon, voilà, maintenant, ça devrait marcher
Sinon, en se passant de TCanvas, on peut réaliser la même fonction avec les API Windows en se passant d'un TCanvas (puisque un "HDC" est fait pour ça...) :
1 2 3 4 5 6 7 8
|
function NbPoint(DC : HDC):integer; stdcall;
var ARect:TRect;
begin
GetClipBox(DC, ARect);
Largeur:=ARect.Right-ARect.Left;
Result := Largeur;
end; |
Bon dev
Partager