simple use clr (.net framework 4.x) in c++
- C++ 98.5%
- Batchfile 1.5%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| main | ||
| .gitignore | ||
| app.manifest | ||
| app.rc | ||
| build.bat | ||
| cpp2clr.cpp | ||
| cpp2clr.hpp | ||
| example.cpp | ||
| example2.cpp | ||
| example3.cpp | ||
| example4.cpp | ||
| LLMS.md | ||
| README.md | ||
ВОТ ЩАС РАБОТАЕТ
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
Что делает скрипт:
- Собирает
cpp2clr.dllиlibcpp2clr.a - Компилирует
app.res(манифест ComCtl32 v6) - Компилирует
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.0–ldc.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)