kekyo / IL2C

IL2C - A translator for ECMA-335 CIL/MSIL to C language.
Apache License 2.0
401 stars 36 forks source link

Error compiling project with IL2C #113

Closed Duy-Thanh closed 2 years ago

Duy-Thanh commented 2 years ago

Hello

First of all, I just want to say thank you for this great project, I hope you continue to actively develop this project. All other previous projects I tried had last commits over 3 years, and moreover, I failed to compile them on my Visual Studio 2022 with Windows 11, so I gave up on them for this library

I have a project written in Windows Forms .NET Framework technology, and I have used Microsoft's upgrade-assistant to migrate them to .NET 6.0. And my application runs fine on .NET 6.0 and not a single broken feature.

When I apply IL2C to my converted project, when I compile I get the following error:

Error MSB4018 The "Translate" task failed unexpectedly.
System.NullReferenceException: Object reference not set to an instance of an object.
   at IL2C.Metadata.MetadataContext.<>c__DisplayClass19_0.<GetOrAddType>b__0() in D:\PROJECT\IL2C\IL2C.Core\Metadata\MetadataContext.cs:line 291
   at IL2C.Metadata.MetadataContext.GetOrAddMember[TINformation,TReference](TReference memberReference, Func`1 generator) in D:\PROJECT\IL2C\IL2C.Core\Metadata\MetadataContext.cs:line 236
   at IL2C.Metadata.TypeInformation.get_BaseType() in D:\PROJECT\IL2C\IL2C.Core\Metadata\TypeInformation.cs:line 406
   at IL2C.AssemblyPreparer.Prepare(TranslateContext translateContext, Func`2 predictType, Func`2 predictMethod) in D:\PROJECT\IL2C\IL2C.Core\AssemblyPreparer.cs:line 280
   at IL2C.SimpleDriver.Translate(TextWriter logw, CodeTextStorage storage, Boolean readSymbols, Boolean enableBundler, TargetPlatforms targetPlatform, DebugInformationOptions debugInformationOptions, String assemblyPath) in D:\PROJECT\IL2C\IL2C.Core\SimpleDriver.cs:line 38
   at IL2C.SimpleDriver.TranslateAll(TextWriter logw, String outputPath, Boolean readSymbols, Boolean enableCpp, Boolean enableBundler, TargetPlatforms targetPlatform, DebugInformationOptions debugInformationOptions, IEnumerable`1 assemblyPaths) in D:\PROJECT\IL2C\IL2C.Core. 121
   at IL2C.Translate.Execute() in D:\PROJECT\IL2C\IL2C.Tasks\Translate.cs:line 86
   at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute()
   at Microsoft.Build.BackEnd.TaskBuilder.<ExecuteInstantiatedTask>d__26.MoveNext() GenshinImpactBooster C:\Users\lolva\.nuget\packages\il2c.build\0.4.113\build\IL2C.Build.targets 19

Output:

1>GenshinImpactBooster -> E:\Data\Projects_MSVS\GenshinImpactBooster\GenshinImpactBooster\bin\Debug\net6.0-windows\GenshinImpactBooster.dll
1>C:\Users\lolva\.nuget\packages\il2c.build\0.4.113\build\IL2C.Build.targets(19,9): error MSB4018: The "Translate" task failed unexpectedly.
1>C:\Users\lolva\.nuget\packages\il2c.build\0.4.113\build\IL2C.Build.targets(19,9): error MSB4018: System.NullReferenceException: Object reference not set to an instance of an object.
1>C:\Users\lolva\.nuget\packages\il2c.build\0.4.113\build\IL2C.Build.targets(19,9): error MSB4018: at IL2C.Metadata.MetadataContext.<>c__DisplayClass19_0.< GetOrAddType>b__0() in D:\PROJECT\IL2C\IL2C.Core\Metadata\MetadataContext.cs:line 291
1>C:\Users\lolva\.nuget\packages\il2c.build\0.4.113\build\IL2C.Build.targets(19,9): error MSB4018: at IL2C.Metadata.MetadataContext.GetOrAddMember[TINformation,TReference ](TReference memberReference, Func`1 generator) in D:\PROJECT\IL2C\IL2C.Core\Metadata\MetadataContext.cs:line 236
1>C:\Users\lolva\.nuget\packages\il2c.build\0.4.113\build\IL2C.Build.targets(19,9): error MSB4018: at IL2C.Metadata.TypeInformation.get_BaseType() in D :\PROJECT\IL2C\IL2C.Core\Metadata\TypeInformation.cs:line 406
1>C:\Users\lolva\.nuget\packages\il2c.build\0.4.113\build\IL2C.Build.targets(19,9): error MSB4018: at IL2C.AssemblyPreparer.Prepare(TranslateContext translateContext, Func` 2 predictType, Func`2 predictMethod) in D:\PROJECT\IL2C\IL2C.Core\AssemblyPreparer.cs:line 280
1>C:\Users\lolva\.nuget\packages\il2c.build\0.4.113\build\IL2C.Build.targets(19,9): error MSB4018: at IL2C.SimpleDriver.Translate(TextWriter logw, CodeTextStorage storage , Boolean readSymbols, Boolean enableBundler, TargetPlatforms targetPlatform, DebugInformationOptions debugInformationOptions, String assemblyPath) in D:\PROJECT\IL2C\IL2C.Core\SimpleDriver.cs:line 38
1>C:\Users\lolva\.nuget\packages\il2c.build\0.4.113\build\IL2C.Build.targets(19,9): error MSB4018: at IL2C.SimpleDriver.TranslateAll(TextWriter logw, String outputPath , Boolean readSymbols, Boolean enableCpp, Boolean enableBundler, TargetPlatforms targetPlatform, DebugInformationOptions debugInformationOptions, IEnumerable`1 assemblyPaths) in D:\PROJECT\IL2C\IL2C.Core\SimpleDriver.cs:line 121
1>C:\Users\lolva\.nuget\packages\il2c.build\0.4.113\build\IL2C.Build.targets(19,9): error MSB4018: at IL2C.Translate.Execute() in D:\ PROJECT\IL2C\IL2C.Tasks\Translate.cs:line 86
1>C:\Users\lolva\.nuget\packages\il2c.build\0.4.113\build\IL2C.Build.targets(19,9): error MSB4018: at Microsoft.Build.BackEnd.TaskExecutionHost.Microsoft.Build.BackEnd.ITaskExecutionHost.Execute()
1>C:\Users\lolva\.nuget\packages\il2c.build\0.4.113\build\IL2C.Build.targets(19,9): error MSB4018: at Microsoft.Build.BackEnd.TaskBuilder.<ExecuteInstantiatedTask> d__26.MoveNext()
1>Done building project "GenshinImpactBooster.csproj" -- FAILED.
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
Duy-Thanh commented 2 years ago

Any help is always appreciated

kekyo commented 2 years ago

Thanks for trying IL2C. Probably, general purpose applications (including Windows Forms, as you have shown) cannot run on IL2C yet.

The fact that your application runs on Windows Forms (and I'm assuming from your project name :) that it's a complex application) makes me wonder if it's possible to run it in IL2C.

I think the most likely option for converting such an application into a single native binary is a project called "corert" in the original .NET team.

However, corert project is still work in progress for a long time, and it is still too difficult for the average developer to try.


Bit off topics.

For reference, here is what I consider to be the shortest path to a working GUI application:

Right now, the most challenging issues are related to Generic type. Not only code analysis, but also type instantiation issues, memory layout, building process, and a lot of topics related to footprint reduction are quite high difficulty issues.

Alternatively, I'm thinking that it might be better to limit it to the console process, so that host OS native binaries that work first anyway can be generated using just the standard build process (i.e., just dotnet build).

Duy-Thanh commented 2 years ago

Thank you very much for your detailed reply @kekyo

True to what you said, this is a complex application. This application manages the activities of processes, services, and communicates with the Registry and WMI. It recognizes when the game is running and then does the work of speeding up and when the game stops it will revert the changes and count the time played, etc.

I also guess you can already guess what my app will do by the project name :) Yes, this is an app to speed up the computer while playing Genshin Impact. I made this tool for my hobby and part of me also wanted to give users an acceleration tool to give them peace of mind while playing the game.

