内存泄露?(100分)

  • 主题发起人 主题发起人 nullbert
  • 开始时间 开始时间
你的代码可真……*$#&%^@#!
算了,过后再说这个。

你的代码量有大量Create(主要是MetaFile的),但就是没有对应Free,这能不出内存漏洞
吗?内存漏洞的可怕之处就在于运行时不会报任何错误,直到进程耗尽所有可用内的存。会报错Access Violation
只是访问了无效的地址而已。
tprintdlg.report(acanvas:tcanvas);这个函数很有问题,acanvas的分配与释放根本不是
对应的,而且还有一次递归的调用,访问地址的错误很能就是出现在这个函数里。
注意:内存的分配和释放一定要对应!像你的report函数里有类似的代码:

with acanvas do
try
begin
if a > 100 then
//[red]如果这个条件不满足,就不会有Canvas被创建,当你的程序完成下面这次
//递归调用,执行到finally后面的free时,就会因为试图释放一个无效的对象而
//报内存访问错误![/red]
begin
report(tmetafilecanvas.Create(...)); //一个临时的Canvas被建立
...
end;
finally
free;
end;

你的程序中不少全局变量的应用,这使我们不可能很容易地读通你的程序,从而不可能帮
你分析出更多的错误,最终问题的解决还是要靠你自己!

建议多看一些书写优良,条理清晰的程序代码,并试着进一步改良你的代码风格。
 
那么,为什么在未编译成动态连接库文件时
运行正常,我是反复测试了的。
编译成动态连接后的唯一改动是printdlg的动态创建,
 
由于你的myadoquery和mydatasource不是Tprintdlg的成员,所以你在动态建立Tprintdlg的
时候并没有建立它们的实例,之后你访问这个无效的对象的时候,就产生了内存访问错误。
你的TPrintDlg.init方法其实只是一个把指针相互指一下的过程,并没有建立对象实例的
代码。如果你的项目原来是用了DataModule的话,问题就更是出在这里了,因为在动态连接
库项目中,DataModule的实例是不会被自动建立的,必须自已写代码建立。

如果逐行调试一下你的程序,就不难发现问题在哪一步。逐行调试动态链接库的方法是:
点击“Run”菜单,选“Parameters”,在Host Application中填入你要用来调用此动态链
接库的文件,确定后,在动态链接库项目源文件的相关地方设上断点,执行即可。
 
为什么在第一次预览时,每一列的距离都相等,而不是和实际距离相等。
然后,我用鼠标把列竖线拖动一下,然后就和实际距离相等了
这和report(tmetafilecanvas.Create(mymetafile[j],printer.handle));有关吗?
 
我做了修改,还是不行!大家再看一下,到底我错在哪儿?
向所有曾经帮我的人致敬!并希望你们能继续帮我把程序做好。
向所有愿意帮助我和即将帮助我的人致谢!
unit Unit2;

interface

uses Windows, SysUtils, Classes, Graphics, Forms, Controls, StdCtrls,
Buttons, ExtCtrls,printers, Dialogs, DB, ADODB,dbgrids, Grids;

const
leftblank=1;
rightblank=1;
topblank=1;
bottomblank=2;

type
Tprintdlg = class(TForm)
Panel1: TPanel;
PrinterSetupDialog1: TPrinterSetupDialog;
Button1: TButton;
Button2: TButton;
OKBtn: TButton;
CancelBtn: TButton;
Button3: TButton;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
ScrollBox1: TScrollBox;
Panel2: TPanel;
Image1: TImage;
Button4: TButton;
Button5: TButton;
procedure Button1Click(Sender: TObject);
procedure Button3Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure Button4Click(Sender: TObject);
procedure Button5Click(Sender: TObject);
procedure preview;
function execute:boolean;
constructor init(adoquery:tadoquery;datasource:tdatasource;dbgrid:tdbgrid);
private
public
end;

var
mymetafile:array of tmetafile;
rownum:array of integer;
colnum:array of integer;
p,prepagenum:integer;
adoquery1:tadoquery;
datasource1:tdatasource;
dbgrid1:tdbgrid;
printdlg:tprintdlg;

procedure myprint(app:tapplication;adoquery:tadoquery;datasource:tdatasource;dbgrid:tdbgrid);export;

implementation


{$R *.dfm}

