尝试释放带有对象的 StringList 时出现的复杂问题使我的应用程序崩溃

在Windows 10的Delphi 10.4.2 win-32 VCL应用程序中,我用这段代码收集了一些窗口的句柄和程序路径:

function GetPathFromPID(const PID: Cardinal): string;
var
  hProcess: THandle;
  Path: array[0..MAX_PATH - 1] of Char;
begin
  hProcess := Winapi.Windows.openprocess(Winapi.Windows.PROCESS_QUERY_INFORMATION or Winapi.Windows.PROCESS_VM_READ,False,PID);
  if hProcess <> 0 then
  try
    if Winapi.PsAPI.GetModuleFileNameEx(hProcess,Path,Winapi.Windows.MAX_PATH) = 0 then
      RaiseLastOSError;
    Result := Path;
  finally
    Winapi.Windows.CloseHandle(hProcess)
  end
  else
    RaiseLastOSError;
end;

function EnumWinProc(wHandle: Winapi.Windows.HWND; aList: TStringList): Winapi.Windows.Bool; stdcall;
var
  strPath: string;
  IsAppMainWin: Boolean;
  ProcId: Cardinal;
begin
  IsAppMainWin := IsWindowVisible(wHandle)              and // Visible
    (GetWindow(wHandle,Winapi.Windows.GW_OWNER) = 0)   and // Not owned by other windows
    (GetParent(wHandle) = 0)                            and // Does not have any parent
    (GetWindowLong(wHandle,Winapi.Windows.GWL_EXSTYLE) and Winapi.Windows.WS_EX_TOOLWINDOW = 0); // Not a tool window

  if IsAppMainWin then
  begin
    GetWindowThreadProcessID(wHandle,ProcId);

    try
      strPath := GetPathFromPID(ProcId);
    except
      strPath := 'UnknownProgramPath';
    end;

    aList.AddObject(strPath,TObject(wHandle));
  end;

  Result := True;
end;

procedure ClearList(List: TStringList);
// https://stackoverflow.com/questions/9148659/how-to-free-objects-in-stringlist-in-delphi-7
var
  i: Integer;
begin
  // crash occurs here!
  for i := 0 to pred(List.Count) do
    List.Objects[i].Free;
  List.Clear;
end;

procedure TformMain.OutputAllAppWindows;
begin
  var sl := TStringList.Create;
  try
    sl.OwnsObjects := True;

    EnumWindows(@EnumWinProc,Winapi.Windows.LPARAM(sl));

    for var i := 0 to sl.Count - 1 do
    begin
      CodeSite.Send('window handle',Winapi.Windows.HWND(sl.Objects[i]));
      CodeSite.Send('program-path sl[i]',sl[i]);
    end;
    ClearList(sl); // EDIT: forgot this line!
  finally
    sl.Free; 
  end;
end;

崩溃是由 EurekaLog 报告的:

尝试释放带有对象的 StringList 时出现的复杂问题使我的应用程序崩溃

2.1 日期:2021 年 7 月 31 日星期六 22:36:53 +0200
2.2 地址:005509D2
2.5 类型:EInvalidPointer
2.6 消息:应用程序尝试释放无效或未知的内存块:$00010AE2 OBJECT [?] 0 字节。
2.7 编号:B5002468
2.8 计数:1
2.11 发送:0

这是在 EurekaLog 调用堆栈的顶部:

尝试释放带有对象的 StringList 时出现的复杂问题使我的应用程序崩溃

dukx95 回答:尝试释放带有对象的 StringList 时出现的复杂问题使我的应用程序崩溃

这里有两个问题:

首先,您将整数作为对象放入字符串列表中,因此您不能将这些“对象”视为对象,因为它们不是。

特别是,没有什么可以释放的,你不能释放这些“对象”;这相当于执行 TObject(some random pointer).Free

其次,如果您确实已经将真实对象放入列表中,那么您仍然会遇到错误,因为您首先会自己释放它们,而无需nil调用它们的引用,所以字符串列表的析构函数会尝试“销毁”这些悬空指针指向的东西。再次,糟糕。

本文链接:https://www.f2er.com/3888.html

大家都在问