MSWindowsServices.avt

Переключить прокрутку окна
Загрузить этот исходный код

/*
    Реализация среды исполнения языка программирования
    Объектно-ориентированный продвинутый векторный транслятор

    Copyright © 2021, 2024, 2026 Малик Разработчик

    Это свободная программа: вы можете перераспространять ее и/или изменять
    ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
    в каком она была опубликована Фондом свободного программного обеспечения;
    либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

    Эта программа распространяется в надежде, что она будет полезной,
    но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
    или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
    общественной лицензии GNU.

    Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
    вместе с этой программой. Если это не так, см.
    <https://www.gnu.org/licenses/>.
*/

package platform.dependent.mswindows.services;

import avt.io.*;
import platform.dependent.mswindows.kernel.*;
import platform.independent.filesystem.*;
import platform.independent.osservices.*;
import platform.independent.util.*;

public final class MSWindowsServices(platform.dependent.PlatformServices)
{
    private static int startThreadResult;
    private static CriticalSection startThreadOperation;

    private static Process currentProcess;

    private static OrderedTable fileSystemRootTable;
    private static CriticalSection fileSystemRootOperation;

    private static OutOfResourcesError errorOutOfResources;

    private static final long TAGGED_STACK_DATA_AREA_SIZE;
    private static final long TAGGED_STACK_CONTEXT_AREA_SIZE;

    public static void finalization() { finalize(); }

    public static boolean initialization() {
        int size = class.instanceSize;
        long ptr = Kernel.virtualAlloc(0, size + (-size & (MemoryRegion.PAGE_SIZE - 1)), Kernel.MEM_COMMIT, Kernel.PAGE_READWRITE);
        return ptr != 0 && initialize(ptr, class);
    }

    private static void initErrors() {
        errorOutOfResources = new OutOfResourcesError(platform.independent.osservices.package.getResourceString("!machine-error.out-of-resources"));
    }

    private static void initServices() {
        startThreadOperation = new CriticalSection();
        fileSystemRootTable = new OrderedTable();
        fileSystemRootOperation = new CriticalSection();
        currentProcess = new CurrentProcess();
        String workingDirectory = currentProcess.workingDirectory;
        if(workingDirectory.length >= 4 && workingDirectory[0] == '/' && workingDirectory[2] == ':' && workingDirectory[3] == '/')
        {
            char volumeLetter = workingDirectory[1];
            if(volumeLetter >= 'A' && volumeLetter <= 'Z' || volumeLetter >= 'a' && volumeLetter <= 'z')
            {
                volumeLetter &= 0x005f;
                String rootPath = new String(new char[] { '/', volumeLetter, ':' });
                fileSystemRootTable[rootPath] = new FileSystemDescriptor(rootPath, workingDirectory.substring(3));
            }
        }
    }

    private static void protectImportMemoryRegion() {
        long2 regionBounds = getImportMemoryRegionPointers();
        long regionBegin = regionBounds[0];
        long regionEnd = regionBounds[1];
        Kernel.virtualProtect(regionBegin, regionEnd - regionBegin + (-regionEnd & (MemoryRegion.PAGE_SIZE - 1)), Kernel.PAGE_READONLY);
    }

    private static int getDaysCount(int year, int month) {
        switch(month + 1)
        {
            case  1:
            case  3:
            case  5:
            case  7:
            case  8:
            case 10:
            case 12: return 31;
            case  4:
            case  6:
            case  9:
            case 11: return 30;
            case  2: return ++year % (year % 100 == 0 ? 400 : 4) == 0 ? 29 : 28;
            default: return 0;
        }
    }

    private static native long getThreadEntryPoint();

    private static native long2 getImportMemoryRegionPointers();

    private int fldProcessorNumberOfCores;
    private long fldMinimumApplicationAddress;
    private long fldMaximumApplicationAddress;
    private String fldOperatingSystemVersion;

    public () {  }

    /* время */

    public int currentOffsetInMillis() {
        TimeZoneInfo tzinfo = new TimeZoneInfo();
        Kernel.getTimeZoneInfo(tzinfo.getPointer());
        return -60000 * tzinfo.bias;
    }

    public long currentTimeInMillis() {
        SystemTime time = new SystemTime();
        Kernel.getSystemTime(time.getPointer());
        int yer;
        int year = yer = time.year - 1 & 0xffff;
        int month = time.month - 1;
        int day = time.dayOfMonth - 1;
        int hour = time.hour;
        int minute = time.minute;
        int second = time.second;
        int millisecond = time.millisecond;
        int days = 146097 * (year / 400);
        year %= 400;
        days += 36524 * (year / 100);
        year %= 100;
        days += 1461 * (year / 4) + 365 * (year % 4) + day;
        for(int mnt = 0; mnt < month; mnt++) days += getDaysCount(yer, mnt);
        return days * 86400000L + hour * 3600000L + minute * 60000L + second * 1000L + millisecond;
    }

