В этой статье я расскажу, как написать билдер своего софта на C#. Компилировать будем простейшую форму, у которой будет динамически меняться Caption (текст заголовка). Для компилирования используются Namespacы: Microsoft.CSharp System.CodeDom.Compiler В них содержатся необходимые нам инструменты, например такие, как CSharpCodeProvider. Эта штука позволяет компилировать нам код из строки с помощью метода CompileAssemblyFromSource(). Этим мы и воспользуемся. Хранить свой код мы будем в самом приложении, чтобы не раздавать сорцы. Так как C# — JIT-язык, то после создания билдера его надо хорошо закриптовать, инструментов для этого куча, в гугле все есть, защиту .NET я описывать в этой статье не буду. Итак, создаем проект WinForms. Так как у меня будет пустая форма, то ничего добавлять я не стану. Теперь важно: весь код необходимо перенести в один файл. Все классы, Program.cs, Form1.Designer.Cs и т.д. Это можно сделать простым копипастом и переносом using’ов вверх. Объединив все, я получил: PHP: using System; using System.Windows.Forms; namespace builder { public partial class Form1 : Form { public Form1() { InitializeComponent(); } } } namespace builder { partial class Form1 { /// <summary> /// Требуется переменная конструктора. /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// Освободить все используемые ресурсы. /// </summary> /// <param name="disposing">истинно, если управляемый ресурс должен быть удален; иначе ложно.</param> protected override void Dispose(bool disposing) { if (disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Код, автоматически созданный конструктором форм Windows /// <summary> /// Обязательный метод для поддержки конструктора - не изменяйте /// содержимое данного метода при помощи редактора кода. /// </summary> private void InitializeComponent() { this.SuspendLayout(); // // Form1 // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(292, 243); this.Name = "Form1"; this.Text = "Form1"; this.ResumeLayout(false); } #endregion } } namespace builder { static class Program { /// <summary> /// Главная точка входа для приложения. /// </summary> [STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Form1()); } } } Сохраняем это в .txt файл, создаем новый проект — наш компилятор. В его ресурсы добавляем .txt файл. Меняем необходимый динамический текст на какой-нибудь другой, у меня это %_form_caption_% Т.е. в ресурсах строчку this.Text = "Form1"; надо поменять на this.Text = "%_form_caption_%"; Важный момент: в настройках ресурса необходимо поставить эту настройку, иначе мы не сможем ее прочитать. Я долго искал ошибку, пока случайно не наткнулся на данное свойство. Теперь дизайним нашу форму как хотим, ставим textbox и button. Обработчик нажатия кнопки: PHP: private void Button1Click(object sender, EventArgs e) { using (Stream stream = Assembly.GetExecutingAssembly() .GetManifestResourceStream("builder.Resources.res.txt")) { if (stream != null) using (var reader = new StreamReader(stream)) { string result = reader.ReadToEnd().Replace("%_form_caption_%", textBox1.Text.Replace(""", "\"")); var providerOptions = new Dictionary<string, string> { {"CompilerVersion", "v3.5"} }; CompilerResults results; using (var provider = new CSharpCodeProvider(providerOptions)) { var Params = new CompilerParameters { OutputAssembly = Directory.GetCurrentDirectory() + "/build.exe", GenerateExecutable = true, CompilerOptions = "/t:winexe" }; Params.ReferencedAssemblies.Add("System.Windows.Forms.dll"); Params.ReferencedAssemblies.Add("System.dll"); Params.ReferencedAssemblies.Add("System.Drawing.dll"); results = provider.CompileAssemblyFromSource(Params, result); } if (results.Errors.Count == 0) { MessageBox.Show("Компиляция успешно завершена!", "Compilation", MessageBoxButtons.OK, MessageBoxIcon.Asterisk); } foreach (CompilerError compilerError in results.Errors) { MessageBox.Show(string.Format("Ошибка: {0}", compilerError.ErrorText)); } } } } Давайте разберем этот код. Начнем со строчки: Она создает поток данных, в котором находится содержимое нашего файла с исходниками. Важно: builder — необходимо поменять на namespace нашего компилятора res.txt — на имя вашего ресурса (.txt файла). Далее: В этой строчке происходит формирование новых значений, замена статического %_form_caption_% на динамический textBox1.Text. Обратите внимание на Replace(""", "\"") — это экранирование кавычек. Если пользователь введет что-то, содержащее кавычки, например Hello, "user", то в новом исходнике он будет выглядеть как и это вызовет синтаксическую ошибку. Дальше идет копипаст с MSDN, его нет смысла объяснять. Обращу внимание только на следующие строчки: CompilerOptions = "/t:winexe" — так как мы генерируем не консольное, а WinForms приложение, то необходимо указать это компилятору напрямую. В противном случае на программе из выхода мы получим консольное приложение, поверх которого запустится наше. Params.ReferencedAssemblies.Add("System.Windows.Forms.dll"); Params.ReferencedAssemblies.Add("System.dll"); Params.ReferencedAssemblies.Add("System.Drawing.dll"); — Все using’и необходимо добавлять только так, иначе при компиляции программа не сможет их найти Вот вообщем-то и все, остальное я думаю и так понятно. Результат: Скачать исходники проекта и компилированную версию: http://www.box.com/s/6buh0qj7bspka5jfljez Статья не моя. Взято с: http://www.bafoed.net/post/365/ p.s От себя лично, давно когда я писал возник вопрос. Обратился к автору : - как добавить импорт юзер32.длл? я про билдер, ибо при компиляции дллимпорт будет нот фаунд. А автор этой статьи писал , что : – Все using’и необходимо добавлять только так, иначе при компиляции программа не сможет их найти Вот и вопрос как добавить юсинг для импорта? - Params.ReferencedAssemblies.Add("System.Runtime.InteropServices.dll"); аналогично для каждого используемого using'а в билде.