simple use clr (.net framework 4.x) in c++
  • C++ 98.5%
  • Batchfile 1.5%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
2026-09-09 20:31:11 +03:00
main init: add all current project files 2026-09-09 20:31:11 +03:00
.gitignore init: add all current project files 2026-09-09 20:31:11 +03:00
app.manifest init: add all current project files 2026-09-09 20:31:11 +03:00
app.rc init: add all current project files 2026-09-09 20:31:11 +03:00
build.bat init: add all current project files 2026-09-09 20:31:11 +03:00
cpp2clr.cpp init: add all current project files 2026-09-09 20:31:11 +03:00
cpp2clr.hpp init: add all current project files 2026-09-09 20:31:11 +03:00
example.cpp init: add all current project files 2026-09-09 20:31:11 +03:00
example2.cpp init: add all current project files 2026-09-09 20:31:11 +03:00
example3.cpp init: add all current project files 2026-09-09 20:31:11 +03:00
example4.cpp init: add all current project files 2026-09-09 20:31:11 +03:00
LLMS.md init: add all current project files 2026-09-09 20:31:11 +03:00
README.md init: add all current project files 2026-09-09 20:31:11 +03:00

ВОТ ЩАС РАБОТАЕТ

cpp2clr

Легковесный мост между нативным C++ (MinGW g++) и .NET Framework (CLR). Без MSVC, без /clr, без C++/CLI — только чистый g++ и COM/reflection под капотом.