    /* память */

    public void deallocateRegion(long2 region, int flags) {
        long address = region[0];
        long size = region[1];
        int freeFlags = Kernel.MEM_DECOMMIT;
        if((flags & MemoryRegion.RESERVED) == 0)
        {
            size = 0;
            freeFlags = Kernel.MEM_RELEASE;
        }
        Kernel.virtualFree(address, size, freeFlags);
    }

    public void setRegionProtectionBits(long2 region, int pbits) {
        int protect;
        switch(pbits & (MemoryRegion.EXECUTABLE | MemoryRegion.READABLE | MemoryRegion.WRITEABLE))
        {
            case MemoryRegion.READABLE:
            {
                protect = Kernel.PAGE_READONLY;
                break;
            }
            case MemoryRegion.WRITEABLE:
            case MemoryRegion.READABLE | MemoryRegion.WRITEABLE:
            {
                protect = Kernel.PAGE_READWRITE;
                break;
            }
            case MemoryRegion.EXECUTABLE:
            {
                protect = Kernel.PAGE_EXECUTE;
                break;
            }
            case MemoryRegion.EXECUTABLE | MemoryRegion.READABLE:
            {
                protect = Kernel.PAGE_EXECUTE_READ;
                break;
            }
            case MemoryRegion.EXECUTABLE | MemoryRegion.WRITEABLE:
            case MemoryRegion.EXECUTABLE | MemoryRegion.READABLE | MemoryRegion.WRITEABLE:
            {
                protect = Kernel.PAGE_EXECUTE_READWRITE;
                break;
            }
            default:
            {
                protect = Kernel.PAGE_NOACCESS;
            }
        }
        if(Kernel.virtualProtect(region[0], region[1], protect)[0] == 0)
        {
            throw new IllegalArgumentException(String.format(avt.lang.package.getResourceString("illegal-argument"), new Object[] { "region" }));
        }
    }

    public int getRegionProtectionBits(long2 region) {
        MemoryBasicInfo mbinfo = new MemoryBasicInfo();
        if(Kernel.virtualQuery(region[0], mbinfo.getPointer(), MemoryBasicInfo.class.structSize) == 0)
        {
            throw new IllegalArgumentException(String.format(avt.lang.package.getResourceString("illegal-argument"), new Object[] { "region" }));
        }
        switch(mbinfo.protect)
        {
            case Kernel.PAGE_READONLY         : return MemoryRegion.READABLE;
            case Kernel.PAGE_READWRITE        : return MemoryRegion.READABLE | MemoryRegion.WRITEABLE;
            case Kernel.PAGE_WRITECOPY        : return MemoryRegion.READABLE | MemoryRegion.WRITEABLE | MemoryRegion.SHARED;
            case Kernel.PAGE_EXECUTE          : return MemoryRegion.EXECUTABLE;
            case Kernel.PAGE_EXECUTE_READ     : return MemoryRegion.EXECUTABLE | MemoryRegion.READABLE;
            case Kernel.PAGE_EXECUTE_READWRITE: return MemoryRegion.EXECUTABLE | MemoryRegion.READABLE | MemoryRegion.WRITEABLE;
            case Kernel.PAGE_EXECUTE_WRITECOPY: return MemoryRegion.EXECUTABLE | MemoryRegion.READABLE | MemoryRegion.WRITEABLE | MemoryRegion.SHARED;
            default                           : return 0;
        }
    }

