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-pathsso before call kernel we need convert
Win32-pathnoNT-pathfor path transformations exist some close functions
RtlDosPathNameTo*NtPathName*inntdllall transformations
Win32->NTpath 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-pathand convert it toNThere - so no any different - are sayGetFileAttributesWcalled 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();
}