Entwickler-Ecke

Basistechnologien - Programm, um Programme zu erstellen


VampireSilence - Di 10.05.11 17:19
Titel: Programm, um Programme zu erstellen
Ich sitze gerade an einem Programm, das kleine Autostart-Programme erstellen soll. Diese sollen dann auf eine CD gespeichert und per Autorun.inf aufgerufen werden und nen kleines "Hallo, ich bin foobar" ausspucken.

Das mit der INI war verglichen zum Rest nen Klacks (erledigt => kann ich erstellen).

Nun soll aber die *.exe erstellt werden, die im Grunde genommen nur eine anfängliche MessageBox.Show(string myText) ausführen soll, wobei "myText" beim Erstellen definiert und dann in die *.exe übergeben werden soll. Würde man das manuell erstellen, wäre das also nur eine Zeile, aber warum einfach, wenns auch kompliziert geht ? :P
Jedenfalls: Danach soll noch ggf. ein Bild angehangen werden können, am besten komprimiert (Zip-Class gefunden => kann ich erstellen) und dann als Hintergrundgrafik (Splash) dargestellt werden (Form.BorderDings = none, also auch kein Problem).

Ein Anwendungsbeispiel:
Eine CD wird eingelegt, die Bilder, Videos und Texte enthält und als Autostart, meldet sie sich mit einem Bild und dem Text "Herzlichen Glückwunsch zum Dr.-Titel von AB und XY". Und mein Programm soll sowas nun erstellen können.

Die Frage, die jetzt noch bleibt: Wie erstelle ich also quasi einen Compiler ? Gibt es sowas wie ein php-eval()-Äquivalent, mit dem ich das umsetzen könnte ? Oder ist sowas sehr kompliziert und ich sollte es lieber lassen ? ^^"

mfg
- VampireSilence


Th69 - Di 10.05.11 19:15

Hallo,

mittels CodeDOM kann man aus .NET heraus Assemblies (d.h. auch EXE-Dateien) generieren lassen. Die zugehörige Klasse lautet: CSharpCodeProvider (bzw. VBCodeProvider für VB.NET) aus dem Microsoft.CSharp-Namensbereich.

Du kannst dir auch mal das Beispielprogramm http://www.codeproject.com/KB/cs/cscompiler.aspx ansehen, d.h. mittels weniger Code-Zeilen ist dies simpel umzusetzen.

Viel Erfolg!

P.S. Ich habe noch drei weitere Beispiele gefunden:
http://www.codeproject.com/KB/cs/MiniCompiler.aspx
http://www.codeproject.com/KB/dotnet/DynamicCompileAndRun.aspx
http://www.codeproject.com/KB/codegen/Run-Time_Code_Generation1.aspx (kleines Tutorial)


VampireSilence - Mi 11.05.11 01:43

Erstmal vielen Dank für die schnelle Hilfe ! Bin auch schon ein ganzes Stück weiter.

Habe jetzt erstmal klein angefangen, mit der MessageBox. Bin aber hier schon auf ein Problem gestoßen, und zwar ist beim erstellten Programm die Dosbox im Hintergrund sichtbar, obwohl ich eine AssemblyInfo mit [assembly: ComVisible(false)] angehangen habe. Muss das auf nem speziellen Weg eingebunden werden, oder was mache ich falsch ?

Mein Code bisher:


C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
119:
120:
121:
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134:
135:
136:
            CSharpCodeProvider _CodeProvider = new CSharpCodeProvider();

            String[] referenceAssemblies = { "System.dll""System.Drawing.dll""System.Data.dll""System.Windows.Forms.dll" };
            string _AssemblyName = "newAssembly.exe";

            CompilerParameters _CompilerParameters = new CompilerParameters(referenceAssemblies, _AssemblyName);
            
            _CompilerParameters.GenerateExecutable = true;
            _CompilerParameters.GenerateInMemory = false;

            String[] CSharpSourceCode =
            {
                // ASSEMBLY INFORMATIONS
                "using System.Reflection;\r\n" +
                "using System.Runtime.CompilerServices;\r\n" +
                "using System.Runtime.InteropServices;\r\n" +

                "// Allgemeine Informationen über eine Assembly werden über die folgenden \r\n" +
                "// Attribute gesteuert. Ändern Sie diese Attributwerte, um die Informationen zu ändern,\r\n" +
                "// die mit einer Assembly verknüpft sind.\r\n" +
                "[assembly: AssemblyTitle(\"program\")]\r\n" +
                "[assembly: AssemblyDescription(\"\")]\r\n" +
                "[assembly: AssemblyConfiguration(\"\")]\r\n" +
                "[assembly: AssemblyCompany(\"\")]\r\n" +
                "[assembly: AssemblyProduct(\"program\")]\r\n" +
                "[assembly: AssemblyCopyright(\"Copyright ©  2011 by VampireSilence\")]\r\n" +
                "[assembly: AssemblyTrademark(\"\")]\r\n" +
                "[assembly: AssemblyCulture(\"\")]\r\n" +

                "// Durch Festlegen von ComVisible auf \"false\" werden die Typen in dieser Assembly unsichtbar \r\n" +
                "// für COM-Komponenten. Wenn Sie auf einen Typ in dieser Assembly von \r\n" +
                "// COM zugreifen müssen, legen Sie das ComVisible-Attribut für diesen Typ auf \"true\" fest.\r\n" +
                "[assembly: ComVisible(false)]\r\n" +

                "// Die folgende GUID bestimmt die ID der Typbibliothek, wenn dieses Projekt für COM verfügbar gemacht wird\r\n" +
                "[assembly: Guid(\"e24b4c01-8c2f-4d1c-bbca-037c321f6514\")]\r\n" +

                "// Versionsinformationen für eine Assembly bestehen aus den folgenden vier Werten:\r\n" +
                "//\r\n" +
                "//      Hauptversion\r\n" +
                "//      Nebenversion \r\n" +
                "//      Buildnummer\r\n" +
                "//      Revision\r\n" +
                "//\r\n" +
                "// Sie können alle Werte angeben oder die standardmäßigen Build- und Revisionsnummern \r\n" +
                "// übernehmen, indem Sie \"*\" eingeben:\r\n" +
                "// [assembly: AssemblyVersion(\"1.0.*\")]\r\n" +
                "[assembly: AssemblyVersion(\"1.0.0.0\")]\r\n" +
                "[assembly: AssemblyFileVersion(\"1.0.0.0\")]\r\n",

                // MAIN CODE
                "using System;\r\n" +
                "using System.Collections.Generic;\r\n" +
                "using System.ComponentModel;\r\n" +
                "using System.Data;\r\n" +
                "using System.Drawing;\r\n" +
                "using System.Text;\r\n" +
                "using System.Windows.Forms;\r\n" +

                "namespace Test\r\n" +
                "{\r\n" +
                "   static class Program\r\n" +
                "   {\r\n" +
                "       /// <summary>\r\n" +
                "       /// Der Haupteinstiegspunkt für die Anwendung.\r\n" +
                "       /// </summary>\r\n" +
                "       [STAThread]\r\n" +
                "       static void Main()\r\n" +
                "       {\r\n" +
                "           Application.EnableVisualStyles();\r\n" +
                "           Application.SetCompatibleTextRenderingDefault(false);\r\n" +
                "           Application.Run(new Form1());\r\n" +
                "       }\r\n" +
                "   }\r\n" +
                "  partial class Form1\r\n" +
                "    {\r\n" +
                "        /// <summary>\r\n" +
                "        /// Erforderliche Designervariable.\r\n" +
                "        /// </summary>\r\n" +
                "        private System.ComponentModel.IContainer components = null;\r\n" +

                "        /// <summary>\r\n" +
                "        /// Verwendete Ressourcen bereinigen.\r\n" +
                "        /// </summary>\r\n" +
                "        /// <param name=\"disposing\">True, wenn verwaltete Ressourcen gelöscht werden sollen; andernfalls False.</param>\r\n" +
                "        protected override void Dispose(bool disposing)\r\n" +
                "        {\r\n" +
                "            if (disposing && (components != null))\r\n" +
                "            {\r\n" +
                "                components.Dispose();\r\n" +
                "            }\r\n" +
                "            base.Dispose(disposing);\r\n" +
                "        }\r\n" +

                "        #region Vom Windows Form-Designer generierter Code\r\n" +

                "        /// <summary>\r\n" +
                "        /// Erforderliche Methode für die Designerunterstützung.\r\n" +
                "        /// Der Inhalt der Methode darf nicht mit dem Code-Editor geändert werden.\r\n" +
                "        /// </summary>\r\n" +
                "        private void InitializeComponent()\r\n" +
                "        {\r\n" +
                "            this.SuspendLayout();\r\n" +
                "            // \r\n" +
                "            // Form1\r\n" +
                "            // \r\n" +
                "            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);\r\n" +
                "            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;\r\n" +
                "            this.ClientSize = new System.Drawing.Size(292, 268);\r\n" +
                "            this.Name = \"Form1\";\r\n" +
                "            this.Text = \"Form1\";\r\n" +
                "            this.Load += new System.EventHandler(this.Form1_Load);\r\n" +
                "            this.ResumeLayout(false);\r\n" +

                "        }\r\n" +

                "        #endregion\r\n" +
                "    }\r\n" +

                "   public partial class Form1 : Form\r\n" +
                "   {\r\n" +
                "       public Form1()\r\n" +
                "       {\r\n" +
                "           InitializeComponent();\r\n" +
                "       }\r\n" +

                "       private void Form1_Load(object sender, EventArgs e)\r\n" +
                "       {\r\n" +
                "           MessageBox.Show(\"test ! :)\");\r\n" +
                "       }\r\n" +
                "   }\r\n" +
                "}\r\n"

            };

            CompilerResults _CompilerResults = _CodeProvider.CompileAssemblyFromSource(_CompilerParameters, CSharpSourceCode);


Danke nochmal.

mfg
- VampireSilence


Th69 - Mi 11.05.11 09:42

Hallo VampireSilence,

ComVisible hat nichts mit der DOS-Box (Konsolenfenster) zu tun, sondern steuert nur, ob die öffentlichen Member der Assembly auch für Programme auf Basis von Component Object Model (COM) [http://de.wikipedia.org/wiki/Component_Object_Model] sichtbar und zugreifbar sind (steht aber ja auch in dem Kommentar in deinem Quellcode ;-)).

Du mußt bei den CompilerParameters noch die CompilerOptionen so setzen, daß eine Windows-Anwendung erzeugt wird (und keine Konsolenanwendung):

C#-Quelltext
1:
_CompilerParameters.CompilerOptions = "/target:winexe";                    

Die kompletten Compileroptionen (für C#) findest du unter: http://msdn.microsoft.com/de-de/library/6s2x2bzy%28v=VS.100%29.aspx

P.S. Anstatt hart-codiert den Source als Strings im Programmcode zu setzen, wäre es wohl einfacher diesen in eine Texdatei oder aber als Ressource auszulagern (denn das erspart dir das lästige "in Anführungsstriche setzen, evtl. noch escapen und \r\n zu ergänzen" (wobei letzteres dem Compiler ja völlig egal ist - Whitespaces werden ja eh überlesen ;-)).