    public long2 allocateRegion(long2 region, int flags) {
        final long MEMORY_START_ADDRESS = 0xffff800000000000L;
        final long MEMORY_LIMIT_ADDRESS = 0x0000800000000000L;
        long address = region[0];
        long size = region[1];
        if(size < 0 || size > MEMORY_LIMIT_ADDRESS - MEMORY_START_ADDRESS || address != 0 && (address + size > MEMORY_LIMIT_ADDRESS || address < MEMORY_START_ADDRESS))
        {
            if(errorOutOfResources == null) return 0;
            throw new IllegalArgumentException(String.format(avt.lang.package.getResourceString("illegal-argument"), new Object[] { "region" }));
        }
        address &= -MemoryRegion.PAGE_SIZE;
        if(size == 0) size = 1;
        size += -size & (MemoryRegion.PAGE_SIZE - 1);
        int allocationFlags = Kernel.MEM_COMMIT;
        if((flags & MemoryRegion.RESERVED) != 0)
        {
            allocationFlags = Kernel.MEM_RESERVE;
            if((flags & (MemoryRegion.EXECUTABLE | MemoryRegion.READABLE | MemoryRegion.WRITEABLE)) != 0) allocationFlags |= Kernel.MEM_COMMIT;
        }
        if((flags & MemoryRegion.DOWN) != 0)
        {
            allocationFlags |= Kernel.MEM_TOP_DOWN;
        }
        int allocationProtect = Kernel.PAGE_NOACCESS;
        switch(flags & (MemoryRegion.EXECUTABLE | MemoryRegion.READABLE | MemoryRegion.WRITEABLE))
        {
            case MemoryRegion.READABLE:
            {
                allocationProtect = Kernel.PAGE_READONLY;
                break;
            }
            case MemoryRegion.WRITEABLE:
            case MemoryRegion.READABLE | MemoryRegion.WRITEABLE:
            {
                allocationProtect = Kernel.PAGE_READWRITE;
                break;
            }
            case MemoryRegion.EXECUTABLE:
            {
                allocationProtect = Kernel.PAGE_EXECUTE;
                break;
            }
            case MemoryRegion.EXECUTABLE | MemoryRegion.READABLE:
            {
                allocationProtect = Kernel.PAGE_EXECUTE_READ;
                break;
            }
            case MemoryRegion.EXECUTABLE | MemoryRegion.WRITEABLE:
            case MemoryRegion.EXECUTABLE | MemoryRegion.READABLE | MemoryRegion.WRITEABLE:
            {
                allocationProtect = Kernel.PAGE_EXECUTE_READWRITE;
                break;
            }
        }
        if((address = Kernel.virtualAlloc(address, size, allocationFlags, allocationProtect)) == 0) switch(Kernel.getLastError())
        {
            default:
            {
                if(errorOutOfResources == null) return 0;
                throw new IllegalArgumentException(avt.lang.package.getResourceString("illegal-argument.passed"));
            }
            case Kernel.ERROR_NOT_ENOUGH_MEMORY:
            {
                if(errorOutOfResources == null) return 0;
                throw errorOutOfResources;
            }
            case Kernel.NO_ERROR:
        }
        return new long2 { address, size };
    }

    public long2[] enumerateRegions() {
        MemoryBasicInfo mbinfo = new MemoryBasicInfo();
        long mbiPtr = mbinfo.getPointer();
        long mbiSize = MemoryBasicInfo.class.structSize;
        long address = fldMinimumApplicationAddress;
        long limit = fldMaximumApplicationAddress + 1;
        int length = 0;
        long2[] result = new long2[0x3f];
        while(address < limit && Kernel.virtualQuery(address, mbiPtr, mbiSize) != 0)
        {
            long size = mbinfo.regionSize;
            if(mbinfo.state != Kernel.MEM_FREE)
            {
                if(length == result.length) Array.copy(result, 0, result = new long2[length << 1 | 1], 0, length);
                result[length++] = new long2 { address, size };
            }
            address += size;
        }
        if(length != result.length) Array.copy(result, 0, result = new long2[length], 0, length);
        return result;
    }

    /* событие */

    public void destroyEvent(long eventDs) { Kernel.closeHandle(eventDs); }

    public void setSignalledEvent(long eventDs) { Kernel.setEvent(eventDs); }

    public void clearSignalledEvent(long eventDs) { Kernel.resetEvent(eventDs); }

    public void waitSignalledEvent(long eventDs, long timeInMillis, int timeInNanos) {
        final long timeMaximum = 0xfffffffeL;
        if(timeInMillis < Long.MAX_VALUE && timeInNanos >= 500000 || timeInMillis == 0 && timeInNanos > 0) timeInMillis++;
        Kernel.waitForSingleObject(eventDs, timeInMillis <= 0 ? Kernel.INFINITE : timeInMillis >= timeMaximum ? (int) timeMaximum : (int) timeInMillis);
    }

    public long createEvent(boolean manualReset, boolean initialState, char[] name) { return Kernel.createEvent(0, manualReset, initialState, name.getPointer()); }

    /* поток исполнения */

    public void yieldThread() { Kernel.switchToThread(); }