procedure myprint(app:tapplication;adoquery:tadoquery;datasource:tdatasource;dbgrid:tdbgrid);
var
pointx,pointy:integer;
pointscale,printstep:integer;
i,r,k,pagenum,colnum:integer;
x,y:integer;
s:string;
begin
printdlg:=tprintdlg.Create(app);
printdlg.init(adoquery,datasource,dbgrid);
with printdlg do
if execute then
begin
PointX:=Trunc(GetDeviceCaps(Printer.Handle,LOGPIXELSX)/2.54);
PointY:=Trunc(GetDeviceCaps(Printer.Handle,LOGPIXELSY)/2.54);
PointScale:=Trunc(GetDeviceCaps(Printer.Handle,LOGPIXELSX)/Screen.PixelsPerInch+1.5);
printer.Canvas.Font.Name:='宋体';
printer.canvas.Font.Size:=10;
s:='出货分类统计表';
PrintStep:=printer.canvas.TextHeight(s)+16;
x:=PointX*LeftBlank;
y:=PointY*TopBlank;
k:=1;
colnum:=0;
pagenum:=1;
if (adoquery.Active=true) and (adoquery.RecordCount>0) then
begin
printer.BeginDoc;
adoquery.First;
while not adoquery.Eof do
begin
for i:=0 to DBGrid.FieldCount-1 do
begin
if (x+DBGrid.Columns.Items.Width*PointScale)<=(Printer.PageWidth-PointX*RightBlank) then
begin
if i=0 then
begin
printer.Canvas.moveto(x,y+200);
printer.canvas.lineto(x,y+200+printstep);
end;
printer.Canvas.moveto(x,y+200);
printer.Canvas.lineto(x+dbgrid.Columns.Items.Width*pointscale,y+200);
if y=PointY*TopBlank then
begin
printer.Canvas.Font.Name:='黑体';
printer.canvas.Font.Size:=14;
Printer.Canvas.TextOut((Printer.PageWidth-printer.Canvas.TextWidth(s)) div 2,y+8,s);
printer.Canvas.Font.Name:='宋体';
printer.canvas.Font.Size:=10;
Printer.Canvas.TextOut(x+8,y+8+200,DBGrid.Columns.Title.Caption);
printer.canvas.moveto(x+dbgrid.Columns.Items.Width*pointscale,y+200);
printer.Canvas.lineto(x+dbgrid.Columns.Items.Width*pointscale,y+200+printstep);
colnum:=colnum+1;
end
else
begin
Printer.Canvas.TextOut(x+8,y+200+8,DBGrid.Fields.asString);
printer.Canvas.moveto(x+dbgrid.Columns.Items.Width*pointscale,y+200);
printer.Canvas.lineto(x+dbgrid.Columns.Items.Width*pointscale,y+200+printstep);
end;
end;
x:=x+DBGrid.Columns.Items.Width*PointScale;
end;

if not (y=PointY*TopBlank) then
adoquery.next;
x:=PointX*LeftBlank;
y:=y+PrintStep;
if (y+PrintStep)>(Printer.PageHeight-PointY*BottomBlank) then
begin
if k=1 then
begin
r:=adoquery.recno;
pagenum:=trunc(adoquery.recordcount/r)+1;
end;
for i:=0 to colnum-1 do
begin
printer.canvas.moveto(x,y+200);
printer.canvas.lineto(x+dbgrid.Columns.Items.Width*pointscale,y+200);
x:=x+dbgrid.Columns.Items.width*pointscale;
end;
x:=pointx*leftblank;
printer.Canvas.TextOut(x+8,y+200+8,'第'+inttostr(k)+'页'+''+''+'共'+inttostr(pagenum)+'页');
Printer.NewPage;
y:=PointY*TopBlank;
k:=k+1;
end; //换页
end;//adoquery
for i:=0 to colnum-1 do
begin
printer.Canvas.moveto(x,y+200);
printer.canvas.lineto(x+dbgrid.Columns.Items.Width*pointscale,y+200);
x:=x+dbgrid.Columns.Items.width*pointscale;
end;
x:=pointx*leftblank;
printer.Canvas.TextOut(x+8,printer.PageHeight-bottomblank*pointy,'第'+inttostr(k)+'页'+''+''+'共'+inttostr(pagenum)+'页');
printer.EndDoc;
adoquery.First;
showMessage('打印完成 共'+inttostr(pagenum)+'页');
end;
end;

