@KeithMiller , 'C:\Temp\123' .
Delphi XE (so - Unicode!) article:
type
NTSTATUS = Cardinal;
TFileInformationClass = (
FileDirectoryInformation = 1,
FileFullDirectoryInformation,
FileBothDirectoryInformation,
FileBasicInformation,
FileStandardInformation,
FileInternalInformation,
FileEaInformation,
FileAccessInformation,
FileNameInformation,
FileRenameInformation,
FileLinkInformation,
FileNamesInformation,
FileDispositionInformation,
FilePositionInformation,
FileFullEaInformation,
FileModeInformation,
FileAlignmentInformation,
FileAllInformation,
FileAllocationInformation,
FileEndOfFileInformation,
FileAlternateNameInformation,
FileStreamInformation,
FilePipeInformation,
FilePipeLocalInformation,
FilePipeRemoteInformation,
FileMailslotQueryInformation,
FileMailslotSetInformation,
FileCompressionInformation,
FileObjectIdInformation,
FileCompletionInformation,
FileMoveClusterInformation,
FileQuotaInformation,
FileReparsePointInformation,
FileNetworkOpenInformation,
FileAttributeTagInformation,
FileTrackingInformation,
FileIdBothDirectoryInformation,
FileIdFullDirectoryInformation,
FileValidDataLengthInformation,
FileShortNameInformation,
FileIoCompletionNotificationInformation,
FileIoStatusBlockRangeInformation,
FileIoPriorityHintInformation,
FileSfioReserveInformation,
FileSfioVolumeInformation,
FileHardLinkInformation,
FileProcessIdsUsingFileInformation,
FileNormalizedNameInformation,
FileNetworkPhysicalNameInformation,
FileIdGlobalTxDirectoryInformation,
FileIsRemoteDeviceInformation,
FileAttributeCacheInformation,
FileNumaNodeInformation,
FileStandardLinkInformation,
FileRemoteProtocolInformation,
FileMaximumInformation
);
PIOStatusBlock = ^TIOStatusBlock;
TIOStatusBlock = packed record
case Boolean of
False: (Status: NTSTATUS; P: Pointer;);
True: (Information: ULONG_PTR);
end;
PFileStreamInformation = ^TFileStreamInformation;
TFileStreamInformation = packed record
NextEntryOffset: ULONG;
StreamNameLength: ULONG;
StreamSize: LARGE_INTEGER;
StreamAllocationSize: LARGE_INTEGER;
StreamName: array[0..0] of Char;
end;
type
TNtQueryInformationFile = function(FileHandle: THandle; IoStatusBlock: PIOStatusBlock;
FileInformation: Pointer; Length: ULONG; FileInformationClass: TFileInformationClass): NTSTATUS; stdcall;
procedure GetAlternateFileStreamNames(const FileName: string; StreamNames: TStrings);
var
hNT, hFile: THandle;
NtQueryInformationFile: TNtQueryInformationFile;
Buffer: array[Word] of Byte;
ioStatus: TIOStatusBlock;
P: PFileStreamInformation;
S: string;
L: Integer;
begin
hNT := GetModuleHandle('ntdll.dll');
if hNT = 0 then
Exit;
NtQueryInformationFile := GetProcAddress(hNT, 'NtQueryInformationFile');
if @NtQueryInformationFile = nil then
Exit;
FillChar(Buffer, SizeOf(Buffer), 0);
hFile := CreateFile(PChar(FileName), 0, FILE_SHARE_READ or FILE_SHARE_WRITE, nil, OPEN_EXISTING, 0, 0);
try
if NtQueryInformationFile(hFile, @ioStatus, @Buffer[0], SizeOf(Buffer), FileStreamInformation) = 0 then
begin
StreamNames.BeginUpdate;
try
StreamNames.Clear;
P := @Buffer[0];
while Assigned(P) do
begin
SetString(S, P^.StreamName, P^.StreamNameLength div SizeOf(Char));
// strip trailing :$DATA
L := Length(S);
if (L >= 6) and (StrComp(@S[L - 5], ':$DATA') = 0) then
Delete(S, L - 5, L);
StreamNames.Add(S);
if P^.NextEntryOffset = 0 then
P := nil
else
P := Pointer(Integer(P) + P^.NextEntryOffset); //@Buffer[P^.NextEntryOffset];
end;
finally
StreamNames.EndUpdate;
end;
end;
finally
CloseHandle(hFile);
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
StreamNames: TStringList;
begin
StreamNames := TStringList.Create;
try
GetAlternateFileStreamNames('C:\Temp\123', StreamNames);
ShowMessage(StreamNames.Text);
finally
StreamNames.Free;
end;
end;
, , , :
':' - ,':123.txt' -':345.txt' - second alternative stream
Completely untested and strange, it must also be changed for D2007 and earlier.