7

For determining the canonical path to a file specified by relative path or a path containing \..\ in the middle, stackoverflow suggests using GetFullPathName() here or GetLongPathName() here.

What is the difference between these functions?

The intent is to get paths starting with the drive letter from relative paths (like ..\someDir\someFile.txt and someOtherDir\someFile.txt) and to eliminate extra \..\ from the paths (like C:\dirA\dirB\..\someFile.txt -> C:\dirA\someFile.txt).

Community
  • 1
  • 1
Serge Rogatch
  • 11,119
  • 4
  • 58
  • 117
  • 6
    Have you tried reading the references for e.g. [`GetFullPathName`](https://msdn.microsoft.com/en-us/library/windows/desktop/aa364963%28v=vs.85%29.aspx) and [`GetLongPathName`](https://msdn.microsoft.com/en-us/library/windows/desktop/aa364980%28v=vs.85%29.aspx)? – Some programmer dude Jul 06 '15 at 14:59
  • 1
    @JoachimPileborg, yes. Have you? It is not easy to catch the difference reliably by reading the references. I thought it would be easier to explain for someone who has experience with both. The problem was with e.g. PathCanonicalize not nearly canonicalizing the path, nevertheless its name says so. Only in Debug I realized that, then read the reference again and realized where that odd behavior of PathCanonicalize is documented. – Serge Rogatch Jul 06 '15 at 15:10
  • 1
    I spent a few minutes at those references and my confidence only dropped that I could authoritatively explain the difference. I'm looking forward to learning the answer. – Drew Dormann Jul 06 '15 at 15:18
  • 1
    One major difference, as I understand it, is that `GetFullPathName` does no long/short name conversion. So if you have `verlongnamehere` and pass it as `verylo~1` then `GetFullPathName` returns it as `verylo~1` while `GetLongPathName` converts it to the long version `verlongnamehere` (and `GetShortPathName` returns `verlongnamehere` as `verylo~1`). Also, `GetFullPathName` seems to be using some global state or such, making it non thread-safe or usable from a DLL. – Some programmer dude Jul 06 '15 at 15:24
  • @JoachimPileborg, how can GetLongPathName() canonicalize relative paths without getting current directory (the "global state") too? – Serge Rogatch Jul 06 '15 at 15:30
  • Well, who knows if that's the *only* global state? Also, `GetLongPathName` reference doesn't say anything about it actually resolving relative paths, only that it converts a path from its short form to its long form. `GetFullPathName` does the actual relative to absolute pathname resolution, which then can be passed to `GetLongPathName` or `GetShortPathName`. – Some programmer dude Jul 06 '15 at 15:33

1 Answers1

9

GetFullPathName resolves file names and relative path names to absolute paths, by prepending the current working directory of the calling process.

GetLongPathName only resolves short (8.3) names to long names.

Note that the latter requires disk access, so a relative path will be probably be resolved by using the current working directory, too.

tl;dr:
Call GetFullPathName to resolve a relative path to an absolute one.
Call GetLongPathName to resolve an absolute path that may contain a short (8.3) name to long name form.


Be careful:

Current working directory is a per-process resource, and can get changed e.g. by the standard file open dialog. I would use this only for resolving command line arguments that may be relative to the CWD the program was started in.

A long path name may not exist for every 8.3 named file.

peterchen
  • 38,919
  • 19
  • 95
  • 176
  • It seems you'are right and the text here http://pdh11.blogspot.com/2009/05/pathcanonicalize-versus-what-it-says-on.html confirms that "The plan is, use GetFullPathName() to turn relative paths into absolute, then repeatedly call QueryDosDevice() to unwind subst’d drive letters, then call GetLongPathName() to get rid of 8.3-ness and canonicalise case". So GetLongPathName() canonicalizes a relative path only if it starts with `.` or `..`. – Serge Rogatch Jul 06 '15 at 15:45
  • 2
    The docs say *GetFullPathName does not convert the specified file name, lpFileName. If the specified file name exists, you can use GetLongPathName or GetShortPathName to convert to long or short path names, respectively.* That seems to contradict the second paragraph of this answer. – David Heffernan Jul 06 '15 at 20:03
  • d'oh! removed incorrect informaiton, thanks @DavidHeffernan – peterchen Jul 07 '15 at 18:23