I am trying to use the GetShortPathName() function to give me the short version of two paths, but it succeeds in only one path and fails in the other path.
// Get the game directory path
wchar_t GameDirPath[MAX_PATH] = L"\0";
GetCurrentDirectory(MAX_PATH, GameDirPath);
// Get the engine directory path
wchar_t EngineDirPath[MAX_PATH] = L"\0";
wcscat(EngineDirPath, GameDirPath);
wcscat(EngineDirPath, L"\\Assets\\Engine\\");
// Get the short path of the engine directory
wchar_t EngineShortPath[MAX_PATH] = L"\0";
GetShortPathName(EngineDirPath, EngineShortPath, MAX_PATH);
The following gives me the correct short path:
D:\Games\NEEDFO~1\Assets\Engine\
But this one doesn't:
D:\Games\FIFA 97\Assets\Engine\
Note that the two examples exist in the same folder "Games".
In short:
I want to pass the path to "DOSBox.exe" as a parameter but it doesn't accept the windows paths like this "D:\Games\FIFA 97\Assets\Engine", so you must convert it to a DOS path like this "D:\Games\FIFA97~1\Assets\Engine", so, I try to use the GetShortPathName() function to do that mission.
Why does this problem happen, and how can I solve it?
As the documentation explicitly states:
If the specified path is already in its short form and conversion is not needed, the function simply copies the specified path to the buffer specified by the lpszShortPath parameter.
The API behaves as documented. There's nothing that needs to be fixed.
Back to 90s, when DOS OS was largely used, files and directories names were limited to a maximum length of 8 characters (8.3 format; meaning 8 bytes for the file name and 3 for the file extension).
So hello.txt file was admitted, and helloguys.txt (9 chars log) was "illegal".
With Windows this limitation has beeen removed, and short names have been introduced in order to convert paths to DOS compliant format.
Now that we know what a short path is, we can analyze your case. In path
D:\Games\Fifa 97\Assets\Engine\
every token is DOS compliant. So what is the short version of this path? Well, the path itself. And that's why GetShortPathName( ) returns an unchanged path.
You can find a wide description in docs page.
I am writing a File System Driver for Windows 7. I'm using the Dokan library. In the FindFiles function I want to set the 8.3 alternate name. I am assuming that will show up if I use dir /x but it doesn't. I have tried passing a null terminated string then changed to a blank padded (not null terminated) string as coded below. Neither one show the alternate name the dir /x.
See http://msdn.microsoft.com/en-us/library/windows/desktop/aa365740%28v=vs.85%29.aspx for a reference to cAlternateFileName in struct _WIN32_FIND_DATA.
Does anyone have any information on this?
Here is a clip from my code:
wsprintf(w_surfaceName, L"S%d-P%02x~1", pCartIDtable[count].dsmNumber, pCartIDtable[count].pltrNumber);
wp = wcschr(w_surfaceName, L'\0');
wmemset(wp, L' ', _countof(w_surfaceName) - (wp - w_surfaceName));
wmemcpy(findData.cAlternateFileName, w_surfaceName, _countof(findData.cAlternateFileName));
FillFindData(&findData, DokanFileInfo);
Either the file doesn't have an 8.3 short-name, or the field hasn't been filled in.
Some versions of Windows have short-name generation turned off by default. Some people have short-name generation turned of just to make the file system faster. Even if you have short-name generation turned on now, that doesn't retro-actively go and generate short names across your existing file system.
And the field is not filled in anyway if the request was only for "FindExInfoBasic".
Dokan does not support 8.3 short-names at this point. Progress for implementation of this feature is tracked at: https://github.com/dokan-dev/dokany/issues/301
Question
I am looking for something that would fulfil the expected semantics of an imagined isRemovable() method in the QFile class.
In QFile reference there is a permissions() method mentioned that returns a set of flags QFileDevice::Permission wich basically corresponds to file permissions. There is also isReadable() and isWritable() but how can I in a relatively portable way know with certainty that I would be able to remove (delete) a file without actually trying?
Answer
Short answers with short and simple source-code are preferred.
You can remove a file if you have permissions to write both to a file and to it's containing directory. So, the solution (which I've tested on Centos Linux) will be:
QFileInfo fileInfo(filepath);
QFileInfo dirInfo(fileInfo.path());
bool isRemovable = fileInfo.isWritable() && dirInfo.isWritable();
Is there a Windows API function that I can pass a string value to that will return a value indicating whether a file name is valid or not?
I need to verify that a file name is valid, and I'm looking for an easy way to do it without re-inventing the wheel. I'm working in straight C, but targeting the Win32 API.
If there's no such function built-in, how would I go about writing my own? Is there a general algorithm or pattern that Windows follows for determining file name validity?
The problem is not so simple, because it depends from what you consider a "valid file name".
The Windows APIs used with UNC paths will let you happily create a lot of names that are deemed invalid inside normal paths, since with the prefix \\?\ you are telling to the Windows APIs to just deliver the path to the filesystem driver, without performing any check; the filesystems themselves often do not really care about what it's used as a file name, once they know that some string is only the file name (i.e. the path/name split has already been done) they generally treat it just as an opaque sequence of characters.
On the other hand, if you want to play it safe, you should perform validation according to the rules specified by the MSDN document you already linked for Win32 names; I don't think that any file system is allowed to have more stringent rules than these on file naming. On the other hand, violating such requirements, although can be supported by the kernel itself, often give bad headaches to many "normal" applications that expect to deal with "traditional" Win32 paths.
But, in my opinion, if you have to create the file immediately, the best validation you can do is to try to actually create/open the file, letting the OS do such work for you, and be prepared to handle gracefully a failure (GetLastError should return ERROR_BAD_PATHNAME). This will check any other restriction you have on creating such file, e.g. that your application has the appropriate permissions, that the path is not on a readonly medium, ...
If, for some reason, this is not possible, you may like the shell function PathCleanupSpec: provided the requested file name and the directory in the file system where it has to be created, this function will remove all the invalid characters (I'm not sure about reserved DOS names, they are not listed in its documentation) making the path "probably valid" and notifying you if any modification was made (so you can use it also only for validation).
Notice that this function is marked as "modifiable or removable in any future Windows version", although Microsoft policy is generally that "anything that made it way to a public header will remain public forever".
In case you are checking if the file name is valid in the sense "can the file be named like this?" :
No, there is no function to directly check that. You will have to write you own function.
But, if you know what is a valid file name (the valid file name does now contain any of the following: \ / : * ? " < > |) that shouldn't be such a problem.
You could perhaps help your self with some of these functions from ctype.h (with them you can check if a specific character belongs to some specific character classes):
http://www.cplusplus.com/reference/clibrary/cctype/
This function gives you the list of invalid chars for a filename. Up to you to check that your filename doesn't contain any:
public static char[] Path.GetInvalidFileNameChars()
Docs here.
Note that if you want to validate a directory name, you should use GetInvalidPathChars().
EDIT: Oooops! Sorry, I thought you were on .NET. Using Reflector, here's what this functions boils down to:
'"', '<', '>', '|',
'\0', '\x0001', '\x0002', '\x0003', '\x0004', '\x0005', '\x0006',
'\a', '\b', '\t', '\n', '\v', '\f', '\r',
'\x000e', '\x000f', '\x0010', '\x0011', '\x0012', '\x0013', '\x0014', '\x0015',
'\x0016', '\x0017', '\x0018', '\x0019', '\x001a', '\x001b', '\x001c', '\x001d',
'\x001e', '\x001f',
':', '*', '?', '\\', '/'
Note that, in addition, there are reserved names such as prn, con, com1, com2,... , lpt1, lpt2,...
I am trying to use _findfirst() Windows API in C to match file name using wildcards.
If I am passing ????????.txt then I am expecting it will match all the files in a directory with 8 characters only, but it matches more than that.
Is there any thing wrong with this usage?
I would guess that it is matching on the short name. On windows all files have a long name and a DOS 8.3 short name. Therefore "????????.txt" is effectively the same as "*.txt".
Also on a pedantic note, _findfirst() is not part of the Windows API. Is it part of the Microsoft C run-time library.