Ejemplo n.º 1
0
    /// <summary>
    /// Compiles and/or executes C# file or its project.
    /// If <paramref name="run"/> is false, returns 1 if compiled, 0 if failed to compile.
    /// Else returns: process id if started now, 0 if failed, (int)script.RunResult_.deferred if scheduled to run later, (int)script.RunResult_.editorThread if runs in editor thread.
    /// </summary>
    /// <param name="run">If true, compiles if need and executes. If false, always compiles and does not execute.</param>
    /// <param name="f">C# file. Does nothing if null or not C# file.</param>
    /// <param name="args">To pass to Main.</param>
    /// <param name="noDefer">Don't schedule to run later.</param>
    /// <param name="wrPipeName">Pipe name for script.writeResult.</param>
    /// <param name="runFromEditor">Starting from the Run button or menu Run command. Can restart etc.</param>
    /// <remarks>
    /// Saves editor text if need.
    /// Calls <see cref="Compiler.Compile"/>.
    /// Must be always called in the main UI thread (Environment.CurrentManagedThreadId == 1), because calls its file model functions.
    /// </remarks>
    public static int CompileAndRun(bool run, FileNode f, string[] args = null, bool noDefer = false, string wrPipeName = null, bool runFromEditor = false)
    {
#if TEST_STARTUP_SPEED
        args = new string[] { perf.ms.ToString() };         //and in script use this code: print.it(perf.ms-Convert.ToInt64(args[0]));
#endif

        App.Model.Save.TextNowIfNeed(onlyText: true);
        App.Model.Save.WorkspaceNowIfNeed();         //because the script may kill editor, eg if runs in editor thread

        if (f == null)
        {
            return(0);
        }
        if (f.FindProject(out var projFolder, out var projMain))
        {
            f = projMain;
        }

        //can be set to run other script instead.
        //	Useful for library projects. Single files have other alternatives - move to a script project or move code to a script file.
        if (run)
        {
            var f2 = f.TestScript;
            if (f2 != null)
            {
                if (!f2.FindProject(out projFolder, out projMain))
                {
                    f = f2;
                }
                else if (projMain != f)
                {
                    f = projMain;
                }
                else
                {
                    print.it($"<>The test script {f2.SciLink()} cannot be in the project folder {projFolder.SciLink()}"); return(0);
                }
            }
        }

        if (!f.IsCodeFile)
        {
            return(0);
        }

        bool ok = Compiler.Compile(run ? ECompReason.Run : ECompReason.CompileAlways, out var r, f, projFolder);

        if (run && (r.role == Au.Compiler.ERole.classFile || r.role == Au.Compiler.ERole.classLibrary))           //info: if classFile, compiler sets r.role and returns false (does not compile)
        {
            _OnRunClassFile(f, projFolder);
            return(0);
        }

        if (!ok)
        {
            return(0);
        }
        if (!run)
        {
            return(1);
        }

        if (r.role == Au.Compiler.ERole.editorExtension)
        {
            RunAssembly.Run(r.file, args, handleExceptions: true);
            return((int)script.RunResult_.editorThread);
        }

        return(App.Tasks.RunCompiled(f, r, args, noDefer, wrPipeName, runFromEditor: runFromEditor));
    }
Ejemplo n.º 2
0
    //[STAThread] //we use TrySetApartmentState instead
    static void Main(string[] args)
    {
        string asmFile, fullPathRefs; int pdbOffset, flags;

        if (args.Length != 1)
        {
            return;
        }
        string pipeName = args[0];         //if(!pipeName.Starts(@"\\.\pipe\Au.Task-")) return;

        int nr = 0;

#if false
        //With NamedPipeClientStream faster by 1 ms, because don't need to JIT. But problems:
        //1. Loads System and System.Core immediately, making slower startup.
        //2. This process does not end when editor process ended, because then Connect spin-waits for server created.
        using (var pipe = new NamedPipeClientStream(".", pipeName.Substring(9), PipeDirection.In)) {
            pipe.Connect();
            var b = new byte[10000];
            nr = pipe.Read(b, 0, b.Length);
        }
#else
        //APerf.First();
        //_PrepareTest();
        //APerf.NW();

        for (int i = 0; i < 3; i++)
        {
            if (Api.WaitNamedPipe(pipeName, i == 2 ? -1 : 100))
            {
                break;
            }
            if (Marshal.GetLastWin32Error() != Api.ERROR_SEM_TIMEOUT)
            {
                return;
            }
            //APerf.First();
            switch (i)
            {
            case 0: _Prepare1(); break;             //~25 ms with cold CPU
                //case 1: _Prepare2(); break; //~15 ms with cold CPU
            }
            //APerf.NW();
        }
        //APerf.First();
        using (var pipe = Api.CreateFile(pipeName, Api.GENERIC_READ, 0, default, Api.OPEN_EXISTING, 0)) {
            if (pipe.Is0)
            {
                ADebug.PrintNativeError_(); return;
            }
            //APerf.Next();
            int size; if (!Api.ReadFile(pipe, &size, 4, out nr, default) || nr != 4)
            {
                return;
            }
            //APerf.Next();
            if (!Api.ReadFileArr(pipe, out var b, size, out nr) || nr != size)
            {
                return;
            }
            //APerf.Next();

            //ADebug.PrintLoadedAssemblies(true, true);
            //APerf.First();

            var a = Au.Util.Serializer_.Deserialize(b);
            ATask.Init_(ATRole.MiniProgram, a[0]);
            asmFile = a[1]; pdbOffset = a[2]; flags = a[3]; args = a[4]; fullPathRefs = a[5];
            string wrp = a[6]; if (wrp != null)
            {
                Environment.SetEnvironmentVariable("ATask.WriteResult.pipe", wrp);
            }
            AFolders.Workspace = (string)a[7];
        }
#endif
        //APerf.Next();

        bool mtaThread = 0 != (flags & 2);         //app without [STAThread]
        if (mtaThread == s_isSTA)
        {
            _SetComApartment(mtaThread ? ApartmentState.MTA : ApartmentState.STA);
        }

        if (0 != (flags & 4))
        {
            Api.AllocConsole();                          //meta console true
        }
        //if(0 != (flags & 1)) { //hasConfig
        //	var config = asmFile + ".config";
        //	if(AFile.ExistsAsFile(config, true)) AppDomain.CurrentDomain.SetData("APP_CONFIG_FILE", config);
        //}

        if (s_hook == null)
        {
            _Hook();
        }

        //APerf.Next();
        try { RunAssembly.Run(asmFile, args, pdbOffset, fullPathRefs: fullPathRefs); }
        catch (Exception ex) { AOutput.Write(ex); }
        finally { s_hook?.Dispose(); }
    }