    public void setThreadPriority(long2 threadId, int priority) {
        int usedId = (int) threadId[1];
        long handle = Kernel.openThread(Kernel.THREAD_SET_LIMITED_INFORMATION, false, usedId);
        if(handle == Kernel.NULL) return;
        try
        {
            switch(priority)
            {
                case Thread.MIN_PRIORITY:
                {
                    priority = Kernel.THREAD_PRIORITY_IDLE;
                    break;
                }
                case Thread.LOW_PRIORITY - 1:
                {
                    priority = Kernel.THREAD_PRIORITY_LOWEST;
                    break;
                }
                case Thread.LOW_PRIORITY:
                {
                    priority = Kernel.THREAD_PRIORITY_BELOW_NORMAL;
                    break;
                }
                case Thread.NORM_PRIORITY - 1:
                case Thread.NORM_PRIORITY:
                case Thread.NORM_PRIORITY + 1:
                {
                    priority = Kernel.THREAD_PRIORITY_NORMAL;
                    break;
                }
                case Thread.HIGH_PRIORITY:
                {
                    priority = Kernel.THREAD_PRIORITY_ABOVE_NORMAL;
                    break;
                }
                case Thread.HIGH_PRIORITY + 1:
                {
                    priority = Kernel.THREAD_PRIORITY_HIGHEST;
                    break;
                }
                default:
                {
                    priority = Kernel.THREAD_PRIORITY_TIME_CRITICAL;
                }
            }
            Kernel.setThreadPriority(handle, priority);
        } finally
        {
            Kernel.closeHandle(handle);
        }
    }

    public void setThreadDescription(long2 threadId, byte[] src, int offset, int length) {
        int usedId = (int) threadId[1];
        long handle = Kernel.openThread(Kernel.THREAD_SET_LIMITED_INFORMATION, false, usedId);
        if(handle == Kernel.NULL) return;
        try
        {
            Kernel.setThreadDescription(handle, src.getPointer() + offset);
        } finally
        {
            Kernel.closeHandle(handle);
        }
    }

    public boolean isAliveThread(long threadMainId) {
        int usedId = (int) threadMainId;
        long handle = Kernel.openThread(Kernel.THREAD_QUERY_LIMITED_INFORMATION, false, usedId);
        if(handle == Kernel.NULL) return false;
        boolean result;
        try
        {
            int2 exitCode = Kernel.getExitCodeThread(handle);
            result = exitCode[0] != 0 && exitCode[1] == Kernel.STILL_ACTIVE;
        } finally
        {
            Kernel.closeHandle(handle);
        }
        return result;
    }

    public int getThreadPriority(long2 threadId) {
        int usedId = (int) threadId[1];
        long handle = Kernel.openThread(Kernel.THREAD_QUERY_LIMITED_INFORMATION, false, usedId);
        if(handle == Kernel.NULL) return 0;
        int result = 0;
        try
        {
            switch(Kernel.getThreadPriority(handle))
            {
                case Kernel.THREAD_PRIORITY_IDLE:
                {
                    result = Thread.MIN_PRIORITY;
                    break;
                }
                case Kernel.THREAD_PRIORITY_LOWEST:
                {
                    result = Thread.LOW_PRIORITY - 1;
                    break;
                }
                case Kernel.THREAD_PRIORITY_BELOW_NORMAL:
                {
                    result = Thread.LOW_PRIORITY;
                    break;
                }
                case Kernel.THREAD_PRIORITY_NORMAL:
                {
                    result = Thread.NORM_PRIORITY;
                    break;
                }
                case Kernel.THREAD_PRIORITY_ABOVE_NORMAL:
                {
                    result = Thread.HIGH_PRIORITY;
                    break;
                }
                case Kernel.THREAD_PRIORITY_HIGHEST:
                {
                    result = Thread.HIGH_PRIORITY + 1;
                    break;
                }
                case Kernel.THREAD_PRIORITY_TIME_CRITICAL:
                {
                    result = Thread.MAX_PRIORITY;
                    break;
                }
            }
        } finally
        {
            Kernel.closeHandle(handle);
        }
        return result;
    }

    public int getThreadDescription(long2 threadId, byte[] dst, int offset) {
        int usedId = (int) threadId[1];
        long handle = Kernel.openThread(Kernel.THREAD_QUERY_LIMITED_INFORMATION, false, usedId);
        if(handle == Kernel.NULL) return 0;
        int result;
        try
        {
            result = Kernel.getThreadDescription(handle, dst.getPointer() + offset);
        } finally
        {
            Kernel.closeHandle(handle);
        }
        return result;
    }

    public int getActiveThreadsQuantity() {
        ThreadEntry32 threadInfoObj = new ThreadEntry32() { dwSize = ThreadEntry32.class.structSize };
        long threadInfoPtr = threadInfoObj.getPointer();
        int thisProcessId = Kernel.getCurrentProcessId();
        int result = 0;
        long handle = Kernel.createToolHelp32Snapshot(Kernel.TH32CS_SNAPTHREAD, 0);
        try
        {
            if(Kernel.thread32First(handle, threadInfoPtr)) do
            {
                if(threadInfoObj.th32OwnerProcessID == thisProcessId) result++;
            } while(Kernel.thread32Next(handle, threadInfoPtr));
        } finally
        {
            Kernel.closeHandle(handle);
        }
        return result;
    }

