using FastReport.Design.PageDesigners.Code; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using RoslynPad.Roslyn; using System; using System.Collections.Generic; using System.Collections.Immutable; using System.IO; using System.Reflection; namespace FastReport.WPF.RoslynPad { internal class MyRoslynHost : RoslynHost { private ProjectId projectId; private DocumentId additionalDocumentId; private RoslynWorkspace workspace; private string languageName; private string FindLocalAssembly(string name) { if (name == null || name.Trim() == "") return null; // old report version if (string.Compare(name, "System.Windows.Forms.DataVisualization.dll", true) == 0) name = "FastReport.DataVisualization.dll"; // WPF versions of FastReport assemblies if (string.Compare(name, "System.Windows.Forms.dll", true) == 0) name = "FastReport.Forms.WPF.dll"; // See if the required assembly is present locally string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, name); if (File.Exists(path)) return path; return null; } private string GetRefAssemblyPath(Type type) { // dlls located here (example paths, dependent on arch & fw version): //"C:\Program Files\dotnet\shared\Microsoft.NETCore.App\6.0.14\" or "C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App\6.0.14\" // ref dlls with associated xml files located here: //"C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\6.0.14\ref\net6.0\" string dllPath = Path.GetDirectoryName(type.Assembly.Location); string refPath = ""; if (dllPath.Contains(@"shared\Microsoft.NETCore.App", StringComparison.OrdinalIgnoreCase)) { refPath = dllPath.Replace(@"shared\Microsoft.NETCore.App", @"packs\Microsoft.NETCore.App.Ref", StringComparison.OrdinalIgnoreCase); } else if (dllPath.Contains(@"shared\Microsoft.WindowsDesktop.App", StringComparison.OrdinalIgnoreCase)) { refPath = dllPath.Replace(@"shared\Microsoft.WindowsDesktop.App", @"packs\Microsoft.WindowsDesktop.App.Ref", StringComparison.OrdinalIgnoreCase); } else { // no ref dlls installed? Return default dll path (no xml comments though) return dllPath; } refPath = Path.Combine(refPath, "ref", "net") + type.Assembly.GetName().Version.ToString(2); if (Directory.Exists(refPath)) return refPath; return dllPath; } private string GetRefAssemblyFileName(Type type) { return Path.Combine(GetRefAssemblyPath(type), Path.GetFileName(type.Assembly.Location)); } private MetadataReference[] GetRefAssemblies(string[] assemblies) { List refAssemblies = new List(); // system assemblies. Add them all string refPath = GetRefAssemblyPath(typeof(Object)); foreach (var fileName in Directory.GetFiles(refPath, "*.dll")) refAssemblies.Add(CreateMetadataReference(fileName)); // System.Drawing.Common (xml doc: missing for some types such as Bitmap. VS has the same issue) string sysDrawingDll = GetRefAssemblyFileName(typeof(System.Drawing.Image)); if (File.Exists(sysDrawingDll)) refAssemblies.Add(CreateMetadataReference(sysDrawingDll)); // assemblies from Report.ReferencedAssemblies. Search in the exe folder. Note that system assemblies in this list will be ignored foreach (string name in assemblies) { var asm = FindLocalAssembly(name); if (asm != null) refAssemblies.Add(CreateMetadataReference(asm)); } // FastReport main assembly refAssemblies.Add(CreateMetadataReference(typeof(Report).Assembly.Location)); return refAssemblies.ToArray(); } protected override ParseOptions CreateDefaultParseOptions() { return new CSharpParseOptions(kind: SourceCodeKind.Regular, languageVersion: LanguageVersion.Default); } public override RoslynWorkspace CreateWorkspace() { workspace = new MyRoslynWorkspace(HostServices, roslynHost: this); return workspace; } private string HiddenClassName { get { return languageName == LanguageNames.CSharp ? "hiddenClass.cs" : "hiddenClass.vb"; } } private ParseOptions GetParseOptions() { if (languageName == LanguageNames.CSharp) return new CSharpParseOptions(kind: SourceCodeKind.Regular, languageVersion: LanguageVersion.Default); return new Microsoft.CodeAnalysis.VisualBasic.VisualBasicParseOptions(kind: SourceCodeKind.Regular); } protected override CompilationOptions CreateCompilationOptions(DocumentCreationArgs args, bool addDefaultImports) { if (languageName == LanguageNames.CSharp) return new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary, usings: addDefaultImports ? DefaultImports : ImmutableArray.Empty, allowUnsafe: true, sourceReferenceResolver: new SourceFileResolver(ImmutableArray.Empty, args.WorkingDirectory), // all #r references are resolved by the editor/msbuild metadataReferenceResolver: DummyScriptMetadataResolver.Instance, nullableContextOptions: NullableContextOptions.Disable); return new Microsoft.CodeAnalysis.VisualBasic.VisualBasicCompilationOptions(OutputKind.DynamicallyLinkedLibrary, sourceReferenceResolver: new SourceFileResolver(ImmutableArray.Empty, args.WorkingDirectory), metadataReferenceResolver: DummyScriptMetadataResolver.Instance); } protected override Project CreateProject(Solution solution, DocumentCreationArgs args, CompilationOptions compilationOptions, Project previousProject = null) { var name = args.Name ?? "Program"; projectId = ProjectId.CreateNewId(name); solution = solution.AddProject(ProjectInfo.Create( projectId, VersionStamp.Create(), name, name, languageName, isSubmission: false, parseOptions: GetParseOptions(), compilationOptions: compilationOptions, metadataReferences: previousProject != null ? ImmutableArray.Empty : DefaultReferences, projectReferences: previousProject != null ? new[] { new ProjectReference(previousProject.Id) } : null) ); additionalDocumentId = DocumentId.CreateNewId(projectId); solution = solution.AddDocument(additionalDocumentId, HiddenClassName, " "); var project = solution.GetProject(projectId); return project; } public void SetAdditionalInfo(string hiddenClassText, string[] assemblies) { var solution = workspace.CurrentSolution; var project = solution.GetProject(projectId); project = project.WithMetadataReferences(GetRefAssemblies(assemblies)); solution = project.Solution; solution = solution.RemoveDocument(additionalDocumentId); additionalDocumentId = DocumentId.CreateNewId(projectId); solution = solution.AddDocument(additionalDocumentId, HiddenClassName, hiddenClassText); workspace.TryApplyChanges(solution); } public MyRoslynHost(SyntaxType syntaxType) : base(syntaxType == SyntaxType.Cs ? new[] { Assembly.Load("RoslynPad.Roslyn.Windows"), Assembly.Load("RoslynPad.Editor.Windows"), } : new[] { Assembly.Load("RoslynPad.Roslyn.Windows"), Assembly.Load("RoslynPad.Editor.Windows"), Assembly.Load("Microsoft.CodeAnalysis.VisualBasic.Features"), Assembly.Load("Microsoft.CodeAnalysis.VisualBasic.Workspaces"), }, null) { this.languageName = syntaxType == SyntaxType.Cs ? LanguageNames.CSharp : LanguageNames.VisualBasic; } } }