2010. február 7., vasárnap

Convert short file names to long ones


Problem/Question/Abstract:

How do I convert a short (alias) filename or directory name into its long equivalent?

Answer:

Solve 1:

{Parameters:

shortname:
File name or path to convert. This can be a fully qualified file name or a path relative to the current directory. It can contain long and / or short forms for the names.

Returns:
Fully qualified filename using the long names for all elements of the path.

Description:
Recursively uses FindFirst to find the long names for the path elements.

Error Conditions:
Will raise an exception if any part of the path was not found.

Created:
15.01.98 14:09:26 by Peter Below}

function GetLongFilename(shortname: string): string;

  function GetL(shortname: string): string;
  var
    srec: TSearchRec;
  begin
    { Lob off the last element of the passed name. If we received only a root name,
    e.g. c:\, ExtractFileDir returns the path unchanged. }
    Result := ExtractFileDir(shortname);
    if (Result <> shortname) then
    begin
      { We still have an unconverted path element. So convert the last one in
                  the current shortname and combine the resulting long name with what we get
                        by calling ourselves recursively with the rest of the path. }
      if FindFirst(shortname, faAnyfile, srec) = 0 then
      try
        Result := GetL(Result) + '\' + srec.Name;
      finally
        FindClose(srec);
      end
      else
        raise Exception.CreateFmt('Path %s does not exist!', [shortname]);
    end
    else
      { Only the root remains. Remove the backslash since the caller will add it
                  back anyway. }
      Delete(Result, length(result), 1);
  end;

begin
  { Create fully qualified path and pass it to the converter. }
  Result := GetL(ExpandFilename(shortname));
end;


Solve 2:

{Get LFN from 8.3}

function GetLongPathName(const PathName: string): string;
var
  Drive: string;
  Path: string;
  SearchRec: TSearchRec;
begin
  if PathName = '' then
    Exit;
  Drive := ExtractFileDrive(PathName);
  Path := Copy(PathName, Length(Drive) + 1, Length(PathName));
  if (Path = '') or (Path = '\') then
  begin
    Result := PathName;
    if Result[Length(Result)] = '\' then
      Delete(Result, Length(Result), 1);
  end
  else
  begin
    Path := GetLongPathName(ExtractFileDir(PathName));
    if FindFirst(PathName, faAnyFile, SearchRec) = 0 then
    begin
      Result := Path + '\' + SearchRec.FindData.cFileName;
      FindClose(SearchRec);
    end
    else
      Result := Path + '\' + ExtractFileName(PathName);
  end;
end;


Solve 3:

You could try the following. It should work on Win95 and above.

unit WhateverYouWantToCallIt;

interface

function LongPathFromShort(const ShortPath: string): string;

implementation

uses
  Windows, SysUtils, ActiveX, ShlObj;

function LongPathFromShort(const ShortPath: string): string;
var
  iAttributes: Cardinal;
  iEaten: Cardinal;
  IntfDesktop: IShellFolder;
  IntfMalloc: IMalloc;
  pItemList: PItemIDList;
  sFile: WideString;
  szFile: array[0..MAX_PATH] of Char;
begin
  Result := ShortPath;
  if not FileExists(ShortPath) then
    Exit;
  if Succeeded(SHGetDesktopFolder(IntfDesktop)) then
  begin
    sFile := ShortPath;
    iAttributes := 0;
    if Succeeded(IntfDesktop.ParseDisplayName(0, nil, POleStr(sFile),
      iEaten, pItemList, iAttributes)) then
    begin
      SHGetPathFromIDList(pItemList, szFile);
      Result := szFile;
      SHGetMalloc(IntfMalloc);
      IntfMalloc.Free(pItemList)
    end
  end
end;

end.


Solve 4:

GetFullPathName converts a relative path to an absolute path. You can use GetLongPathName, but this requires Win98 and later or Win2k and later.

function GetLongName(const APath: string): string;
var
  Buffer: array[0..MAX_PATH] of Char;
  Required: Integer;
begin
  Required := GetLongPathName(PChar(APath), Buffer, Length(Buffer));
  if Required > MAX_PATH then {Buffer too small}
  begin
    SetLength(Result, Required - 1);
    GetLongPathName(PChar(APath), Pointer(Result), Required);
  end
  else if Required = 0 then {Error}
    Result := APath
  else
    SetString(Result, Buffer, Required);
end;

For an ANSI only function you can reduce the above to:

function GetLongName(const APath: AnsiString): AnsiString;
var
  Buffer: array[0..MAX_PATH] of AnsiChar;
  Required: Integer;
begin
  Required := GetLongPathNameA(PChar(APath), Buffer, Length(Buffer));
  SetString(Result, Buffer, Required);
end;

If you need to support for Win95 or WinNT, you can use this function:

function GetLongPathName(Path: string): string;
var
  I: Integer;
  SearchHandle: THandle;
  FindData: TWin32FindData;
  IsBackSlash: Boolean;
begin
  Path := ExpandFileName(Path);
  Result := ExtractFileDrive(Path);
  I := Length(Result);
  if Length(Path) <= I then {only drive}
    Exit;
  if Path[I + 1] = '\' then
  begin
    Result := Result + '\';
    Inc(I);
  end;
  Delete(Path, 1, I);
  repeat
    I := Pos('\', Path);
    IsBackSlash := I > 0;
    if not IsBackSlash then
      I := Length(Path) + 1;
    SearchHandle := FindFirstFile(PChar(Result + Copy(Path, 1, I - 1)), FindData);
    if SearchHandle <> INVALID_HANDLE_VALUE then
    begin
      try
        Result := Result + FindData.cFileName;
        if IsBackSlash then
          Result := Result + '\';
      finally
        Windows.FindClose(SearchHandle);
      end;
    end
    else
    begin
      Result := Result + Path;
      Break;
    end;
    Delete(Path, 1, I);
  until Length(Path) = 0;
end;

Nincsenek megjegyzések:

Megjegyzés küldése