Exemple #1
0
        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);
        }
Exemple #2
0
        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);
        }