Delphi调用私有函数触发Access Violation:空指针引用排查求助
Delphi TTaskDialog 触发 Access Violation 错误排查与解决
问题描述
学习Delphi时,调用私有函数ShowDialog触发Access Violation at Address 00xxxxx错误,错误发生在代码行tb := TTaskDialogBaseButtonItem.Create(nil);,怀疑是空指针引用但无法定位,已尝试实例化并释放TTaskDialog和TTaskDialogBaseButtonItem,问题仍存在。
错误截图:
相关代码:
unit SandBox; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls; type TForm1 = class(TForm) AhojButton: TButton; procedure AhojButtonClick(Sender: TObject); private procedure ShowDialog(amount: Integer); public end; var Form1: TForm1; implementation {$R *.dfm} procedure TForm1.ShowDialog(amount: Integer); var td: TTaskDialog; var tb: TTaskDialogBaseButtonItem; begin try td := TTaskDialog.Create(nil); tb := TTaskDialogBaseButtonItem.Create(nil); td.Caption := 'Warning'; td.Text := 'Continue or Close?'; td.MainIcon := tdiWarning; td.CommonButtons := []; tb := td.Buttons.Add; tb.Caption := 'Continue'; tb.ModalResult := 100; tb := td.Buttons.Add; tb.Caption := 'Close'; tb.ModalResult := 101; td.Execute; if td.ModalResult = 100 then ShowMessage('Continue') else if td.ModalResult = 101 then ShowMessage('Close'); finally td.Free; tb.Free; end; end; procedure TForm1.AhojButtonClick(Sender: TObject); begin ShowDialog(100); end; end.
问题原因
- 错误手动创建按钮实例:
TTaskDialog.Buttons.Add方法会自动创建并返回按钮实例,无需手动调用TTaskDialogBaseButtonItem.Create(nil),手动创建的实例未关联到TTaskDialog的管理体系,会引发内存引用混乱。 - 重复赋值与非法释放:手动创建的
tb实例被td.Buttons.Add的返回值覆盖,导致该实例内存泄漏;同时TTaskDialog释放时会自动销毁其管理的按钮,后续手动释放tb会触发对已释放内存的二次访问,直接引发Access Violation。
解决代码
修改ShowDialog函数,移除手动创建按钮的代码,且无需手动释放按钮:
procedure TForm1.ShowDialog(amount: Integer); var td: TTaskDialog; tb: TTaskDialogBaseButtonItem; begin try td := TTaskDialog.Create(nil); td.Caption := 'Warning'; td.Text := 'Continue or Close?'; td.MainIcon := tdiWarning; td.CommonButtons := []; tb := td.Buttons.Add; tb.Caption := 'Continue'; tb.ModalResult := 100; tb := td.Buttons.Add; tb.Caption := 'Close'; tb.ModalResult := 101; td.Execute; if td.ModalResult = 100 then ShowMessage('Continue') else if td.ModalResult = 101 then ShowMessage('Close'); finally // TTaskDialog释放时会自动销毁所有关联按钮 td.Free; end; end;
关键说明
TTaskDialog的Buttons集合会自动管理内部按钮的生命周期,调用Add时框架已完成实例创建与关联,无需手动干预。- 仅需保证
TTaskDialog被正确释放,其下属的所有按钮资源会由框架自动清理,避免手动释放引发的内存非法访问。
内容的提问来源于stack exchange,提问作者Jakub Sluka
相关产品推荐
相关产品推荐