    public long startThread(Runnable ref) {
        if(ref == null)
        {
            throw new NullPointerException(String.format(avt.lang.package.getResourceString("null-pointer.argument"), new Object[] { "ref" }));
        }
        int result;
        startThreadOperation.lock();
        try
        {
            startThreadResult = 0;
            long2 handleAndId = Kernel.createThread(0, 0x1000, getThreadEntryPoint(), ref, 0);
            if(handleAndId[0] == Kernel.NULL)
            {
                throw errorOutOfResources;
            }
            do
            {
                Kernel.switchToThread();
                if(startThreadResult < 0)
                {
                    throw errorOutOfResources;
                }
            } while(startThreadResult == 0);
            result = (int) handleAndId[1];
        } finally
        {
            startThreadOperation.unlock();
        }
        return result;
    }

    public long2 getCurrentThreadId() {
        int id = Kernel.getCurrentThreadId();
        return new int2 { id, id };
    }

    public long[] getActiveThreadsMainIds() {
        ThreadEntry32 threadInfoObj = new ThreadEntry32() { dwSize = ThreadEntry32.class.structSize };
        long threadInfoPtr = threadInfoObj.getPointer();
        int thisProcessId = Kernel.getCurrentProcessId();
        int length = 0;
        long[] result = new long[0x0f];
        long handle = Kernel.createToolHelp32Snapshot(Kernel.TH32CS_SNAPTHREAD, 0);
        try
        {
            if(Kernel.thread32First(handle, threadInfoPtr)) do
            {
                if(threadInfoObj.th32OwnerProcessID == thisProcessId)
                {
                    if(length == result.length) Array.copy(result, 0, result = new long[length << 1 | 1], 0, length);
                    result[length++] = threadInfoObj.th32ThreadID;
                }
            } while(Kernel.thread32Next(handle, threadInfoPtr));
        } finally
        {
            Kernel.closeHandle(handle);
        }
        if(length != result.length) Array.copy(result, 0, result = new long[length], 0, length);
        return result;
    }

    public platform.dependent.Mutex newMutex() { return new CriticalSection(); }

    public platform.dependent.Monitor newMonitor() { return new Monitor(); }

    /* процесс */

    public void exit(int exitCode) { Kernel.exitProcess(exitCode); }

    public void closeProcessDescriptor(long2 procDs) {
        Kernel.closeHandle(procDs[0]);
        Kernel.closeHandle(procDs[1]);
    }

    public void joinProcess(long2 procDs, long timeInMillis, int timeInNanos) {
        final long timeMaximum = 0xfffffffeL;
        if(timeInMillis < Long.MAX_VALUE && timeInNanos >= 500000 || timeInMillis == 0 && timeInNanos > 0) timeInMillis++;
        Kernel.waitForSingleObject(procDs[0], timeInMillis <= 0 ? Kernel.INFINITE : timeInMillis >= timeMaximum ? (int) timeMaximum : (int) timeInMillis);
    }

    public boolean isProcessTerminated(long2 procDs) { return Kernel.waitForSingleObject(procDs[0], 0) == Kernel.WAIT_OBJECT_0; }

    public boolean isPlatformOutputStream(ByteWriter stream) { return stream instanceof HandleOutputStream; }

    public boolean isPlatformInputStream(ByteReader stream) { return stream instanceof HandleInputStream; }

    public boolean isCurrentProcessHasInstance() {
        ProcessEntry32 processInfoObj = new ProcessEntry32() { dwSize = ProcessEntry32.class.structSize };
        long processInfoPtr = processInfoObj.getPointer();
        int thisProcessId = Kernel.getCurrentProcessId();
        char[] thisModulePathChars = new char[Kernel.MAX_PATH + 1];
        char[] anotModulePathChars = new char[Kernel.MAX_PATH + 1];
        int thisModulePathLength = Kernel.getModuleFileName(0, thisModulePathChars.getPointer(), Kernel.MAX_PATH + 1);
        int anotModulePathLength = 0;
        long anotModulePathPtr = anotModulePathChars.getPointer();
        long snapshotHandle = Kernel.createToolHelp32Snapshot(Kernel.TH32CS_SNAPPROCESS, 0);
        try
        {
            if(Kernel.process32First(snapshotHandle, processInfoPtr)) do
            {
                int anotProcessId = processInfoObj.th32ProcessId;
                if(thisProcessId == anotProcessId) continue;
                long processHandle = Kernel.openProcess(Kernel.PROCESS_QUERY_INFORMATION | Kernel.PROCESS_QUERY_LIMITED_INFORMATION | Kernel.PROCESS_VM_READ, false, anotProcessId);
                if(processHandle == 0) continue;
                try
                {
                    anotModulePathChars[0] = '\0';
                    anotModulePathLength = Kernel.getModuleFileNameEx(processHandle, 0, anotModulePathPtr, Kernel.MAX_PATH + 1);
                } finally
                {
                    Kernel.closeHandle(processHandle);
                }
                if(thisModulePathLength == anotModulePathLength && Array.offsetOfNonEqual(thisModulePathChars, 0, anotModulePathChars, 0, thisModulePathLength) == Comparable.INDEFINITE)
                {
                    return true;
                }
            } while(Kernel.process32Next(snapshotHandle, processInfoPtr));
        } finally
        {
            Kernel.closeHandle(snapshotHandle);
        }
        return false;
    }