One thing to mention here is that C# applications run in the middle (ie have to run through the .NET Runtime / .NET Framework Runtime) and this is really inconvenient. Today's games can take up GBs of RAM and take up most of the processing speed, so running the application through the Runtime is probably not a good idea, it will reduce the performance of the application and system (Like this application of mine, it took up 14MB of RAM when working and 3% CPU processing). This number may be small, but for mid-range configuration computers, users will consider it a thorn that needs to be eliminated for stable gaming. So I decided to move the project to C++ right from C# without having to rewrite it from scratch. (because C++ is fast, there is no need to run through Runtime because it compiles to native code that can be run directly)

All the projects I've tried in the past have been abandoned, and I have failed to compile those tools (because those tools use outdated versions of Visual Studio and they may no longer compatible with VS2022). This project is probably the only one still in development that I know of that works on VS2022

Another thing is that I don't use the default Windows look and feel, instead I have developed one of my own, but unfortunately even having moved all that code into the same project, IL2C still doesn't work (But without IL2C everything goes smoothly)

I also had some new findings. The error code "Translating" appears in my custom UI rendering code. Specifically, the following code:

        private GraphicsPath GetFigurePath(Rectangle rect, float radius)
        {
            GraphicsPath path = new GraphicsPath();
            float curveSize = radius * 2F;

            path.StartFigure();

            path.AddArc(rect.X,
                rect.Y,
                curveSize,
                curveSize,
                180,
                90);

            path.AddArc(rect.Right - curveSize,
                rect.Y,
                curveSize,
                curveSize,
                270,
                90);

            path.AddArc(rect.Right - curveSize,
                rect.Bottom - curveSize,
                curveSize,
                curveSize,
                0,
                90);

            path.AddArc(rect.X,
                rect.Bottom - curveSize,
                curveSize,
                curveSize,
                90,
                90);

            path.CloseFigure();

            return path;
        }

And:

 protected override void OnPaint(PaintEventArgs pevent)
        {
            base.OnPaint(pevent);
            pevent.Graphics.SmoothingMode = SmoothingMode.HighQuality;

            Rectangle rectSurface = this.ClientRectangle;
            Rectangle rectBorder = Rectangle.Inflate(rectSurface, -borderSize, -borderSize);

            int smoothSize = 2;

            if (borderSize > 0)
            {
                smoothSize = borderSize;
            }

            if (borderSize > 2) // Rounded Button
            {
                using (GraphicsPath pathSurface = GetFigurePath(rectSurface, borderRadius))
                using (GraphicsPath pathBorder = GetFigurePath(rectBorder, borderRadius - borderSize))
                using (Pen penSurface = new Pen(this.Parent.BackColor, smoothSize))
                using (Pen penBorder = new Pen(borderColor, borderSize))
                {
                    // Button Surface
                    this.Region = new Region(pathSurface);

                    // Draw surface border for HD result
                    pevent.Graphics.DrawPath(penSurface, pathSurface);

                    // Button Border
                    if (borderSize >= 1)
                    {
                        // Draw control border
                        pevent.Graphics.DrawPath(penBorder, pathBorder);
                    }
                }
            }
            else // Normal Button
            {
                // Button Surface
                this.Region = new Region(rectSurface);

                // Button border
                if (borderSize >= 1)
                {
                    using (Pen penBorder = new Pen(borderColor, borderSize))
                    {
                        penBorder.Alignment = PenAlignment.Inset;
                        pevent.Graphics.DrawRectangle(penBorder,
                            0,
                            0,
                            this.Width - 1,
                            this.Height - 1);
                    }
                }
            }
        }

is code that is known to not work with IL2C. The first code gives an error in GraphicsPath, the second code gives an error on OnPaint()

And about compatibility: I tried IL2C on .NET Framework 4.8 with simple Console application and.... it works:

Build started...
1>------ Build started: Project: ConsoleApp1, Configuration: Debug Any CPU ------
1>  ConsoleApp1 -> E:\Data\Projects_MSVS\ConsoleApp1\ConsoleApp1\bin\Debug\ConsoleApp1.exe
1>  IL2C: Preparing assembly: "E:\Data\Projects_MSVS\ConsoleApp1\ConsoleApp1\bin\Debug\ConsoleApp1.exe" ... done.
1>  IL2C: Writing: "E:\Data\Projects_MSVS\ConsoleApp1\ConsoleApp1\bin\Debug\IL2C\include\ConsoleApp1.h" ... Done.
1>  IL2C: Writing: "E:\Data\Projects_MSVS\ConsoleApp1\ConsoleApp1\bin\Debug\IL2C\include\ConsoleApp1\ConsoleApp1\Program.h" ... Done.
1>  IL2C: Writing: "E:\Data\Projects_MSVS\ConsoleApp1\ConsoleApp1\bin\Debug\IL2C\src\ConsoleApp1_internal.h" ... Done.
1>  IL2C: Writing: "E:\Data\Projects_MSVS\ConsoleApp1\ConsoleApp1\bin\Debug\IL2C\src\ConsoleApp1_internal.c" ... Done.
1>  IL2C: Writing: "E:\Data\Projects_MSVS\ConsoleApp1\ConsoleApp1\bin\Debug\IL2C\src\ConsoleApp1\ConsoleApp1\Program.c" ... Done.
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

