TShellTreeView 内存泄漏
TShellTreeView memory leak
我正在使用 MadExcept 来跟踪内存泄漏。如果我将 TShellTreeView 放在表单上并且 运行 应用程序 MadExcept 报告内存泄漏。只是打开和关闭,没有别的。我在 XE8 下使用 XE6 包,因为这是最后一个发布的 AFAIK。
我知道以前的 delphi 版本存在一些问题,但我认为这些问题已在 XE6 软件包中修复。
这是应用程序关闭后显示的 MadExcept Window:
有什么想法吗?
是的,madExcept 是正确的,这是意料之中的,因为它的质量非常高。这确实是您使用的代码中的一个缺陷。它看起来像这样:
function CreateRootFolder(RootFolder: TShellFolder; OldRoot : TRoot;
var NewRoot: TRoot): TShellFolder;
var
P: PWideChar;
NewPIDL: PItemIDList;
NumChars,
Flags,
HR: LongWord;
ErrorMsg : string;
begin
HR := S_FALSE;
if GetEnumValue(TypeInfo(TRootFolder), NewRoot) >= 0 then
begin
HR := SHGetSpecialFolderLocation(
0,
nFolder[GetCSIDLType(NewRoot)],
NewPIDL);
end
else if Length(NewRoot) > 0 then
begin
if NewRoot[Length(NewRoot)] = ':' then NewRoot := NewRoot + '\';
NumChars := Length(NewRoot);
Flags := 0;
P := StringToOleStr(NewRoot);
HR := DesktopShellFolder.ParseDisplayName(0, nil, P, NumChars, NewPIDL, Flags);
end;
if HR <> S_OK then
begin
{ TODO : Remove the next line? }
// Result := RootFolder;
ErrorMsg := Format( SErrorSettingPath, [ NewRoot ] );
NewRoot := OldRoot;
raise Exception.Create( ErrorMsg );
end;
Result := CreateRootFromPIDL(NewPIDL);
if Assigned(RootFolder) then RootFolder.Free;
end;
在两个分支中,调用者有责任销毁NewPIDL
。代码没有这样做。通过阅读文档可以看出这一点:
将函数的最后部分修改为:
Result := CreateRootFromPIDL(NewPIDL);
if Assigned(RootFolder) then RootFolder.Free;
CoTaskMemFree(NewPIDL);
我可以确认我已经测试了这个变化。我测试了原始代码并重现了您报告的泄漏。然后我如上所述更改了代码,并且 madExcept 报告没有泄漏。
您无法实现同样的效果意味着您没有执行修改后的代码。也许您正在使用运行时包并且没有重新编译修改后的代码。或许还有另一种解释。无论如何,我完全清楚你未能消除泄漏是因为你仍然是 运行 原始未修改的代码。
我正在使用 MadExcept 来跟踪内存泄漏。如果我将 TShellTreeView 放在表单上并且 运行 应用程序 MadExcept 报告内存泄漏。只是打开和关闭,没有别的。我在 XE8 下使用 XE6 包,因为这是最后一个发布的 AFAIK。
我知道以前的 delphi 版本存在一些问题,但我认为这些问题已在 XE6 软件包中修复。
这是应用程序关闭后显示的 MadExcept Window:
有什么想法吗?
是的,madExcept 是正确的,这是意料之中的,因为它的质量非常高。这确实是您使用的代码中的一个缺陷。它看起来像这样:
function CreateRootFolder(RootFolder: TShellFolder; OldRoot : TRoot;
var NewRoot: TRoot): TShellFolder;
var
P: PWideChar;
NewPIDL: PItemIDList;
NumChars,
Flags,
HR: LongWord;
ErrorMsg : string;
begin
HR := S_FALSE;
if GetEnumValue(TypeInfo(TRootFolder), NewRoot) >= 0 then
begin
HR := SHGetSpecialFolderLocation(
0,
nFolder[GetCSIDLType(NewRoot)],
NewPIDL);
end
else if Length(NewRoot) > 0 then
begin
if NewRoot[Length(NewRoot)] = ':' then NewRoot := NewRoot + '\';
NumChars := Length(NewRoot);
Flags := 0;
P := StringToOleStr(NewRoot);
HR := DesktopShellFolder.ParseDisplayName(0, nil, P, NumChars, NewPIDL, Flags);
end;
if HR <> S_OK then
begin
{ TODO : Remove the next line? }
// Result := RootFolder;
ErrorMsg := Format( SErrorSettingPath, [ NewRoot ] );
NewRoot := OldRoot;
raise Exception.Create( ErrorMsg );
end;
Result := CreateRootFromPIDL(NewPIDL);
if Assigned(RootFolder) then RootFolder.Free;
end;
在两个分支中,调用者有责任销毁NewPIDL
。代码没有这样做。通过阅读文档可以看出这一点:
将函数的最后部分修改为:
Result := CreateRootFromPIDL(NewPIDL);
if Assigned(RootFolder) then RootFolder.Free;
CoTaskMemFree(NewPIDL);
我可以确认我已经测试了这个变化。我测试了原始代码并重现了您报告的泄漏。然后我如上所述更改了代码,并且 madExcept 报告没有泄漏。
您无法实现同样的效果意味着您没有执行修改后的代码。也许您正在使用运行时包并且没有重新编译修改后的代码。或许还有另一种解释。无论如何,我完全清楚你未能消除泄漏是因为你仍然是 运行 原始未修改的代码。