    public int getProcessExitCode(long2 procDs) {
        int2 result = Kernel.getExitCodeProcess(procDs[0]);
        return result[0] == 0 ? 0 : result[1];
    }

    public long getCurrentProcessId() { return Kernel.getCurrentProcessId(); }

    public long2 startProcess(platform.dependent.ProcessParameters ref) throws DirectoryNotFoundException, FileNotFoundException, IOException {
        int length = 0;
        StringBuilder string = new StringBuilder();
        /* приоритет */
        int priorityClass = Kernel.NORMAL_PRIORITY_CLASS;
        switch(ref.priority)
        {
            case Process.MIN_PRIORITY:
            {
                priorityClass = Kernel.IDLE_PRIORITY_CLASS;
                break;
            }
            case Process.LOW_PRIORITY - 1:
            case Process.LOW_PRIORITY:
            {
                priorityClass = Kernel.BELOW_NORMAL_PRIORITY_CLASS;
                break;
            }
            case Process.NORM_PRIORITY - 1:
            case Process.NORM_PRIORITY:
            case Process.NORM_PRIORITY + 1:
            {
                priorityClass = Kernel.NORMAL_PRIORITY_CLASS;
                break;
            }
            case Process.HIGH_PRIORITY:
            case Process.HIGH_PRIORITY + 1:
            {
                priorityClass = Kernel.ABOVE_NORMAL_PRIORITY_CLASS;
                break;
            }
            case Process.MAX_PRIORITY:
            {
                priorityClass = Kernel.HIGH_PRIORITY_CLASS;
                break;
            }
        }
        /* рабочая папка */
        length = string.append(toInternalPath(ref.workingDirectory)).length;
        char[] workingDirectory = new char[length + 1];
        string.getChars(0, length, workingDirectory, 0);
        /* командная строка */
        string.clear();
        String moduleFileName;
        for(String[] arguments = ref.arguments, int alength = arguments.length, int aindex = 0; aindex < alength; aindex++)
        {
            String argument = arguments[aindex];
            if(aindex <= 0)
            {
                moduleFileName = argument;
            } else
            {
                string.append(' ');
            }
            if(argument.length > 0 && argument.indexOf(' ') < 0)
            {
                string.append(argument);
                continue;
            }
            string.append('\"').append(argument).append('\"');
        }
        length = string.length;
        char[] commandLine = new char[length + 1];
        string.getChars(0, length, commandLine, 0);
        /* переменные среды */
        string.clear();
        for(Object[] environment = ref.environment, int vlength = environment.length, int vindex = 0; vindex < vlength; vindex++)
        {
            string.append(environment[vindex]).append('\0');
        }
        length = string.append('\0').length;
        char[] environment = new char[length + 1];
        string.getChars(0, length, environment, 0);
        /* стандартные потоки ввода-вывода */
        long stdInHandle = Kernel.INVALID_HANDLE_VALUE;
        HandleInputStream stdInStream = (HandleInputStream) ref.standardInput;
        if(stdInStream != null) Kernel.setHandleInfo(stdInHandle = stdInStream.handle, Kernel.HANDLE_FLAG_INHERIT, Kernel.HANDLE_FLAG_INHERIT);
        long stdOutHandle = Kernel.INVALID_HANDLE_VALUE;
        HandleOutputStream stdOutStream = (HandleOutputStream) ref.standardOutput;
        if(stdOutStream != null) Kernel.setHandleInfo(stdOutHandle = stdOutStream.handle, Kernel.HANDLE_FLAG_INHERIT, Kernel.HANDLE_FLAG_INHERIT);
        long stdErrHandle = Kernel.INVALID_HANDLE_VALUE;
        HandleOutputStream stdErrStream = (HandleOutputStream) ref.standardError;
        if(stdErrStream != null) Kernel.setHandleInfo(stdErrHandle = stdErrStream.handle, Kernel.HANDLE_FLAG_INHERIT, Kernel.HANDLE_FLAG_INHERIT);
        /* создание процесса */
        StartupInfo startupInfo = new StartupInfo() {
            dwSize = StartupInfo.class.structSize,
            dwFlags = Kernel.STARTF_USESTDHANDLES,
            hStdInput = stdInHandle,
            hStdOutput = stdOutHandle,
            hStdError = stdErrHandle
        };
        ProcessInfo processInfo = new ProcessInfo();
        if(!Kernel.createProcess(
            0,
            commandLine.getPointer(),
            0,
            0,
            true,
            Kernel.CREATE_UNICODE_ENVIRONMENT | priorityClass,
            environment.getPointer(),
            workingDirectory.getPointer(),
            startupInfo.getPointer(),
            processInfo.getPointer()
        )) switch(Kernel.getLastError())
        {
            case Kernel.ERROR_FILE_NOT_FOUND:
            case Kernel.ERROR_PATH_NOT_FOUND:
            {
                throw new FileNotFoundException(platform.independent.filesystem.package.getResourceString("not-found.file")) {
                    fileName = moduleFileName
                };
            }
            case Kernel.ERROR_DIRECTORY:
            {
                throw new DirectoryNotFoundException(platform.independent.filesystem.package.getResourceString("not-found.directory")) {
                    directoryName = new String(workingDirectory, 0, workingDirectory.length - 1)
                };
            }
            default:
            {
                throw errorOutOfResources;
            }
        }
        return new long2 { processInfo.hProcess, processInfo.hThread };
    }