I hope the above code will give you more basis to find bugs and solve potential errors of IL2C in the future.

It may take some time to fix the bug and make IL2C mature, so I'll be patiently waiting for your feedback and new versions. Happy coding

NCLnclNCL commented 1 year ago

Cảm ơn bạn rất nhiều vì đã trả lời chi tiết@kekyo

Đúng như những gì bạn đã nói, đây là một ứng dụng phức tạp. Ứng dụng này quản lý hoạt động của các quy trình, dịch vụ và liên lạc với Cơ quan đăng ký và WMI. Nó nhận biết khi nào trò chơi đang chạy và sau đó thực hiện công việc tăng tốc và khi trò chơi dừng, nó sẽ hoàn nguyên các thay đổi và đếm thời gian đã chơi, v.v.

Tôi cũng đoán là bạn đã đoán được ứng dụng của tôi sẽ làm gì với tên dự án :) Vâng, đây là ứng dụng tăng tốc máy tính khi chơi Genshin Impact. Tôi tạo ra công cụ này vì sở thích của mình và một phần trong tôi cũng muốn cung cấp cho người dùng một công cụ tăng tốc để họ yên tâm khi chơi game.

Một điều cần nói ở đây là các ứng dụng C# chạy ở giữa (tức là phải chạy qua .NET Runtime/.NET Framework Runtime) và điều này thực sự bất tiện. Các game hiện nay có thể ngốn hàng GB RAM và chiếm phần lớn tốc độ xử lý nên việc chạy ứng dụng qua Runtime có lẽ không phải là ý kiến ​​hay, nó sẽ làm giảm hiệu suất của ứng dụng và hệ thống (Giống như ứng dụng này của tôi, nó mất nhiều thời gian hơn). tăng 14 MB RAM khi làm việc và xử lý CPU 3%). Con số này có thể không nhỏ nhưng với những máy tính cấu hình tầm trung, người dùng sẽ coi đó là một cái gai cần loại bỏ để chơi game ổn định. Vì vậy, tôi quyết định chuyển dự án sang C++ ngay từ C# mà không cần phải viết lại từ đầu. (vì C++ nhanh nên không cần chạy qua Runtime vì nó biên dịch thành mã gốc có thể chạy trực tiếp)

Tất cả các dự án mà tôi đã thử trước đây đều đã bị bỏ dở và tôi đã không biên dịch được các công cụ đó (vì những công cụ đó sử dụng các phiên bản Visual Studio đã lỗi thời và chúng có thể không còn tương thích với VS2022 nữa). Dự án này có lẽ là dự án duy nhất vẫn đang được phát triển mà tôi biết hoạt động trên VS2022

Một điều nữa là tôi không sử dụng giao diện mặc định của Windows, thay vào đó tôi đã phát triển một giao diện của riêng mình, nhưng thật không may, ngay cả khi đã chuyển tất cả mã đó vào cùng một dự án, IL2C vẫn không hoạt động (Nhưng không có IL2C thì mọi thứ vẫn ổn). thông suốt)

Tôi cũng có một số phát hiện mới. Mã lỗi "Dịch" xuất hiện trong mã hiển thị giao diện người dùng tùy chỉnh của tôi. Cụ thể là đoạn mã sau:

        private GraphicsPath GetFigurePath(Rectangle rect, float radius)
        {
            GraphicsPath path = new GraphicsPath();
            float curveSize = radius * 2F;

            path.StartFigure();

            path.AddArc(rect.X,
                rect.Y,
                curveSize,
                curveSize,
                180,
                90);

            path.AddArc(rect.Right - curveSize,
                rect.Y,
                curveSize,
                curveSize,
                270,
                90);

            path.AddArc(rect.Right - curveSize,
                rect.Bottom - curveSize,
                curveSize,
                curveSize,
                0,
                90);

            path.AddArc(rect.X,
                rect.Bottom - curveSize,
                curveSize,
                curveSize,
                90,
                90);

            path.CloseFigure();

            return path;
        }

