I am currently developing an aspx page that calls a winform. The issue at hand is passing the textbox variable from the web page, through the ProcessStartInfo event, to the winform textbox to retrieve an image. The viewer is from a vendor but is only applicable in a winform environment but the other information is coming from a CF page, to an href and to a nonfunctional web image viewer. Is what I am doing possible?
Aspx page code:
namespace ImageView
{
public partial class _Default : System.Web.UI.Page
{
protected void page Load(object sender, EventArgs e)
{
TextBox1.Text = Request.QueryString["DKT_ID"].ToString();
//TextBox2.Text = Request.QueryString["Name"].ToString();
//TextBox3.Text = Request.QueryString["Age"].ToString();
ProcessStartInfo psi = new ProcessStartInfo(#"C:\ImageViewer\ImageView.exe");
psi.WindowStyle = ProcessWindowStyle.Normal;
Process p = new Process();
p.EnableRaisingEvents = true;
p.Exited += new EventHandler(MyExited);
p.StartInfo = psi;
p.Start();
}
Winform code:
//SQL section for returning images
#region "Images Query"
ImageQuery = "SELECT isn AS isn ";
ImageQuery += "FROM bc_bcc_document (NOLOCK) ";
ImageQuery += "WHERE barcode_id = ? ";
DataTable Imagetable = new DataTable();
Imagetable.Columns.Add("ISN", typeof(Int32));
DataRow Imagerows;
//fills table with Images information
OdbcCommand comd = new OdbcCommand(ImageQuery);
string conne = "Dsn=XXXX; uid=XXXXX; pwd=XXXXXX";
using (OdbcConnection connected = new OdbcConnection(conne))
{
comd.Connection = connected;
connected.Open();
comd.Parameters.AddWithValue("barcode_id", txtBarcode.Text);
OdbcDataReader readar = comd.ExecuteReader();
while (readar.Read())
{
isn = Convert.ToInt32(readar["isn"].ToString().TrimEnd());
Imagerows = Imagetable.NewRow();
Imagerows["ISN"] = isn;
}
readar.Close();
Just pass the arguments from the web page like this
var proc = new Process
{
EnableRaisingEvents = false,
StartInfo = new ProcessStartInfo()
{
UseShellExecute = false,
FileName = path,
Arguments = Request.QueryString["DKT_ID"].ToString()
}
};
proc.Start();
and read the command line arguments in your WinForms application like this -
string singleArgument = Environment.GetCommandLineArgs()[1];
P.S - assuming that you are passing a single argument, that's why Environment.GetCommandLineArgs()[1] is used
because at [0]th position, you will get the path and [1]st position in the array would be useful to you.
Did you try to use ClickOnce? I think could be interesting, once if your client doesnt have that application installed, clickOnce will do install before start the application.
And you can pass args also.
http://msdn.microsoft.com/en-us/library/ms172242(v=vs.110).aspx
Related
I want to call a Python script from my winform C# application. I checked for some solutions and followed following approaches. One using Inter-Process communication and one using IronPython
Approach 1 : Using Inter-Process Communication
private void BtnSumPy_Click(object sender, EventArgs e)
{
string python = #"C:\Programs\Python\Python37-32\python.exe";
// python app to call
string myPythonApp = #"C:\mypath\\SamplePy\SamplePy2\SamplePy2.py";
// dummy parameters to send Python script
int x = 3;
int y = 4;
// Create new process start info
ProcessStartInfo myProcessStartInfo = new ProcessStartInfo(python);
// make sure we can read the output from stdout
myProcessStartInfo.UseShellExecute = false;
myProcessStartInfo.RedirectStandardOutput = true;
// start python app with 3 arguments
// 1st arguments is pointer to itself,
// 2nd and 3rd are actual arguments we want to send
myProcessStartInfo.Arguments = myPythonApp + " " + x + " " + y;
Process myProcess = new Process();
// assign start information to the process
myProcess.StartInfo = myProcessStartInfo;
// start the process
myProcess.Start();
// Read the standard output of the app we called.
// in order to avoid deadlock we will read output first
// and then wait for process terminate:
StreamReader myStreamReader = myProcess.StandardOutput;
string myString = myStreamReader.ReadLine();
/*if you need to read multiple lines, you might use:
string myString = myStreamReader.ReadToEnd() */
// wait exit signal from the app we called and then close it.
myProcess.WaitForExit();
myProcess.Close();
lblAns.Text = myString;
}
The issue with above approach is that Python.exe will have to installed on the local machines as well, as winform app is going to run locally on the system.
Approach 2: Using IronPython
private void BtnJsonPy_Click(object sender, EventArgs e)
{
// 1. Create Engine
var engine = Python.CreateEngine();
//2. Provide script and arguments
var script = #"C:\Users\simeh\source\HDFC\repos\SamplePy\SamplePy2\SamplePy2.py"; // provide full path
var source = engine.CreateScriptSourceFromFile(script);
// dummy parameters to send Python script
int x = 3;
int y = 4;
var argv = new List<string>();
argv.Add("");
argv.Add(x.ToString());
argv.Add(y.ToString());
engine.GetSysModule().SetVariable("argv", argv);
//3. redirect output
var eIO = engine.Runtime.IO;
var errors = new MemoryStream();
eIO.SetErrorOutput(errors, Encoding.Default);
var results = new MemoryStream();
eIO.SetOutput(results, Encoding.Default);
//4. Execute script
var scope = engine.CreateScope();
var lib = new[]
{
"C:\\path\\SamplePy\\packages\\IronPython.2.7.9\\lib",
"C:\\path\\SamplePy\\packages\\IronPython.2.7.9",
};
engine.SetSearchPaths(lib);
engine.ExecuteFile(script, scope);
//source.Execute(scope);
//5. Display output
string str(byte[] x1) => Encoding.Default.GetString(x1);
Console.WriteLine("Errrors");
Console.WriteLine(str(errors.ToArray()));
Console.WriteLine();
Console.WriteLine("Results");
Console.WriteLine(str(results.ToArray()));
}
The issue I get here is that I keep getting errors like 'Json module error' or 'PIL module error'
I read somewhere that PIL won't currently work with IronPython because it uses a native C library.
The python script has ML logic and uses OCR etc., for image processing and hence requires PIL, which cannot be done in IronPython.
So any better approach or ways or suggestions on how to call Python script from Winform C# application.
Thanks In Advance!!!..
The solution is here for 'import error' open the cmd and go to the AppData>Local>Programs>Python>Python37-32 then write this
pip3 install json
if u wanna run .py file from c# the import modules must be in the directory of python.exe
for example ı imported the cv2 and the others libs to Python37-32 dir. After this my program worked fine.
This is my code:
timer1.Enabled = true;
progressBar1.Value += 10;
string myPythonApp = "C://Users//giris//Desktop//staj_proje_son//main.py";
string cmdArguments = "/c \"python " + myPythonApp + " " + "--ogrencioptik " + textBox2.Text + " " + "--cevapkagidi " + textBox1.Text + " " + "--sonuckayit " + textBox3.Text + "\"";
ProcessStartInfo start = new ProcessStartInfo();
start.FileName = "cmd.exe";
start.UseShellExecute = false;
start.WorkingDirectory = "C://Users//giris//Desktop//staj_proje_son//";
start.Arguments = cmdArguments;
start.RedirectStandardOutput = false;
start.RedirectStandardError = true;
start.CreateNoWindow = true;
Process process = Process.Start(start);
timer1.Start();
process.WaitForExit();
timer1.Stop();
timer1.Enabled = false;
progressBar1.Value = 100;
MessageBox.Show("İşlem Bitti");
button3.Enabled = true;
Note:
All the textbox.text is the path for a folder.
I have some code that is creating a PNG file of a graph of Nodes using GraphViz's dot program. This first time through the code works perfectly. However, if I try to run the method again it fails because the file is still considered in use by windows.
Here is the relevant code to start the dot.exe process:
private void MakePng()
{
string args = "-o" + graphPath + " -Tpng " + dotPath;
Process process = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = VizGraphPath;
info.Arguments = args;
info.UseShellExecute = false;
info.CreateNoWindow = true;
process.StartInfo = info;
process.EnableRaisingEvents = true;
process.Exited += new EventHandler(Process_Exited);
process.Start();
}
private void Process_Exited(object sender, EventArgs e)
{
UpdateCanvas();
}
The various string variables named xxxPath are just static strings to the correct file paths. When the program starts up and I run this code everything works perfectly. But if I reset my graph and try to run this set of code again it fails to create a new PNG. The old one is still there. To test something out I added this line:
private void MakePng()
{
string args = "-o" + graphPath + " -Tpng " + dotPath;
File.Delete(graphPath);
Which works the first time through. But the second time it throws a Exception stating File is still in use. So I'm guessing somehow when the Process I start exits, the File Handle it created is still in use even though it exited? Any suggestions about how to figure out why its still in use or how to fix it?
My UpdateCanvas function is also accessing the file that is locked:
public void UpdateCanvas()
{
Bitmap image = new Bitmap(graphPath);
pbCanvas.Image = image;
}
Do i need to something when loading a bitmap from a file to release the file?
It was indeed the Bitmap locking the file. I had to dispose of it before the file would be unlocked.
Your file is locked by new Bitmap.
Rewrite it with:
public void UpdateCanvas()
{
Image img;
using (var bmpTemp = new Bitmap(graphPath))
{
img = new Bitmap(bmpTemp);
}
pbCanvas.Image = img;
}
Process class implements IDisposable, so you need to despose resources. Also, you can add WatForExit method to be sure, your process finished:
private void MakePng()
{
string args = "-o" + graphPath + " -Tpng " + dotPath;
using(Process process = new Process())
{
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = VizGraphPath;
info.Arguments = args;
info.UseShellExecute = false;
info.CreateNoWindow = true;
process.StartInfo = info;
process.EnableRaisingEvents = true;
process.Start();
process.WaitForExit(10*1000); //10 seconds
}
UpdateCanvas();
}
I am working with the WMI API for c# in order to connect to a remote server and execute some commands. I have successfully established a connection. All I need now is to redirect the output of the remote CMD into a log file in my local machine.
Here is my code :
ConnectionOptions options = new ConnectionOptions();
options.Username = "login";
options.Password = "password";
ManagementScope scope = new ManagementScope("\\\\myserver\\root\\cimv2", options);
scope.Options.EnablePrivileges = true;
scope.Options.Impersonation = System.Management.ImpersonationLevel.Impersonate;
try
{
scope.Connect();
System.Management.ManagementClass local_ClassInstance = new System.Management.ManagementClass(scope, new System.Management.ManagementPath("Win32_Process"), null);
Console.WriteLine("SUCCESS");
//execute the command
System.Management.ManagementBaseObject local_InParams = local_ClassInstance.GetMethodParameters("Create");
local_InParams["CommandLine"] = #"cmd.exe /C myCommand";
local_InParams["CurrentDirectory"] = #"mypath";
System.Management.ManagementBaseObject local_ManagementBaseObject = local_ClassInstance.InvokeMethod("Create", local_InParams, null);
}
catch (Exception e)
{
Console.WriteLine("FAILURE"+e.ToString());
}
Edit
I tried to accomplish this by using the '>' primitive :
local_InParams["CommandLine"] = "command > log.txt";
But the output file that I created doesn't contain anything.
I tried also to do this using a process
Process myProcess = new Process();
myProcess.StartInfo.FileName = "ipconfig";
myProcess.StartInfo.Arguments = "/all";
myProcess.StartInfo.RedirectStandardOutput = true;
myProcess.StartInfo.UseShellExecute = false;
myProcess.Start();
myProcess.WaitForExit();
string myResult = myProcess.StandardOutput.ReadToEnd();
Console.WriteLine(myResult);
myProcess.Close();
But the process does not return the information that I want because I want the output of cmd of the remote machine (Because I want the log of the behaviour of the server while running the command).
Any Help please ?
I too had an issue with capturing, and found ANOTHER redirect that works similar to what you have...
myProcess.StartInfo.RedirectStandardError = true;
// trap normal data received AND any ERROR data received too
myProcess.OutputDataReceived += DOSOutputResultsHandler;
myProcess.ErrorDataReceived += DOSOutputErrorsHandler;
I also have two string builder properties for capturing the output responses on my class that does the DOS Call process
StringBuilder DOSOutputResults = new StringBuilder();
StringBuilder DOSOutputErrors = new StringBuilder();
protected void DOSOutputResultsHandler(object sendingProcess,
System.Diagnostics.DataReceivedEventArgs outLine)
{
if (!string.IsNullOrEmpty(outLine.Data))
// track data into the NORMAL output string builder
DOSOutputResults.Append(Environment.NewLine + outLine.Data);
}
protected void DOSOutputErrorsHandler(object sendingProcess,
System.Diagnostics.DataReceivedEventArgs outLine)
{
if (!String.IsNullOrEmpty(outLine.Data))
// track data into the ERROR output string builder
DOSOutputErrors.Append(Environment.NewLine + outLine.Data);
}
Additionally, for using the primitive ">" redirection, there is also a "2>" redirection that handles errors not redirected to normal output. I found this out when dealing with DOS calls to Java.
I'm trying to use the following C# code to compile Java using javac:
Process p = new Process();
p.StartInfo.FileName = "javac";
Directory.CreateDirectory(Application.StartupPath + #"/TempJava");
p.StartInfo.Arguments = "-d "Application.StartupPath + #"/TempJava" + files;
p.Start();
"files" represents a string variable containing the name(s) of the *.java files.
All in all, I want to create a new folder, and then take the Java files (from where ever they may be located) and compile it into a class file(s) in TempJava.
For some reason, the code doesn't work, no errors, no warnings, but when I run it and check TempJava, there's no files in it.
Just because your child process ends with a possible error, it doesn't mean your parent process must be aware of it.
Inspect the process' exit code and standard output stream, and especially the standard error stream. Your answer lies in there...
here i have 2 buttons run and compile here is some code to help.
private void comp_Click(object sender, EventArgs e)
{
string text = "javac " + label1.Text + file + "#pause" + "#stop";
text = text.Replace("#", System.Environment.NewLine);
File.WriteAllText(label1.Text + "Compile.bat", text);
Process proc = null;
try
{
proc = new Process();
proc.StartInfo.FileName = label1.Text + "Compile.bat";
proc.StartInfo.CreateNoWindow = false;
proc.Start();
proc.WaitForExit();
}
catch
{
}
}
private void runp_Click(object sender, EventArgs e)
{
string news = file.Remove(file.Length - 5);
string text = "java " + news + "#pause";
text = text.Replace("#", System.Environment.NewLine);
File.WriteAllText(label1.Text + "Run.bat", text);
Process proc = null;
try
{
proc = new Process();
proc.StartInfo.FileName = label1.Text + "Run.bat";
proc.StartInfo.WorkingDirectory = label1.Text.Remove(label1.Text.Length - 1);
proc.StartInfo.CreateNoWindow = true;
proc.Start();
proc.WaitForExit();
}
catch
{
}
}
all i really do is create a batch and run it using c#.
I am currently working on a program, that can handle Minecraft servers. I am running my batch witch logs the server, and i now want the batch (called batch in my code) to log in my listbox called lg_log.
If it is possible, how can I do that?
I am programming in visual studio - Windows forms in c#.
Edit: This is my code:
Process batch = new Process();
string PathtoRunFile = #"\Servers\Base\start_server.bat";
string current_directory = Directory.GetCurrentDirectory();
string server_base = #"\Servers\Base";
string working_directory = current_directory + server_base;
batch.StartInfo.FileName = current_directory + PathtoRunFile;
batch.StartInfo.Arguments = "";
batch.StartInfo.WorkingDirectory = working_directory;
batch.StartInfo.UseShellExecute = true;
batch.Start();
The Process.StartInfo contains properties like RedirectStandardOutput. By setting this flag to true, you will be able to add an event handler to batch.StartInfo.OutputDataReceived and listen for any events. Somewhat like so:
Edit: You might also want to enable redirecting the ErrorOutput in order to receive error messages.
Edit: As requested, here is a fully working example. Make sure that test.bat exists.
using System.Diagnostics;
using System.Drawing;
using System.Windows.Forms;
public class Program {
public static void Main() {
var form = new Form {ClientSize = new Size(400, 300)};
var button = new Button {Location = new Point(0, 0), Text = "Start", Size = new Size(400, 22)};
var listBox = new ListBox {Location = new Point(0, 22), Size = new Size(400, 278)};
form.Controls.AddRange(new Control[] {button, listBox});
button.Click += (sender, eventArgs) => {
var info = new ProcessStartInfo("test.bat") {UseShellExecute = false, RedirectStandardOutput = true};
var proc = new Process {StartInfo = info, EnableRaisingEvents = true};
proc.OutputDataReceived += (obj, args) => {
if (args.Data != null) {
listBox.Items.Add(args.Data);
}
};
proc.Start();
proc.BeginOutputReadLine();
};
form.ShowDialog();
}
}