    public Process getCurrentProcess() { return currentProcess; }

    public platform.dependent.EnvironmentTable newEnvironmentTable() { return new EnvironmentTable(); }

    public ByteStream newPipe() {
        long2 pipeDs = Kernel.createPipe(0, 0x100000);
        if(pipeDs == 0)
        {
            throw errorOutOfResources;
        }
        return new PipeStream(pipeDs[0], pipeDs[1]);
    }

    public String getConsoleInputCharsetName() { return "CP-" + Int.toString(Kernel.getConsoleInputCP()); }

    public String getConsoleOutputCharsetName() { return "CP-" + Int.toString(Kernel.getConsoleOutputCP()); }

    /* файловая система */

    public boolean isObjectPathCaseSensitive() { return false; }

    public boolean isInternalPathFull(String internalPath) {
        int length = internalPath.length;
        if(length >= 2 && internalPath[1] == ':' && (length <= 2 || internalPath[2] == '\\'))
        {
            char volumeLetter = internalPath[0];
            return volumeLetter >= 'A' && volumeLetter <= 'Z' || volumeLetter >= 'a' && volumeLetter <= 'z';
        }
        return false;
    }

    public FileSystemRoot[] enumerateRoots() throws IOException {
        char[] internalRootPath = new char[] { '\0', ':', '\\', '\0' };
        long internalRootPathPtr = internalRootPath.getPointer();
        int rootsLength = 0;
        FileSystemRoot[] rootsArray = new FileSystemRoot['Z' - 'A' + 1];
        fileSystemRootOperation.lock();
        try
        {
            for(char volumeLetter = 'A'; volumeLetter <= 'Z'; volumeLetter++)
            {
                internalRootPath[0] = volumeLetter;
                if(Kernel.getDriveType(internalRootPathPtr) > Kernel.DRIVE_NO_ROOT_DIR)
                {
                    String rootPath = new String(new char[] { '/', volumeLetter, ':' });
                    FileSystemRoot volumeDescriptor = (FileSystemRoot) fileSystemRootTable[rootPath];
                    if(volumeDescriptor == null)
                    {
                        fileSystemRootTable[rootPath] = volumeDescriptor = new FileSystemDescriptor(rootPath, "/");
                    }
                    rootsArray[rootsLength++] = volumeDescriptor;
                }
            }
        } finally
        {
            fileSystemRootOperation.unlock();
        }
        rootsArray.length = rootsLength;
        return rootsArray;
    }

    public FileSystemRoot getRoot(String objectPath) throws FileSystemNotFoundException, IOException {
        int length = objectPath.length;
        char volumeLetter;
        if(
            length < 3 ||
            objectPath[0] != '/' ||
            ((volumeLetter = objectPath[1]) < 'A' || volumeLetter > 'Z') && (volumeLetter < 'a' || volumeLetter > 'z') ||
            objectPath[2] != ':' ||
            length > 3 && objectPath[3] != '/'
        )
        {
            throw new IllegalObjectNameException(String.format(platform.independent.filesystem.package.getResourceString("illegal-argument.object-name"), new Object[] { "objectPath" }));
        }
        volumeLetter &= 0x005f;
        FileSystemRoot volumeDescriptor;
        fileSystemRootOperation.lock();
        try
        {
            String rootPath = objectPath.substring(0, 3);
            volumeDescriptor = (FileSystemRoot) fileSystemRootTable[rootPath];
            if(volumeDescriptor == null)
            {
                char[] internalRootPath = new char[] { volumeLetter, ':', '\\', '\0' };
                if(Kernel.getDriveType(internalRootPath.getPointer()) <= Kernel.DRIVE_NO_ROOT_DIR)
                {
                    throw new FileSystemNotFoundException(platform.independent.osservices.package.getResourceString("not-found.root-path")) { path = new String(internalRootPath, 0, 3) };
                }
                fileSystemRootTable[rootPath] = volumeDescriptor = new FileSystemDescriptor(rootPath, "/");
            }
        } finally
        {
            fileSystemRootOperation.unlock();
        }
        return volumeDescriptor;
    }