printdlg.free;

end;
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////打印预览/////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////







procedure tprintdlg.preview;
var
i,r,j:integer;
pointx,pointy,pointscale:integer;
printstep:integer;
x,y:integer;
s:string;

mymetafilecanvas:tmetafilecanvas;
begin
setlength(rownum,20);
setlength(colnum,20);
setlength(mymetafile,20);
for i:=0 to 20-1 do
begin
rownum:=0;
colnum:=0;
end;
j:=1;
prepagenum:=1;
ADOQuery1.First;
while not adoquery1.Eof do
begin
mymetafile[j]:=tmetafile.Create;
mymetafilecanvas:=tmetafilecanvas.create(mymetafile[j],printer.handle);

PointX:=Trunc(GetDeviceCaps(Printer.Handle,LOGPIXELSX)/2.54);
PointY:=Trunc(GetDeviceCaps(Printer.Handle,LOGPIXELSY)/2.54);
PointScale:=Trunc(GetDeviceCaps(Printer.Handle,LOGPIXELSX)/Screen.PixelsPerInch+1.5);
printer.Canvas.Font.Name:='宋体';
printer.canvas.Font.Size:=10;
s:='出货分类统计表';
PrintStep:=printer.canvas.TextHeight(s)+16;
x:=PointX*LeftBlank;
y:=PointY*TopBlank;

while (not adoquery1.Eof) and ((y+printstep)<(Printer.PageHeight-PointY*BottomBlank)) do
begin
for i:=0 to DBGrid1.FieldCount-1 do
begin
if (x+DBGrid1.Columns.Items.Width*PointScale)<=(Printer.PageWidth-PointX*RightBlank) then
begin
if i=0 then
begin
mymetafilecanvas.moveto(x,y+200);
mymetafilecanvas.lineto(x,y+200+printstep);
end;
mymetafilecanvas.moveto(x,y+200);
mymetafilecanvas.lineto(x+dbgrid1.Columns.Items.Width*pointscale,y+200);
if y=PointY*TopBlank then
begin
mymetafilecanvas.Font.Name:='黑体';
mymetafilecanvas.Font.Size:=96;
mymetafilecanvas.TextOut((Printer.PageWidth-printer.Canvas.TextWidth(s)) div 2,y+8,s);
mymetafilecanvas.Font.Name:='宋体';
mymetafilecanvas.Font.Size:=68;
mymetafilecanvas.TextOut(x+8,y+8+200,DBGrid1.Columns.Title.Caption);
mymetafilecanvas.moveto(x+dbgrid1.Columns.Items.Width*pointscale,y+200);
mymetafilecanvas.lineto(x+dbgrid1.Columns.Items.Width*pointscale,y+200+printstep);
colnum[j]:=colnum[j]+1;
end
else
begin
mymetafilecanvas.TextOut(x+8,y+200+8,DBGrid1.Fields.asString);
mymetafilecanvas.moveto(x+dbgrid1.Columns.Items.Width*pointscale,y+200);
mymetafilecanvas.lineto(x+dbgrid1.Columns.Items.Width*pointscale,y+200+printstep);
end;
end;
x:=x+DBGrid1.Columns.Items.Width*PointScale;
end;
if not (y=PointY*TopBlank) then
adoquery1.next;
x:=PointX*LeftBlank;
y:=y+PrintStep;
end;



if j=1 then
begin
r:=adoquery1.recno;
prepagenum:=trunc(adoquery1.recordcount/r)+1;
end;
for i:=0 to colnum[j]-1 do
begin
mymetafilecanvas.moveto(x,y+200);
mymetafilecanvas.lineto(x+dbgrid1.Columns.Items.Width*pointscale,y+200);
x:=x+dbgrid1.Columns.Items.width*pointscale;
end;
x:=pointx*leftblank;
mymetafilecanvas.TextOut(x+8,y+200+8,'第'+inttostr(j)+'页'+''+''+'共'+inttostr(prepagenum)+'页');
rownum[j]:=adoquery1.recno-rownum[j-1];



if j=prepagenum then
begin
rownum[j]:=adoquery1.recordcount-rownum[j-1];
for i:=0 to colnum[j]-1 do
begin
mymetafilecanvas.moveto(x,y+200);
mymetafilecanvas.lineto(x+dbgrid1.Columns.Items.Width*pointscale,y+200);
x:=x+dbgrid1.Columns.Items.width*pointscale;
end;
x:=pointx*leftblank;
mymetafilecanvas.TextOut(x+8,printer.PageHeight-bottomblank*pointy,'第'+inttostr(j)+'页'+''+''+'共'+inttostr(prepagenum)+'页');
end;

