示例#1
0
            public bool WaitAndRead(WaitHandle hProcess, Action <string> results)
            {
                bool  R = false;
                char *b = null; const int bLen = 7900;
                var   ev = new ManualResetEvent(false);

                try {
                    var ha = new WaitHandle[2] {
                        ev, hProcess
                    };
                    for (bool useSB = false; ; useSB = results == null)
                    {
                        var o = new Api.OVERLAPPED {
                            hEvent = ev.SafeWaitHandle.DangerousGetHandle()
                        };
                        if (!Api.ConnectNamedPipe(_hPipe, &o))
                        {
                            int e = lastError.code;
                            if (e != Api.ERROR_PIPE_CONNECTED)
                            {
                                if (e != Api.ERROR_IO_PENDING)
                                {
                                    break;
                                }
                                int wr = WaitHandle.WaitAny(ha);
                                if (wr != 0)
                                {
                                    Api.CancelIo(_hPipe); R = true; break;
                                }                                                                                       //task ended
                                if (!Api.GetOverlappedResult(_hPipe, ref o, out _, false))
                                {
                                    Api.DisconnectNamedPipe(_hPipe); break;
                                }
                            }
                        }

                        if (b == null)
                        {
                            b = (char *)MemoryUtil.Alloc(bLen);
                        }
                        bool readOK;
                        while (((readOK = Api.ReadFile(_hPipe, b, bLen, out int n, null)) || (lastError.code == Api.ERROR_MORE_DATA)) && n > 0)
                        {
                            n /= 2;
                            if (!readOK)
                            {
                                useSB = true;
                            }
                            if (useSB)                               //rare
                            {
                                _sb ??= new StringBuilder(bLen);
                                if (results == null && _s != null)
                                {
                                    _sb.Append(_s);
                                }
                                _s = null;
                                _sb.Append(b, n);
                            }
                            else
                            {
                                _s = new string(b, 0, n);
                            }
                            if (readOK)
                            {
                                if (results != null)
                                {
                                    results(ResultString);
                                    _sb?.Clear();
                                }
                                break;
                            }
                            //note: MSDN says must use OVERLAPPED with ReadFile too, but works without it.
                        }
                        Api.DisconnectNamedPipe(_hPipe);
                        if (!readOK)
                        {
                            break;
                        }
                    }
                }
                finally {
                    ev.Dispose();
                    MemoryUtil.Free(b);
                }
                return(R);
            }
示例#2
0
文件: Run.cs 项目: 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);
    }