    public String getUserConfigDir() throws IOException {
        String internalPath;
        label0:
        {
            with(currentProcess.environment) if((internalPath = operator []("AppData")) == null || internalPath.length <= 0)
            {
                if((internalPath = operator []("UserProfile")) == null)
                {
                    throw new IOException(avt.io.package.getResourceString("io"));
                }
                if(!internalPath.endsWith("\\")) internalPath = internalPath + '\\';
                internalPath = internalPath + "AppData\\Roaming\\";
                break label0;
            }
            if(!internalPath.endsWith("\\")) internalPath = internalPath + '\\';
        }
        String objectPath = toObjectPath(internalPath);
        with(getRoot(objectPath), fileSystem) for(String subdirPath = objectPath.substring(path.length), int pos = 0; (pos = subdirPath.indexOf('/', pos + 1)) >= 0; )
        {
            String checkPath = subdirPath.substring(0, pos);
            if(!isObjectExists(checkPath)) createDirectory(checkPath);
        }
        return objectPath;
    }

    public String getUserCacheDir() throws IOException { return getUserLocalDir(); }

    public String getUserLocalDir() throws IOException {
        String internalPath;
        label0:
        {
            with(currentProcess.environment) if((internalPath = operator []("LocalAppData")) == null || internalPath.length <= 0)
            {
                if((internalPath = operator []("UserProfile")) == null)
                {
                    throw new IOException(avt.io.package.getResourceString("io"));
                }
                if(!internalPath.endsWith("\\")) internalPath = internalPath + '\\';
                internalPath = internalPath + "AppData\\Local\\";
                break label0;
            }
            if(!internalPath.endsWith("\\")) internalPath = internalPath + '\\';
        }
        String objectPath = toObjectPath(internalPath);
        with(getRoot(objectPath), fileSystem) for(String subdirPath = objectPath.substring(path.length), int pos = 0; (pos = subdirPath.indexOf('/', pos + 1)) >= 0; )
        {
            String checkPath = subdirPath.substring(0, pos);
            if(!isObjectExists(checkPath)) createDirectory(checkPath);
        }
        return objectPath;
    }

    public String toInternalPath(String objectPath) {
        if(objectPath.startsWith("/")) objectPath = objectPath.substring(1);
        return objectPath.replaceAll('/', '\\');
    }

    public String toObjectPath(String internalPath) {
        if(!internalPath.startsWith("\\")) internalPath = '/' + internalPath;
        return internalPath.replaceAll('\\', '/');
    }

    /* свойства платформы */

    public int processorNumberOfCores { read = fldProcessorNumberOfCores }

    public String operatingSystemName { read = "Microsoft Windows" }

    public String operatingSystemVersion { read = fldOperatingSystemVersion }

    public String lineSeparator { read = "\u000d\u000a" }

    /* инициализация и финализация */

    protected void afterConstruction() {
        protectImportMemoryRegion();
        initErrors();
        try
        {
            SystemInfo sysinfo = new SystemInfo();
            Kernel.getSystemInfo(sysinfo.getPointer());
            KUSER_SHARED_DATA kusdata = (KUSER_SHARED_DATA) KUSER_SHARED_DATA.class.newStructAt(0x7ffe0000L);
            fldProcessorNumberOfCores = sysinfo.dwNumberOfProcessors;
            fldMinimumApplicationAddress = sysinfo.lpMinimumApplicationAddress;
            fldMaximumApplicationAddress = sysinfo.lpMaximumApplicationAddress;
            fldOperatingSystemVersion = (new StringBuilder()).append(kusdata.ntMajorVersion).append('.').append(kusdata.ntMinorVersion).append('.').append(kusdata.ntBuildNumber).toString();
            sysinfo = null;
            kusdata = null;
        } catch(Exception exception) {  }
        initServices();
        super.afterConstruction();
    }

    /* защищённые члены из Runtime */

    protected boolean isCanonicalPointer(long ptr) {
        long minAddress = fldMinimumApplicationAddress;
        long maxAddress = fldMaximumApplicationAddress;
        return (minAddress | maxAddress) != 0 ? ptr >= minAddress && ptr <= maxAddress : super.isCanonicalPointer(ptr);
    }
}