Delphi 事件处理期间的堆栈信息

Delphi Stack Info during Event Handling

调试事件时,我希望看到 "complete" 堆栈,特别是实际事件或触发事件的方法。

一个简单的示例是将 ComboBox 放在窗体上,然后编写 onChange 事件。 onChange 事件将在用户更改 comboBox 时触发(很明显),但它也可以通过其他例程触发,例如,在启动时,formActivate 将触发它。

如果我在组合框的 OnChange 事件中放置一个断点,我将看不到触发堆栈。为什么会这样,我如何在调试期间获得此 "other" 堆栈信息?

我知道我可以逐步完成事件,它最终会把我带回触发代码,这不是我要找的。

谢谢!


我想我会 post 启用 dcu 的工作原理的图像。请注意,FormCreate 事件现在实际上出现在堆栈中。

这是两个不同堆栈跟踪的图像。两者的断点完全相同,请注意在第二个启用调试 dcu 后,我从我的代码中获取堆栈信息(不仅仅是 vcl/rtl)。

我怀疑您遗漏了堆栈跟踪中的 RTL/VCL 函数。要使它们显示出来,请在项目选项中启用 Debug DCUs

After enabling Debug DCU's, I saw my own code in the stack. Specifically the FormCreate handler only appeared after enabling debug dcus. I was surprised by this.

this:

基于框架的方法的堆栈框架

RTL 和 VCL 单元在 "Stack Frames" 选项关闭的情况下编译。这意味着任何基于帧的方法都无法找到 RTL/VCL 单元中的短例程。

然而,这个事实也有不太明显的后果。考虑这段代码:

procedure TForm1.Button1Click(Sender: TObject);
begin
  TStringList.Create;
end;

此代码通过泄漏 TStringList 的实例创建了一个简单的内存泄漏。跟踪工具将检测泄漏并为其构建调用堆栈。由于为您的项目启用了 "Stack Frames" 选项,Button1Click 例程具有堆栈帧。人们可能期望基于帧的跟踪方法会发现对 Button1Click 的调用并将其添加到调用堆栈。

事实并非如此。

Button1Click 的堆栈帧允许方法识别调用者(在本例中:TControl.Click)。那是因为堆栈帧不包含有关例程 本身 的信息。它包含有关呼叫者的信息:return地址。 Return Button1Click 例程的地址将指向 TControl.Click。

但是 Button1Click 呢?由于 TStringList 是来自 RTL 的 class - 它是在没有 "Stack Frames" 选项的情况下编译的。因此,构造函数没有栈帧(因为它是非常简单的代码并且不需要栈帧)。因此,基于帧的跟踪方法无法识别 Button1Click 例程。