Возможности

  • Только 2 файла: cpp2clr.hpp + cpp2clr.cpp
  • MinGW g++ 13/14/15+ — работает из коробки
  • Создание объектов и вызов методов: get_type(...).create(...), .call(...)
  • Свойства через operator[]: form["Text"] = "Привет", form["Width"] = 800
  • Индексаторы: arr[0], dict["key"], list[i], .count()
  • Range-based for: for (auto item : collection) по любому IEnumerable
  • C++ лямбды с захватом на события: btn.on("Click", [&](value s, value e) { ... })
  • Отписка от событий: btn.off("Click", token)
  • Generics: get_generic_type("List\1", { get_type("System.String") }), make_generic(...), call_generic(...)`
  • Перегрузки и ref/out: call_explicit(...), call_with_ref(...) (например Int32.TryParse)
  • Операторы на value: +, -, *, /, %, ==, !=, <, <=, >, >=
  • Zero-Copy Pinning: arr.pin() — прямой int32_t* в managed-массив без копирования
  • Динамическая компиляция C#: compile_class(source, "MyNamespace.MyClass") — выполнение C# в памяти на лету
  • Async/Task: task.wait(), task.get_result(), task.continue_with(...)
  • ComCtl32 v6: встроенный манифест Windows 10/11, EnableVisualStyles() — современный внешний вид без Win95
  • Исключения: cpp2clr::clr_exception с текстом ошибки CLR и HRESULT

Структура проекта

cpp2clr/
├── cpp2clr.hpp           # API (C++17)
├── cpp2clr.cpp           # Реализация: CLR хостинг, COM reflection, мост
├── example.cpp           # Пример 1: Console, Math, WinForms, нативный callback
├── example2.cpp          # Пример 2: полноэкранная форма (Maximized + None + White)
├── example3.cpp          # Пример 3: динамический текст по центру при ресайзе
├── example4.cpp          # Пример 4: лямбды, Generics, Pinning, Async Task
├── app.manifest          # Манифест ComCtl32 v6 (Windows 10/11 визуальные стили)
├── app.rc                # Файл ресурсов
├── build.bat             # Сборка DLL + всех примеров
│
└── main/                 # CIL Дизассемблер и Транспилятор
    ├── main.cpp          # Основной инструмент: .exe -> .il -> .cpp
    ├── ecma335_parser.hpp# Парсер ECMA-335 CIL (опкоды, метаданные, транспиляция)
    └── build.bat         # Сборка main.exe

Сборка

cpp2clr.dll + примеры

build.bat

Что делает скрипт:

  1. Собирает cpp2clr.dll и libcpp2clr.a
  2. Компилирует app.res (манифест ComCtl32 v6)
  3. Компилирует example.exe, example2.exe, example3.exe, example4.exe

Вручную:

g++ -std=c++17 -O2 -shared -DCPP2CLR_EXPORTS -o cpp2clr.dll cpp2clr.cpp -Wl,--out-implib,libcpp2clr.a -lole32 -loleaut32 -luuid
windres app.rc -O coff -o app.res
g++ -std=c++17 -O2 -o example.exe example.cpp app.res -L. -lcpp2clr

Транспилятор (main/)

cd main
build.bat

Автоматически скопирует cpp2clr.dll и libcpp2clr.a из корня, если их нет.


Транспилятор: .exe → C++

main/main.exe читает любой .NET .exe, дизассемблирует CIL и генерирует нативный C++ файл через cpp2clr.

cd main
main.exe path\to\MyApp.exe

Выводит:

  • MyApp_reconstructed.il — читаемый CIL (ECMA-335)
  • MyApp_transpiled.cpp — C++ файл для компиляции

Компиляция результата:

g++ -std=c++17 -O2 -o MyApp_native.exe MyApp_transpiled.cpp -L. -lcpp2clr

Что поддерживает транспилятор

  • Все основные CIL опкоды (ECMA-335 compliant, включая ldc.i4.m1 / ldc.i4.0ldc.i4.8)
  • WinForms: Form, Button, Label, PictureBox, Font, Color, Size, Point
  • Свойства: FormBorderStyle, WindowState, SizeMode, Anchor, BackColor, ForeColor
  • Строки в кодировке UTF-16LE из #US потока (включая кириллицу)
  • Unicode пути к файлам (пробелы, тире, кириллица в имени файла)
  • Явные реализации интерфейсов (ISupportInitialize.BeginInit/EndInit)
  • Embedded ресурсы (изображения, иконки из .exe)

Быстрый старт (cpp2clr API)

#include "cpp2clr.hpp"
using namespace cpp2clr;

int main() {
    // 1. Статический метод
    get_type("Console").call("WriteLine", "Привет из C++!");

    // 2. Math с возвратом значения
    double sq = get_type("Math").call("Sqrt", 144.0).to_double(); // 12.0

    // 3. WinForms окно
    load_assembly("System.Windows.Forms");
    get_type("Application").call("EnableVisualStyles");

    value form = get_type("Form").create();
    form["Text"] = "cpp2clr";
    form["Width"] = 500;
    form["Height"] = 350;
    form["StartPosition"] = 1; // CenterScreen

    value btn = get_type("Button").create();
    btn["Text"] = "Нажми!";
    btn["Left"] = 140; btn["Top"] = 130;

    // 4. C++ лямбда на событие
    btn.on("Click", [&](value s, value e) {
        get_type("MessageBox").call("Show", "Привет!", "cpp2clr");
    });

    form.get("Controls").call("Add", btn);
    get_type("Application").call("Run", form);
}

Компиляция:

g++ -std=c++17 -O2 -o myapp.exe myapp.cpp -L. -lcpp2clr

Generics

// List<string>
type listT = get_generic_type("System.Collections.Generic.List`1",
                              { get_type("System.String") });
value list = listT.create();
list.call("Add", "Apple");
list.call("Add", "Banana");

for (auto item : list)
    std::cout << item.to_string() << "\n";

// Dictionary<string, int>
type dictT = get_generic_type("System.Collections.Generic.Dictionary`2",
    { get_type("System.String"), get_type("System.Int32") });
value dict = dictT.create();
dict["Score"] = 100;
int s = dict["Score"].to_int(); // 100

Zero-Copy Pinning

value arr = get_type("System.Int32[]").create(5);
{
    pinned_buffer pin = arr.pin();
    int32_t* raw = static_cast<int32_t*>(pin.data());
    for (int i = 0; i < 5; ++i) raw[i] = (i + 1) * 10;
} // автоматический unpin

for (int i = 0; i < 5; ++i)
    std::cout << arr[i].to_int() << " "; // 10 20 30 40 50

Динамическая компиляция C#

type t = compile_class(R"(
    using System;
    namespace Foo {
        public class Bar {
            public static string Hello(string name) => "Hi, " + name + "!";
        }
    }
)", "Foo.Bar");

std::string result = t.call("Hello", "World").to_string(); // "Hi, World!"

Требования

  • Windows (XP и выше, рекомендуется 10/11)
  • .NET Framework 4.x
  • MinGW-w64 g++ (версия 13+, C++17)
  • windres (входит в MinGW, нужен только для app.res)