You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi调用私有函数触发Access Violation:空指针引用排查求助

Delphi TTaskDialog 触发 Access Violation 错误排查与解决

问题描述

学习Delphi时,调用私有函数ShowDialog触发Access Violation at Address 00xxxxx错误,错误发生在代码行tb := TTaskDialogBaseButtonItem.Create(nil);,怀疑是空指针引用但无法定位,已尝试实例化并释放TTaskDialog和TTaskDialogBaseButtonItem,问题仍存在。

错误截图:
Access Violation错误截图

相关代码:

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.

问题原因

  1. 错误手动创建按钮实例:TTaskDialog.Buttons.Add方法会自动创建并返回按钮实例,无需手动调用TTaskDialogBaseButtonItem.Create(nil),手动创建的实例未关联到TTaskDialog的管理体系,会引发内存引用混乱。
  2. 重复赋值与非法释放:手动创建的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.17 12:10:09