Yes, madExcept is correct which is to be expected because it is of exceptionally high quality. This is indeed a defect in the code you use. It looks like this:
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;
In both branches, it is the responsibility of the caller to destroy NewPIDL
. The code does not do so. That this is so can be discerned by reading the documentation:
Amend the final part of the function to be like so:
Result := CreateRootFromPIDL(NewPIDL);
if Assigned(RootFolder) then RootFolder.Free;
CoTaskMemFree(NewPIDL);
I can confirm that I have tested this change. I tested the original code and reproduced the leak that you reported. I then changed the code as described above and madExcept reports no leak.
That you have been unable to achieve the same means that you are not executing the modified code. Perhaps you are using runtime packages and have not recompiled the modified code. Or perhaps there is another explanation. Anyway, it is completely clear to me that your failure to remove the leak is because you are still running the original unmodified code.