gpt4 book ai didi

delphi - 如何避免函数结果被函数内部的Free破坏?

转载 作者:行者123 更新时间:2023-12-03 14:58:40 26 4
gpt4 key购买 nike

此代码创建一个 AV:

function PAIsMainAppWindow(Wnd: THandle): Boolean;
var
ParentWnd: THandle;
ExStyle: DWORD;
begin
if IsWindowVisible(Wnd) then
begin
ParentWnd := THandle(GetWindowLongPtr(Wnd, GWLP_HWNDPARENT));
ExStyle := GetWindowLongPtr(Wnd, GWL_EXSTYLE);
Result := ((ParentWnd = 0) or (ParentWnd = GetDesktopWindow)) and
((ExStyle and WS_EX_TOOLWINDOW = 0) or (ExStyle and WS_EX_APPWINDOW <> 0));
end
else
Result := False;
end;

function PAEnumTaskWindowsProc(Wnd: THandle; List: TStrings): Boolean; stdcall;
var
Caption: array [0..1024] of Char;
begin
if PAIsMainAppWindow(Wnd) and (GetWindowText(Wnd, Caption, SizeOf(Caption)) > 0) then
List.AddObject(ExtractFileName(GetProcessNameFromWnd(Wnd)), Pointer(Wnd));
Result := True;
end;

function PAGetTaskWindowHandleFromProcess(const AProcessName: string): THandle;
var
sl: TStringList;
i: Integer;
begin
Result := 0;

sl := TStringList.Create(True); // stringlist owns objects
try
if EnumWindows(@PAEnumTaskWindowsProc, LPARAM(sl)) then
begin
for i := 0 to sl.Count - 1 do
begin
if SameText(AProcessName, sl[i]) then
begin
Result := THandle(sl.Objects[i]);
BREAK;
end;
end;
end;
finally
sl.Free; // AV!
end;
end;

ChromeHandle := PAGetTaskWindowHandleFromProcess('chrome.exe');

很明显,AV 的发生是因为释放字符串列表也会破坏函数结果。但如何避免这种情况呢?

最佳答案

首先,让我们看一下实际的代码。字符串列表不包含对象。它装有窗 Handlebars 。所以 OwnsObjects 根本不合适。这将假设 Objects[] 中的内容是 Delphi 类的实例,并在这些实例上调用 Free。这就是失败发生的地方。

您不拥有这些窗口句柄,因此您不应尝试销毁它们。

因此,不要将 OwnsObjects 设置为 True,问题就会消失。即替换这一行:

sl := TStringList.Create(True); // stringlist owns objects

这样:

sl := TStringList.Create;

此外,您还将这些对象转换为 THandle。这是错误的,但这并不重要。但从语义上讲,这些是窗口句柄,因此将它们转换为 HWND。事实上,在任何使用 THandle 的地方,您都应该使用 HWND

还有其他错误。当您调用 GetWindowText 时,您传递的是缓冲区的大小而不是其长度。这意味着您在缓冲区长度上撒了谎。因为这些是宽字符,所以缓冲区的长度只有您声称的一半。寻找桌面窗口的父窗口感觉是错误的。

<小时/>

为了便于论证,我们假设您的字符串列表确实包含对象。在这种情况下,在理想的情况下,字符串列表类将提供一个Extract方法,该方法是从所属容器中删除对象而不破坏该对象的传统方法。因此,您可以执行 OwnsObjects 随机播放。

if SameText(AProcessName, sl[i]) then
begin
sl.OwnsObjects := False;
Result := TSomeObject(sl.Objects[i]);
sl.Objects[i] := nil;
sl.OwnsObjects := True;
BREAK;
end;

如果您愿意,可以在创建字符串列表时将 OwnsObjects 设置为 False,并且仅将其设置为 True就在您调用 Free 之前。

关于delphi - 如何避免函数结果被函数内部的Free破坏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34359797/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com