Files
2026-04-29 17:10:47 +02:00

3786 lines
148 KiB
C++

/*****************************************************************************/
/* Page06NtFileInfo.cpp Copyright (c) Ladislav Zezula 2005 */
/*---------------------------------------------------------------------------*/
/* Description : */
/*---------------------------------------------------------------------------*/
/* Date Ver Who Comment */
/* -------- ---- --- ------- */
/* 01.11.05 1.00 Lad The first version of Page06NtFileInfo.cpp */
/*****************************************************************************/
#include "FileTest.h"
#include "resource.h"
//-----------------------------------------------------------------------------
// Local defines
#define WM_RELOADITEMS (WM_USER + 0x1000)
#define WM_SHOW_DATE_FORMATS (WM_USER + 0x1001)
#define INITIAL_FILEINFO_BUFFER_SIZE 0x10000
static UNICODE_STRING NullString = RTL_CONSTANT_STRING(L"NULL");
//-----------------------------------------------------------------------------
// Description of data structures for file info classes
// Values for FILE_CASE_SENSITIVE_INFORMATION::Flags
static TFlagInfo CaseSensitiveFlags[] =
{
FLAGINFO_BITV(FILE_CS_FLAG_CASE_SENSITIVE_DIR),
FLAGINFO_END()
};
TStructMember FileStatBasicInformationMembers[] =
{
{_T("FileId"), TYPE_FILEID64, sizeof(LARGE_INTEGER)},
{_T("CreationTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastAccessTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastWriteTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("ChangeTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("AllocationSize"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("EndOfFile"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("FileAttributes"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember*)FileAttributesValues}},
{_T("ReparseTag"), TYPE_UINT32, sizeof(ULONG)},
{_T("NumberOfLinks"), TYPE_UINT32, sizeof(ULONG)},
{_T("DeviceType"), TYPE_UINT32, sizeof(ULONG)},
{_T("DeviceCharacteristics"), TYPE_UINT32, sizeof(ULONG)},
{_T("Reserved"), TYPE_UINT32, sizeof(ULONG)},
{_T("VolumeSerialNumber"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("FileId"), TYPE_FILEID128, sizeof(FILE_ID_128)},
{NULL}
};
TStructMember FileId64ExtdDirectoryInformationMembers[] =
{
{_T("NextEntryOffset"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileIndex"), TYPE_UINT32, sizeof(ULONG)},
{_T("CreationTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastAccessTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastWriteTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("ChangeTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("EndOfFile"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("AllocationSize"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("FileAttributes"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember*)FileAttributesValues}},
{_T("FileNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("EaSize"), TYPE_UINT32, sizeof(ULONG)},
{_T("ReparsePointTag"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileId"), TYPE_FILEID64, sizeof(LARGE_INTEGER)},
{_T("FileName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_ID_EXTD_DIR_INFORMATION, FileNameLength)},
{NULL}
};
TStructMember FileId64ExtdBothDirectoryInformationMembers[] =
{
{_T("NextEntryOffset"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileIndex"), TYPE_UINT32, sizeof(ULONG)},
{_T("CreationTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastAccessTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastWriteTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("ChangeTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("EndOfFile"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("AllocationSize"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("FileAttributes"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember*)FileAttributesValues}},
{_T("FileNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("EaSize"), TYPE_UINT32, sizeof(ULONG)},
{_T("ReparsePointTag"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileId"), TYPE_FILEID64, sizeof(LARGE_INTEGER)},
{_T("ShortNameLength"), TYPE_UINT8, sizeof(CCHAR)},
{_T("<padding>"), TYPE_PADDING, sizeof(WCHAR)},
{_T("ShortName"), TYPE_VNAME_FIEBD, sizeof(WCHAR[12])},
{_T("FileName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_ID_EXTD_DIR_INFORMATION, FileNameLength)},
{NULL}
};
TStructMember FileIdAllExtdDirectoryInformationMembers[] =
{
{_T("NextEntryOffset"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileIndex"), TYPE_UINT32, sizeof(ULONG)},
{_T("CreationTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastAccessTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastWriteTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("ChangeTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("EndOfFile"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("AllocationSize"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("FileAttributes"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember*)FileAttributesValues}},
{_T("FileNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("EaSize"), TYPE_UINT32, sizeof(ULONG)},
{_T("ReparsePointTag"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileId"), TYPE_FILEID64, sizeof(LARGE_INTEGER)},
{_T("FileId128"), TYPE_FILEID128, sizeof(FILE_ID_128)},
{_T("FileName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_ID_EXTD_DIR_INFORMATION, FileNameLength)},
{NULL}
};
TStructMember FileIdAllExtdBothDirectoryInformationMembers[] =
{
{_T("NextEntryOffset"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileIndex"), TYPE_UINT32, sizeof(ULONG)},
{_T("CreationTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastAccessTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastWriteTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("ChangeTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("EndOfFile"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("AllocationSize"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("FileAttributes"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember*)FileAttributesValues}},
{_T("FileNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("EaSize"), TYPE_UINT32, sizeof(ULONG)},
{_T("ReparsePointTag"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileId"), TYPE_FILEID64, sizeof(LARGE_INTEGER)},
{_T("FileId128"), TYPE_FILEID128, sizeof(FILE_ID_128)},
{_T("ShortNameLength"), TYPE_UINT8, sizeof(CCHAR)},
{_T("<padding>"), TYPE_PADDING, sizeof(WCHAR)},
{_T("ShortName"), TYPE_VNAME_FIEBD, sizeof(WCHAR[12])},
{_T("FileName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_ID_EXTD_DIR_INFORMATION, FileNameLength)},
{NULL}
};
// Values for FILE_FS_ATTRIBUTE_INFORMATION::FileSystemAttributes
TFlagInfo FileSystemAttributesValues[] =
{
FLAGINFO_BITV(FILE_CASE_SENSITIVE_SEARCH),
FLAGINFO_BITV(FILE_CASE_PRESERVED_NAMES),
FLAGINFO_BITV(FILE_UNICODE_ON_DISK),
FLAGINFO_BITV(FILE_PERSISTENT_ACLS),
FLAGINFO_BITV(FILE_FILE_COMPRESSION),
FLAGINFO_BITV(FILE_VOLUME_QUOTAS),
FLAGINFO_BITV(FILE_SUPPORTS_SPARSE_FILES),
FLAGINFO_BITV(FILE_SUPPORTS_REPARSE_POINTS),
FLAGINFO_BITV(FILE_SUPPORTS_REMOTE_STORAGE),
FLAGINFO_BITV(FILE_RETURNS_CLEANUP_RESULT_INFO),
FLAGINFO_BITV(FILE_SUPPORTS_POSIX_UNLINK_RENAME),
FLAGINFO_BITV(FILE_SUPPORTS_BYPASS_IO),
FLAGINFO_BITV(FILE_SUPPORTS_STREAM_SNAPSHOTS),
FLAGINFO_BITV(FILE_SUPPORTS_CASE_SENSITIVE_DIRS),
FLAGINFO_BITV(FILE_VOLUME_IS_COMPRESSED),
FLAGINFO_BITV(FILE_SUPPORTS_OBJECT_IDS),
FLAGINFO_BITV(FILE_SUPPORTS_ENCRYPTION),
FLAGINFO_BITV(FILE_NAMED_STREAMS),
FLAGINFO_BITV(FILE_READ_ONLY_VOLUME),
FLAGINFO_BITV(FILE_SEQUENTIAL_WRITE_ONCE),
FLAGINFO_BITV(FILE_SUPPORTS_TRANSACTIONS),
FLAGINFO_BITV(FILE_SUPPORTS_HARD_LINKS),
FLAGINFO_BITV(FILE_SUPPORTS_EXTENDED_ATTRIBUTES),
FLAGINFO_BITV(FILE_SUPPORTS_OPEN_BY_FILE_ID),
FLAGINFO_BITV(FILE_SUPPORTS_USN_JOURNAL),
FLAGINFO_BITV(FILE_SUPPORTS_INTEGRITY_STREAMS),
FLAGINFO_BITV(FILE_SUPPORTS_BLOCK_REFCOUNTING),
FLAGINFO_BITV(FILE_SUPPORTS_SPARSE_VDL),
FLAGINFO_BITV(FILE_DAX_VOLUME),
FLAGINFO_BITV(FILE_SUPPORTS_GHOSTING),
FLAGINFO_END()
};
TStructMember FileUnknownInformationMembers[] =
{
{_T("BinaryData"), TYPE_ARRAY8_VARIABLE, 0},
{NULL, TYPE_NONE, 0}
};
TStructMember FileDirectoryInformationMembers[] =
{
{_T("NextEntryOffset"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileIndex"), TYPE_UINT32, sizeof(ULONG)},
{_T("CreationTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastAccessTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastWriteTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("ChangeTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("EndOfFile"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("AllocationSize"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("FileAttributes"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileAttributesValues}},
{_T("FileNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileNameLength)},
{NULL}
};
TStructMember FileFullDirectoryInformationMembers[] =
{
{_T("NextEntryOffset"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileIndex"), TYPE_UINT32, sizeof(ULONG)},
{_T("CreationTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastAccessTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastWriteTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("ChangeTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("EndOfFile"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("AllocationSize"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("FileAttributes"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileAttributesValues}},
{_T("FileNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("EaSize"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_FULL_DIR_INFORMATION, FileNameLength)},
{NULL}
};
TStructMember FileBothDirectoryInformationMembers[] =
{
{_T("NextEntryOffset"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileIndex"), TYPE_UINT32, sizeof(ULONG)},
{_T("CreationTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastAccessTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastWriteTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("ChangeTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("EndOfFile"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("AllocationSize"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("FileAttributes"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileAttributesValues}},
{_T("FileNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("EaSize"), TYPE_UINT32, sizeof(ULONG)},
{_T("ShortNameLength"), TYPE_UINT8, sizeof(BYTE)}, // Although CCHAR, it has 2 bytes because of alignment
{_T("<padding>"), TYPE_PADDING, sizeof(WCHAR)},
{_T("ShortName"), TYPE_VNAME_FBDI, sizeof(WCHAR[12])},
{_T("FileName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileNameLength)},
{NULL}
};
TStructMember FileBasicInformationMembers[] =
{
{_T("CreationTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastAccessTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastWriteTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("ChangeTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("FileAttributes"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileAttributesValues}},
{NULL, TYPE_NONE, 0}
};
TStructMember FileStandardInformationMembers[] =
{
{_T("AllocationSize"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("EndOfFile"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("NumberOfLinks"), TYPE_UINT32, sizeof(ULONG)},
{_T("DeletePending"), TYPE_BOOLEAN, sizeof(BOOLEAN)},
{_T("Directory"), TYPE_BOOLEAN, sizeof(BOOLEAN)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileStandardInformationMembersEx[] =
{
{ _T("AllocationSize"), TYPE_UINT64, sizeof(LARGE_INTEGER) },
{ _T("EndOfFile"), TYPE_UINT64, sizeof(LARGE_INTEGER) },
{ _T("NumberOfLinks"), TYPE_UINT32, sizeof(ULONG) },
{ _T("DeletePending"), TYPE_BOOLEAN, sizeof(BOOLEAN) },
{ _T("Directory"), TYPE_BOOLEAN, sizeof(BOOLEAN) },
{ _T("AlternateStream"), TYPE_BOOLEAN, sizeof(BOOLEAN) },
{ _T("MetadataAttribute"), TYPE_BOOLEAN, sizeof(BOOLEAN) },
{ NULL, TYPE_NONE, 0 }
};
TStructMember FileInternalInformationMembers[] =
{
{_T("IndexNumber"), TYPE_FILEID64, sizeof(LARGE_INTEGER)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileEaInformationMembers[] =
{
{_T("EaSize"), TYPE_UINT32, sizeof(ULONG)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileAccessInformationMembers[] =
{
{_T("AccessFlags"), TYPE_FLAG32, sizeof(ACCESS_MASK), NULL, {(TStructMember *)AccessMaskValues}},
{NULL, TYPE_NONE, 0}
};
TStructMember FileNameInformationMembers[] =
{
{_T("FileNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_NAME_INFORMATION, FileNameLength)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileRenameInformationMembers[] =
{
{_T("ReplaceIfExists"), TYPE_BOOLEAN, sizeof(BOOLEAN)},
{_T("<padding>"), TYPE_PADDING, sizeof(HANDLE)},
{_T("RootDirectory"), TYPE_DIR_HANDLE, sizeof(HANDLE)},
{_T("FileNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_RENAME_INFORMATION, FileNameLength)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileLinkInformationMembers[] =
{
{_T("ReplaceIfExists"), TYPE_BOOLEAN, sizeof(ULONG)},
{_T("<padding>"), TYPE_PADDING, sizeof(HANDLE)},
{_T("RootDirectory"), TYPE_DIR_HANDLE, sizeof(HANDLE)},
{_T("FileNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_LINK_INFORMATION, FileNameLength)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileLinkEntryMembers[] =
{
{_T("NextEntryOffset"), TYPE_UINT32, sizeof(LARGE_INTEGER)}, // alignment
{_T("ParentFileId"), TYPE_FILEID64,sizeof(LARGE_INTEGER)},
{_T("FileNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileName"), TYPE_WNAME_L32W, FIELD_OFFSET(FILE_LINK_ENTRY_INFORMATION, FileNameLength)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileNamesInformationMembers[] =
{
{_T("NextEntryOffset"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileIndex"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_NAMES_INFORMATION, FileNameLength)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileDispositionInformationMembers[] =
{
{_T("DeleteFile"), TYPE_BOOLEAN, sizeof(BOOLEAN)},
{NULL, TYPE_NONE, 0}
};
TStructMember FilePositionInformationMembers[] =
{
{_T("CurrentByteOffset"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileFullEaInformationMembers[] =
{
{_T("NextEntryOffset"), TYPE_UINT32, sizeof(ULONG)},
{_T("Flags"), TYPE_UINT8, sizeof(UCHAR)},
{_T("EaNameLength"), TYPE_UINT8, sizeof(UCHAR)},
{_T("EaValueLength"), TYPE_UINT16, sizeof(USHORT)},
{_T("EaName"), TYPE_CNAME_L8B, FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaNameLength)},
// {_T("EaValue"), TYPE_ARRAY, FIELD_OFFSET(FILE_FULL_EA_INFORMATION, EaValueLength)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileModeInformationMembers[] =
{
{_T("Mode"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)CreateOptionsValues}},
{NULL, TYPE_NONE, 0}
};
static TFlagInfo FileAlignmentValues[] =
{
FLAGINFO_NUMV(FILE_BYTE_ALIGNMENT),
FLAGINFO_NUMV(FILE_WORD_ALIGNMENT),
FLAGINFO_NUMV(FILE_LONG_ALIGNMENT),
FLAGINFO_NUMV(FILE_QUAD_ALIGNMENT),
FLAGINFO_NUMV(FILE_OCTA_ALIGNMENT),
FLAGINFO_NUMV(FILE_32_BYTE_ALIGNMENT),
FLAGINFO_NUMV(FILE_64_BYTE_ALIGNMENT),
FLAGINFO_NUMV(FILE_128_BYTE_ALIGNMENT),
FLAGINFO_NUMV(FILE_256_BYTE_ALIGNMENT),
FLAGINFO_NUMV(FILE_512_BYTE_ALIGNMENT),
FLAGINFO_END()
};
TStructMember FileAlignmentInformationMembers[] =
{
{_T("AlignmentRequirement"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileAlignmentValues}},
{NULL, TYPE_NONE, 0}
};
TStructMember FileAllInformationMembers[] =
{
{_T("FILE_BASIC_INFORMATION"), TYPE_STRUCT, sizeof(FILE_BASIC_INFORMATION), NULL, {FileBasicInformationMembers}},
{_T("FILE_STANDARD_INFORMATION"), TYPE_STRUCT, sizeof(FILE_STANDARD_INFORMATION), NULL, {FileStandardInformationMembers}},
{_T("FILE_INTERNAL_INFORMATION"), TYPE_STRUCT, sizeof(FILE_INTERNAL_INFORMATION), NULL, {FileInternalInformationMembers}},
{_T("FILE_EA_INFORMATION"), TYPE_STRUCT, sizeof(FILE_EA_INFORMATION), NULL, {FileEaInformationMembers}},
{_T("FILE_ACCESS_INFORMATION"), TYPE_STRUCT, sizeof(FILE_ACCESS_INFORMATION), NULL, {FileAccessInformationMembers}},
{_T("FILE_POSITION_INFORMATION"), TYPE_STRUCT, sizeof(FILE_POSITION_INFORMATION), NULL, {FilePositionInformationMembers}},
{_T("FILE_MODE_INFORMATION"), TYPE_STRUCT, sizeof(FILE_MODE_INFORMATION), NULL, {FileModeInformationMembers}},
{_T("FILE_ALIGNMENT_INFORMATION"),TYPE_STRUCT, sizeof(FILE_ALIGNMENT_INFORMATION), NULL, {FileAlignmentInformationMembers}},
{_T("FILE_NAME_INFORMATION"), TYPE_STRUCT, sizeof(FILE_NAME_INFORMATION), NULL, {FileNameInformationMembers}},
{NULL, TYPE_NONE, 0}
};
TStructMember FileAllocationInformationMembers[] =
{
{_T("AllocationSize"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileEndOfFileInformationMembers[] =
{
{_T("EndOfFile"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{NULL, TYPE_NONE, 0}
};
#define FileAlternateNameInformationMembers FileNameInformationMembers
TStructMember FileStreamInformationMembers[] =
{
{_T("NextEntryOffset"), TYPE_UINT32, sizeof(ULONG)},
{_T("StreamNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("StreamSize"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("StreamAllocationSize"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("StreamName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_STREAM_INFORMATION, StreamNameLength)},
{NULL, TYPE_NONE, 0}
};
static TFlagInfo FilePipeReadModeValues[] =
{
FLAGINFO_NUMV(FILE_PIPE_BYTE_STREAM_MODE),
FLAGINFO_NUMV(FILE_PIPE_MESSAGE_MODE),
FLAGINFO_END()
};
static TFlagInfo FilePipeCompletionModeValues[] =
{
FLAGINFO_NUMV(FILE_PIPE_QUEUE_OPERATION),
FLAGINFO_NUMV(FILE_PIPE_COMPLETE_OPERATION),
FLAGINFO_END()
};
TStructMember FilePipeInformationMembers[] =
{
{_T("ReadMode"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FilePipeReadModeValues}},
{_T("CompletionMode"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FilePipeCompletionModeValues}},
{NULL, TYPE_NONE, 0}
};
static TFlagInfo FilePipeTypeValues[] =
{
FLAGINFO_MASK(FILE_PIPE_BYTE_STREAM_TYPE | FILE_PIPE_MESSAGE_TYPE, FILE_PIPE_BYTE_STREAM_MODE),
FLAGINFO_MASK(FILE_PIPE_BYTE_STREAM_TYPE | FILE_PIPE_MESSAGE_TYPE, FILE_PIPE_MESSAGE_TYPE),
FLAGINFO_BITV(FILE_PIPE_REJECT_REMOTE_CLIENTS),
FLAGINFO_END()
};
static TFlagInfo FilePipeConfigurationValues[] =
{
FLAGINFO_NUMV(FILE_PIPE_INBOUND),
FLAGINFO_NUMV(FILE_PIPE_OUTBOUND),
FLAGINFO_NUMV(FILE_PIPE_FULL_DUPLEX),
FLAGINFO_END()
};
static TFlagInfo FilePipeStateValues[] =
{
FLAGINFO_NUMV(FILE_PIPE_DISCONNECTED_STATE),
FLAGINFO_NUMV(FILE_PIPE_LISTENING_STATE),
FLAGINFO_NUMV(FILE_PIPE_CONNECTED_STATE),
FLAGINFO_NUMV(FILE_PIPE_CLOSING_STATE),
FLAGINFO_END()
};
static TFlagInfo FilePipeEndValues[] =
{
FLAGINFO_NUMV(FILE_PIPE_CLIENT_END),
FLAGINFO_NUMV(FILE_PIPE_SERVER_END),
FLAGINFO_END()
};
TStructMember FilePipeLocalInformationMembers[] =
{
{_T("NamedPipeType"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FilePipeTypeValues}},
{_T("NamedPipeConfiguration"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FilePipeConfigurationValues}},
{_T("MaximumInstances"), TYPE_UINT32, sizeof(ULONG)},
{_T("CurrentInstances"), TYPE_UINT32, sizeof(ULONG)},
{_T("InboundQuota"), TYPE_UINT32, sizeof(ULONG)},
{_T("ReadDataAvailable"), TYPE_UINT32, sizeof(ULONG)},
{_T("OutboundQuota"), TYPE_UINT32, sizeof(ULONG)},
{_T("WriteQuotaAvailable"), TYPE_UINT32, sizeof(ULONG)},
{_T("NamedPipeState"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FilePipeStateValues}},
{_T("NamedPipeEnd"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FilePipeEndValues}},
{NULL, TYPE_NONE, 0}
};
TStructMember FilePipeRemoteInformationMembers[] =
{
{_T("CollectDataTime"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("MaximumCollectionCount"), TYPE_UINT32, sizeof(ULONG)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileMailslotQueryInformationMembers[] =
{
{_T("MaximumMessageSize"), TYPE_UINT32, sizeof(ULONG)},
{_T("MailslotQuota"), TYPE_UINT32, sizeof(ULONG)},
{_T("NextMessageSize"), TYPE_UINT32, sizeof(ULONG)},
{_T("MessagesAvailable"), TYPE_UINT32, sizeof(ULONG)},
{_T("ReadTimeout"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileMailslotSetInformationMembers[] =
{
{_T("ReadTimeout"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{NULL, TYPE_NONE, 0}
};
static TFlagInfo FileCompressionFormatValues[] =
{
FLAGINFO_NUMV(COMPRESSION_FORMAT_NONE),
FLAGINFO_NUMV(COMPRESSION_FORMAT_DEFAULT),
FLAGINFO_NUMV(COMPRESSION_FORMAT_LZNT1),
FLAGINFO_END()
};
TStructMember FileCompressionInformationMembers[] =
{
{_T("CompressedFileSize"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("CompressionFormat"), TYPE_FLAG16, sizeof(USHORT), NULL, {(TStructMember *)FileCompressionFormatValues}},
{_T("CompressionUnitShift"), TYPE_UINT8, sizeof(UCHAR)},
{_T("ChunkShift"), TYPE_UINT8, sizeof(UCHAR)},
{_T("ClusterShift"), TYPE_UINT8, sizeof(UCHAR)},
{_T("Reserved[0]"), TYPE_UINT8, sizeof(UCHAR)},
{_T("Reserved[1]"), TYPE_UINT8, sizeof(UCHAR)},
{_T("Reserved[2]"), TYPE_UINT8, sizeof(UCHAR)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileObjectIdInformationMembers[] =
{
{_T("FileReference"), TYPE_FILEID64, sizeof(LONGLONG)},
{_T("ObjectId"), TYPE_FILEID128, sizeof(UCHAR[16])},
{_T("BirthVolumeId"), TYPE_GUID, sizeof(UCHAR[16])},
{_T("BirthObjectId"), TYPE_FILEID128, sizeof(UCHAR[16])},
{_T("DomainId"), TYPE_GUID, sizeof(UCHAR[16])},
{NULL, TYPE_NONE, 0}
};
TStructMember FileCompletionInformationMembers[] =
{
{_T("Port"), TYPE_HANDLE, sizeof(HANDLE)},
{_T("Key"), TYPE_POINTER, sizeof(PVOID)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileMoveClusterInformationMembers[] =
{
{_T("ClusterCount"), TYPE_UINT32, sizeof(ULONG)},
{_T("<padding>"), TYPE_PADDING, sizeof(HANDLE)},
{_T("RootDirectory"), TYPE_DIR_HANDLE, sizeof(HANDLE)},
{_T("FileNameLength"), TYPE_FILETIME, sizeof(ULONG)},
{_T("FileName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_MOVE_CLUSTER_INFORMATION, FileNameLength)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileQuotaInformationMembers[] =
{
{_T("NextEntryOffset"), TYPE_UINT32, sizeof(ULONG)},
{_T("SidLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("ChangeTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("QuotaUsed"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("QuotaThreshold"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("QuotaLimit"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("Sid"), TYPE_SID, sizeof(SID)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileReparsePointInformationMembers[] =
{
{_T("FileReference"), TYPE_FILEID64, sizeof(LONGLONG)},
{_T("Tag"), TYPE_UINT32, sizeof(ULONG)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileNetworkOpenInformationMembers[] =
{
{_T("CreationTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastAccessTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastWriteTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("ChangeTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("AllocationSize"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("EndOfFile"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("FileAttributes"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileAttributesValues}},
{NULL, TYPE_NONE, 0}
};
TStructMember FileAttributeTagInformationMembers[] =
{
{_T("FileAttributes"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileAttributesValues}},
{_T("ReparseTag"), TYPE_UINT32, sizeof(ULONG)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileTrackingInformationMembers[] =
{
{_T("DestinationFile"), TYPE_HANDLE, sizeof(HANDLE)},
{_T("ObjectInformationLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("ObjectInformation"), TYPE_UINT8, sizeof(CHAR)}, // TODO: TYPE_FTI_NAME
{NULL, TYPE_NONE, 0}
};
TStructMember FileIdBothDirectoryInformationMembers[] =
{
{_T("NextEntryOffset"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileIndex"), TYPE_UINT32, sizeof(ULONG)},
{_T("CreationTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastAccessTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastWriteTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("ChangeTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("EndOfFile"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("AllocationSize"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("FileAttributes"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileAttributesValues}},
{_T("FileNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("EaSize"), TYPE_UINT32, sizeof(ULONG)},
{_T("ShortNameLength"), TYPE_UINT8, sizeof(BYTE)}, // Although CCHAR, it has 2 bytes because of alignment
{_T("<padding>"), TYPE_PADDING, sizeof(WCHAR)},
{_T("ShortName"), TYPE_VNAME_FIBD, sizeof(WCHAR[13])}, // One more WCHAR due to alignment
{_T("FileId"), TYPE_FILEID64, sizeof(LARGE_INTEGER)},
{_T("FileName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_ID_BOTH_DIR_INFORMATION, FileNameLength)},
{NULL}
};
TStructMember FileIdFullDirectoryInformationMembers[] =
{
{_T("NextEntryOffset"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileIndex"), TYPE_UINT32, sizeof(ULONG)},
{_T("CreationTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastAccessTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastWriteTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("ChangeTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("EndOfFile"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("AllocationSize"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("FileAttributes"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileAttributesValues}},
{_T("FileNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("EaSize"), TYPE_UINT32, sizeof(LARGE_INTEGER)}, // Size is larger due to alignment
{_T("FileId"), TYPE_FILEID64, sizeof(LARGE_INTEGER)},
{_T("FileName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_ID_FULL_DIR_INFORMATION, FileNameLength)},
{NULL}
};
TStructMember FileValidDataLengthInformationMembers[] =
{
{_T("ValidDataLength"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{NULL, TYPE_NONE, 0}
};
#define FileShortNameInformationMembers FileNameInformationMembers
TStructMember FileIoCompletionNotificationInformationMembers[] =
{
{_T("Flags"), TYPE_UINT32, sizeof(ULONG)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileIoStatusBlockRangeInformationMembers[] =
{
{_T("IoStatusBlockRange"), TYPE_POINTER, sizeof(void *)},
{_T("Length"), TYPE_UINT32, sizeof(ULONG)},
{NULL, TYPE_NONE, 0}
};
static TFlagInfo IoPriorityHintValues[] =
{
FLAGINFO_NUMV(IoPriorityVeryLow),
FLAGINFO_NUMV(IoPriorityLow),
FLAGINFO_NUMV(IoPriorityNormal),
FLAGINFO_NUMV(IoPriorityHigh),
FLAGINFO_NUMV(IoPriorityCritical),
FLAGINFO_END()
};
TStructMember FileIoPriorityHintInformationMembers[] =
{
{_T("PriorityHint"), TYPE_FLAG32, sizeof(IO_PRIORITY_HINT), NULL, {(TStructMember *)IoPriorityHintValues}},
{NULL, TYPE_NONE, 0}
};
TStructMember FileSfioReserveInformationMembers[] =
{
{_T("RequestsPerPeriod"), TYPE_UINT32, sizeof(ULONG)},
{_T("Period"), TYPE_UINT32, sizeof(ULONG)},
{_T("RetryFailures"), TYPE_BOOLEAN, sizeof(BOOLEAN)},
{_T("Discardable"), TYPE_BOOLEAN, sizeof(BOOLEAN)},
{_T("<padding>"), TYPE_PADDING, sizeof(ULONG)},
{_T("RequestSize"), TYPE_UINT32, sizeof(ULONG)},
{_T("NumOutstandingRequests"), TYPE_UINT32, sizeof(ULONG)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileSfioVolumeInformationMembers[] =
{
{_T("MaximumRequestsPerPeriod"), TYPE_UINT32, sizeof(ULONG)},
{_T("MinimumPeriod"), TYPE_UINT32, sizeof(ULONG)},
{_T("MinimumTransferSize"),TYPE_UINT32, sizeof(ULONG)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileHardLinkInformationMembers[] =
{
{_T("BytesNeeded"), TYPE_UINT32, sizeof(ULONG)},
{_T("EntriesReturned"), TYPE_UINT32, sizeof(ULONG)},
{_T("Entry"), TYPE_CHAINED_STRUCT, 0, NULL, FileLinkEntryMembers},
{NULL, TYPE_NONE, 0}
};
TStructMember FileProcessIdsUsingFileInformationMembers[] =
{
{_T("NumberOfProcessIdsInList"), TYPE_UINT32, sizeof(ULONG)},
{_T("<padding>"), TYPE_PADDING, sizeof(HANDLE)},
{_T("ProcessIdList"), TYPE_ARRAY_PROCESS, FIELD_OFFSET(FILE_PROCESS_IDS_USING_FILE_INFORMATION, NumberOfProcessIdsInList)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileNetworkPhysicalNameInformationMembers[] =
{
{_T("FileNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_NAME_INFORMATION, FileNameLength)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileNormalizedNameInformationMembers[] =
{
{_T("FileNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_NAME_INFORMATION, FileNameLength)},
{NULL, TYPE_NONE, 0}
};
TFlagInfo FileTxFlagsValues[] =
{
FLAGINFO_BITV(FILE_ID_GLOBAL_TX_DIR_INFO_FLAG_WRITELOCKED),
FLAGINFO_BITV(FILE_ID_GLOBAL_TX_DIR_INFO_FLAG_VISIBLE_TO_TX),
FLAGINFO_BITV(FILE_ID_GLOBAL_TX_DIR_INFO_FLAG_VISIBLE_OUTSIDE_TX),
FLAGINFO_END()
};
TStructMember FileIdGlobalTxDirectoryInformationMembers[] =
{
{_T("NextEntryOffset"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileIndex"), TYPE_UINT32, sizeof(ULONG)},
{_T("CreationTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastAccessTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastWriteTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("ChangeTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("EndOfFile"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("AllocationSize"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("FileAttributes"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileAttributesValues}},
{_T("FileNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileId"), TYPE_FILEID64, sizeof(LARGE_INTEGER)},
{_T("LockingTransactionId"), TYPE_GUID, sizeof(GUID)},
{_T("TxInfoFlags"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileTxFlagsValues}},
{_T("FileName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_ID_GLOBAL_TX_DIR_INFORMATION, FileNameLength)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileIsRemoteDeviceInformationMembers[] =
{
{_T("IsRemote"), TYPE_BOOLEAN, sizeof(BOOLEAN)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileNumaNodeInformationMembers[] =
{
{_T("NodeNumber"), TYPE_UINT32, sizeof(ULONG)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileStandardLinkInformationMembers[] =
{
{_T("NumberOfAccessibleLinks"), TYPE_UINT32, sizeof(ULONG)},
{_T("TotalNumberOfLinks"), TYPE_UINT32, sizeof(ULONG)},
{_T("DeletePending"), TYPE_BOOLEAN, sizeof(BOOLEAN)},
{_T("Directory"), TYPE_BOOLEAN, sizeof(BOOLEAN)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileRemoteProtocolInformationMembers[] =
{
{_T("StructureVersion"), TYPE_UINT16, sizeof(USHORT)},
{_T("StructureSize"), TYPE_UINT16, sizeof(USHORT)},
{_T("Protocol"), TYPE_UINT32, sizeof(ULONG)},
{_T("ProtocolMajorVersion"), TYPE_UINT16, sizeof(USHORT)},
{_T("ProtocolMinorVersion"), TYPE_UINT16, sizeof(USHORT)},
{_T("ProtocolRevision"), TYPE_UINT16, sizeof(USHORT)},
{_T("Reserved"), TYPE_UINT16, sizeof(USHORT)},
{_T("GenericReserved.Reserved[0x0]"), TYPE_UINT32, sizeof(ULONG)},
{_T("GenericReserved.Reserved[0x1]"), TYPE_UINT32, sizeof(ULONG)},
{_T("GenericReserved.Reserved[0x2]"), TYPE_UINT32, sizeof(ULONG)},
{_T("GenericReserved.Reserved[0x3]"), TYPE_UINT32, sizeof(ULONG)},
{_T("GenericReserved.Reserved[0x4]"), TYPE_UINT32, sizeof(ULONG)},
{_T("GenericReserved.Reserved[0x5]"), TYPE_UINT32, sizeof(ULONG)},
{_T("GenericReserved.Reserved[0x6]"), TYPE_UINT32, sizeof(ULONG)},
{_T("GenericReserved.Reserved[0x7]"), TYPE_UINT32, sizeof(ULONG)},
{_T("ProtocolReserved.Reserved[0x0]"), TYPE_UINT32, sizeof(ULONG)},
{_T("ProtocolReserved.Reserved[0x1]"), TYPE_UINT32, sizeof(ULONG)},
{_T("ProtocolReserved.Reserved[0x2]"), TYPE_UINT32, sizeof(ULONG)},
{_T("ProtocolReserved.Reserved[0x3]"), TYPE_UINT32, sizeof(ULONG)},
{_T("ProtocolReserved.Reserved[0x4]"), TYPE_UINT32, sizeof(ULONG)},
{_T("ProtocolReserved.Reserved[0x5]"), TYPE_UINT32, sizeof(ULONG)},
{_T("ProtocolReserved.Reserved[0x6]"), TYPE_UINT32, sizeof(ULONG)},
{_T("ProtocolReserved.Reserved[0x7]"), TYPE_UINT32, sizeof(ULONG)},
{_T("ProtocolReserved.Reserved[0x8]"), TYPE_UINT32, sizeof(ULONG)},
{_T("ProtocolReserved.Reserved[0x9]"), TYPE_UINT32, sizeof(ULONG)},
{_T("ProtocolReserved.Reserved[0xA]"), TYPE_UINT32, sizeof(ULONG)},
{_T("ProtocolReserved.Reserved[0xB]"), TYPE_UINT32, sizeof(ULONG)},
{_T("ProtocolReserved.Reserved[0xC]"), TYPE_UINT32, sizeof(ULONG)},
{_T("ProtocolReserved.Reserved[0xD]"), TYPE_UINT32, sizeof(ULONG)},
{_T("ProtocolReserved.Reserved[0xE]"), TYPE_UINT32, sizeof(ULONG)},
{_T("ProtocolReserved.Reserved[0xF]"), TYPE_UINT32, sizeof(ULONG)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileVolumeNameInformationMembers[] =
{
{_T("DeviceNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("DeviceName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_VOLUME_NAME_INFORMATION, DeviceNameLength)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileIdInformationMembers[] =
{
{_T("VolumeSerialNumber"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("FileId"), TYPE_FILEID128, sizeof(FILE_ID_128)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileIdExtdDirectoryInformationMembers[] =
{
{_T("NextEntryOffset"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileIndex"), TYPE_UINT32, sizeof(ULONG)},
{_T("CreationTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastAccessTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastWriteTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("ChangeTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("EndOfFile"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("AllocationSize"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("FileAttributes"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileAttributesValues}},
{_T("FileNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("EaSize"), TYPE_UINT32, sizeof(ULONG)},
{_T("ReparsePointTag"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileId"), TYPE_FILEID128, sizeof(FILE_ID_128)},
{_T("FileName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_ID_EXTD_DIR_INFORMATION, FileNameLength)},
{NULL}
};
TStructMember FileHardLinkFullIdInformationMembers[] =
{
{_T("NextEntryOffset"), TYPE_UINT32, sizeof(ULONG)},
{_T("<alignment>"), TYPE_UINT32, sizeof(ULONG)},
{_T("ParentFileId"), TYPE_FILEID128, sizeof(FILE_ID_128)},
{_T("FileName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_LINK_ENTRY_FULL_ID_INFORMATION, FileNameLength)},
{NULL}
};
TStructMember FileIdExtdBothDirectoryInformationMembers[] =
{
{_T("NextEntryOffset"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileIndex"), TYPE_UINT32, sizeof(ULONG)},
{_T("CreationTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastAccessTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastWriteTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("ChangeTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("EndOfFile"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("AllocationSize"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("FileAttributes"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileAttributesValues}},
{_T("FileNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("EaSize"), TYPE_UINT32, sizeof(ULONG)},
{_T("ReparsePointTag"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileId"), TYPE_FILEID128, sizeof(FILE_ID_128)},
{_T("ShortNameLength"), TYPE_UINT8, sizeof(BYTE)}, // Although CCHAR, it has 2 bytes because of alignment
{_T("<padding>"), TYPE_PADDING, sizeof(WCHAR)},
{_T("ShortName"), TYPE_VNAME_FIEBD, sizeof(WCHAR[12])},
{_T("FileName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_BOTH_DIR_INFORMATION, FileNameLength)},
{NULL}
};
TFlagInfo FileDispositionInformationExValues[] =
{
// FLAGINFO_BITV(FILE_DISPOSITION_DO_NOT_DELETE), // Zero; not an actual flag
FLAGINFO_BITV(FILE_DISPOSITION_DELETE),
FLAGINFO_BITV(FILE_DISPOSITION_POSIX_SEMANTICS),
FLAGINFO_BITV(FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK),
FLAGINFO_BITV(FILE_DISPOSITION_ON_CLOSE),
FLAGINFO_BITV(FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE),
FLAGINFO_END()
};
TStructMember FileDispositionInformationExMembers[] =
{
{ _T("DispositionFlags"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileDispositionInformationExValues}},
{ NULL, TYPE_NONE, 0 }
};
TFlagInfo FileRenameInformationExValues[] =
{
FLAGINFO_BITV(FILE_RENAME_REPLACE_IF_EXISTS),
FLAGINFO_BITV(FILE_RENAME_POSIX_SEMANTICS),
FLAGINFO_BITV(FILE_RENAME_SUPPRESS_PIN_STATE_INHERITANCE),
FLAGINFO_BITV(FILE_RENAME_SUPPRESS_STORAGE_RESERVE_INHERITANCE),
FLAGINFO_BITV(FILE_RENAME_NO_INCREASE_AVAILABLE_SPACE),
FLAGINFO_BITV(FILE_RENAME_NO_DECREASE_AVAILABLE_SPACE),
FLAGINFO_BITV(FILE_RENAME_IGNORE_READONLY_ATTRIBUTE),
FLAGINFO_BITV(FILE_RENAME_FORCE_RESIZE_TARGET_SR),
FLAGINFO_BITV(FILE_RENAME_FORCE_RESIZE_SOURCE_SR),
FLAGINFO_END()
};
TStructMember FileRenameInformationExMembers[] =
{
{ _T("Flags"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileRenameInformationExValues}},
{ _T("<padding>"), TYPE_PADDING, sizeof(HANDLE) },
{ _T("RootDirectory"), TYPE_DIR_HANDLE, sizeof(HANDLE) },
{ _T("FileNameLength"), TYPE_UINT32, sizeof(ULONG) },
{ _T("FileName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_RENAME_INFORMATION_EX, FileNameLength) },
{ NULL, TYPE_NONE, 0 }
};
TFlagInfo FileStorageClassValues[] =
{
FLAGINFO_NUMV(FileStorageTierClassUnspecified),
FLAGINFO_NUMV(FileStorageTierClassCapacity),
FLAGINFO_NUMV(FileStorageTierClassPerformance),
FLAGINFO_END()
};
TFlagInfo FileStorageFlagsValues[] =
{
FLAGINFO_BITV(QUERY_STORAGE_CLASSES_FLAGS_MEASURE_WRITE),
FLAGINFO_BITV(QUERY_STORAGE_CLASSES_FLAGS_MEASURE_READ),
FLAGINFO_END()
};
TStructMember FileDesiredStorageClassInformationMembers[] =
{
{_T("Class"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileStorageClassValues}},
{_T("Flags"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileStorageFlagsValues}},
{ NULL }
};
TStructMember FileStatInformationMembers[] =
{
{_T("FileId"), TYPE_FILEID64, sizeof(LARGE_INTEGER)},
{_T("CreationTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastAccessTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastWriteTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("ChangeTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("AllocationSize"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("EndOfFile"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("FileAttributes"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileAttributesValues}},
{_T("ReparseTag"), TYPE_UINT32, sizeof(ULONG)},
{_T("NumberOfLinks"), TYPE_UINT32, sizeof(ULONG)},
{_T("EffectiveAccess"), TYPE_FLAG32, sizeof(ACCESS_MASK), NULL, {(TStructMember *)AccessMaskValues}},
{ NULL, TYPE_NONE, 0 }
};
TStructMember FileMemoryPartitionInformationMembers[] =
{
{_T("OwnerPartitionHandle"), TYPE_HANDLE, sizeof(TYPE_HANDLE)},
{_T("AllFlags"), TYPE_UINT32, sizeof(UINT32)},
{ NULL, TYPE_NONE, 0 }
};
TFlagInfo FileLxFlagsValues[] =
{
FLAGINFO_BITV(LX_FILE_METADATA_HAS_UID),
FLAGINFO_BITV(LX_FILE_METADATA_HAS_GID),
FLAGINFO_BITV(LX_FILE_METADATA_HAS_MODE),
FLAGINFO_BITV(LX_FILE_METADATA_HAS_DEVICE_ID),
FLAGINFO_BITV(LX_FILE_CASE_SENSITIVE_DIR),
FLAGINFO_END()
};
TStructMember FileStatLxInformationMembers[] =
{
{_T("FileId"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("CreationTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastAccessTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("LastWriteTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("ChangeTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("AllocationSize"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("EndOfFile"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("FileAttributes"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileAttributesValues}},
{_T("ReparseTag"), TYPE_UINT32, sizeof(ULONG)},
{_T("NumberOfLinks"), TYPE_UINT32, sizeof(ULONG)},
{_T("AccessMask"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)AccessMaskValues}},
{_T("EffectiveAccess"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)AccessMaskValues}},
{_T("LxFlags"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileLxFlagsValues}},
{_T("LxUid"), TYPE_UINT32, sizeof(ULONG)},
{_T("LxGid"), TYPE_UINT32, sizeof(ULONG)},
{_T("LxMode"), TYPE_UINT32, sizeof(ULONG)},
{_T("LxDeviceIdMajor"), TYPE_UINT32, sizeof(ULONG)},
{_T("LxDeviceIdMinor"), TYPE_UINT32, sizeof(ULONG)},
{ NULL, TYPE_NONE, 0 }
};
TStructMember FileCaseSensitiveInformationMembers[] =
{
{_T("Flags"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)CaseSensitiveFlags}},
{ NULL, TYPE_NONE, 0 }
};
TFlagInfo FileLinkInformationExValues[] =
{
FLAGINFO_BITV(FILE_LINK_REPLACE_IF_EXISTS),
FLAGINFO_BITV(FILE_LINK_POSIX_SEMANTICS),
FLAGINFO_BITV(FILE_LINK_SUPPRESS_STORAGE_RESERVE_INHERITANCE),
FLAGINFO_BITV(FILE_LINK_NO_INCREASE_AVAILABLE_SPACE),
FLAGINFO_BITV(FILE_LINK_NO_DECREASE_AVAILABLE_SPACE),
FLAGINFO_BITV(FILE_LINK_IGNORE_READONLY_ATTRIBUTE),
FLAGINFO_BITV(FILE_LINK_FORCE_RESIZE_TARGET_SR),
FLAGINFO_BITV(FILE_LINK_FORCE_RESIZE_SOURCE_SR),
FLAGINFO_END()
};
TStructMember FileLinkInformationExMembers[] =
{
{_T("Flags"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileLinkInformationExValues}},
{_T("<padding>"), TYPE_PADDING, sizeof(HANDLE) },
{_T("RootDirectory"), TYPE_DIR_HANDLE, sizeof(HANDLE)},
{_T("FileNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_LINK_INFORMATION, FileNameLength)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileStorageReserveIdInformationMembers[] =
{
{_T("StorageReserveId"), TYPE_UINT32, sizeof(ULONG)},
{NULL, TYPE_NONE, 0}
};
TFlagInfo FileKnownFolderValues[] =
{
FLAGINFO_NUMV(KnownFolderNone),
FLAGINFO_NUMV(KnownFolderDesktop),
FLAGINFO_NUMV(KnownFolderDocuments),
FLAGINFO_NUMV(KnownFolderDownloads),
FLAGINFO_NUMV(KnownFolderMusic),
FLAGINFO_NUMV(KnownFolderPictures),
FLAGINFO_NUMV(KnownFolderVideos),
FLAGINFO_END()
};
TStructMember FileKnownFolderInformationMembers[] =
{
{_T("Type"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileKnownFolderValues}},
{NULL, TYPE_NONE, 0}
};
#define FileAttributeCacheInformationMembers FileUnknownInformationMembers
#define FileRenameInformationBypassAccessCheckMembers FileRenameInformationMembers
#define FileLinkInformationBypassAccessCheckMembers FileLinkInformationMembers
#define FileReplaceCompletionInformationMembers FileCompletionInformationMembers
#define FileRenameInformationExBypassAccessCheckMembers FileRenameInformationExMembers
#define FileCaseSensitiveInformationBypassAccessCheckMembers FileCaseSensitiveInformationMembers
#define FileLinkInformationExBypassAccessCheckMembers FileLinkInformationExMembers
#define FileCaseSensitiveInformationForceAccessCheckMembers FileCaseSensitiveInformationMembers
TInfoData FileInfoData[] =
{
FILE_INFO_READONLY(FileDirectoryInformation, FILE_DIRECTORY_INFORMATION, TRUE),
FILE_INFO_READONLY(FileFullDirectoryInformation, FILE_FULL_DIR_INFORMATION, TRUE),
FILE_INFO_READONLY(FileBothDirectoryInformation, FILE_BOTH_DIR_INFORMATION, TRUE),
FILE_INFO_EDITABLE(FileBasicInformation, FILE_BASIC_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileStandardInformation, FILE_STANDARD_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileInternalInformation, FILE_INTERNAL_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileEaInformation, FILE_EA_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileAccessInformation, FILE_ACCESS_INFORMATION, FALSE),
FILE_INFO_READONLY(FileNameInformation, FILE_NAME_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileRenameInformation, FILE_RENAME_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileLinkInformation, FILE_LINK_INFORMATION, FALSE),
FILE_INFO_READONLY(FileNamesInformation, FILE_NAMES_INFORMATION, TRUE),
FILE_INFO_EDITABLE(FileDispositionInformation, FILE_DISPOSITION_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FilePositionInformation, FILE_POSITION_INFORMATION, FALSE),
FILE_INFO_READONLY(FileFullEaInformation, FILE_FULL_EA_INFORMATION, TRUE),
FILE_INFO_EDITABLE(FileModeInformation, FILE_MODE_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileAlignmentInformation, FILE_ALIGNMENT_INFORMATION, FALSE),
FILE_INFO_READONLY(FileAllInformation, FILE_ALL_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileAllocationInformation, FILE_ALLOCATION_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileEndOfFileInformation, FILE_END_OF_FILE_INFORMATION, FALSE),
FILE_INFO_READONLY(FileAlternateNameInformation, FILE_NAME_INFORMATION, FALSE),
FILE_INFO_READONLY(FileStreamInformation, FILE_STREAM_INFORMATION, TRUE),
FILE_INFO_EDITABLE(FilePipeInformation, FILE_PIPE_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FilePipeLocalInformation, FILE_PIPE_LOCAL_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FilePipeRemoteInformation, FILE_PIPE_REMOTE_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileMailslotQueryInformation, FILE_MAILSLOT_QUERY_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileMailslotSetInformation, FILE_MAILSLOT_SET_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileCompressionInformation, FILE_COMPRESSION_INFORMATION, FALSE),
FILE_INFO_READONLY(FileObjectIdInformation, FILE_OBJECTID_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileCompletionInformation, FILE_COMPLETION_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileMoveClusterInformation, FILE_MOVE_CLUSTER_INFORMATION, FALSE),
FILE_INFO_READONLY(FileQuotaInformation, FILE_QUOTA_INFORMATION, TRUE),
FILE_INFO_EDITABLE(FileReparsePointInformation, FILE_REPARSE_POINT_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileNetworkOpenInformation, FILE_NETWORK_OPEN_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileAttributeTagInformation, FILE_ATTRIBUTE_TAG_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileTrackingInformation, FILE_TRACKING_INFORMATION, FALSE),
FILE_INFO_READONLY(FileIdBothDirectoryInformation, FILE_ID_BOTH_DIR_INFORMATION, TRUE),
FILE_INFO_READONLY(FileIdFullDirectoryInformation, FILE_ID_FULL_DIR_INFORMATION, TRUE),
FILE_INFO_EDITABLE(FileValidDataLengthInformation, FILE_VALID_DATA_LENGTH_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileShortNameInformation, FILE_NAME_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileIoCompletionNotificationInformation, FILE_IO_COMPLETION_NOTIFICATION_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileIoStatusBlockRangeInformation, FILE_IOSTATUSBLOCK_RANGE_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileIoPriorityHintInformation, FILE_IO_PRIORITY_HINT_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileSfioReserveInformation, FILE_SFIO_RESERVE_INFORMATION, FALSE),
FILE_INFO_READONLY(FileSfioVolumeInformation, FILE_SFIO_VOLUME_INFORMATION, FALSE),
FILE_INFO_READONLY(FileHardLinkInformation, FILE_LINKS_INFORMATION, FALSE),
FILE_INFO_READONLY(FileProcessIdsUsingFileInformation, FILE_PROCESS_IDS_USING_FILE_INFORMATION, FALSE),
FILE_INFO_READONLY(FileNormalizedNameInformation, FILE_NORMALIZED_NAME_INFORMATION, FALSE),
FILE_INFO_READONLY(FileNetworkPhysicalNameInformation, FILE_NETWORK_PHYSICAL_NAME_INFORMATION, FALSE),
FILE_INFO_READONLY(FileIdGlobalTxDirectoryInformation, FILE_ID_GLOBAL_TX_DIRECTORY_INFORMATION, TRUE),
FILE_INFO_READONLY(FileIsRemoteDeviceInformation, FILE_IS_REMOTE_DEVICE_INFORMATION, FALSE),
FILE_INFO_READONLY(FileAttributeCacheInformation, FILE_ATTRIBUTE_CACHE_INFORMATION, FALSE),
FILE_INFO_READONLY(FileNumaNodeInformation, FILE_NUMA_NODE_INFORMATION, FALSE),
FILE_INFO_READONLY(FileStandardLinkInformation, FILE_STANDARD_LINK_INFORMATION, FALSE),
FILE_INFO_READONLY(FileRemoteProtocolInformation, FILE_REMOTE_PROTOCOL_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileRenameInformationBypassAccessCheck, FILE_RENAME_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileLinkInformationBypassAccessCheck, FILE_LINK_INFORMATION, FALSE),
FILE_INFO_READONLY(FileVolumeNameInformation, FILE_VOLUME_NAME_INFORMATION, FALSE),
FILE_INFO_READONLY(FileIdInformation, FILE_ID_INFORMATION, FALSE),
FILE_INFO_READONLY(FileIdExtdDirectoryInformation, FILE_ID_EXTD_DIR_INFORMATION, TRUE),
FILE_INFO_EDITABLE(FileReplaceCompletionInformation, FILE_COMPLETION_INFORMATION, FALSE),
FILE_INFO_READONLY(FileHardLinkFullIdInformation, FILE_LINK_ENTRY_FULL_ID_INFORMATION, TRUE),
FILE_INFO_READONLY(FileIdExtdBothDirectoryInformation, FILE_ID_EXTD_BOTH_DIR_INFORMATION, TRUE),
FILE_INFO_EDITABLE(FileDispositionInformationEx, FILE_DISPOSITION_INFORMATION_EX, FALSE),
FILE_INFO_EDITABLE(FileRenameInformationEx, FILE_RENAME_INFORMATION_EX, FALSE),
FILE_INFO_EDITABLE(FileRenameInformationExBypassAccessCheck,FILE_RENAME_INFORMATION_EX, FALSE),
FILE_INFO_EDITABLE(FileDesiredStorageClassInformation, FILE_DESIRED_STORAGE_CLASS_INFORMATION, FALSE),
FILE_INFO_READONLY(FileStatInformation, FILE_STAT_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileMemoryPartitionInformation, FILE_MEMORY_PARTITION_INFORMATION, FALSE),
FILE_INFO_READONLY(FileStatLxInformation, FILE_STAT_LX_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileCaseSensitiveInformation, FILE_CASE_SENSITIVE_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileLinkInformationEx, FILE_LINK_INFORMATION_EX, FALSE),
FILE_INFO_EDITABLE(FileLinkInformationExBypassAccessCheck, FILE_LINK_INFORMATION_EX, FALSE),
FILE_INFO_EDITABLE(FileStorageReserveIdInformation, FILE_SET_STORAGE_RESERVE_ID_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileCaseSensitiveInformationForceAccessCheck, FILE_CASE_SENSITIVE_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileKnownFolderInformation, FILE_KNOWN_FOLDER_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileStatBasicInformation, FILE_STAT_BASIC_INFORMATION, FALSE),
FILE_INFO_READONLY(FileId64ExtdDirectoryInformation, FILE_ID_64_EXTD_DIR_INFORMATION, TRUE),
FILE_INFO_READONLY(FileId64ExtdBothDirectoryInformation, FILE_ID_64_EXTD_BOTH_DIR_INFORMATION, TRUE),
FILE_INFO_READONLY(FileIdAllExtdDirectoryInformation, FILE_ID_ALL_EXTD_DIR_INFORMATION, TRUE),
FILE_INFO_READONLY(FileIdAllExtdBothDirectoryInformation, FILE_ID_ALL_EXTD_BOTH_DIR_INFORMATION, TRUE),
{FileMaximumInformation}
};
//-----------------------------------------------------------------------------
// Description of data structures for FS info classes
TStructMember FileFsVolumeInformationMembers[] =
{
{_T("VolumeCreationTime"), TYPE_FILETIME, sizeof(LARGE_INTEGER)},
{_T("VolumeSerialNumber"), TYPE_UINT32, sizeof(ULONG)},
{_T("VolumeLabelLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("SupportsObjects"), TYPE_BOOLEAN, sizeof(WCHAR)}, // Aligned to 2
{_T("VolumeLabel"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_FS_VOLUME_INFORMATION, VolumeLabelLength)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileFsLabelInformationMembers[] =
{
{_T("VolumeLabelLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("VolumeLabel"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_FS_LABEL_INFORMATION, VolumeLabelLength)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileFsSizeInformationMembers[] =
{
{_T("TotalAllocationUnits"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("AvailableAllocationUnits"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("SectorsPerAllocationUnit"), TYPE_UINT32, sizeof(ULONG)},
{_T("BytesPerSector"), TYPE_UINT32, sizeof(ULONG)},
{NULL, TYPE_NONE, 0}
};
TFlagInfo FileDeviceCharacteristicsValues[] =
{
FLAGINFO_BITV(FILE_REMOVABLE_MEDIA),
FLAGINFO_BITV(FILE_READ_ONLY_DEVICE),
FLAGINFO_BITV(FILE_FLOPPY_DISKETTE),
FLAGINFO_BITV(FILE_WRITE_ONCE_MEDIA),
FLAGINFO_BITV(FILE_REMOTE_DEVICE),
FLAGINFO_BITV(FILE_DEVICE_IS_MOUNTED),
FLAGINFO_BITV(FILE_VIRTUAL_VOLUME),
FLAGINFO_BITV(FILE_AUTOGENERATED_DEVICE_NAME),
FLAGINFO_BITV(FILE_DEVICE_SECURE_OPEN),
FLAGINFO_BITV(FILE_CHARACTERISTIC_PNP_DEVICE),
FLAGINFO_BITV(FILE_CHARACTERISTIC_TS_DEVICE),
FLAGINFO_BITV(FILE_CHARACTERISTIC_WEBDAV_DEVICE),
FLAGINFO_BITV(FILE_CHARACTERISTIC_CSV),
FLAGINFO_BITV(FILE_DEVICE_ALLOW_APPCONTAINER_TRAVERSAL),
FLAGINFO_BITV(FILE_PORTABLE_DEVICE),
FLAGINFO_BITV(FILE_REMOTE_DEVICE_VSMB),
FLAGINFO_BITV(FILE_DEVICE_REQUIRE_SECURITY_CHECK),
FLAGINFO_END()
};
TStructMember FileFsDeviceInformationMembers[] =
{
{_T("DeviceType"), TYPE_UINT32, sizeof(ULONG)},
{_T("Characteristics"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileDeviceCharacteristicsValues}},
{NULL, TYPE_NONE, 0}
};
TStructMember FileFsAttributeInformationMembers[] =
{
{_T("FileSystemAttributes"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileSystemAttributesValues}},
{_T("MaximumComponentNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileSystemNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileSystemName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_FS_ATTRIBUTE_INFORMATION, FileSystemNameLength)},
{NULL, TYPE_NONE, 0}
};
TFlagInfo FileSystemControlFlagValues[] =
{
FLAGINFO_BITV(FILE_VC_QUOTA_TRACK),
FLAGINFO_BITV(FILE_VC_QUOTA_ENFORCE),
FLAGINFO_BITV(FILE_VC_CONTENT_INDEX_DISABLED),
FLAGINFO_BITV(FILE_VC_LOG_QUOTA_THRESHOLD),
FLAGINFO_BITV(FILE_VC_LOG_QUOTA_LIMIT),
FLAGINFO_BITV(FILE_VC_LOG_VOLUME_THRESHOLD),
FLAGINFO_BITV(FILE_VC_LOG_VOLUME_LIMIT),
FLAGINFO_BITV(FILE_VC_QUOTAS_INCOMPLETE),
FLAGINFO_BITV(FILE_VC_QUOTAS_REBUILDING),
FLAGINFO_END()
};
TStructMember FileFsControlInformationMembers[] =
{
{_T("FreeSpaceStartFiltering"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("FreeSpaceThreshold"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("FreeSpaceStopFiltering"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("DefaultQuotaThreshold"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("DefaultQuotaLimit"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("FileSystemControlFlags"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileSystemControlFlagValues}},
{NULL, TYPE_NONE, 0}
};
TStructMember FileFsFullSizeInformationMembers[] =
{
{_T("TotalAllocationUnits"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("CallerAvailableAllocationUnits"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("ActualAvailableAllocationUnits"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("SectorsPerAllocationUnit"), TYPE_UINT32, sizeof(ULONG)},
{_T("BytesPerSector"), TYPE_UINT32, sizeof(ULONG)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileFsObjectIdInformationMembers[] =
{
{_T("ObjectId"), TYPE_GUID, sizeof(UCHAR[16])},
{_T("ExtendedInfo"), TYPE_ARRAY8_FIXED, sizeof(UCHAR[48])},
{NULL, TYPE_NONE, 0}
};
TStructMember FileFsDriverPathInformationMembers[] =
{
{_T("DriverInPath"), TYPE_BOOLEAN, sizeof(ULONG)},
{_T("DriverNameLength"), TYPE_UINT32, sizeof(ULONG)},
{_T("DriverName"), TYPE_WNAME_L32B, FIELD_OFFSET(FILE_FS_DRIVER_PATH_INFORMATION, DriverNameLength)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileFsVolumeFlagsInformationMembers[] =
{
{_T("Flags"), TYPE_UINT32, sizeof(ULONG)},
{NULL, TYPE_NONE, 0}
};
TFlagInfo FileSystemSectorFlagValues[] =
{
FLAGINFO_BITV(SSINFO_FLAGS_ALIGNED_DEVICE),
FLAGINFO_BITV(SSINFO_FLAGS_PARTITION_ALIGNED_ON_DEVICE),
FLAGINFO_BITV(SSINFO_FLAGS_NO_SEEK_PENALTY),
FLAGINFO_BITV(SSINFO_FLAGS_TRIM_ENABLED),
FLAGINFO_BITV(SSINFO_FLAGS_BYTE_ADDRESSABLE),
FLAGINFO_END()
};
TStructMember FileFsSectorSizeInformationMembers[] =
{
{_T("LogicalBytesPerSector"), TYPE_UINT32, sizeof(ULONG)},
{_T("PhysicalBytesPerSectorForAtomicity"), TYPE_UINT32, sizeof(ULONG)},
{_T("PhysicalBytesPerSectorForPerformance"), TYPE_UINT32, sizeof(ULONG)},
{_T("FileSystemEffectivePhysicalBytesPerSectorForAtomicity"), TYPE_UINT32, sizeof(ULONG)},
{_T("Flags"), TYPE_FLAG32, sizeof(ULONG), NULL, {(TStructMember *)FileSystemSectorFlagValues}},
{_T("ByteOffsetForSectorAlignment"), TYPE_UINT32, sizeof(ULONG)},
{_T("ByteOffsetForPartitionAlignment"), TYPE_UINT32, sizeof(ULONG)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileFsDataCopyInformationMembers[] =
{
{_T("NumberOfCopies"), TYPE_UINT32, sizeof(ULONG)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileFsMetadataSizeInformationMembers[] =
{
{_T("TotalMetadataAllocationUnits"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("SectorsPerAllocationUnit"), TYPE_UINT32, sizeof(ULONG)},
{_T("BytesPerSector"), TYPE_UINT32, sizeof(ULONG)},
{NULL, TYPE_NONE, 0}
};
TStructMember FileFsFullSizeInformationExMembers[] =
{
{_T("ActualTotalAllocationUnits"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("ActualAvailableAllocationUnits"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("ActualPoolUnavailableAllocationUnits"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("CallerTotalAllocationUnits"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("CallerAvailableAllocationUnits"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("CallerPoolUnavailableAllocationUnits"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("UsedAllocationUnits"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("TotalReservedAllocationUnits"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("VolumeStorageReserveAllocationUnits"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("AvailableCommittedAllocationUnits"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("PoolAvailableAllocationUnits"), TYPE_UINT64, sizeof(LARGE_INTEGER)},
{_T("SectorsPerAllocationUnit"), TYPE_UINT32, sizeof(ULONG)},
{_T("BytesPerSector"), TYPE_UINT32, sizeof(ULONG)},
{NULL, TYPE_NONE, 0}
};
TInfoData FsInfoData[] =
{
FILE_INFO_EDITABLE(FileFsVolumeInformation, FILE_FS_VOLUME_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileFsLabelInformation, FILE_FS_LABEL_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileFsSizeInformation, FILE_FS_SIZE_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileFsDeviceInformation, FILE_FS_DEVICE_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileFsAttributeInformation, FILE_FS_ATTRIBUTE_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileFsControlInformation, FILE_FS_CONTROL_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileFsFullSizeInformation, FILE_FS_FULL_SIZE_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileFsObjectIdInformation, FILE_FS_OBJECTID_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileFsDriverPathInformation, FILE_FS_DRIVER_PATH_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileFsVolumeFlagsInformation, FILE_FS_VOLUME_FLAGS_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileFsSectorSizeInformation, FILE_FS_SECTOR_SIZE_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileFsDataCopyInformation, FILE_FS_DATA_COPY_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileFsMetadataSizeInformation, FILE_FS_METADATA_SIZE_INFORMATION, FALSE),
FILE_INFO_EDITABLE(FileFsFullSizeInformationEx, FILE_FS_FULL_SIZE_INFORMATION_EX, FALSE),
{FileFsMaximumInformation}
};
#define InitialFileInfo FileBasicInformation
#define InitialFsInfo FileFsVolumeInformation
//-----------------------------------------------------------------------------
// Tooltip variables
static UINT_PTR nTimerTooltip = 0;
static HANDLE hDirTarget = NULL;
static HWND hToolTip = NULL;
//-----------------------------------------------------------------------------
// Forward definitions
static int FillStructMembersChained(
HWND hTreeView,
HTREEITEM hParentItem,
TStructMember * pMembers,
LPBYTE pbData,
LPBYTE pbDataEnd
);
//-----------------------------------------------------------------------------
// Conversion functions
#define NEXT_ENTRY_OFFSET_ATRIFICIAL 0x80000000
typedef struct _CHAINED_ENTRY
{
ULONG NextEntryOffset;
} CHAINED_ENTRY, *PCHAINED_ENTRY;
static PCHAINED_ENTRY DirEntry_Find(LPBYTE PtrEntry, ULONG_PTR DataLength)
{
PCHAINED_ENTRY DirEntry = (PCHAINED_ENTRY)PtrEntry;
LPBYTE EndEntry = PtrEntry + DataLength;
while(DirEntry->NextEntryOffset != 0 && PtrEntry < EndEntry)
{
PtrEntry = PtrEntry + DirEntry->NextEntryOffset;
DirEntry = (PCHAINED_ENTRY)PtrEntry;
}
return DirEntry;
}
static void DirEntry_Mark(PCHAINED_ENTRY LastEntry, LPBYTE pbDataPtr)
{
LPBYTE pbLastEntry = (LPBYTE)LastEntry;
// At this point, the last entry's "next" offset should be zero
assert(LastEntry->NextEntryOffset == 0);
assert(pbDataPtr > pbLastEntry);
// Set the last entry's offset to the next item.
LastEntry->NextEntryOffset = NEXT_ENTRY_OFFSET_ATRIFICIAL | (ULONG)(pbDataPtr - pbLastEntry);
}
static int GetAlignedDataLength(LPBYTE pbStructPtr, LPBYTE pbData, int nTypeSize, int nAlignmentSize)
{
int nCurrentOffset = (int)(pbData - pbStructPtr);
int nAlignMask = nAlignmentSize - 1;
int nAlignedSize = (nTypeSize + nAlignMask) & ~nAlignMask;
return nAlignedSize - (nCurrentOffset & nAlignMask);
}
static LPTSTR AStringToItemText(
LPTSTR szBuffer,
LPTSTR szEndChar,
LPSTR VarString,
ULONG LengthInBytes,
BOOL bTextForEdit)
{
size_t nNameLength = LengthInBytes / sizeof(CHAR);
// Include the preceding quotas, if necessary
if(!bTextForEdit && szEndChar > szBuffer)
*szBuffer++ = _T('\"');
// Copy the string itself
for(ULONG i = 0; i < nNameLength; i++)
{
if(szEndChar > szBuffer)
*szBuffer++ = *VarString++;
}
// Close the string with quotas, if needed
if(!bTextForEdit && szEndChar > szBuffer)
*szBuffer++ = _T('\"');
*szBuffer = 0;
return szBuffer;
}
static LPTSTR WStringToItemText(
LPTSTR szBuffer,
LPTSTR szEndChar,
LPWSTR VarString,
ULONG LengthInBytes,
BOOL bTextForEdit)
{
size_t nNameLength;
// The file name can't be longer than MAX_USHORT
if(LengthInBytes > 0xFFFE)
LengthInBytes = 0xFFFE;
nNameLength = LengthInBytes / sizeof(WCHAR);
// Include the preceding quotas, if necessary
if(!bTextForEdit && szEndChar > szBuffer)
*szBuffer++ = _T('\"');
// Copy the string itself
for(size_t i = 0; i < nNameLength; i++)
{
if(szEndChar > szBuffer)
*szBuffer++ = *VarString++;
}
// Include the terminating quotation mark, if necessary
// and terminate the string with zero
if(!bTextForEdit && szEndChar > szBuffer)
*szBuffer++ = _T('\"');
*szBuffer = 0;
return szBuffer;
}
static LPTSTR CreateFullName(LPCTSTR szDirectory, LPCWSTR szPlainName, ULONG cbPlainName)
{
LPTSTR szFileName;
LPTSTR szFilePtr;
size_t cchDirectory = _tcslen(szDirectory);
size_t cchLength;
// Allocate buffer
cchLength = cchDirectory + 1 + (cbPlainName / sizeof(WCHAR)) + 1;
szFileName = szFilePtr = new TCHAR[cchLength];
if(szFileName != NULL)
{
// Do we need a backslash?
if(cchDirectory > 0)
{
// Copy the directory name
memcpy(szFilePtr, szDirectory, cchDirectory * sizeof(TCHAR));
szFilePtr += cchDirectory;
// Add backslash if needed
if(szFilePtr[-1] != _T('\\'))
*szFilePtr++ = _T('\\');
}
// Copy the plain name
memcpy(szFilePtr, szPlainName, cbPlainName);
szFilePtr[cbPlainName / sizeof(TCHAR)] = 0;
}
return szFileName;
}
static void FillComboBoxFiltered(HWND hWndCombo, TInfoData * pInfoList, LPCTSTR szFilterText)
{
TCHAR szItemText[256];
// Disable redrawing and remove all items
EnableRedraw(hWndCombo, FALSE);
// Delete all items
while(ComboBox_DeleteString(hWndCombo, 0) > 0);
// Fill the combo box
while(pInfoList->szInfoClass != NULL)
{
// Convert the string to uppercase
StringCchCopy(szItemText, _countof(szItemText), pInfoList->szInfoClass);
CharUpper(szItemText);
// If the item contains the substring, include it in the list
if(_tcsstr(szItemText, szFilterText))
ComboBox_AddString(hWndCombo, pInfoList->szInfoClass);
// Move to the next item
pInfoList++;
}
// Enable redrawing and redraw
EnableRedraw(hWndCombo);
}
/*
static int SearchItemList(TInfoData * pInfoList, LPCTSTR szEditText, int nTextLength, int * piSelStart)
{
TInfoData * pInfoItem;
// Search the list, try to find the text from the beginning of the item
for(pInfoItem = pInfoList; pInfoItem->szInfoClass != NULL; pInfoItem++)
{
// Does the begin of the item match?
if(!_tcsnicmp(pInfoItem->szInfoClass, szEditText, nTextLength))
{
*piSelStart = nTextLength;
return (int)(pInfoItem - pInfoList);
}
}
// Search the list, try to find the text with "File" prefix
for(pInfoItem = pInfoList; pInfoItem->szInfoClass != NULL; pInfoItem++)
{
LPCTSTR szItemText = pInfoItem->szInfoClass;
// Compare all words in the item text
while(szItemText[0] != 0)
{
// Skip the word
szItemText++;
while(szItemText[0] != 0 && IsCharUpper(szItemText[0]) == FALSE)
szItemText++;
// Does the begin of the word match?
if(szItemText[0] != 0 && _tcsnicmp(szItemText, szEditText, nTextLength) == 0)
{
*piSelStart = (int)(szItemText - pInfoItem->szInfoClass) + nTextLength;
return (int)(pInfoItem - pInfoList);
}
}
}
return -1;
}
*/
static NTSTATUS TextToDirHandle(LPCTSTR szText, PHANDLE phHandle)
{
OBJECT_ATTRIBUTES ObjAttr;
UNICODE_STRING FileName = {0, 0, NULL};
IO_STATUS_BLOCK IoStatus;
NTSTATUS Status;
HANDLE FileHandle = NULL;
// If we already have a directory handle, close it
if(IsHandleValid(hDirTarget))
NtClose(hDirTarget);
hDirTarget = NULL;
// Convert the file name to NT name
InitializeObjectAttributes(&ObjAttr, &FileName, OBJ_CASE_INSENSITIVE, NULL, NULL);
Status = FileNameToUnicodeString(&FileName, szText);
// Open the file/directory
if(NT_SUCCESS(Status))
{
Status = NtOpenFile(&FileHandle,
FILE_WRITE_DATA,
&ObjAttr,
&IoStatus,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
0);
}
// Now put the handle to the target
if(NT_SUCCESS(Status))
{
hDirTarget = FileHandle;
*phHandle = FileHandle;
}
return Status;
}
static LPTSTR FileIDToFileName(
LPCTSTR szVolumeName,
PVOID pvFileID,
ULONG cbFileID)
{
PFILE_NAME_INFORMATION pFileInfo = NULL;
OBJECT_ATTRIBUTES ObjAttr;
IO_STATUS_BLOCK IoStatus;
UNICODE_STRING DeviceName;
UNICODE_STRING FileName;
NTSTATUS Status = STATUS_SUCCESS;
HANDLE VolumeHandle = NULL;
HANDLE FileHandle = NULL;
LPTSTR szFileName = NULL;
BYTE FileInfoBuff[0x400];
// Sanity check
assert(cbFileID == sizeof(ULONGLONG));
// Prepare the native name of the volume
Status = FileNameToUnicodeString(&DeviceName, szVolumeName);
// Open the volume
if(NT_SUCCESS(Status))
{
// Make the OBJECT_ATTRIBUTES structure
InitializeObjectAttributes(&ObjAttr, &DeviceName, OBJ_CASE_INSENSITIVE, NULL, NULL);
// Now try to open the volume/directory/file
// Use FILE_READ_ATTRIBUTES as the desired access;
// this allows us to bypass sharing violations
Status = NtCreateFile(&VolumeHandle,
FILE_READ_ATTRIBUTES, //FILE_READ_DATA,
&ObjAttr,
&IoStatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN,
0,
NULL,
0);
}
// Prepare opening the file
if(NT_SUCCESS(Status))
{
InitializeObjectAttributes(&ObjAttr, &FileName, OBJ_CASE_INSENSITIVE, VolumeHandle, NULL);
FileName.MaximumLength =
FileName.Length = (USHORT)cbFileID;
FileName.Buffer = (PWSTR)pvFileID;
Status = NtOpenFile(&FileHandle,
FILE_READ_ATTRIBUTES,
&ObjAttr,
&IoStatus,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN_BY_FILE_ID | FILE_OPEN_REPARSE_POINT);
}
// Query the file name
if(NT_SUCCESS(Status))
{
pFileInfo = (PFILE_NAME_INFORMATION)FileInfoBuff;
memset(pFileInfo, 0, sizeof(FileInfoBuff));
Status = NtQueryInformationFile(FileHandle,
&IoStatus,
pFileInfo,
sizeof(FileInfoBuff),
FileNameInformation);
}
// Allocate the file name
if(NT_SUCCESS(Status))
{
// Copy the volume-relative file name
szFileName = new TCHAR[(pFileInfo->FileNameLength / 2) + 1];
if(szFileName != NULL)
{
memcpy(szFileName, pFileInfo->FileName, pFileInfo->FileNameLength);
szFileName[pFileInfo->FileNameLength / 2] = 0;
}
}
// Close handles
if(FileHandle != NULL)
NtClose(FileHandle);
if(VolumeHandle != NULL)
NtClose(VolumeHandle);
FreeFileNameString(&DeviceName);
return szFileName;
}
static int DataToItemText(TStructMember * pMember, LPTSTR szBuffer, size_t nMaxChars, BOOL bTextForEdit)
{
LPTSTR szEndChar = szBuffer + nMaxChars - 1;
// If there is not even space for ending zero, do nothing
if(nMaxChars == 0)
return 0;
// Insert "MemberName: " prefix
if(bTextForEdit == FALSE)
{
StringCchPrintfEx(szBuffer, (szEndChar - szBuffer), &szBuffer, NULL, 0, _T("%s: "), pMember->szMemberName);
}
// Now insert the member value
switch(pMember->nDataType)
{
case TYPE_BOOLEAN:
{
LPCTSTR szBoolean = (*(PBOOLEAN)(pMember->pbDataPtr)) ? _T("TRUE") : _T("FALSE");
StringCchCopyEx(szBuffer, (szEndChar - szBuffer), szBoolean, &szBuffer, NULL, 0);
break;
}
case TYPE_UINT8:
{
PUCHAR pucValue = (PUCHAR)pMember->pbDataPtr;
StringCchPrintfEx(szBuffer, (szEndChar - szBuffer), &szBuffer, NULL, 0, _T("0x%02lX"), *pucValue);
break;
}
case TYPE_UINT16:
{
PUSHORT pusValue = (PUSHORT)pMember->pbDataPtr;
StringCchPrintfEx(szBuffer, (szEndChar - szBuffer), &szBuffer, NULL, 0, _T("0x%04lX"), *pusValue);
break;
}
case TYPE_UINT32:
{
PULONG pulValue = (PULONG)pMember->pbDataPtr;
StringCchPrintfEx(szBuffer, (szEndChar - szBuffer), &szBuffer, NULL, 0, _T("0x%08lX"), *pulValue);
break;
}
case TYPE_UINT64:
{
PLARGE_INTEGER pliValue = (PLARGE_INTEGER)pMember->pbDataPtr;
StringCchPrintfEx(szBuffer, (szEndChar - szBuffer), &szBuffer, NULL, 0, _T("%08lX-%08lX"), pliValue->HighPart, pliValue->LowPart);
break;
}
case TYPE_FILEID128:
{
PLARGE_INTEGER pliValue = (PLARGE_INTEGER)pMember->pbDataPtr;
StringCchPrintfEx(szBuffer, (szEndChar - szBuffer), &szBuffer, NULL, 0, _T("%016I64X-%016I64X"), pliValue[1].QuadPart, pliValue[0].QuadPart);
break;
}
case TYPE_ARRAY8_FIXED:
{
LPBYTE pbData = (LPBYTE)pMember->pbDataPtr;
if(szEndChar > szBuffer)
*szBuffer++ = _T('"');
for(UINT i = 0; i < pMember->nMemberSize; i++)
{
StringCchPrintfEx(szBuffer, (szEndChar - szBuffer), &szBuffer, NULL, 0, _T("%02lX "), *pbData++);
}
if(szEndChar > szBuffer)
*szBuffer++ = _T('"');
break;
}
case TYPE_HANDLE:
case TYPE_POINTER:
{
PHANDLE phHandle = (PHANDLE)pMember->pbDataPtr;
StringCchPrintfEx(szBuffer, (szEndChar - szBuffer), &szBuffer, NULL, 0, _T("%p"), *phHandle);
break;
}
case TYPE_DIR_HANDLE:
{
PHANDLE phHandle = (PHANDLE)pMember->pbDataPtr;
if(*phHandle != NULL)
{
StringCchPrintfEx(szBuffer, (szEndChar - szBuffer), &szBuffer, NULL, 0, _T("%p"), *phHandle);
break;
}
// Display a prompt text
szBuffer += LoadString(g_hInst, IDS_ENTER_DIRECTORY_NAME, szBuffer, (int)(szEndChar - szBuffer));
break;
}
case TYPE_FLAG8:
{
PBYTE pbValue = (PBYTE)pMember->pbStructPtr;
StringCchPrintfEx(szBuffer, (szEndChar - szBuffer), &szBuffer, NULL, 0, _T("0x%02hhX"), *pbValue);
break;
}
case TYPE_FLAG16:
{
PWORD pwValue = (PWORD)pMember->pbStructPtr;
StringCchPrintfEx(szBuffer, (szEndChar - szBuffer), &szBuffer, NULL, 0, _T("0x%04hX"), *pwValue);
break;
}
case TYPE_FLAG32:
{
PULONG pulValue = (PULONG)pMember->pbStructPtr;
StringCchPrintfEx(szBuffer, (szEndChar - szBuffer), &szBuffer, NULL, 0, _T("0x%08lX"), *pulValue);
break;
}
case TYPE_FILETIME:
{
szBuffer = FileTimeToText(szBuffer,
szEndChar,
(PFILETIME)pMember->pbDataPtr,
bTextForEdit);
break;
}
case TYPE_CNAME_L8B:
{
// Use this if it's name as CHAR array, of variable length.
// The 'nMemberSize' must contain offset of 8-bit value, containing length
// of the string in bytes.
PUCHAR PtrLength = (PUCHAR)(pMember->pbStructPtr + pMember->nMemberSize);
ULONG Length = *PtrLength;
// Process the file name as non-null-terminated
// array of WCHARs with variable length
szBuffer = AStringToItemText(szBuffer,
szEndChar,
(LPSTR)pMember->pbDataPtr,
Length,
bTextForEdit);
break;
}
case TYPE_WNAME_L32B:
{
// Use this if it's name as WCHAR array, of variable length.
// The 'nMemberSize' must contain offset of 32-bit value, containing length
// of the string in bytes.
PULONG PtrLength = (PULONG)(pMember->pbStructPtr + pMember->nMemberSize);
ULONG Length = *PtrLength;
// Process the file name as non-null-terminated
// array of WCHARs with variable length
szBuffer = WStringToItemText(szBuffer,
szEndChar,
(LPWSTR)pMember->pbDataPtr,
Length,
bTextForEdit);
break;
}
case TYPE_WNAME_L32W:
{
// Use this if it's name as WCHAR array, of variable length.
// The 'nMemberSize' must contain offset of 32-bit value, containing length
// of the string in WCHARs.
PULONG PtrLength = (PULONG)(pMember->pbStructPtr + pMember->nMemberSize);
ULONG Length = *PtrLength;
// Process the file name as non-null-terminated
// array of WCHARs with variable length
szBuffer = WStringToItemText(szBuffer,
szEndChar,
(LPWSTR)pMember->pbDataPtr,
Length * sizeof(WCHAR),
bTextForEdit);
break;
}
case TYPE_VNAME_FBDI: // ShortName in FILE_BOTH_DIR_INFORMATION
{
PFILE_BOTH_DIR_INFORMATION FileInfo;
// We have to take the whole structure and get the length
// (the name doesn't have to be zero terminated)
FileInfo = (PFILE_BOTH_DIR_INFORMATION)pMember->pbStructPtr;
// Process the file name as non-null-terminated
// string with variable length
szBuffer = WStringToItemText(szBuffer,
szEndChar,
FileInfo->ShortName,
FileInfo->ShortNameLength,
bTextForEdit);
break;
}
case TYPE_VNAME_FIBD: // ShortName in FILE_ID_BOTH_DIR_INFORMATION
{
PFILE_ID_BOTH_DIR_INFORMATION FileInfo;
// We have to take the whole structure and get the length
// (the name must not be zero terminated)
FileInfo = (PFILE_ID_BOTH_DIR_INFORMATION)
(pMember->pbDataPtr - FIELD_OFFSET(FILE_ID_BOTH_DIR_INFORMATION, ShortName));
// Process the stream name as non-null-terminated string
// with variable length
szBuffer = WStringToItemText(szBuffer,
szEndChar,
FileInfo->ShortName,
FileInfo->ShortNameLength,
bTextForEdit);
break;
}
case TYPE_VNAME_FIEBD: // ShortName in FILE_ID_EXTD_BOTH_DIR_INFORMATION
{
PFILE_ID_EXTD_BOTH_DIR_INFORMATION FileInfo;
// We have to take the whole structure and get the length
// (the name must not be zero terminated)
FileInfo = (PFILE_ID_EXTD_BOTH_DIR_INFORMATION)
(pMember->pbDataPtr - FIELD_OFFSET(FILE_ID_EXTD_BOTH_DIR_INFORMATION, ShortName));
// Process the stream name as non-null-terminated string
// with variable length
szBuffer = WStringToItemText(szBuffer,
szEndChar,
FileInfo->ShortName,
FileInfo->ShortNameLength,
bTextForEdit);
break;
}
case TYPE_FILEID64: // File ID (unresolved)
{
PLARGE_INTEGER pFileId = (PLARGE_INTEGER)pMember->pbDataPtr;
StringCchPrintfEx(szBuffer, (szEndChar - szBuffer), &szBuffer, NULL, 0, _T("%08lX-%08lX"), pFileId->HighPart, pFileId->LowPart);
break;
}
case TYPE_GUID:
{
LPGUID pGuid = (LPGUID)pMember->pbDataPtr;
TCHAR szGuidText[0x40];
GuidToString(pGuid, szGuidText, _countof(szGuidText));
StringCchPrintfEx(szBuffer, (szEndChar - szBuffer), &szBuffer, NULL, 0, _T("%s"), szGuidText);
break;
}
case TYPE_SID:
{
PSID pSid = (PSID)pMember->pbDataPtr;
TCHAR szSidText[SECURITY_MAX_SID_STRING_CHARACTERS];
if(IsValidSid(pSid))
{
SidToString(pSid, szSidText, _countof(szSidText), TRUE);
}
StringCchPrintfEx(szBuffer, (szEndChar - szBuffer), &szBuffer, NULL, 0, _T("%s"), IsValidSid(pSid) ? szSidText : _T("<invalid>"));
break;
}
default:
StringCchPrintfEx(szBuffer, (szEndChar - szBuffer), &szBuffer, NULL, 0, _T("<unsupported>"));
// No break here !!
case TYPE_STRUCT:
break;
}
// Terminate the buffer with EOS
*szBuffer = 0;
return ERROR_SUCCESS;
}
static NTSTATUS ItemTextToData(TStructMember * pMember, LPTSTR szItemText)
{
// Now insert the member value
switch(pMember->nDataType)
{
case TYPE_BOOLEAN:
{
PBOOLEAN pbValue = (PBOOLEAN)pMember->pbDataPtr;
if(!_tcsicmp(szItemText, _T("TRUE")) || !_tcsicmp(szItemText, _T("1")))
{
*pbValue = TRUE;
return STATUS_SUCCESS;
}
if(!_tcsicmp(szItemText, _T("FALSE")) || !_tcsicmp(szItemText, _T("0")))
{
*pbValue = FALSE;
return STATUS_SUCCESS;
}
break;
}
case TYPE_UINT8:
{
PUCHAR pucValue = (PUCHAR)pMember->pbDataPtr;
int nValue = 0;
int nRoot = 10;
// We allow either text or binary value
if(szItemText[0] == _T('0') && toupper(szItemText[1]) == _T('X'))
{
szItemText += 2;
nRoot = 16;
}
// Convert the text value to binary data
nValue = StrToInt(szItemText, &szItemText, nRoot);
if(*szItemText != 0 || nValue > 0xFF)
return STATUS_INVALID_DATA_FORMAT;
*pucValue = (UCHAR)nValue;
return STATUS_SUCCESS;
}
case TYPE_UINT16:
{
PUSHORT pusValue = (PUSHORT)pMember->pbDataPtr;
int nValue = 0;
int nRoot = 10;
// We allow either text or binary value
if(szItemText[0] == _T('0') && toupper(szItemText[1]) == _T('X'))
{
szItemText += 2;
nRoot = 16;
}
// Convert the text value to binary data
nValue = StrToInt(szItemText, &szItemText, nRoot);
if(*szItemText != 0 || nValue > 0xFFFF)
return STATUS_INVALID_DATA_FORMAT;
*pusValue = (USHORT)nValue;
return STATUS_SUCCESS;
}
case TYPE_UINT32:
{
PULONG pulValue = (PULONG)pMember->pbDataPtr;
int nRoot = 10;
// We allow either text or binary value
if(szItemText[0] == _T('0') && toupper(szItemText[1]) == _T('X'))
{
szItemText += 2;
nRoot = 16;
}
*pulValue = (ULONG)StrToInt(szItemText, &szItemText, nRoot);
return (*szItemText == 0) ? STATUS_SUCCESS : STATUS_INVALID_DATA_FORMAT;
}
case TYPE_UINT64:
{
PLARGE_INTEGER pliValue = (PLARGE_INTEGER)pMember->pbDataPtr;
ULONG ulValue;
// There must be two hexa values separated by '-'
ulValue = (ULONG)StrToInt(szItemText, &szItemText, 16);
if(*szItemText == _T('-'))
{
pliValue->HighPart = ulValue;
pliValue->LowPart = (ULONG)StrToInt(szItemText + 1, &szItemText, 16);
}
else
{
pliValue->HighPart = 0;
pliValue->LowPart = ulValue;
}
return (*szItemText == 0) ? STATUS_SUCCESS : STATUS_INVALID_DATA_FORMAT;
}
case TYPE_FILETIME:
{
return TextToFileTime(szItemText, (PFILETIME)pMember->pbDataPtr);
}
case TYPE_DIR_HANDLE:
{
return TextToDirHandle(szItemText, (PHANDLE)pMember->pbDataPtr);
}
case TYPE_FLAG8:
case TYPE_FLAG16:
case TYPE_FLAG32:
{
int nRoot = 10;
// We allow either text or binary value
if(szItemText[0] == _T('0') && toupper(szItemText[1]) == _T('X'))
{
szItemText += 2;
nRoot = 16;
}
ULONG ulValue = (ULONG)StrToInt(szItemText, &szItemText, nRoot);
switch (pMember->nDataType)
{
case TYPE_FLAG8:
*(PBYTE)pMember->pbStructPtr = (BYTE)ulValue;
break;
case TYPE_FLAG16:
*(PWORD)pMember->pbStructPtr = (WORD)ulValue;
break;
case TYPE_FLAG32:
*(PULONG)pMember->pbStructPtr = ulValue;
break;
}
return (*szItemText == 0) ? STATUS_SUCCESS : STATUS_INVALID_DATA_FORMAT;
}
case TYPE_WNAME_L32B:
{
// Use this if it's name as WCHAR array, of variable length.
// The 'nMemberSize' must contain offset of 32-bit value, containing length
// of the string in bytes.
PULONG PtrLength = (PULONG)(pMember->pbStructPtr + pMember->nMemberSize);
ULONG Length;
// Copy the string
Length = (ULONG)(wcslen(szItemText) * sizeof(WCHAR));
memcpy(pMember->pbDataPtr, szItemText, Length);
*PtrLength = Length;
return STATUS_SUCCESS;
}
}
return STATUS_NOT_SUPPORTED;
}
static int InsertTreeItemFlags32(
HWND hTreeView,
HTREEITEM hParentItem,
TStructMember * pMember,
LPBYTE pbData,
LPBYTE pbDataEnd)
{
TStructMember * pMemberInfo;
TCHAR szItemText[128] = {0};
// Sanity check
assert((UINT)(pbDataEnd - pbData) >= pMember->nMemberSize);
UNREFERENCED_PARAMETER(pbDataEnd);
assert(pMember->pFlags != NULL);
// Allocate the data structure
pMemberInfo = new TStructMember;
if(pMemberInfo != NULL)
{
// Fill in the item data structure
pMemberInfo->szMemberName = pMember->szMemberName;
pMemberInfo->nDataType = pMember->nDataType;
pMemberInfo->nMemberSize = pMember->nMemberSize;
pMemberInfo->pbStructPtr = pbData;
pMemberInfo->pFlags = pMember->pFlags;
// Insert the tree item to the tree
if(DataToItemText(pMemberInfo, szItemText, _countof(szItemText), FALSE) == ERROR_SUCCESS)
InsertTreeItem(hTreeView, hParentItem, szItemText, pMemberInfo);
}
return pMember->nMemberSize;
}
static NTSTATUS OpenProcessAnyMethod(PHANDLE ProcessHandle, HANDLE ProcessId)
{
ULONG dwProcessId = (DWORD)(DWORD_PTR)ProcessId;
HANDLE hProcess;
// Try normal access
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwProcessId);
if(hProcess != NULL)
{
ProcessHandle[0] = hProcess;
return STATUS_SUCCESS;
}
// Try with limited access
hProcess = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, FALSE, dwProcessId);
if(hProcess != NULL)
{
ProcessHandle[0] = hProcess;
return STATUS_SUCCESS;
}
return STATUS_ACCESS_DENIED;
}
static NTSTATUS GetProcessImageFileNameByProcessId(HANDLE ProcessId, UNICODE_STRING & ImageName)
{
SYSTEM_PROCESS_ID_INFORMATION processIdInfo;
NTSTATUS Status;
HANDLE hProcess;
BYTE NameBuff[0x200] = {0};
// Method 1 (Vista+): Try to retrieve the process image file name by PID.
// This does not require an open process handle. Credit: Matthijs Lavrijsen
processIdInfo.UniqueProcessId = ProcessId;
processIdInfo.ImageName = ImageName;
Status = NtQuerySystemInformation(SystemProcessIdInformation, &processIdInfo, sizeof(processIdInfo), NULL);
if(NT_SUCCESS(Status))
{
ImageName.Length = processIdInfo.ImageName.Length;
return Status;
}
// Method 2) Use OpenProcess and query the image name
Status = OpenProcessAnyMethod(&hProcess, ProcessId);
if(NT_SUCCESS(Status))
{
// Retrieve the process information
Status = NtQueryInformationProcess(hProcess, ProcessImageFileName, NameBuff, sizeof(NameBuff), NULL);
CloseHandle(hProcess);
// If succeeded, copy the name
if(NT_SUCCESS(Status))
{
PUNICODE_STRING TempName = (PUNICODE_STRING)NameBuff;
size_t CopyLength;
// For "System" process (PID = 0x04), the function succeeds but doesn't return anything
if(TempName->Buffer && TempName->Length)
{
CopyLength = min(ImageName.MaximumLength, TempName->Length);
memcpy(ImageName.Buffer, TempName->Buffer, CopyLength);
ImageName.Length = (USHORT)CopyLength;
}
}
}
return Status;
}
static size_t InsertTreeItemProcess(HWND hTreeView, HTREEITEM hSubItem, HANDLE ProcessId, int nIndex)
{
UNICODE_STRING ImageName;
LPCWSTR szPlainName = NULL;
LPCWSTR szFormat;
NTSTATUS Status;
WCHAR szBuffer[0x200] = {0};
ULONG dwProcessId = (DWORD)(DWORD_PTR)ProcessId;
// Initialize the UNICODE_STRING holding the file name
ImageName.MaximumLength = (USHORT)(sizeof(szBuffer) - sizeof(WCHAR));
ImageName.Length = 0;
ImageName.Buffer = szBuffer;
// Try to retrieve the process image file name
Status = GetProcessImageFileNameByProcessId(ProcessId, ImageName);
if(NT_SUCCESS(Status) && ImageName.Length)
{
ImageName.Buffer[ImageName.Length / sizeof(WCHAR)] = L'\0';
szPlainName = GetPlainName(ImageName.Buffer);
}
else if(dwProcessId == 0)
{
szPlainName = L"System Idle Process";
}
else if(dwProcessId == 4)
{
szPlainName = L"System";
}
// Construct the image name
szFormat = (szPlainName != NULL) ? _T("[0x%02X]: %u (%s)") : _T("[0x%02X]: %u (unknown)");
StringCchPrintf(szBuffer, _countof(szBuffer), szFormat, nIndex, dwProcessId, szPlainName);
InsertTreeItem(hTreeView, hSubItem, szBuffer);
return sizeof(UINT_PTR);
}
static int InsertTreeItemByDataType(
HWND hTreeView,
HTREEITEM hParentItem,
TStructMember * pMember,
PBYTE pbStructPtr,
PBYTE pbDataPtr,
PBYTE pbDataEnd)
{
TStructMember * pMemberInfo;
TCHAR szItemText[1024] = _T("");
int nBytesUsed = pMember->nMemberSize;
if(pMember->nDataType == TYPE_ARRAY8_VARIABLE)
{
UINT nTotalDataLength = (UINT)(pbDataEnd - pbDataPtr);
UINT nChunkDataLength;
// Limit the total length to 1024 bytes
nBytesUsed = nTotalDataLength;
if(nTotalDataLength > 1024)
nTotalDataLength = 1024;
// Enter multiple lines, 1 paragraph per line
while(nTotalDataLength != 0)
{
// Find out the maximum data length
nChunkDataLength = min(nTotalDataLength, 0x10);
// Allocate the data structure
pMemberInfo = new TStructMember;
if(pMemberInfo != NULL)
{
// Fill in the item data structure
pMemberInfo->szMemberName = pMember->szMemberName;
pMemberInfo->nDataType = TYPE_ARRAY8_FIXED;
pMemberInfo->nMemberSize = nChunkDataLength;
pMemberInfo->pbStructPtr = pbStructPtr;
pMemberInfo->pbDataPtr = pbDataPtr;
// Get the item text
if(DataToItemText(pMemberInfo, szItemText, _countof(szItemText), FALSE) == ERROR_SUCCESS)
InsertTreeItem(hTreeView, hParentItem, szItemText, pMemberInfo);
}
// Move the pointer
nTotalDataLength -= nChunkDataLength;
pbDataPtr += nChunkDataLength;
}
}
else
{
// Allocate the data structure
pMemberInfo = new TStructMember;
if(pMemberInfo != NULL)
{
// Fill in the item data structure
pMemberInfo->szMemberName = pMember->szMemberName;
pMemberInfo->nDataType = pMember->nDataType;
pMemberInfo->nMemberSize = pMember->nMemberSize;
pMemberInfo->pbStructPtr = pbStructPtr;
pMemberInfo->pbDataPtr = pbDataPtr;
// Get the item text
if(DataToItemText(pMemberInfo, szItemText, _countof(szItemText), FALSE) == ERROR_SUCCESS)
InsertTreeItem(hTreeView, hParentItem, szItemText, pMemberInfo);
}
}
return nBytesUsed;
}
static int GetStructLength(TStructMember * pMember)
{
int nStructLength = 0;
// We don't need recursion here; structure members in structures
// have also their size present, so we just add it
for(; pMember->szMemberName != NULL; pMember++)
nStructLength += pMember->nMemberSize;
// If the structure size is greater than 4 bytes,
// we have to align it to 8-byte boundary
if(nStructLength > 0x04)
nStructLength = ALIGN_INT64(nStructLength);
return nStructLength;
}
static void EnableOrDisableButtons(HWND hDlg)
{
TFileTestData * pData = GetDialogData(hDlg);
BOOL bEnable = FALSE;
// Controls on the dialog will be enabled only if the
// handle is valid and it is a NT handle
if(IsHandleValid(pData->hFile))
bEnable = TRUE;
if(GetDlgItem(hDlg, IDC_QUERY_INFO) != NULL)
EnableDlgItems(hDlg, bEnable, IDC_QUERY_INFO, IDC_QUERY_DIR, IDC_SET_INFO, 0);
if(GetDlgItem(hDlg, IDC_QUERY_VOL_INFO) != NULL)
EnableDlgItems(hDlg, bEnable, IDC_QUERY_VOL_INFO, IDC_SET_VOL_INFO, 0);
}
static PUNICODE_STRING GetQueryDirectoryMask(HWND hDlg, UINT nID)
{
PUNICODE_STRING FileMask;
SIZE_T cbToAllocate;
SIZE_T cbFileMask;
HWND hWndChild = GetDlgItem(hDlg, nID);
int nTextLength;
// Retrieve the length of the mask
nTextLength = GetWindowTextLength(hWndChild);
cbFileMask = (nTextLength * sizeof(WCHAR));
cbToAllocate = sizeof(UNICODE_STRING) + cbFileMask + sizeof(WCHAR);
FileMask = (PUNICODE_STRING)HeapAlloc(g_hHeap, HEAP_ZERO_MEMORY, cbToAllocate);
if(FileMask != NULL)
{
// Initialize the self-relative UNICODE_STRING
FileMask->MaximumLength = (USHORT)(cbFileMask + sizeof(WCHAR));
FileMask->Length = (USHORT)(cbFileMask);
FileMask->Buffer = (LPWSTR)(FileMask + 1);
// Copy the string
GetWindowText(hWndChild, FileMask->Buffer, nTextLength + 1);
// Special case: If the text is "NULL", then a NULL UNICODE_STRING is returned
if(!RtlCompareUnicodeString(FileMask, &NullString, TRUE))
{
HeapFree(g_hHeap, 0, FileMask);
FileMask = NULL;
}
}
return FileMask;
}
static int ReloadTreeViewItems(HWND hDlg, HWND hTreeView, HTREEITEM hParentItem)
{
TStructMember * pMemberInfo;
HTREEITEM hItem = TreeView_GetNextItem(hTreeView, hParentItem, TVGN_CHILD);
TVITEM tvi;
TCHAR szItemText[1024];
// Process all items at the same level
while(hItem != NULL)
{
// Retrieve data struct associated with treeview item
pMemberInfo = (TStructMember *)TreeView_GetItemParam(hTreeView, hItem);
// If any structure associated, get its text
if(pMemberInfo != NULL)
{
// Get the item text
if(DataToItemText(pMemberInfo, szItemText, _countof(szItemText), FALSE) == ERROR_SUCCESS)
{
ZeroMemory(&tvi, sizeof(TVITEM));
tvi.mask = TVIF_TEXT;
tvi.hItem = hItem;
tvi.pszText = szItemText;
TreeView_SetItem(hTreeView, &tvi);
}
}
// If the tree view item has a subitem, we have to recursively
// reload subtree too
if(TreeView_GetNextItem(hTreeView, hItem, TVGN_CHILD) != NULL)
ReloadTreeViewItems(hDlg, hTreeView, hItem);
// And finally, move to the next item at the same level
hItem = TreeView_GetNextItem(hTreeView, hItem, TVGN_NEXT);
}
return TRUE;
}
static size_t FillStructureMembers(
HWND hTreeView,
HTREEITEM hParentItem,
TStructMember * pMembers,
LPBYTE pbData,
LPBYTE pbDataEnd)
{
HTREEITEM hSubItem;
LPBYTE pbStructPtr = pbData; // Pointer to the begin of the structure
size_t nTotalLength = 0; // Length, in bytes, of the structure member
// Hack: In Windows 10, the FILE_STANDARD_INFORMATION becomes FILE_STANDARD_INFORMATION_EX
if(pMembers == FileStandardInformationMembers && g_dwWinVer >= 0x0A00)
pMembers = FileStandardInformationMembersEx;
// Parse the members and fill them
for(; pMembers->szMemberName != NULL; pMembers++)
{
size_t nDataLength = 0;
switch(pMembers->nDataType)
{
case TYPE_STRUCT:
assert(pMembers->pSubItems != NULL);
hSubItem = InsertTreeItem(hTreeView, hParentItem, pMembers->szMemberName);
nDataLength = FillStructureMembers(hTreeView,
hSubItem,
pMembers->pSubItems,
pbData,
pbDataEnd);
break;
case TYPE_CHAINED_STRUCT:
hSubItem = InsertTreeItem(hTreeView, hParentItem, pMembers->szMemberName);
nDataLength = FillStructMembersChained(hTreeView,
hSubItem,
pMembers->pSubItems,
pbData,
pbDataEnd);
break;
case TYPE_ARRAY_PROCESS:
{
// Use this if it's array of handles or INT_PTRs
// The 'nMemberSize' must contain offset of 32-bit value, containing length
// of the string in bytes.
PHANDLE HandleArray = (PHANDLE)pbData;
PULONG PtrHandleCount = (PULONG)(pbStructPtr + pMembers->nMemberSize);
// Insert the subitem
hSubItem = InsertTreeItem(hTreeView, hParentItem, pMembers->szMemberName);
// Parse the array of process ID
if(PtrHandleCount && PtrHandleCount[0])
{
for(ULONG i = 0; i < PtrHandleCount[0]; i++)
{
nDataLength += InsertTreeItemProcess(hTreeView, hSubItem, HandleArray[i], i);
}
}
break;
}
case TYPE_FLAG8:
case TYPE_FLAG16:
case TYPE_FLAG32: // Insert the flag array
nDataLength = InsertTreeItemFlags32(hTreeView, hParentItem, pMembers, pbData, pbDataEnd);
// If there is an alignment following the data member, do a proper alignment
if(pMembers[1].nDataType == TYPE_PADDING)
{
nDataLength = GetAlignedDataLength(pbStructPtr, pbData, pMembers[0].nMemberSize, pMembers[1].nMemberSize);
pMembers++;
}
break;
default:
// Insert the data member
nDataLength = InsertTreeItemByDataType(hTreeView, hParentItem, pMembers, pbStructPtr, pbData, pbDataEnd);
// If there is an alignment following the data member, do a proper alignment
if(pMembers[1].nDataType == TYPE_PADDING)
{
nDataLength = GetAlignedDataLength(pbStructPtr, pbData, pMembers[0].nMemberSize, pMembers[1].nMemberSize);
pMembers++;
}
break;
}
// Move the data pointer and total length by the item size
nTotalLength += nDataLength;
pbData += nDataLength;
}
// If the structure size is greater than 4 bytes,
// we have to align it to 8-byte boundary
if(nTotalLength > 0x04)
nTotalLength = ALIGN_INT64(nTotalLength);
// At the end, we have to round the structure size up to 8-byte boundary
TreeView_Expand(hTreeView, hParentItem, TVE_EXPAND);
return nTotalLength;
}
// This function fills a variable length structure
// The data structure must contain "ULONG NextEntryOffset"
// as its very first member
static int FillStructMembersChained(
HWND hTreeView,
HTREEITEM hParentItem,
TStructMember * pMembers,
LPBYTE pbData,
LPBYTE pbDataEnd)
{
HTREEITEM hItem;
LPBYTE pbDataBegin = pbData;
TCHAR szItemName[128];
int nIndex = 0;
// Insert infos about the streams
while(pbData < pbDataEnd)
{
PCHAINED_ENTRY ChainedEntry = (PCHAINED_ENTRY)(pbData);
ULONG NextEntryOffset = ChainedEntry->NextEntryOffset;
// Fixup entries with artificial NextEntryOffset
if(ChainedEntry->NextEntryOffset & NEXT_ENTRY_OFFSET_ATRIFICIAL)
{
NextEntryOffset &= ~NEXT_ENTRY_OFFSET_ATRIFICIAL;
ChainedEntry->NextEntryOffset = 0;
}
StringCchPrintf(szItemName, _countof(szItemName), _T("[%u]"), nIndex++);
hItem = InsertTreeItem(hTreeView, hParentItem, szItemName, pbData);
FillStructureMembers(hTreeView, hItem, pMembers, pbData, pbDataEnd);
// If the "NextEntryOffset" is zero, we stop searching
if(NextEntryOffset == 0)
break;
pbData += NextEntryOffset;
}
// At the end, we have to round the structure size up to 8-byte boundary
// Return the total length of the stream info
TreeView_Expand(hTreeView, hParentItem, TVE_EXPAND);
return (ULONG)(pbData - pbDataBegin);
}
static size_t FillDialogWithFileInfo(HWND hDlg, TInfoData * pInfoData, int nInfoClass)
{
TFileTestData * pData = GetDialogData(hDlg);
HTREEITEM hRootItem = NULL;
LPBYTE pbNtInfoBuffEnd = pData->NtInfoData.pbData + pData->NtInfoData.cbData;
HWND hTreeView = GetDlgItem(hDlg, IDC_FILE_INFO);
HWND hComment = GetDlgItem(hDlg, IDC_COMMENT);
size_t nInputLength = 0;
BOOL bEnable = FALSE;
BOOL bShowTreeView = FALSE;
// Delete all items in the tree view
TreeView_DeleteAllItems(hTreeView);
// File infos and FS infos start from 1
assert(nInfoClass >= 1);
pInfoData = pInfoData + nInfoClass - 1;
// Fill the tree view.
// For some structures (like FILE_STREAM_INFORMATION),
// we have to do it manually, because our data struct description
// don't allow us to process the variable structs following each other
if(pInfoData->szStructName != NULL)
{
hRootItem = InsertTreeItem(hTreeView, TVI_ROOT, pInfoData->szStructName);
if(hRootItem != NULL && pInfoData->pStructMembers != NULL)
{
// Chained structures, like FILE_DIRECTORY_INFORMATION,
// require different approach.
if(pInfoData->bIsChain == FALSE)
{
nInputLength = FillStructureMembers(hTreeView,
hRootItem,
pInfoData->pStructMembers,
pData->NtInfoData.pbData,
pbNtInfoBuffEnd);
}
else
{
nInputLength = FillStructMembersChained(hTreeView,
hRootItem,
pInfoData->pStructMembers,
pData->NtInfoData.pbData,
pbNtInfoBuffEnd);
}
// Expand all subitems
bShowTreeView = TRUE;
bEnable = TRUE;
}
}
// Enable/disable input length and setinfo button
EnableDlgItems(hDlg, bEnable, IDC_INPUT_LENGTH_TITLE,
IDC_INPUT_LENGTH,
IDC_DEFAULT_LENGTH,
IDC_MAXIMUM_LENGTH,
0);
// Enable/disable the buttons
EnableOrDisableButtons(hDlg);
// Show/hide the tree view
if(bShowTreeView != IsWindowVisible(hTreeView))
{
ShowWindow(hTreeView, bShowTreeView ? SW_SHOW : SW_HIDE);
ShowWindow(hComment, bShowTreeView ? SW_HIDE : SW_SHOW);
}
return nInputLength;
}
static void FillDialogWithMasks(HWND hWndCombo)
{
ComboBox_InsertString(hWndCombo, -1, _T("NULL"));
ComboBox_InsertString(hWndCombo, -1, _T("*"));
ComboBox_InsertString(hWndCombo, -1, _T("*.*"));
ComboBox_InsertString(hWndCombo, -1, _T("*.exe"));
ComboBox_SetCurSel(hWndCombo, 0);
}
VOID CALLBACK TimerTooltipProc(HWND hDlg, UINT /* uMsg */, UINT_PTR /* idEvent */, DWORD /* dwTime */)
{
// Destroy the tooltip window
if(hToolTip != NULL)
DestroyWindow(hToolTip);
hToolTip = NULL;
// Kill the timer
if(nTimerTooltip != 0)
KillTimer(hDlg, nTimerTooltip);
nTimerTooltip = 0;
}
static int CopyItemToClipboard(HWND hDlg, TStructMember * pMemberInfo)
{
HGLOBAL hMem = NULL;
LPTSTR szClipboard = NULL;
size_t cbMemberData = 0;
DWORD dwErrCode = ERROR_CAN_NOT_COMPLETE;
// Get the binary length of the data
if(pMemberInfo->nDataType == TYPE_WNAME_L32B)
cbMemberData = *(PULONG)(pMemberInfo->pbStructPtr + pMemberInfo->nMemberSize);
// Only for known data
assert(cbMemberData != 0);
// Allocate space for clipboard
hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, cbMemberData + 2);
if(hMem != NULL)
{
// Lock the memory
szClipboard = (LPTSTR)GlobalLock(hMem);
if(szClipboard != NULL)
{
// Copy the data to the clipboard
CopyMemory(szClipboard, pMemberInfo->pbDataPtr, cbMemberData);
GlobalUnlock(hMem);
// Open the clipboard
if(OpenClipboard(hDlg))
{
EmptyClipboard();
if(SetClipboardData(CF_UNICODETEXT, hMem))
dwErrCode = ERROR_SUCCESS;
CloseClipboard();
}
}
GlobalFree(hMem);
}
return dwErrCode;
}
static bool FileIdHasFileName(HWND hTreeView, HTREEITEM hItem)
{
TVITEM tvi;
bool bResult = false;
// Allocate buffer for a maximum possible file name length
tvi.mask = TVIF_TEXT;
tvi.hItem = hItem;
tvi.pszText = new TCHAR[MAX_NT_PATH + 1];
tvi.cchTextMax = MAX_NT_PATH;
if(tvi.pszText != NULL)
{
// Load the tree view text
TreeView_GetItem(hTreeView, &tvi);
if(tvi.cchTextMax != 0)
{
// If there is a file name tail (" (\"), then we have file name there
if(_tcschr(tvi.pszText, _T('(')))
bResult = true;
}
delete [] tvi.pszText;
}
return bResult;
}
static TInfoData * GetSelectedInfoClass(HWND hDlg, UINT nIDCombo, TInfoData * pInfoData)
{
TCHAR szSelection[MAX_PATH];
HWND hWndCombo = GetDlgItem(hDlg, nIDCombo);
int nSelection = ComboBox_GetCurSel(hWndCombo);
// If there's an active selection,
// we need to find the proper item by the string
if(nSelection != CB_ERR)
{
// Retrieve the actually selected item
if(ComboBox_GetLBText(hWndCombo, nSelection, szSelection) > 0)
{
// Find the proper info class
for(int i = 0; pInfoData[i].szInfoClass != NULL; i++)
{
if(!_tcsicmp(pInfoData[i].szInfoClass, szSelection))
{
return pInfoData + i;
}
}
}
}
return NULL;
}
//-----------------------------------------------------------------------------
// Message handlers
static TAnchors * pAnchors1 = NULL; // For NtFileInfo
static TAnchors * pAnchors2 = NULL; // For NtVolInfo
static int OnInitDialog(HWND hDlg, LPARAM lParam)
{
TFileTestData * pData;
PROPSHEETPAGE * pPage = (PROPSHEETPAGE *)lParam;
TAnchors * pAnchors = NULL;
HWND hWndChild;
// Allocate the buffer for file information class.
// Hopefully the struct size will never exceed 32 KB
pData = (TFileTestData *)pPage->lParam;
// Initialize the dialog
SetDialogData(hDlg, pPage->lParam);
hDirTarget = NULL;
// Configure dialog resizing
if(pData->bEnableResizing)
{
if(GetDlgItem(hDlg, IDC_QUERY_INFO) != NULL)
{
pAnchors1 = new TAnchors(hDlg);
pAnchors = pAnchors1;
}
if(GetDlgItem(hDlg, IDC_QUERY_VOL_INFO) != NULL)
{
pAnchors2 = new TAnchors(hDlg);
pAnchors = pAnchors2;
}
pAnchors->AddAnchor(hDlg, IDC_FILE_INFO_CLASS_TITLE, akLeft | akTop | akRight);
pAnchors->AddAnchor(hDlg, IDC_FILE_INFO_CLASS, akLeft | akTop | akRight);
pAnchors->AddAnchor(hDlg, IDC_VOL_INFO_CLASS_TITLE, akLeft | akTop | akRight);
pAnchors->AddAnchor(hDlg, IDC_VOL_INFO_CLASS, akLeft | akTop | akRight);
// pAnchors->AddAnchor(hDlg, IDC_SEARCH_MASK_TITLE, akLeft | akTop);
// pAnchors->AddAnchor(hDlg, IDC_SEARCH_MASK, akLeft | akTop);
pAnchors->AddAnchor(hDlg, IDC_INPUT_LENGTH_TITLE, akLeft | akTop | akRight);
pAnchors->AddAnchor(hDlg, IDC_INPUT_LENGTH, akLeft | akTop | akRight);
pAnchors->AddAnchor(hDlg, IDC_DEFAULT_LENGTH, akTop | akRight);
pAnchors->AddAnchor(hDlg, IDC_MAXIMUM_LENGTH, akTop | akRight);
pAnchors->AddAnchor(hDlg, IDC_COMMENT, akAll);
pAnchors->AddAnchor(hDlg, IDC_FILE_INFO, akAll);
pAnchors->AddAnchor(hDlg, IDC_QUERY_INFO, akLeft | akBottom);
pAnchors->AddAnchor(hDlg, IDC_QUERY_DIR, akLeftCenter | akBottom);
pAnchors->AddAnchor(hDlg, IDC_SET_INFO, akRight | akBottom);
pAnchors->AddAnchor(hDlg, IDC_QUERY_VOL_INFO, akLeft | akBottom);
pAnchors->AddAnchor(hDlg, IDC_SET_VOL_INFO, akRight | akBottom);
pAnchors->AddAnchor(hDlg, IDC_RESULT_FRAME, akLeft | akRight | akBottom);
pAnchors->AddAnchor(hDlg, IDC_ERROR_CODE_TITLE, akLeft | akBottom);
pAnchors->AddAnchor(hDlg, IDC_ERROR_CODE, akLeft | akRight | akBottom);
pAnchors->AddAnchor(hDlg, IDC_INFORMATION_TITLE, akLeft | akBottom);
pAnchors->AddAnchor(hDlg, IDC_INFORMATION, akLeft | akRight | akBottom);
}
// Allocate default size for the FileInfo.
pData->NtInfoData.SetLength(INITIAL_FILEINFO_BUFFER_SIZE);
// Fill the combo box with names of file information classes
hWndChild = GetDlgItem(hDlg, IDC_FILE_INFO_CLASS);
if(hWndChild != NULL)
{
// Fill all info classes for NtSetInformationFile
FillComboBoxFiltered(hWndChild, FileInfoData, _T(""));
ComboBox_SetCurSel(hWndChild, (int)InitialFileInfo - 1);
SetFocus(hWndChild);
// Initialize tree view with structure for current
// file information class
FillDialogWithFileInfo(hDlg, FileInfoData, (int)InitialFileInfo);
}
// Fill the combo box with names of volume information classes
hWndChild = GetDlgItem(hDlg, IDC_VOL_INFO_CLASS);
if(hWndChild != NULL)
{
// Fill all info classes for NtSetVolumeInformationFile
FillComboBoxFiltered(hWndChild, FsInfoData, _T(""));
ComboBox_SetCurSel(hWndChild, (int)InitialFsInfo - 1);
SetFocus(hWndChild);
// Initialize tree view with structure for current
// file information class
FillDialogWithFileInfo(hDlg, FsInfoData, (int)InitialFsInfo);
}
// Configure the search mask edit box
hWndChild = GetDlgItem(hDlg, IDC_SEARCH_MASK);
if(hWndChild != NULL)
FillDialogWithMasks(hWndChild);
// Initialize the in/out data length
Hex2DlgText32(hDlg, IDC_INPUT_LENGTH, (DWORD)(pData->NtInfoData.cbData));
// Configure the buttons
EnableOrDisableButtons(hDlg);
return TRUE;
}
// Posted when the item label has been edited.
// We will fix the tree item to contain "Name: Value" text
static int OnReloadItems(HWND hDlg, HWND hTreeView, HTREEITEM hTreeItem)
{
// If the treeview edit process has not been completed yet,
// post the processing again
if(TreeView_GetEditControl(hTreeView) != NULL)
{
PostMessage(hDlg, WM_RELOADITEMS, (WPARAM)hTreeView, (LPARAM)hTreeItem);
return TRUE;
}
ReloadTreeViewItems(hDlg, hTreeView, hTreeItem);
return TRUE;
}
static int OnShowDateFormats(HWND hDlg, HWND hTreeItem, HTREEITEM hItem)
{
TOOLINFO ti;
LPTSTR szText;
TCHAR szDateFormatPrefix[120];
TCHAR szTimeFormatPrefix[120];
TCHAR szTitle[120];
POINT pt;
RECT rect;
int nMaxChars = 0x1000;
// Get the position of the treeview item
TreeView_GetItemRect(hTreeItem, hItem, &rect, TRUE);
pt.x = rect.left + (rect.right - rect.left) / 2;
pt.y = rect.top + (rect.bottom - rect.top) / 2;
ClientToScreen(hTreeItem, &pt);
// Allocate text for error
szText = new TCHAR[nMaxChars + 1];
if(szText == NULL)
return TRUE;
// Prepare the text for the tooltip
LoadString(g_hInst, IDS_BAD_DATETIME_FORMAT, szTitle, _countof(szTitle));
LoadString(g_hInst, IDS_DATE_FORMAT_PREFIX, szDateFormatPrefix, _countof(szDateFormatPrefix));
LoadString(g_hInst, IDS_TIME_FORMAT_PREFIX, szTimeFormatPrefix, _countof(szTimeFormatPrefix));
GetSupportedDateTimeFormats(szDateFormatPrefix, szTimeFormatPrefix, szText, nMaxChars);
// Create the additional tooltip window
if(hToolTip == NULL)
{
hToolTip = CreateWindowEx(WS_EX_TOPMOST,
TOOLTIPS_CLASS,
NULL,
WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP | TTS_BALLOON | TTS_CLOSE,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
hDlg,
NULL,
g_hInst,
NULL);
}
if(hToolTip != NULL)
{
// Set the one (and only one) tooltip window for the list view
ZeroMemory(&ti, sizeof(TOOLINFO));
ti.cbSize = sizeof(TOOLINFO);
ti.uFlags = TTF_TRACK | TTF_TRANSPARENT | TTF_IDISHWND;
ti.hinst = g_hInst;
ti.lpszText = szText;
ti.uId = (UINT_PTR)hTreeItem;
SendMessage(hToolTip, TTM_ADDTOOL, 0, (LPARAM)&ti);
// Set the icon and title
SendMessage(hToolTip, TTM_SETTITLE, TTI_INFO, (LPARAM)szTitle);
// Force the tooltip to be multi-line by specifying max width
GetClientRect(hDlg, &rect);
SendMessage(hToolTip, TTM_SETMAXTIPWIDTH, 0, (LPARAM)(rect.right - rect.left));
// Set the tooltip position
SendMessage(hToolTip, TTM_TRACKPOSITION, 0, MAKELONG(pt.x, pt.y));
// Show the tooltip
SendMessage(hToolTip, TTM_TRACKACTIVATE, TRUE, (LPARAM)&ti);
// Set the tooltip timer
nTimerTooltip = SetTimer(hDlg, WM_TIMER_TOOLTIP, 10000, TimerTooltipProc);
}
// Free buffers and exit
if(szText != NULL)
delete [] szText;
return TRUE;
}
static int OnSetActive(HWND hDlg)
{
EnableOrDisableButtons(hDlg);
return TRUE;
}
static int OnBeginLabelEdit(HWND hDlg, NMTVDISPINFO * pTVDispInfo)
{
TStructMember * pMemberInfo = (TStructMember *)pTVDispInfo->item.lParam;
TInfoData * pInfoData;
NTSTATUS CantEditStatus = STATUS_CANNOT_EDIT_THIS;
TCHAR szItemText[1024] = _T("");
HWND hTreeView = pTVDispInfo->hdr.hwndFrom;
HWND hEdit;
BOOL bStartEditing = FALSE;
bool bCopyToClipboard = false;
bool bEditable = true;
// If there is a tooltip active, destroy it
TimerTooltipProc(hDlg, 0, 0, 0);
// Verify if the selected file info class is editable
pInfoData = GetSelectedInfoClass(hDlg, IDC_FILE_INFO_CLASS, FileInfoData);
if(pInfoData != NULL)
{
if(pInfoData->bIsChain == TRUE || pInfoData->bIsEditable == FALSE)
bEditable = false;
if(pMemberInfo != NULL && pMemberInfo->nDataType == TYPE_WNAME_L32B)
bCopyToClipboard = true;
}
// Verify if the selected FS info class is editable
pInfoData = GetSelectedInfoClass(hDlg, IDC_VOL_INFO_CLASS, FsInfoData);
if(pInfoData != NULL)
{
if(pInfoData->bIsChain == TRUE || pInfoData->bIsEditable == FALSE)
bEditable = false;
}
// If not editable, show message
if(bEditable == false)
{
if(bCopyToClipboard)
{
CopyItemToClipboard(hDlg, pMemberInfo);
CantEditStatus = STATUS_COPIED_TO_CLIPBOARD;
}
SetResultInfo(hDlg, RSI_NTSTATUS | RSI_NOINFO, CantEditStatus);
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, TRUE);
return TRUE;
}
// If the item has an associated struct member, allow editing
if(pMemberInfo != NULL)
{
// Get the edit control which will be shown
hEdit = TreeView_GetEditControl(hTreeView);
if(hEdit != NULL)
{
// Get the item text
if(DataToItemText(pMemberInfo, szItemText, _countof(szItemText), TRUE) == ERROR_SUCCESS)
{
SetWindowText(hEdit, szItemText);
bStartEditing = TRUE;
}
}
}
// If we start editing something, make sure that Esc key will not
// cancel the entire FileTest
DisableCloseDialog(hDlg, bStartEditing);
// Store the result info the dialog's private variables
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, bStartEditing ? FALSE : TRUE);
return TRUE;
}
static int OnEndLabelEdit(HWND hDlg, NMTVDISPINFO * pTVDispInfo)
{
TStructMember * pMemberInfo = (TStructMember *)pTVDispInfo->item.lParam;
NTSTATUS Status;
HWND hTreeView = pTVDispInfo->hdr.hwndFrom;
BOOL bAcceptChanges = FALSE;
// If the item has an associated member, analyze the result text
if(pMemberInfo != NULL && pTVDispInfo->item.pszText != NULL)
{
// Try to convert the text to appropriate data item
Status = ItemTextToData(pMemberInfo, pTVDispInfo->item.pszText);
if(NT_SUCCESS(Status))
{
HTREEITEM hParentItem;
// We have to reload all items at the same level, because
// the ItemTextToData might have changed more than one item data
// (Example: variable length strings editation change also the length)
hParentItem = TreeView_GetNextItem(hTreeView, pTVDispInfo->item.hItem, TVGN_PARENT);
PostMessage(hDlg, WM_RELOADITEMS, (WPARAM)hTreeView, (LPARAM)hParentItem);
bAcceptChanges = TRUE;
}
else
{
// If the user failed to enter proper date/time, show him the possible options
if(pMemberInfo->nDataType == TYPE_FILETIME)
PostMessage(hDlg, WM_SHOW_DATE_FORMATS, (WPARAM)hTreeView, (LPARAM)pTVDispInfo->item.hItem);
// We should warn the user about that the item
// has invalid format for its data type
SetResultInfo(hDlg, RSI_NTSTATUS | RSI_NOINFO, Status);
}
}
// Enable the exit button
DisableCloseDialog(hDlg, FALSE);
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, bAcceptChanges);
return TRUE;
}
static int OnDoubleClick(HWND hDlg, LPNMHDR pNMHDR)
{
TStructMember * pMemberInfo;
TFileTestData * pData = GetDialogData(hDlg);
PLARGE_INTEGER pliValue;
TInfoData * pInfoData;
HTREEITEM hParentItem;
HTREEITEM hItem;
LPCTSTR szFormat = _T("%s: %08X-%08X (%s)");
LPTSTR szFileName = NULL;
LPTSTR szItemText = NULL;
TVITEM tvi;
size_t nLength;
HWND hTreeView;
// Only accept doubleclicks on IDC_FILE_INFO
if(pNMHDR->idFrom != IDC_FILE_INFO)
return TRUE;
hTreeView = GetDlgItem(hDlg, (int)pNMHDR->idFrom);
// Retrieve the selected item
hItem = TreeView_GetSelection(hTreeView);
if(hItem == NULL)
return TRUE;
// Retrieve the item's data
pMemberInfo = (TStructMember *)TreeView_GetItemParam(hTreeView, hItem);
if(pMemberInfo == NULL)
return TRUE;
// Doubleclick on a file ID appends a file name after it
if(pMemberInfo->nDataType == TYPE_FILEID64)
{
// If the file name is not there yet, query the file name
if(FileIdHasFileName(hTreeView, hItem) == false)
{
szFileName = FileIDToFileName(pData->szFileName1, pMemberInfo->pbDataPtr, pMemberInfo->nMemberSize);
if(szFileName != NULL)
{
nLength = _tcslen(pMemberInfo->szMemberName) + _tcslen(szFormat) + 16 + _tcslen(szFileName);
szItemText = new TCHAR[nLength];
if(szItemText != NULL)
{
// Format the item text
pliValue = (PLARGE_INTEGER)pMemberInfo->pbDataPtr;
StringCchPrintf(szItemText, nLength,
szFormat,
pMemberInfo->szMemberName,
pliValue->HighPart,
pliValue->LowPart,
szFileName);
// Apply the item text to the tree view
ZeroMemory(&tvi, sizeof(TVITEM));
tvi.mask = TVIF_TEXT;
tvi.hItem = hItem;
tvi.pszText = szItemText;
TreeView_SetItem(hTreeView, &tvi);
delete [] szItemText;
}
delete [] szFileName;
}
}
else
{
ULONGLONG FileId = *(PULONGLONG)pMemberInfo->pbDataPtr;
TCHAR szFileId[MAX_FILEID_PATH];
FileIDToString(pData, FileId, szFileId);
NtUseFileId(hDlg, szFileId);
}
}
// Doubleclick on a subdirectory or stream name
// creates a full path and switches to "NtCreate"
if(pMemberInfo->nDataType == TYPE_WNAME_L32B)
{
HWND hWndParent = GetParent(hDlg);
HWND hTabCtrl = GetDlgItem(hWndParent, IDC_TAB);
ULONG FileNameLength = *(PULONG)(pMemberInfo->pbStructPtr + pMemberInfo->nMemberSize);
szFileName = CreateFullName(pData->szFileName1, (LPWSTR)pMemberInfo->pbDataPtr, FileNameLength);
if(szFileName != NULL)
{
StringCchCopy(pData->szFileName1, MAX_NT_PATH, szFileName);
TabCtrl_SelectPageByID(hTabCtrl, MAKEINTRESOURCE(IDD_PAGE02_NTCREATE));
delete [] szFileName;
}
}
// Doubleclick on TYPE_FLAG* opens a dialog with flags
if(pMemberInfo->nDataType == TYPE_FLAG8 || pMemberInfo->nDataType == TYPE_FLAG16 || pMemberInfo->nDataType == TYPE_FLAG32)
{
DWORD Flags;
switch (pMemberInfo->nDataType)
{
case TYPE_FLAG8:
Flags = *(PBYTE)pMemberInfo->pbStructPtr;
break;
case TYPE_FLAG16:
Flags = *(PWORD)pMemberInfo->pbStructPtr;
break;
case TYPE_FLAG32:
Flags = *(PDWORD)pMemberInfo->pbStructPtr;
break;
}
if(FlagsDialog(hDlg, IDS_ENTER_FLAGS, pMemberInfo->pFlags, Flags))
{
// Only change the item if editable
pInfoData = GetSelectedInfoClass(hDlg, IDC_FILE_INFO_CLASS, FileInfoData);
if(pInfoData != NULL && pInfoData->bIsEditable)
{
switch (pMemberInfo->nDataType)
{
case TYPE_FLAG8:
*(PBYTE)pMemberInfo->pbStructPtr = (BYTE)Flags;
break;
case TYPE_FLAG16:
*(PWORD)pMemberInfo->pbStructPtr = (WORD)Flags;
break;
case TYPE_FLAG32:
*(PDWORD)pMemberInfo->pbStructPtr = Flags;
break;
}
hParentItem = TreeView_GetNextItem(hTreeView, hItem, TVGN_PARENT);
PostMessage(hDlg, WM_RELOADITEMS, (WPARAM)hTreeView, (LPARAM)hParentItem);
}
}
}
return TRUE;
}
//
// Provides some extension to the default combo box search
//
// When the user types something, the combo box's drop list
// is filtered. Only those items that are in the list are included
//
// If the user types "Stand", then only these items are displayed:
//
// "FileStandardInformation"
// "FileStandardLinkInformation"
//
static int OnComboBoxEditUpdate(HWND hDlg, UINT nID, TInfoData * pInfoData)
{
TCHAR szEditText[MAX_PATH+1];
HWND hWndCombo = GetDlgItem(hDlg, nID);
if(!ComboBox_GetDroppedState(hWndCombo))
ComboBox_ShowDropdown(hWndCombo, TRUE);
// Get the text from the combo box
GetWindowText(hWndCombo, szEditText, MAX_PATH);
// Reset the combo box to only contain items with that substring
CharUpper(szEditText);
FillComboBoxFiltered(hWndCombo, pInfoData, szEditText);
// The text might have been changed by the text filling
return TRUE;
}
static int OnComboBoxItemSelected(HWND hDlg, UINT nID, TInfoData * pInfoData)
{
TFileTestData * pData = GetDialogData(hDlg);
// If there's an active selection, fill the dialog
pInfoData = GetSelectedInfoClass(hDlg, nID, pInfoData);
if(pInfoData != NULL)
{
ZeroMemory(pData->NtInfoData.pbData, pData->NtInfoData.cbData);
FillDialogWithFileInfo(hDlg, pInfoData, 1);
Hex2DlgText32(hDlg, IDC_INPUT_LENGTH, (DWORD)(pData->NtInfoData.cbDataMax));
}
return TRUE;
}
static int OnDefaultLengthClick(HWND hDlg)
{
TFileTestData * pData = GetDialogData(hDlg);
TInfoData * pInfoData;
UINT nDataLength = 0;
// Default length for file info class
pInfoData = GetSelectedInfoClass(hDlg, IDC_FILE_INFO_CLASS, FileInfoData);
if(pInfoData != NULL)
nDataLength = GetStructLength(pInfoData->pStructMembers);
// Default length for FS info class
pInfoData = GetSelectedInfoClass(hDlg, IDC_VOL_INFO_CLASS, FsInfoData);
if(pInfoData != NULL)
nDataLength = GetStructLength(pInfoData->pStructMembers);
pData->NtInfoData.SetLength(nDataLength);
Hex2DlgText32(hDlg, IDC_INPUT_LENGTH, nDataLength);
return TRUE;
}
static int OnMaximumLengthClick(HWND hDlg)
{
TFileTestData * pData = GetDialogData(hDlg);
pData->NtInfoData.SetLength(pData->NtInfoData.cbDataMax);
Hex2DlgText32(hDlg, IDC_INPUT_LENGTH, (DWORD)(pData->NtInfoData.cbDataMax));
return TRUE;
}
static int OnQueryInfoClick(HWND hDlg)
{
FILE_INFORMATION_CLASS FileInfoClass;
TFileTestData * pData = GetDialogData(hDlg);
IO_STATUS_BLOCK IoStatus = {0};
TInfoData * pInfoData;
NTSTATUS Status = STATUS_SUCCESS;
ULONG Length = 0;
// Test if the handle is an NT file handle and get the file info class
if(IsHandleValid(pData->hFile) == FALSE)
return FALSE;
// Get the selected info data
pInfoData = GetSelectedInfoClass(hDlg, IDC_FILE_INFO_CLASS, FileInfoData);
if(pInfoData == NULL)
return FALSE;
// Get the file information class
FileInfoClass = (FILE_INFORMATION_CLASS)(pInfoData->InfoClass);
// Get the input length
DlgText2Hex32(hDlg, IDC_INPUT_LENGTH, &Length);
// If the required length is bigger than the current one, reallocate the buffer
pData->NtInfoData.SetLength(Length);
// Perform the call
if(NT_SUCCESS(Status))
{
Status = NtQueryInformationFile(pData->hFile,
&IoStatus,
pData->NtInfoData.pbData,
Length,
FileInfoClass);
}
// If succeeded, we have to fill the dialog with file info
if(NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW)
FillDialogWithFileInfo(hDlg, FileInfoData, (int)FileInfoClass);
// Set the result status and return
SetResultInfo(hDlg, RSI_NTSTATUS | RSI_INFORMATION, Status, &IoStatus);
return TRUE;
}
static int OnQueryDirClick(HWND hDlg)
{
FILE_INFORMATION_CLASS FileInfoClass;
TFileTestData * pData = GetDialogData(hDlg);
IO_STATUS_BLOCK IoStatus = {0};
PUNICODE_STRING FileMask = NULL;
TInfoData * pInfoData;
ULONG_PTR TotalLength = 0;
NTSTATUS Status = STATUS_SUCCESS;
BOOLEAN RestartScan = TRUE;
HANDLE hEvent = NULL;
ULONG Length = 0;
// Test if the handle is an NT file handle and get the file info class
if(IsHandleValid(pData->hFile) == FALSE)
return FALSE;
// Get the selected info data
pInfoData = GetSelectedInfoClass(hDlg, IDC_FILE_INFO_CLASS, FileInfoData);
if(pInfoData == NULL)
return FALSE;
// Get the file information class
FileInfoClass = (FILE_INFORMATION_CLASS)(pInfoData->InfoClass);
// Get the input mask
FileMask = GetQueryDirectoryMask(hDlg, IDC_SEARCH_MASK);
// Get the input length
DlgText2Hex32(hDlg, IDC_INPUT_LENGTH, &Length);
// If the required length is bigger than the current one, reallocate the buffer
pData->NtInfoData.SetLength(Length);
// Create event for asynchronous calls
if(NT_SUCCESS(Status))
{
hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if(hEvent == NULL)
Status = STATUS_UNSUCCESSFUL;
}
// Perform the directory query. Note that we need to keep enumerating
// until we get out of memory or until STATUS_NO_MORE_FILES is returned.
// https://github.com/ladislav-zezula/FileTest/issues/32
if(NT_SUCCESS(Status))
{
PCHAINED_ENTRY LastEntry = NULL;
LPBYTE pbDataEnd = pData->NtInfoData.pbData + pData->NtInfoData.cbData;
LPBYTE pbDataPtr = pData->NtInfoData.pbData;
// Do not allow buffer overflow
while(pbDataPtr < pbDataEnd)
{
// Perform the single directory query
Status = NtQueryDirectoryFile(pData->hFile,
hEvent,
NULL,
NULL,
&IoStatus,
pbDataPtr,
(ULONG)(pbDataEnd - pbDataPtr),
FileInfoClass,
FALSE,
FileMask,
RestartScan);
// If the operation is pending, we have to wait until it's complete
if(Status == STATUS_PENDING)
{
WaitForSingleObject(hEvent, INFINITE);
Status = IoStatus.Status;
}
// Calculate the total length returned
TotalLength = (pbDataPtr + IoStatus.Information) - pData->NtInfoData.pbData;
// Anything else than STATUS_SUCCESS will break the loop.
// At the end of the search, we expect STATUS_NO_MORE_FILES
if(Status != STATUS_SUCCESS)
break;
// If we have data from the previous search, mark the last entry
// so we can later process the whole buffer as if it was result of a single search
if(LastEntry != NULL)
DirEntry_Mark(LastEntry, pbDataPtr);
LastEntry = DirEntry_Find(pbDataPtr, IoStatus.Information);
// Prepare the 8-byte-aligned pointer to the next directory query
pbDataPtr += ALIGN_TO_SIZE(IoStatus.Information, 0x08);
RestartScan = FALSE;
}
}
// If succeeded, we have to fill the dialog with file info
if(NT_SUCCESS(Status) || Status == STATUS_NO_MORE_FILES || Status == STATUS_BUFFER_OVERFLOW)
{
pData->NtInfoData.SetLength(TotalLength);
FillDialogWithFileInfo(hDlg, FileInfoData, (int)FileInfoClass);
}
// Set the result status and return
if(hEvent != NULL)
CloseHandle(hEvent);
if(FileMask != NULL)
HeapFree(g_hHeap, 0, FileMask);
SetResultInfo(hDlg, RSI_NTSTATUS | RSI_INFORMATION, Status, &IoStatus);
return TRUE;
}
static int OnSetInfoClick(HWND hDlg)
{
FILE_INFORMATION_CLASS FileInfoClass;
TFileTestData * pData = GetDialogData(hDlg);
IO_STATUS_BLOCK IoStatus = {0};
TInfoData * pInfoData;
NTSTATUS Status = STATUS_SUCCESS;
ULONG Length = 0;
// Test if the handle is an NT file handle and get the file info class
if(IsHandleValid(pData->hFile) == FALSE)
return FALSE;
// Get the selected info data
pInfoData = GetSelectedInfoClass(hDlg, IDC_FILE_INFO_CLASS, FileInfoData);
if(pInfoData == NULL)
return FALSE;
// Get the file information class
FileInfoClass = (FILE_INFORMATION_CLASS)(pInfoData->InfoClass);
// Get the length of the input data
DlgText2Hex32(hDlg, IDC_INPUT_LENGTH, &Length);
// If the required length is bigger than the current one, reallocate the buffer
pData->NtInfoData.SetLength(Length);
// Call NtSetInformationFile
if(NT_SUCCESS(Status))
{
Status = NtSetInformationFile(pData->hFile,
&IoStatus,
pData->NtInfoData.pbData,
Length,
FileInfoClass);
}
// Set the result status and return
SetResultInfo(hDlg, RSI_NTSTATUS | RSI_INFORMATION, Status, &IoStatus);
return TRUE;
}
static int OnQueryFsInfoClick(HWND hDlg)
{
FS_INFORMATION_CLASS FsInfoClass;
TFileTestData * pData = GetDialogData(hDlg);
TInfoData * pInfoData;
IO_STATUS_BLOCK IoStatus = {0};
NTSTATUS Status = STATUS_SUCCESS;
ULONG Length = 0;
// Test if the handle is an NT file handle and get the file info class
if(IsHandleValid(pData->hFile) == FALSE)
return FALSE;
// Get the selected info data
pInfoData = GetSelectedInfoClass(hDlg, IDC_VOL_INFO_CLASS, FsInfoData);
if(pInfoData == NULL)
return FALSE;
// Get the file system info class
FsInfoClass = (FS_INFORMATION_CLASS)(pInfoData->InfoClass);
// Get the input length
DlgText2Hex32(hDlg, IDC_INPUT_LENGTH, &Length);
// If the required length is bigger than the current one, reallocate the buffer
pData->NtInfoData.SetLength(Length);
// Perform the call
if(NT_SUCCESS(Status))
{
Status = NtQueryVolumeInformationFile(pData->hFile,
&IoStatus,
pData->NtInfoData.pbData,
Length,
FsInfoClass);
}
// If succeeded, we have to fill the dialog with file info
if(NT_SUCCESS(Status) || Status == STATUS_BUFFER_OVERFLOW)
FillDialogWithFileInfo(hDlg, FsInfoData, (int)FsInfoClass);
// Set the result status and return
SetResultInfo(hDlg, RSI_NTSTATUS | RSI_INFORMATION, Status, &IoStatus);
return TRUE;
}
static int OnSetFsInfoClick(HWND hDlg)
{
FS_INFORMATION_CLASS FsInfoClass;
TFileTestData * pData = GetDialogData(hDlg);
IO_STATUS_BLOCK IoStatus = {0};
TInfoData * pInfoData;
NTSTATUS Status = STATUS_SUCCESS;
ULONG Length = 0;
// Test if the handle is an NT file handle and get the file info class
if(IsHandleValid(pData->hFile) == FALSE)
return FALSE;
// Get the selected info data
pInfoData = GetSelectedInfoClass(hDlg, IDC_VOL_INFO_CLASS, FsInfoData);
if(pInfoData == NULL)
return FALSE;
// Get the file system info class
FsInfoClass = (FS_INFORMATION_CLASS)(pInfoData->InfoClass);
// Get the length of the input data
DlgText2Hex32(hDlg, IDC_INPUT_LENGTH, &Length);
// If the required length is bigger than the current one, reallocate the buffer
pData->NtInfoData.SetLength(Length);
// Call NtSetInformationFile
if(NT_SUCCESS(Status))
{
Status = NtSetVolumeInformationFile(pData->hFile,
&IoStatus,
pData->NtInfoData.pbData,
Length,
FsInfoClass);
}
// Set the result status and return
SetResultInfo(hDlg, RSI_NTSTATUS | RSI_INFORMATION, Status, &IoStatus);
return TRUE;
}
static int OnCommand(HWND hDlg, UINT nNotify, UINT nIDCtrl)
{
if(nNotify == BN_CLICKED || nNotify == 1)
{
switch(nIDCtrl)
{
case ID_EDIT_LABEL:
return TreeView_EditLabel_ID(hDlg, IDC_FILE_INFO);
case IDC_DEFAULT_LENGTH:
return OnDefaultLengthClick(hDlg);
case IDC_MAXIMUM_LENGTH:
return OnMaximumLengthClick(hDlg);
case IDC_QUERY_INFO:
return OnQueryInfoClick(hDlg);
case IDC_QUERY_DIR:
return OnQueryDirClick(hDlg);
case IDC_SET_INFO:
return OnSetInfoClick(hDlg);
case IDC_QUERY_VOL_INFO:
return OnQueryFsInfoClick(hDlg);
case IDC_SET_VOL_INFO:
return OnSetFsInfoClick(hDlg);
}
}
// Extra handling for comboboxes with info class
if(nIDCtrl == IDC_FILE_INFO_CLASS || nIDCtrl == IDC_VOL_INFO_CLASS)
{
switch(nNotify)
{
// Provide more convenient item search than the default one
case CBN_EDITUPDATE:
OnComboBoxEditUpdate(hDlg, nIDCtrl, (nIDCtrl == IDC_FILE_INFO_CLASS) ? FileInfoData : FsInfoData);
return TRUE;
// If the selection has been changed, reflect it in the dialog
case CBN_SELENDOK:
OnComboBoxItemSelected(hDlg, nIDCtrl, (nIDCtrl == IDC_FILE_INFO_CLASS) ? FileInfoData : FsInfoData);
return TRUE;
}
}
return FALSE;
}
static int OnNotify(HWND hDlg, NMHDR * pNMHDR)
{
switch(pNMHDR->code)
{
case PSN_SETACTIVE:
return OnSetActive(hDlg);
case PSN_KILLACTIVE:
TimerTooltipProc(hDlg, WM_TIMER, 0, 0);
break;
case TVN_SELCHANGED:
TimerTooltipProc(hDlg, WM_TIMER, 0, 0);
break;
case TVN_BEGINLABELEDIT:
return OnBeginLabelEdit(hDlg, (NMTVDISPINFO *)pNMHDR);
case TVN_ENDLABELEDIT:
return OnEndLabelEdit(hDlg, (NMTVDISPINFO *)pNMHDR);
case TVN_KEYDOWN:
return OnTVKeyDown_CopyToClipboard(hDlg, (LPNMTVKEYDOWN)pNMHDR);
case NM_DBLCLK:
return OnDoubleClick(hDlg, pNMHDR);
}
return FALSE;
}
static int OnDestroy(HWND hDlg)
{
TimerTooltipProc(hDlg, WM_TIMER, 0, 0);
// Free the first anchors, if exist
if(pAnchors1 != NULL && pAnchors1->GetParentWindow() == hDlg)
{
delete pAnchors1;
pAnchors1 = NULL;
}
// Free the second anchors, if exist
if(pAnchors2 != NULL && pAnchors2->GetParentWindow() == hDlg)
{
delete pAnchors2;
pAnchors2 = NULL;
}
// Close the target directory handle
if(IsHandleValid(hDirTarget))
NtClose(hDirTarget);
hDirTarget = NULL;
return FALSE;
}
//-----------------------------------------------------------------------------
// Public functions
INT_PTR CALLBACK PageProc06(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_INITDIALOG:
return OnInitDialog(hDlg, lParam);
case WM_SIZE:
if(pAnchors1 != NULL && pAnchors1->GetParentWindow() == hDlg)
pAnchors1->OnMessage(uMsg, wParam, lParam);
if(pAnchors2 != NULL && pAnchors2->GetParentWindow() == hDlg)
pAnchors2->OnMessage(uMsg, wParam, lParam);
return FALSE;
case WM_ACTIVATE:
if(wParam == WA_INACTIVE)
TimerTooltipProc(hDlg, WM_TIMER, 0, 0);
break;
case WM_RELOADITEMS:
return OnReloadItems(hDlg, (HWND)wParam, (HTREEITEM)lParam);
case WM_SHOW_DATE_FORMATS:
return OnShowDateFormats(hDlg, (HWND)wParam, (HTREEITEM)lParam);
case WM_COMMAND:
return OnCommand(hDlg, HIWORD(wParam), LOWORD(wParam));
case WM_NOTIFY:
return OnNotify(hDlg, (NMHDR *)lParam);
case WM_DESTROY:
return OnDestroy(hDlg);
}
return FALSE;
}