How to change the EXE in CodeDOM - c#

I am making a c# compiler and my code creates an executable that is automatically created in the startup folder(Working Directory).
Is there any way to change the path in which the EXE is created before creating it.
This code creates an executable in "C:\Users\User\Desktop\CSharp Compiler\CSharp Compiler\bin\Debug"
CSharpCodeProvider csc = new CSharpCodeProvider(new Dictionary<string, string>() { { "CompilerVersion", "v4.0" } });
CompilerParameters parameters = new CompilerParameters(new[] { "mscorlib.dll", "System.Core.dll" }, ProjectName.Text + ".exe", true);
parameters.GenerateExecutable = true;
System.CodeDom.Compiler.TempFileCollection tfc = new TempFileCollection(Application.StartupPath, false);
CompilerResults cr = csc.CompileAssemblyFromSource(parameters, txtcode.Text);
if (cr.Errors.HasErrors)
{
//Do something if there is an error here...
}
else
{
//Start the application if there is no errors
Process.Start(Application.StartupPath + "/" + ProjectName.Text + ".exe");
}

To set the working directory, you need to use the ProcessStartInfo version of Process.Start
It can be as simple as
System.Diagnostics.ProcessStartInfo PSI = new System.Diagnostics.ProcessStartInfo();
PSI.FileName = Application.StartupPath + "/" + ProjectName.Text + ".exe";
PSI.WorkingDirectory = Application.StartupPath;
System.Diagnostics.Process.Start(PSI);

Related

How do I programmatically compile a C# Windows Forms App from a richtextbox? C#

I am trying to do a Visual Studio kind of program, which allows you to type code into a RichTextBox. After pressing F5(Compile), it would compile the code. How would the user compile said code? I know how to use the ConsoleApplication Compiler, but not compiling Windows Forms :(
Could someone help? A code-example is preferable, but at this point, I'll accept ANYTHING!
My current code for Console Apps is this:
CSharpCodeProvider codeProvider = new CSharpCodeProvider();
ICodeCompiler icc = codeProvider.CreateCompiler();
string Output = "MCCACOut.exe";
Button ButtonObject = (Button)sender;
richTextBox201.Text = "";
System.CodeDom.Compiler.CompilerParameters parameters = new CompilerParameters();
//Make sure we generate an EXE, not a DLL
parameters.GenerateExecutable = true;
parameters.OutputAssembly = Output;
CompilerResults results = icc.CompileAssemblyFromSource(parameters, richTextBox301.Text);
if (results.Errors.Count > 0)
{
richTextBox201.ForeColor = Color.Red;
foreach (CompilerError CompErr in results.Errors)
{
richTextBox201.Text = richTextBox201.Text +
"Line number " + CompErr.Line +
", Error Number: " + CompErr.ErrorNumber +
", '" + CompErr.ErrorText + ";" +
Environment.NewLine + Environment.NewLine;
}
}
else
{
//Successful Compile
richTextBox201.ForeColor = Color.Blue;
richTextBox201.Text = "Success!";
//If we clicked run then launch our EXE
Process.Start(Output);
}
Could anyone convert this to compile WinForms instead of ConsoleApp? :)
I think you have to save your file with .cs extension and invoke a process to compile it using c# compiler csc.exe.
After saving the file, you can compile the code using,
C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe [options] filename.cs
Take a look at this for options
You can invoke a process to do this from your IDE.
System.Diagnostics.Process process = new System.Diagnostics.Process();
System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo();
startInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
startInfo.FileName = "cmd.exe";
startInfo.Arguments = "C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe filename.cs";
process.StartInfo = startInfo;
process.Start();
Hope this helps.
Finally, after many, many times of struggling, I got it to work :) With the help of Nishan Chathuranga
string compiledOutput = "Generated.exe";
//COMPILATION WORK
String[] referenceAssemblies = { "System.dll", "System.Drawing.dll", "System.Windows.Forms.dll" };
CodeDomProvider _CodeCompiler = CodeDomProvider.CreateProvider("CSharp");
System.CodeDom.Compiler.CompilerParameters _CompilerParameters =
new System.CodeDom.Compiler.CompilerParameters(referenceAssemblies, "");
_CompilerParameters.OutputAssembly = compiledOutput;
_CompilerParameters.GenerateExecutable = true;
_CompilerParameters.GenerateInMemory = false;
_CompilerParameters.WarningLevel = 3;
_CompilerParameters.TreatWarningsAsErrors = true;
_CompilerParameters.CompilerOptions = "/optimize /target:winexe";//!! HERE IS THE SOLUTION !!
string _Errors = null;
try
{
// Invoke compilation
CompilerResults _CompilerResults = null;
_CompilerResults = _CodeCompiler.CompileAssemblyFromSource(_CompilerParameters, richTextBox1.Text);
if (_CompilerResults.Errors.Count > 0)
{
// Return compilation errors
_Errors = "";
foreach (System.CodeDom.Compiler.CompilerError CompErr in _CompilerResults.Errors)
{
_Errors += "Line number " + CompErr.Line +
", Error Number: " + CompErr.ErrorNumber +
", '" + CompErr.ErrorText + ";\r\n\r\n";
}
}
}
catch (Exception _Exception)
{
// Error occurred when trying to compile the code
_Errors = _Exception.Message;
}
//AFTER WORK
if (_Errors == null)
{
// lets run the program
MessageBox.Show(compiledOutput + " Compiled !");
System.Diagnostics.Process.Start(compiledOutput);
}
else
{
MessageBox.Show("Error occurred during compilation : \r\n" + _Errors);
}
This works like a charm!

