public override async Task <DXCompileResult> Compile(DXCompileParameter parameter) { const double TotalOnReport = 8; int OnReport = 0; // * OnReport Progress await this.OnReport(++OnReport / TotalOnReport); var sw = new Stopwatch(); sw.Start(); // Result var result = new DXCompileResult(parameter.Option); // NameContainer var sharedNameContainer = new NameContainer(); var sharedCallbackContainer = new NameContainer(); // CodeDom var provider = new CSharpCodeProvider(); var compileParam = new CompilerParameters() { GenerateExecutable = true, GenerateInMemory = false, TreatWarningsAsErrors = false, #if DEBUG IncludeDebugInformation = false #else IncludeDebugInformation = true #endif }; // Add WPF Referenced Assembly Assembly[] dependencyLibs = GetReferencedAssemblyNames(parameter).ToArray(); AddReferencedAssemblies(compileParam, dependencyLibs); // * OnReport Progress await this.OnReport(++OnReport / TotalOnReport); // Mapper var mapper = new DXMapper <CSharpCodeMapAttribute>( new WPFMappingProvider(sharedCallbackContainer), sharedNameContainer); // Generator WPFLayoutGenerator layoutGenerator = CreateLayoutGenerator(parameter); CSharpGenerator logicGenerator = CreateLogicGenerator(parameter); layoutGenerator.SetNameContainer(sharedNameContainer); // 공유 이름 컨테이너 설정 logicGenerator.SetNameContainer(sharedNameContainer); // 공유 이름 컨테이너 설정 logicGenerator.SetCallbackContainer(sharedCallbackContainer); // 공유 콜밸 컨테이너 설정 logicGenerator.SetMapper(mapper); // 코드 매핑 설정 // WPF Code Builder var wpfCodeBuilder = new WPFCodeBuilder(parameter, logicGenerator); // 임시 파일 경로 string tempIconPath = compileParam.TempFiles.AddExtension("ico"); string tempResFileName = Path.Combine(Path.GetTempPath(), $"{parameter.Option.ApplicationName}.g.resources"); // 기본 디렉터리 / Build / 어플리케이션이름 / 플랫폼 string directory = Path.Combine(parameter.Option.Directory, "Build", parameter.Option.ApplicationName, parameter.Option.TargetPlatform.ToString()); string exePath = Path.Combine(directory, $"{parameter.Option.ApplicationName}.exe"); compileParam.TempFiles.AddFile(tempResFileName, false); // 출력 폴더 생성 DirectoryEx.Create(directory); // * OnReport Progress await this.OnReport(++OnReport / TotalOnReport); // Generate Native Code string[] screensXaml = layoutGenerator.Generate().ToArray(); var csSources = new List <string>(); foreach (string cs in WPFCompiler.CodeResources.Values) { DXMappingResult mappingResult = wpfCodeBuilder.Build(cs); csSources.Add(mappingResult.Source); } // * OnReport Progress await this.OnReport(++OnReport / TotalOnReport); // 리소스 생성 if (provider.Supports(GeneratorSupport.Resources)) { using (var fs = File.Create(tempResFileName)) { var res = new WPFResourceWriter(fs); // 이미지 리소스 추가 foreach (string img in layoutGenerator.Images) { res.AddImage(img, ""); } // 레이아웃 xaml 추가 for (int i = 0; i < parameter.Screens.Length; i++) { res.AddXaml($"{parameter.Screens[i].GetPageName()}.xaml", "", screensXaml[i]); } res.Close(); } compileParam.EmbeddedResources.Add(tempResFileName); } // * OnReport Progress await this.OnReport(++OnReport / TotalOnReport); // 임시 아이콘 생성 Stream iconStream = GetStreamResource("Resources/IconLogo.ico"); byte[] iconBin = new byte[iconStream.Length]; iconStream.Read(iconBin, 0, iconBin.Length); File.WriteAllBytes(tempIconPath, iconBin); // * OnReport Progress await this.OnReport(++OnReport / TotalOnReport); // 출력 및 컴파일 커맨드라인 설정 compileParam.OutputAssembly = exePath; compileParam.CompilerOptions = $"/target:winexe /win32icon:{tempIconPath}"; #if DEBUG UI.SpacingStackPanel s; var w = new Window() { WindowStartupLocation = WindowStartupLocation.CenterScreen, Content = new ScrollViewer() { Content = (s = new UI.SpacingStackPanel() { Spacing = 40 }) } }; foreach (string xaml in screensXaml) { s.Children.Add( new TextBox() { VerticalScrollBarVisibility = ScrollBarVisibility.Auto, IsReadOnly = true, Text = xaml }); } foreach (string code in csSources) { s.Children.Add( new TextBox() { VerticalScrollBarVisibility = ScrollBarVisibility.Auto, IsReadOnly = true, Text = code }); } w.Show(); #endif // Compile Binary CompilerResults compileResult = provider.CompileAssemblyFromSource(compileParam, csSources.ToArray()); compileParam.TempFiles.Delete(); // 컴파일 시간 기록 sw.Stop(); result.Elapsed = sw.Elapsed; // * OnReport Progress await this.OnReport(++OnReport / TotalOnReport); if (compileResult.Errors.Count > 0) { result.Errors.AddRange(compileResult.Errors.Cast <object>()); } else { result.Outputs.Add(exePath); // Referenced DLL Export foreach (string assemblyFileName in compileParam.ReferencedAssemblies) { if (File.Exists(assemblyFileName) && assemblyFileName.StartsWith(Environment.CurrentDirectory)) { // DLL 복사 File.Copy( assemblyFileName, Path.Combine(directory, Path.GetFileName(assemblyFileName)), true); result.Outputs.Add(assemblyFileName); } } result.IsSuccess = true; } // * OnReport Progress await this.OnReport(++OnReport / TotalOnReport); return(result); }
public override async Task <DXCompileResult> Compile(DXCompileParameter parameter) { const double TotalOnReport = 8; int OnReport = 0; // * OnReport Progress await this.OnReport(++OnReport / TotalOnReport); var sw = new Stopwatch(); sw.Start(); // Result var result = new DXCompileResult(parameter.Option); // NameContainer var sharedLayoutContainer = new ModelNameContainer(); var mainNameContainer = new ModelNameContainer(); var mainCallbackContainer = new ModelNameContainer(); var templateNameContainer = new ModelNameContainer(); var templateCallbackContainer = new ModelNameContainer(); // CodeDom var provider = new CSharpCodeProvider( new Dictionary <string, string>() { { "CompilerVersion", "v4.0" } }); var compileParam = new CompilerParameters() { GenerateExecutable = true, GenerateInMemory = false, TreatWarningsAsErrors = false, #if RELEASE IncludeDebugInformation = false #else IncludeDebugInformation = true #endif }; // Add WPF Referenced Assembly Assembly[] dependencyLibs = GetReferencedAssemblyNames(parameter).ToArray(); AddReferencedAssemblies(compileParam, dependencyLibs); // * OnReport Progress await this.OnReport(++OnReport / TotalOnReport); // Mapper var mapper = new DXMapper <CSharpCodeMapAttribute>( new WPFMappingProvider(mainCallbackContainer), mainNameContainer) { SharedConatiner = sharedLayoutContainer }; var templateMapper = new DXMapper <CSharpCodeMapAttribute>( new WPFMappingProvider(templateCallbackContainer), templateNameContainer) { SharedConatiner = sharedLayoutContainer }; // Generator WPFLayoutGenerator layoutGenerator = CreateLayoutGenerator(parameter); WPFLayoutGenerator templateGenerator = CreateTemplateGenerator(parameter); CSharpGenerator logicGenerator = CreateLogicGenerator(parameter); CSharpGenerator templateLogicGenerator = CreateTemplateLogicGenerator(parameter); // 이름 컨테이너 설정 layoutGenerator.NameContainer = mainNameContainer; templateGenerator.NameContainer = templateNameContainer; logicGenerator.NameContainer = mainNameContainer; templateLogicGenerator.NameContainer = templateNameContainer; // 콜백 컨테이너 설정 logicGenerator.CallbackContainer = mainCallbackContainer; templateLogicGenerator.CallbackContainer = templateCallbackContainer; // 공유 이름 컨테이너 설정 layoutGenerator.SharedContainer = sharedLayoutContainer; templateGenerator.SharedContainer = sharedLayoutContainer; // 코드 매퍼 할당 logicGenerator.Mapper = mapper; templateLogicGenerator.Mapper = templateMapper; // WPF Code Builder var wpfCodeBuilder = new WPFCodeBuilder(parameter, logicGenerator); var wpfTemplateCodeBuilder = new WPFTemplateCodeBuilder(parameter, templateLogicGenerator); var wpfTemplateBuilder = new WPFTemplateBuilder(); // 임시 파일 경로 string tempIconPath = compileParam.TempFiles.AddExtension("ico"); string tempResFileName = Path.Combine(Path.GetTempPath(), $"{parameter.Option.ApplicationName}.g.resources"); string tempAssmResFileName = Path.Combine(Path.GetTempPath(), $"{parameter.Option.ApplicationName}.assembly.g.resources"); // 기본 디렉터리 / Build / 어플리케이션이름 / 플랫폼 string directory = Path.Combine(parameter.Option.Directory, "Build", parameter.Option.ApplicationName, parameter.Option.TargetPlatform.ToString()); string exePath = Path.Combine(directory, $"{parameter.Option.ApplicationName}.exe"); compileParam.TempFiles.AddFile(tempResFileName, false); compileParam.TempFiles.AddFile(tempAssmResFileName, false); // 출력 폴더 생성 DirectoryEx.Create(directory); // * OnReport Progress await this.OnReport(++OnReport / TotalOnReport); // Generate Native Code string[] templatesXaml = templateGenerator.Generate().ToArray(); string[] screensXaml = layoutGenerator.Generate().ToArray(); var csSources = new List <string>(); // DataTemplate Patch string[] templateNames = parameter.Templates .Select(t => $"_{t.GetPageName()}") .ToArray(); for (int i = 0; i < templatesXaml.Length; i++) { templatesXaml[i] = Regex.Replace(templatesXaml[i], $@"\w+:DeXignTemplatePage", $"local:{templateNames[i]}"); templatesXaml[i] = Regex.Replace(templatesXaml[i], @"<\?xml.*?\?>[\r\n]+", ""); } // Create DataTemplate Resources wpfTemplateBuilder.TemplateContents = templatesXaml; wpfTemplateBuilder.TemplateNames = templateNames; string resourceXaml = templateMapper.Build(wpfTemplateBuilder, WPFCompiler.CodeResources["DXResources.xaml"]).Source; resourceXaml = templateMapper.Build(parameter.Option, resourceXaml).Source; // Main Sources foreach (string csName in CSFiles) { DXMappingResult mappingResult = wpfCodeBuilder.Build(WPFCompiler.CodeResources[csName]); csSources.Add(mappingResult.Source); } // Template Sources foreach (string templateName in templateNames) { DXMappingResult mappingResult = wpfTemplateCodeBuilder.Build(WPFCompiler.CodeResources["DXUserControl.cs"]); csSources.Add(mappingResult.Source); } // * OnReport Progress await this.OnReport(++OnReport / TotalOnReport); // 리소스 생성 if (provider.Supports(GeneratorSupport.Resources)) { // 디자인 리소스 using (var fs = File.Create(tempResFileName)) { var res = new WPFResourceWriter(fs); // 이미지 리소스 추가 foreach (string img in layoutGenerator.Images.Concat(templateGenerator.Images).Distinct()) { res.AddImage(img, $"{MD5.GetHash(Path.GetFileName(img))}{Path.GetExtension(img)}", ""); } // 레이아웃 xaml 추가 for (int i = 0; i < parameter.Screens.Length; i++) { res.AddXaml($"{parameter.Screens[i].GetPageName()}.xaml", "", screensXaml[i]); } // 리소스 xaml 추가 res.AddXaml("DXResources.xaml", "", resourceXaml); res.Close(); } // 어셈블리 리소스 using (var fs = File.Create(tempAssmResFileName)) { var res = new WPFResourceWriter(fs); foreach (string dllName in DynamicLibraries) { if (File.Exists(dllName)) { res.AddBinary(dllName, "", File.ReadAllBytes(dllName)); } } res.Close(); } compileParam.EmbeddedResources.Add(tempResFileName); compileParam.EmbeddedResources.Add(tempAssmResFileName); } // * OnReport Progress await this.OnReport(++OnReport / TotalOnReport); // 임시 아이콘 생성 Stream iconStream = GetStreamResource("Resources/IconLogo.ico"); byte[] iconBin = new byte[iconStream.Length]; iconStream.Read(iconBin, 0, iconBin.Length); File.WriteAllBytes(tempIconPath, iconBin); // * OnReport Progress await this.OnReport(++OnReport / TotalOnReport); // 출력 및 컴파일 커맨드라인 설정 compileParam.OutputAssembly = exePath; compileParam.CompilerOptions = $"/target:winexe /win32icon:{tempIconPath}"; // Generate Debugging if (Keyboard.IsKeyDown(Key.LeftShift)) { ShowGeneratedSources( screensXaml .Concat(new[] { resourceXaml }) .Concat(csSources)); } // Compile Binary CompilerResults compileResult = provider.CompileAssemblyFromSource(compileParam, csSources.ToArray()); compileParam.TempFiles.Delete(); // 컴파일 시간 기록 sw.Stop(); result.Elapsed = sw.Elapsed; // * OnReport Progress await this.OnReport(++OnReport / TotalOnReport); if (compileResult.Errors.Count > 0) { result.Errors.AddRange(compileResult.Errors.Cast <object>()); } else { result.Outputs.Add(exePath); // Referenced DLL Export foreach (string assemblyFileName in compileParam.ReferencedAssemblies .Cast <string>() .Where(fileName => File.Exists(fileName) && fileName.StartsWith(Environment.CurrentDirectory))) { if (assemblyFileName.StartsWith(Environment.CurrentDirectory)) { string dllFileName = Path.Combine(directory, Path.GetFileName(assemblyFileName)); if (!DynamicLibraries.Contains(Path.GetFileName(assemblyFileName))) { // DLL 복사 File.Copy( assemblyFileName, dllFileName, true); result.Outputs.Add(assemblyFileName); } else if (File.Exists(dllFileName)) { File.Delete(dllFileName); } } } result.IsSuccess = true; } // * OnReport Progress await this.OnReport(++OnReport / TotalOnReport); return(result); }