despite what is MSDN documentation say :
You can also enable the new long path behavior per app via the manifest:
in test i found that this is not a true. all test done on win10 1607.14393.447(and 14393.0) x64
when i test exe with and without manifest, i discover that manifest have no any effect for CreateFileW
, CreateDirectoryW
, (no sence test more function - why i explain later)
really when LongPathsEnabled
is 1 in registry - long paths worked (without \\?\
prefix). when it 0 - not worked, even if longPathAware
true
in manifest. (code below)
need understand next:
all file function in kernel work only with
NT-paths
so before call kernel we need convert
Win32-path
noNT-path
for path transformations exist some close functions
RtlDosPathNameTo*NtPathName*
inntdll
all transformations
Win32
->NT
path done centrally in this functions, but not direct inCreateFileW
,FindFirstFileW
,GetCompressedFileSizeW
... (other behavior would be extremely illogical)so really enough test 1,2 function, but not all under article (but if somebody not believe and want - let test :) )
- all this
kernel32
(andkernelbase
) api takeWin32-path
and convert it toNT
here - so no any different - are sayGetFileAttributesW
called direct from native c/c++ code or from managed runtime or app container - result will be the same - ALL dependent only from
RtlDosPathNameTo*NtPathName*
internal implementation
ntdll
now implement and export 2 new API
BOOLEAN NTAPI RtlIsLongPathAwareProcessByManifest();
BOOLEAN NTAPI RtlAreLongPathsEnabled();
RtlAreLongPathsEnabled
- looks only in registry (on first call) HKLM\SYSTEM\CurrentControlSet\Control\FileSystem @ LongPathsEnabled
cache result in static var and return true when LongPathsEnabled != 0
. this function called from RtlDosPathNameTo*NtPathName*
when Win32 path exceeds MAX_PATH
and only if long paths enabled - path is converted, otherwise STATUS_NAME_TOO_LONG
returned
RtlIsLongPathAwareProcessByManifest
- looks only in application manifest (by call RtlQueryActivationContextApplicationSettings(0, 0, L"http://schemas.microsoft.com/SMI/2016/WindowsSettings", L"longPathAware");
) when it first time called and again cache result in local static BOOLEAN.
if i not skip something - this function never called from ntdll
and called from kernebase.dll
only from one place - GetTempPathW
. so really result of RtlIsLongPathAwareProcessByManifest
can have effect only for GetTempPathW
result.
but when test this - i view that at all bug in current windows builds here - if length of TMP
environment variable (or TEMP
, etc.. but TMP
queried first) exceeded MAX_PATH
queried RtlAreLongPathsEnabled
and RtlIsLongPathAwareProcessByManifest
and if both returned true (so here AND
logic) - system try got this long TMP
path, but mistake with buffer size on one WCHAR
- as result we hang in infinite loop - [ *- > RtlAllocateHeap
-> STATUS_BUFFER_TOO_SMALL
-> RtlFreeHeap
-> RtlAllocateHeap
-> *]
are somebody can test and confirm or refute this ? not pass link to documentation, but really test.
code which i use for test (with and without correct manifest - confirmed by RtlIsLongPathAwareProcessByManifest
result)
BOOL CreateFolder(LPCWSTR lpPathName)
{
return CreateDirectoryW(lpPathName, 0) || GetLastError() == ERROR_ALREADY_EXISTS;
}
void LPT()
{
// check manifest and registry
BOOLEAN bByManifest = 0, bLongPathsEnabled = 0;
if (HMODULE hmod = GetModuleHandle(L"ntdll"))
{
BOOLEAN (NTAPI * RtlIsLongPathAwareProcessByManifest)();
BOOLEAN (NTAPI * RtlAreLongPathsEnabled)();
if (*(FARPROC*)&RtlIsLongPathAwareProcessByManifest = GetProcAddress(hmod, "RtlIsLongPathAwareProcessByManifest"))
{
bByManifest = RtlIsLongPathAwareProcessByManifest();
}
if (*(FARPROC*)&RtlAreLongPathsEnabled = GetProcAddress(hmod, "RtlAreLongPathsEnabled"))
{
bLongPathsEnabled = RtlAreLongPathsEnabled();
}
}
WCHAR name[128], path[0x8000], *c;
if (bLongPathsEnabled && bByManifest)
{
// hung test in GetTempPathW
__stosw((PUSHORT)path, 'x', MAX_PATH + 1);
path[MAX_PATH + 1] = 0;
if (SetEnvironmentVariable(L"TMP", path))
{
// hung here in infinite loop by windows error
// ---> buffer allocated on sizeof(WCHAR) less than required,
// | got STATUS_BUFFER_TOO_SMALL
// | -< free buffer
GetTempPathW(RTL_NUMBER_OF(path), path);// never return :)
}
}
if (!SHGetFolderPath(0, CSIDL_PROFILE , 0, 0, path))
{
*name = '\\';
__stosw((PUSHORT)name + 1, '3', RTL_NUMBER_OF(name) - 2);
name[RTL_NUMBER_OF(name) - 1] = 0;
c = path + wcslen(path);
int n = 4;
do
{
memcpy(c, name, sizeof(name));
c += RTL_NUMBER_OF(name) - 1;
if (!CreateFolder(path))
{
break;
}
} while (--n);
if (!n)
{
wcscpy(c, L"\\1.txt");
HANDLE hFile = CreateFileW(path, FILE_GENERIC_WRITE, FILE_SHARE_VALID_FLAGS, 0, OPEN_ALWAYS, 0, 0);
if (hFile != INVALID_HANDLE_VALUE)
{
CloseHandle(hFile);
return ;
}
}
}
GetLastError();
}