SQL CLR calling Process.Start hangs or fails

I have checked and there are many posts similar but I cannot solve this. This is a SQL CLR proc to run an exe that parses PDF files. I can run same code as myself in console app. Permissions are not an issue. I am dumping to event log and the ProcessStartInfo is full formed. UseShellExecute - I am not certain. I have also created a .bat file to execute the code - run it manually - it runs fine. Via this CLR program ? Hangs or runs right away but does nothing. At wits end. My goal was to create the CLR using the Nuget from itext but I had a real hard time installing. SQL CLR doesnt support it but I tried anyway.
Thanks in advance.
[Microsoft.SqlServer.Server.SqlProcedure]
public static void PDFToCSVViaExe_CLR()
{
ProcessStartInfo startInfo = new ProcessStartInfo();
string args = #"\\app\Systems\Universal";
args = " \"" + args + "\"" + " \"" + "*" + "\"" + " \"" + "LVM" + "\"";
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = true;
startInfo.FileName = "c:\\SqlCLR\\PDFRipper\\PDFToCSV.exe";
startInfo.WindowStyle = ProcessWindowStyle.Hidden;
startInfo.Arguments = args;
EventLog.WriteEntry(".NET Runtime", startInfo.FileName.ToString()+" " + args, EventLogEntryType.Warning, 1000);
string folder = "C:\\SqlCLR\\PDFRipper\\LVM.bat";
try
{
//using (new ImpersonationNamespace.Impersonation("domain", "user", "password"))
{
EventLog.WriteEntry(".NET Runtime", System.Security.Principal.WindowsIdentity.GetCurrent().Name + " OR " + Environment.UserName, EventLogEntryType.Warning, 1000);
folder = System.IO.Path.GetDirectoryName(folder);
if (!Directory.Exists(folder))
{
throw (new Exception("Directory does not exist for " + folder));
}
else
{ EventLog.WriteEntry(".NET Runtime", folder + " exists.", EventLogEntryType.Warning, 1000); }
// Start the process with the info we specified.
// Call WaitForExit and then the using statement will close.
using (Process exeProcess = Process.Start(startInfo))
{
exeProcess.WaitForExit();
}
}
}
catch (Exception ex)
{
using (EventLog EventLog = new EventLog("Application"))
{
EventLog.Source = "Application";
//eventLog.WriteEntry(ex.Message);
EventLog.WriteEntry(".NET Runtime", ex.Message + "Trace" + ex.StackTrace, EventLogEntryType.Warning, 1000);
//eventLog.WriteEntry(".NET Runtime", ex.Message, EventLogEntryType.Warning, 1000);
}
}

How to send multiple files to the printer with one Process call

I need to print multiple PDF-files from the hard-drive. I have found this beautiful solution of how to send a file to the printer. The problem with this solution is that if you want to print multiple files you have to wait for each file for the process to finish.
in the command shell it is possible to use the same command with multiple filenames: print /D:printerName file1.pdf file2.pdf
and one call would print them all.
unfortunately simply just to put all the filenames into the ProcessStartInfo doesn't work
string filenames = #"file1.pdf file2.pdf file3.pdf"
ProcessStartInfo info = new ProcessStartInfo();
info.Verb = "print";
info.FileName = filenames;
neither does it to put the filenames as Arguments of the Process
info.Arguments = filename;
I always get the error: Cannot find the file!
How can I print a multitude of files with one process call?
Here is an example of how I use it now:
public void printWithPrinter(string filename, string printerName)
{
var procInfo = new ProcessStartInfo();
// the file name is a string of multiple filenames separated by space
procInfo.FileName = filename;
procInfo.Verb = "printto";
procInfo.WindowStyle = ProcessWindowStyle.Hidden;
procInfo.CreateNoWindow = true;
// select the printer
procInfo.Arguments = "\"" + printerName + "\"";
// doesn't work
//procInfo.Arguments = "\"" + printerName + "\"" + " " + filename;
Process p = new Process();
p.StartInfo = procInfo;
p.Start();
p.WaitForInputIdle();
//Thread.Sleep(3000;)
if (!p.CloseMainWindow()) p.Kill();
}
Following should work:
public void PrintFiles(string printerName, params string[] fileNames)
{
var files = String.Join(" ", fileNames);
var command = String.Format("/C print /D:{0} {1}", printerName, files);
var process = new Process();
var startInfo = new ProcessStartInfo
{
WindowStyle = ProcessWindowStyle.Hidden,
FileName = "cmd.exe",
Arguments = command
};
process.StartInfo = startInfo;
process.Start();
}
//CALL
PrintFiles("YourPrinterName", "file1.pdf", "file2.pdf", "file3.pdf");
It's not necessarily a simple solution, but you could merge the pdfs first and then send then to acrobat.
For example, use PdfMerge
Example overload to your initial method:
public void printWithPrinter(string[] fileNames, string printerName)
{
var fileStreams = fileNames
.Select(fileName => (Stream)File.OpenRead(fileName)).ToList();
var bundleFileName = Path.GetTempPath();
try
{
try
{
var bundleBytes = new PdfMerge.PdfMerge().MergeFiles(fileStreams);
using (var bundleStream = File.OpenWrite(bundleFileName))
{
bundleStream.Write(bundleBytes, 0, bundleBytes.Length);
}
}
finally
{
fileStreams.ForEach(s => s.Dispose());
}
printWithPrinter(bundleFileName, printerName);
}
finally
{
if (File.Exists(bundleFileName))
File.Delete(bundleFileName);
}
}

C# run batch file with argument with spaces

I need to run batch file, which has path (can contains spaces) as argument.
Batch file is really simple:
echo off
echo %1 > echotest.txt
Csharp code I am using to run this batch file:
ProcessStartInfo info = new ProcessStartInfo();
info.UserName = KIM_USER;
info.Password = ConvertToSecureString(KIM_USER_PASSWORD);
info.FileName = theTask.Path;
info.Arguments = "\"" + TranslateParameter(theTask.Parameter) + "\"";
info.Domain = Environment.MachineName;
info.WorkingDirectory = Path.GetDirectoryName(theTask.Path);
info.UseShellExecute = false;
info.CreateNoWindow = true;
Process batProcess = Process.Start(info);
batProcess.WaitForExit();
Basically in parameter comes e.g {Test_Path} and this is in TranslateParameter converted to real path, e.g: D:\Test Path\ (contains spaces)
This does not work for me, it returns me exit code 1 everytime.
If i remove \" from info.Arguments, it works, but in output file is just D:\Test
Any suggestions?
Regards
Can you try this if that works:
ProcessStartInfo info = new ProcessStartInfo();
info.UserName = KIM_USER;
info.Password = ConvertToSecureString(KIM_USER_PASSWORD);
info.FileName = theTask.Path + " \"" + TranslateParameter(theTask.Parameter) + "\"";
//info.Arguments = "\"" + TranslateParameter(theTask.Parameter) + "\"";
info.Domain = Environment.MachineName;
info.WorkingDirectory = Path.GetDirectoryName(theTask.Path);
info.UseShellExecute = false;
info.CreateNoWindow = true;
Process batProcess = Process.Start(info);
batProcess.WaitForExit();

Install JMF in silent mode via C#

Is there any way to install JMF in silent mode using C#?
I have jmf.iss and JMF setup.exe and I'm having problems setting the silent parameter:
string[] programArray = {"SETUP.exe","Java-jre-7u45-windows-i586"};
foreach (string path in programArray)
{
using (Process p = new Process())
{
string arg = "passive";
if (path.Contains("SETUP"))
{
arg = "s /f1" + AppDomain.CurrentDomain.BaseDirectory + #"jmf.iss";
}
else if (path.Contains("Java"))
{
arg = "s";
}
p.StartInfo = new ProcessStartInfo(Application.StartupPath + "\\" + path);
p.StartInfo.Arguments = string.Format("/" + arg, path);
p.Start();
//p.WaitForExit();
while (!p.HasExited)
{
Application.DoEvents();
}
}

Categories

Resources