The Path.Combine and CombinePath functions have problems with very long path names, furthermore when the path is not physically on the drive (but for example in a zip file) then it also doesn't work. This implementation works for me:
function ExpandFileNameEx(const BasePath, RelativeFileName: string): string;
var
p:integer;
s,folder:string;
begin
{ Check if Relative file name is a fully qualified path: }
if (pos(':\', RelativeFileName) > 0) or (copy(RelativeFileName,1,2) = '\\') then
Result := RelativeFileName
{ Check if Relative file name is a root path assignment: }
else if copy(RelativeFileName,1,1) = '\' then
begin
Result := IncludeTrailingPathDelimiter(ExtractFileDrive(BasePath))
+ Copy(RelativeFileName,2,Length(RelativeFileName));
end else
begin
{ Check all sub paths in Relative file name: }
Result := BasePath;
s := RelativeFileName;
repeat
p := pos('\', s);
if p > 0 then
begin
folder := Copy(s,1,p-1);
Delete(s, 1,p);
end else
begin
folder := s;
s := '';
end;
if folder <> EmptyStr then
begin
if Folder = '..' then
Result := ExtractFileDir(Result)
else if Folder = '.' then
{ No action }
else
Result := IncludeTrailingPathDelimiter(Result) + Folder;
end;
until p = 0;
end;
end;