Và:

 protected override void OnPaint(PaintEventArgs pevent)
        {
            base.OnPaint(pevent);
            pevent.Graphics.SmoothingMode = SmoothingMode.HighQuality;

            Rectangle rectSurface = this.ClientRectangle;
            Rectangle rectBorder = Rectangle.Inflate(rectSurface, -borderSize, -borderSize);

            int smoothSize = 2;

            if (borderSize > 0)
            {
                smoothSize = borderSize;
            }

            if (borderSize > 2) // Rounded Button
            {
                using (GraphicsPath pathSurface = GetFigurePath(rectSurface, borderRadius))
                using (GraphicsPath pathBorder = GetFigurePath(rectBorder, borderRadius - borderSize))
                using (Pen penSurface = new Pen(this.Parent.BackColor, smoothSize))
                using (Pen penBorder = new Pen(borderColor, borderSize))
                {
                    // Button Surface
                    this.Region = new Region(pathSurface);

                    // Draw surface border for HD result
                    pevent.Graphics.DrawPath(penSurface, pathSurface);

                    // Button Border
                    if (borderSize >= 1)
                    {
                        // Draw control border
                        pevent.Graphics.DrawPath(penBorder, pathBorder);
                    }
                }
            }
            else // Normal Button
            {
                // Button Surface
                this.Region = new Region(rectSurface);

                // Button border
                if (borderSize >= 1)
                {
                    using (Pen penBorder = new Pen(borderColor, borderSize))
                    {
                        penBorder.Alignment = PenAlignment.Inset;
                        pevent.Graphics.DrawRectangle(penBorder,
                            0,
                            0,
                            this.Width - 1,
                            this.Height - 1);
                    }
                }
            }
        }

là mã được biết là không hoạt động với IL2C. Mã đầu tiên báo lỗi trong GraphicsPath, mã thứ hai báo lỗi trên OnPaint()

Và về khả năng tương thích: Tôi đã thử IL2C trên .NET Framework 4.8 với ứng dụng Console đơn giản và.... nó hoạt động:

Build started...
1>------ Build started: Project: ConsoleApp1, Configuration: Debug Any CPU ------
1>  ConsoleApp1 -> E:\Data\Projects_MSVS\ConsoleApp1\ConsoleApp1\bin\Debug\ConsoleApp1.exe
1>  IL2C: Preparing assembly: "E:\Data\Projects_MSVS\ConsoleApp1\ConsoleApp1\bin\Debug\ConsoleApp1.exe" ... done.
1>  IL2C: Writing: "E:\Data\Projects_MSVS\ConsoleApp1\ConsoleApp1\bin\Debug\IL2C\include\ConsoleApp1.h" ... Done.
1>  IL2C: Writing: "E:\Data\Projects_MSVS\ConsoleApp1\ConsoleApp1\bin\Debug\IL2C\include\ConsoleApp1\ConsoleApp1\Program.h" ... Done.
1>  IL2C: Writing: "E:\Data\Projects_MSVS\ConsoleApp1\ConsoleApp1\bin\Debug\IL2C\src\ConsoleApp1_internal.h" ... Done.
1>  IL2C: Writing: "E:\Data\Projects_MSVS\ConsoleApp1\ConsoleApp1\bin\Debug\IL2C\src\ConsoleApp1_internal.c" ... Done.
1>  IL2C: Writing: "E:\Data\Projects_MSVS\ConsoleApp1\ConsoleApp1\bin\Debug\IL2C\src\ConsoleApp1\ConsoleApp1\Program.c" ... Done.
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

Tôi hy vọng đoạn code trên sẽ giúp bạn có thêm cơ sở để tìm ra lỗi và giải quyết các lỗi tiềm ẩn của IL2C trong tương lai.

Có thể mất một thời gian để sửa lỗi và hoàn thiện IL2C, vì vậy tôi sẽ kiên nhẫn chờ phản hồi của bạn và các phiên bản mới. Chúc mừng mã hóa

This with native aot ??