mymetafilecanvas.Free;
j:=j+1;
end;


Image1.picture.Metafile.Clear;
Image1.picture.Metafile:=mymetafile[1];
panel2.Height:=trunc(printer.PageHeight/(pointscale-1.5));
panel2.Width:=trunc(printer.PageWidth/(pointscale-1.5));
adoquery1.First;
end;

constructor tprintdlg.init(adoquery:tadoquery;datasource:tdatasource;dbgrid:tdbgrid);
begin
adoquery1:=adoquery;
datasource1:=datasource;
dbgrid1:=dbgrid;
end;


function tprintdlg.execute:boolean;
var i:integer;
begin
preview;
p:=1;
scrollbox1.AutoScroll:=true;
scrollbox1.vertscrollbar.Range:=trunc(panel2.Height)+100;
scrollbox1.HorzScrollBar.Range:=trunc(panel2.Width)+100;

label1.caption:='1'+''+'/'+''+inttostr(prepagenum);
label2.Caption:=inttostr(rownum[1])+'行'+inttostr(colnum[1])+'列';
label3.Caption:='共'+inttostr(adoquery1.RecordCount)+'行'+''+inttostr(ADOQuery1.FieldCount)+'列';
if showmodal=mrok then result:=true
else begin
for i:=1 to prepagenum do
mymetafile.Free;
result:=false;
end;

end;

procedure Tprintdlg.Button1Click(Sender: TObject);
var i:integer;
begin
with printersetupdialog1 do
begin
if execute then
begin
for i:=1 to prepagenum do
mymetafile.Free;
preview;
p:=1;
scrollbox1.AutoScroll:=true;
scrollbox1.VertScrollBar.Range:=trunc(panel2.Height)+100;
scrollbox1.HorzScrollBar.Range:=trunc(panel2.Width)+100;

label1.caption:='1'+''+'/'+''+inttostr(prepagenum);
label2.Caption:=inttostr(rownum[1])+'行'+inttostr(colnum[1])+'列';
label3.Caption:='共'+inttostr(adoquery1.RecordCount)+'行'+''+inttostr(ADOQuery1.FieldCount)+'列';
end;
end;
end;

procedure Tprintdlg.Button3Click(Sender: TObject);
begin
if p<prepagenum then
begin
p:=p+1;
Image1.Picture.Metafile.clear;
Image1.picture.Metafile:=mymetafile[p];
label1.Caption:=inttostr(p)+''+'/'+''+inttostr(prepagenum);
label2.Caption:=inttostr(rownum[p])+'行'+inttostr(colnum[p])+'列';
end;
end;

procedure Tprintdlg.Button2Click(Sender: TObject);
begin
if p>1 then
begin
p:=p-1;
Image1.picture.Metafile.Clear;
Image1.picture.Metafile:=mymetafile[p];
label1.Caption:=inttostr(p)+''+'/'+''+inttostr(prepagenum);
label2.Caption:=inttostr(rownum[p])+'行'+inttostr(colnum[p])+'列';
end;
end;

procedure Tprintdlg.Button4Click(Sender: TObject);
begin
if panel2.height>100 then
begin
panel2.Height:=panel2.Height div 2;
panel2.width:=panel2.Width div 2;
scrollbox1.AutoScroll:=true;
scrollbox1.vertscrollbar.Range:=trunc(panel2.Height)+100;
scrollbox1.HorzScrollBar.Range:=trunc(panel2.Width)+100;
end;
end;

procedure Tprintdlg.Button5Click(Sender: TObject);
begin
if panel2.height<printer.PageHeight then
begin
panel2.Height:=panel2.Height*2;
panel2.Width:=panel2.Width*2;
scrollbox1.AutoScroll:=true;
scrollbox1.vertscrollbar.Range:=trunc(panel2.Height)+100;
scrollbox1.HorzScrollBar.Range:=trunc(panel2.Width)+100;
end;
end;

end.
 
并且我发现如果表比较小,只有一页,就不会出问题(我测试了50次),
到底是怎么回事?
 
接受答案了.
 
后退
顶部