Exemplo n.º 1
0
Arquivo: Run.cs Projeto: alexfordc/Au
    bool _CanRunNow(FileNode f, Compiler.CompResults r, out RunningTask running, bool runFromEditor = false)
    {
        running = null;
        switch (r.runMode)
        {
        case ERunMode.green:
            running = GetGreenTask();
            break;

        case ERunMode.blue when !(r.ifRunning == EIfRunning.run || (r.ifRunning == EIfRunning.run_restart && !runFromEditor)):
            running = _GetRunning(f);
            break;

        default: return(true);
        }
        return(running == null);
    }
Exemplo n.º 2
0
Arquivo: Run.cs Projeto: alexfordc/Au
    /// <summary>
    /// Executes the compiled assembly in new process.
    /// Returns: process id if started now, 0 if failed, (int)ATask.ERunResult.deferred if scheduled to run later.
    /// </summary>
    /// <param name="f"></param>
    /// <param name="r"></param>
    /// <param name="args"></param>
    /// <param name="noDefer">Don't schedule to run later. If cannot run now, just return 0.</param>
    /// <param name="wrPipeName">Pipe name for ATask.WriteResult.</param>
    /// <param name="ignoreLimits">Don't check whether the task can run now.</param>
    /// <param name="runFromEditor">Starting from the Run button or menu Run command.</param>
    public unsafe int RunCompiled(FileNode f, Compiler.CompResults r, string[] args,
                                  bool noDefer = false, string wrPipeName = null, bool ignoreLimits = false, bool runFromEditor = false)
    {
g1:
        if (!ignoreLimits && !_CanRunNow(f, r, out var running, runFromEditor))
        {
            var  ifRunning = r.ifRunning;
            bool same      = running.f == f;
            if (!same)
            {
                ifRunning = r.ifRunning2 switch
                {
                    EIfRunning2.cancel => EIfRunning.cancel,
                    EIfRunning2.wait => EIfRunning.wait,
                    EIfRunning2.warn => EIfRunning.warn,
                    _ => (ifRunning & ~EIfRunning._restartFlag) switch { EIfRunning.cancel => EIfRunning.cancel, EIfRunning.wait => EIfRunning.wait, _ => EIfRunning.warn }
                };
            }
            else if (ifRunning.Has(EIfRunning._restartFlag))
            {
                if (runFromEditor)
                {
                    ifRunning = EIfRunning.restart;
                }
                else
                {
                    ifRunning &= ~EIfRunning._restartFlag;
                }
            }
            //AOutput.Write(same, ifRunning);
            switch (ifRunning)
            {
            case EIfRunning.cancel:
                break;

            case EIfRunning.wait when !noDefer:
                _q.Insert(0, new _WaitingTask(f, r, args));
                return((int)ATask.ERunResult.deferred);                //-1

            case EIfRunning.restart when _EndTask(running):
                goto g1;

            default:             //warn
                string s1 = same ? "it" : $"{running.f.SciLink}";
                AOutput.Write($"<>Cannot start {f.SciLink} because {s1} is running. You may want to <+properties \"{f.IdStringWithWorkspace}\">change<> <c green>ifRunning<>, <c green>ifRunning2<>, <c green>runMode<>.");
                break;
            }
            return(0);
        }

        _SpUac uac = _SpUac.normal; int preIndex = 0;

        if (!AUac.IsUacDisabled)
        {
            //info: to completely disable UAC on Win7: gpedit.msc/Computer configuration/Windows settings/Security settings/Local policies/Security options/User Account Control:Run all administrators in Admin Approval Mode/Disabled. Reboot.
            //note: when UAC disabled, if our uac is System, IsUacDisabled returns false (we probably run as SYSTEM user). It's OK.
            var IL = AUac.OfThisProcess.IntegrityLevel;
            if (r.uac == EUac.inherit)
            {
                switch (IL)
                {
                case UacIL.High: preIndex = 1; break;

                case UacIL.UIAccess: uac = _SpUac.uiAccess; preIndex = 2; break;
                }
            }
            else
            {
                switch (IL)
                {
                case UacIL.Medium:
                case UacIL.UIAccess:
                    if (r.uac == EUac.admin)
                    {
                        uac = _SpUac.admin;
                    }
                    break;

                case UacIL.High:
                    if (r.uac == EUac.user)
                    {
                        uac = _SpUac.userFromAdmin;
                    }
                    break;

                case UacIL.Low:
                case UacIL.Untrusted:
                case UacIL.Unknown:
                //break;
                case UacIL.System:
                case UacIL.Protected:
                    AOutput.Write($"<>Cannot run {f.SciLink}. Meta comment option <c green>uac {r.uac}<> cannot be used when the UAC integrity level of this process is {IL}. Supported levels are Medium, High and uiAccess.");
                    return(0);
                    //info: cannot start Medium IL process from System process. Would need another function. Never mind.
                }
                if (r.uac == EUac.admin)
                {
                    preIndex = 1;
                }
            }
        }

        string     exeFile, argsString;
        _Preloaded pre = null; byte[] taskParams = null;
        bool       bit32 = r.prefer32bit || AVersion.Is32BitOS;

        if (r.notInCache)          //meta role exeProgram
        {
            exeFile    = Compiler.DllNameToAppHostExeName(r.file, bit32);
            argsString = args == null ? null : Au.Util.AStringUtil.CommandLineFromArray(args);
        }
        else
        {
            exeFile = AFolders.ThisAppBS + (bit32 ? "Au.Task32.exe" : "Au.Task.exe");

            //int iFlags = r.hasConfig ? 1 : 0;
            int iFlags = 0;
            if (r.mtaThread)
            {
                iFlags |= 2;
            }
            if (r.console)
            {
                iFlags |= 4;
            }
            taskParams = Au.Util.Serializer_.SerializeWithSize(r.name, r.file, r.pdbOffset, iFlags, args, r.fullPathRefs, wrPipeName, (string)AFolders.Workspace);
            wrPipeName = null;

            if (bit32 && !AVersion.Is32BitOS)
            {
                preIndex += 3;
            }
            pre        = s_preloaded[preIndex] ??= new _Preloaded(preIndex);
            argsString = pre.pipeName;
        }

        int pid; WaitHandle hProcess = null; bool disconnectPipe = false;

        try {
            //APerf.First();
            var pp = pre?.hProcess;
            if (pp != null && 0 != Api.WaitForSingleObject(pp.SafeWaitHandle.DangerousGetHandle(), 0))              //preloaded process exists
            {
                hProcess     = pp; pid = pre.pid;
                pre.hProcess = null; pre.pid = 0;
            }
            else
            {
                if (pp != null)
                {
                    pp.Dispose(); pre.hProcess = null; pre.pid = 0;
                }                                                                                  //preloaded process existed but somehow ended
                (pid, hProcess) = _StartProcess(uac, exeFile, argsString, wrPipeName);
            }
            Api.AllowSetForegroundWindow(pid);

            if (pre != null)
            {
                //APerf.First();
                var o = new Api.OVERLAPPED {
                    hEvent = pre.overlappedEvent
                };
                if (!Api.ConnectNamedPipe(pre.hPipe, &o))
                {
                    int e = ALastError.Code;
                    if (e != Api.ERROR_PIPE_CONNECTED)
                    {
                        if (e != Api.ERROR_IO_PENDING)
                        {
                            throw new AuException(e);
                        }
                        var ha = stackalloc IntPtr[2] {
                            pre.overlappedEvent, hProcess.SafeWaitHandle.DangerousGetHandle()
                        };
                        int wr = Api.WaitForMultipleObjectsEx(2, ha, false, -1, false);
                        if (wr != 0)
                        {
                            Api.CancelIo(pre.hPipe); throw new AuException("*start task. Preloaded task process ended");
                        }                                                                                                                                    //note: if fails when 32-bit process, rebuild solution with platform x86
                        disconnectPipe = true;
                        if (!Api.GetOverlappedResult(pre.hPipe, ref o, out _, false))
                        {
                            throw new AuException(0);
                        }
                    }
                }
                //APerf.Next();
                if (!Api.WriteFileArr(pre.hPipe, taskParams, out _))
                {
                    throw new AuException(0);
                }
                //APerf.Next();
                Api.DisconnectNamedPipe(pre.hPipe); disconnectPipe = false;
                //APerf.NW('e');

                //start preloaded process for next task. Let it wait for pipe connection.
                if (uac != _SpUac.admin)                  //we don't want second UAC consent
                {
                    try { (pre.pid, pre.hProcess) = _StartProcess(uac, exeFile, argsString, null); }
                    catch (Exception ex) { ADebug.Print(ex); }
                }
            }
        }
        catch (Exception ex) {
            AOutput.Write(ex);
            if (disconnectPipe)
            {
                Api.DisconnectNamedPipe(pre.hPipe);
            }
            hProcess?.Dispose();
            return(0);
        }

        var rt = new RunningTask(f, hProcess, r.runMode != ERunMode.green);

        _Add(rt);
        return(pid);
    }
Exemplo n.º 3
0
Arquivo: Run.cs Projeto: alexfordc/Au
 public _WaitingTask(FileNode f, Compiler.CompResults r, string[] args)
 {
     this.f = f; this.r = r; this.args = args;
 }