public async ThreadingTasks.Task <string> ProcessTemplateAsync(string inputFilename, string content, ITextTemplatingCallback callback, object hierarchy, bool debugging = false) { if (this is ITextTemplatingComponents Component) { Component.Hierarchy = hierarchy; Component.Callback = callback; Component.TemplateFile = inputFilename; LastInvocationRaisedErrors = false; Component.Host.SetFileExtension(SearchForLanguage(content, "C#") ? ".cs" : ".vb"); await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(); try { try { runFactory = await GetTransformationRunFactoryAsync(subSonicOutput.GetOutputTextWriter(), SubSonicCoreVisualStudioAsyncPackage.Singleton.CancellationTokenSource.Token); } catch (Exception ex) { await LogErrorAsync(string.Format(CultureInfo.CurrentCulture, SubSonicCoreErrors.ExceptionStartingRunFactoryProcess, ex), new Location(inputFilename)); runFactory = null; } if (runFactory == null) { await LogErrorAsync(SubSonicCoreErrors.ErrorStartingRunFactoryProcess, new Location(TemplateFile)); if (debugging) { ProcessTemplateEventArgs args = new ProcessTemplateEventArgs { TemplateOutput = SubSonicCoreErrors.DebugErrorOutput, Succeeded = false }; this.OnTransformProcessCompleted(args); } return(SubSonicCoreErrors.DebugErrorOutput); } if (!SubSonicCoreVisualStudioAsyncPackage.Singleton.CancellationTokenSource.IsCancellationRequested) { // we have not been cancelled so let's continue // we need to prepare the transformation and send the important parts over to the T4 Host Process if (Engine.PrepareTransformationRunner(content, Component.Host, runFactory, debugging) is IProcessTransformationRunner runner) { if (!debugging) { // if we are not debugging we can wait for the process to finish // and we do not need to attach to the host process. try { if (runFactory.StartTransformation(runner.RunnerId) is TextTemplatingCallback result) { if (result.Errors.HasErrors) { Callback.Errors.AddRange(result.Errors); foreach (var templateError in result.Errors) { await LogErrorAsync(templateError.Message, templateError.Location, templateError.IsWarning); } } Component.Callback.SetFileExtension(result.Extension); return(result.TemplateOutput); } else if (runFactory.GetErrors(runner.RunnerId) is TemplateErrorCollection errors) { Callback.Errors.AddRange(errors); foreach (var templateError in errors) { await LogErrorAsync(templateError.Message, templateError.Location, templateError.IsWarning); } } } catch (Exception ex) { if (TemplatingEngine.IsCriticalException(ex)) { throw; } await LogErrorAsync(ex.ToString(), new Location(Host.TemplateFile)); } finally { runFactory.DisposeOfRunner(runner.RunnerId); // clean up the runner } } else { // when debugging this we will attach to the process // the ui thread will be waiting for a callback from process to complete generation of file. bool success = false; try { foreach (EnvDTE.Process process in package.DTE.Debugger.LocalProcesses) { if (process.ProcessID == (this.transformProcess?.Id ?? default)) { process.Attach(); success = true; break; } } } catch (Exception attachException) { await LogErrorAsync(string.Format(CultureInfo.CurrentCulture, SubSonicCoreErrors.ExceptionAttachingToRunFactoryProcess, attachException), new Location(inputFilename)); } if (success) { Dispatcher uiDispatcher = Dispatcher.CurrentDispatcher; this.debugThread = new Thread(() => StartTransformation(inputFilename, runner, uiDispatcher)); this.debugThread.Start(); } else { await LogErrorAsync(SubSonicCoreErrors.ErrorAttachingToRunFactoryProcess, new Location(inputFilename)); ProcessTemplateEventArgs args = new ProcessTemplateEventArgs { TemplateOutput = SubSonicCoreErrors.DebugErrorOutput, Succeeded = false }; this.OnTransformProcessCompleted(args); } } } else { ProcessTemplateEventArgs args = new ProcessTemplateEventArgs(); if (debugging) { args.TemplateOutput = SubSonicCoreErrors.DebugErrorOutput; args.Succeeded = false; this.OnTransformProcessCompleted(args); } await LogErrorsAsync(transformationHost.Errors.ToCompilerErrorCollection()); } } } catch (IOException) { if (transformProcess != null) { try { transformProcess.Kill(); } catch (Exception) { } finally { transformProcess = null; } } RemotingServices.Disconnect(new Uri($"ipc://{TransformationRunFactory.TransformationRunFactoryService}")); } } return(SubSonicCoreErrors.DebugErrorOutput); }