Skip to main content
Tweeted twitter.com/StackCodeReview/status/1445494040690974721
edited tags; edited title
Link
200_success
  • 144.2k
  • 22
  • 188
  • 473

Is there anything wrong with my use of GetFinalPathNameByHandle (Windows API) in my Delphi program?function to canonicalize the capitalization in a file path

added 143 characters in body
Source Link
AlexV
  • 141
  • 5

Here is my current (working) function. Do you see anything wrong with it? Especially with GetFinalPathNameByHandle (lpszFilePath, cchFilePath and dwFlags). I also got a suggestion to do a double call to avoid using 64K for FilePath but I don't see how I could optimize memory usage for that part.

Here is my current (working) function. Do you see anything wrong with it? Especially with GetFinalPathNameByHandle (lpszFilePath, cchFilePath and dwFlags).

Here is my current (working) function. Do you see anything wrong with it? Especially with GetFinalPathNameByHandle (lpszFilePath, cchFilePath and dwFlags). I also got a suggestion to do a double call to avoid using 64K for FilePath but I don't see how I could optimize memory usage for that part.

Source Link
AlexV
  • 141
  • 5

Is there anything wrong with my use of GetFinalPathNameByHandle (Windows API) in my Delphi program?

I'm building a small Delphi application where a user can input a file or directory manually by typing it or by selecting it from a dialog . Since it can be input manually, I want to ensure that I save that path as it is on the file system. For example: the user input c:\program files, the path is updated to C:\Program Files since it's how it's stored in the file system.

Here are the my requirements for the function:

  • The input can be a regular path, an UNC path or a \\?\ path.
  • If an invalid (or non-existent) path is provided, the function returns an empty string.
  • The function supports Unicode paths.
  • The function supports paths longer than MAX_PATH (yes it's possible).
  • The function returns "regular" paths (non \\?\ paths).

I'm coming back to Windows development under Delphi after a decade long pause (I've been working on Web services for a while now) so I'm out of touch with the Windows API and Delphi a bit.

Here is my current (working) function. Do you see anything wrong with it? Especially with GetFinalPathNameByHandle (lpszFilePath, cchFilePath and dwFlags).

function GetCaseSensitivePath(const APath: String): String;

const
    EXT_MAX_PATH = 32767;
    UNC_PREFIX = '\\';
    UNIFIED_PREFIX = '\\?\';
    UNIFIED_UNC_PREFIX = UNIFIED_PREFIX + 'UNC\';

var
    UnifiedPath: PWideChar;
    LinkHandle: THandle;
    FilePath: array [0..EXT_MAX_PATH] of WideChar;

begin
    if APath.StartsWith(UNIFIED_PREFIX) then
        UnifiedPath := PWideChar(APath)
    else
        UnifiedPath := PWideChar(IfThen(APath.StartsWith(UNC_PREFIX), UNIFIED_UNC_PREFIX + APath.Substring(Length(UNC_PREFIX)), UNIFIED_PREFIX + APath));

    LinkHandle := CreateFile(UnifiedPath, 0, FILE_SHARE_READ, nil, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);
    try
        Win32Check(LinkHandle <> INVALID_HANDLE_VALUE);
        try
            if GetFinalPathNameByHandle(LinkHandle, FilePath, Length(FilePath), VOLUME_NAME_DOS) > 0 then
            begin
                Result := FilePath;
                if UpperCase(Result.Substring(0, Length(UNIFIED_UNC_PREFIX))) = UNIFIED_UNC_PREFIX then
                    Result := UNC_PREFIX + Result.Substring(Length(UNIFIED_UNC_PREFIX))
                else if Result.StartsWith(UNIFIED_PREFIX) then
                    Result := Result.Substring(Length(UNIFIED_PREFIX));
            end
            else
                RaiseLastOSError;
        finally
            CloseHandle(LinkHandle);
        end;
    except
        on EOSError do
            Result := '';
    end;
end;