How to run a command from a windows service? - c#

I wrote a C# service program to execute a windows command. It is not executing the command but the service is working properly. anyone, please help me to fix this
code
public partial class ScheduledService : ServiceBase
{
Boolean armed = false;
//Initialize the timer
//This method is used to raise event during start of service
Timer timer = new Timer();
public ScheduledService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
//add this line to text file during start of service
TraceService("start service");
//handle Elapsed event
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
//This statement is used to set interval to 1 minute (= 60,000 milliseconds)
timer.Interval = 10000;
}
//This method is used to stop the service
protected override void OnStop()
{
timer.Enabled = false;
TraceService("stopping service");
}
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
ExecuteCommandSync("echo.|clip");
TraceService("Another entry at "+DateTime.Now);
System.Windows.Forms.Clipboard.Clear();
}
private void TraceService(string content)
{
//set up a filestream
FileStream fs = new FileStream(#"d:\ScheduledService.txt",FileMode.OpenOrCreate, FileAccess.Write);
//set up a streamwriter for adding text
StreamWriter sw = new StreamWriter(fs);
//find the end of the underlying filestream
sw.BaseStream.Seek(0, SeekOrigin.End);
//add the text
sw.WriteLine(content);
//add the text to the underlying filestream
sw.Flush();
//close the writer
sw.Close();
}
public void ExecuteCommandSync(object command)
{
try
{
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", "/c " + command);
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
procStartInfo.CreateNoWindow = true;
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procStartInfo;
proc.Start();
}
catch (Exception objException)
{
// Log the exception
}
}
}

You are calling OnElapsedTime after every 10 second, but not doing anything in this function except LogTracing. I guess you wanted to call ExecuteCommandSync from OnElapsedTime to run command.

Related

visual C# is it possible to have more feedback than a progress bar for a process running?

I'm developping an app in C# using microsoft visual studio (windows form).
What i want to do is to manage different environment through one GUI.
Thus, my gui have to start asynchronously some process (which are commandline applications).
The problem is that I can get the standard output of the process only once it's finished, meaning I can't show what the process is doing in runtime.
since the applications I want to run can take quite a long runtime (uploading big files ...) i would like to display the process output in runtime.
Thus, i created a backgroundworker to separate my gui from the process, and i tried to use a temporary file where the process output is written.
then using a FileSystemWatcher, I could use the "change" event to display the messages in my GUI.
My problem is that since the temporary file is open for writting, i can't read from it at the same time.
Here is my code, does anyone have a way to bypass this problem ? or an other way to do it ?
public partial class Form1 : Form
{
Boolean done = false;
private FileSystemWatcher observateur;
public Form1()
{
InitializeComponent();
// delete the temporary file if existing
if (System.IO.File.Exists("C:\\testoutput.txt"))
{
try
{
System.IO.File.Delete("C:\\testoutput.txt");
}
catch (System.IO.IOException exept)
{
Console.WriteLine(exept.Message);
return;
}
}
File.Create("C:\\testoutput.txt");
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler
(backgroundWorker1_ProgressChanged);
observateur = new FileSystemWatcher();
observateur.Filter = "C:\\testoutput.txt";
observateur.Changed += new FileSystemEventHandler(this.OnChanged);
observateur.Created += new FileSystemEventHandler(this.OnCreate);
}
private void OnChanged(object source, FileSystemEventArgs e)
{
// I tried to bypass the problem of having the file opened by copying it but i doesn't work
File.Copy("C:\\testouput.txt", "C:\\TEMP.txt", true);
}
private void OnCreate(object source, FileSystemEventArgs e)
{
Console.WriteLine("Created");
}
private void button3_Click(object sender, EventArgs e)
{
string outputworker = "";
backgroundWorker1.RunWorkerAsync(outputworker);
while (!done)
{
string text = System.IO.File.ReadAllText("C:\\TEMP.txt");
Thread.Sleep(200);
}
}
void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
progressBar1.Value = e.ProgressPercentage;
outputTextArea.Text = "Processing......" + progressBar1.Value.ToString() + "%";
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
string[] args = { "/k " };
string outputWork = e.Argument as string;
backgroundWorker1.ReportProgress(10);
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.WorkingDirectory = "C:\\XXXXXXXXXX";
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = "cmd.exe";
int nArgs = args.Length;
if (nArgs > 0)
{
process.StartInfo.Arguments = args[0];
}
for (int i = 1; i < nArgs; i++)
{
process.StartInfo.Arguments = String.Concat(process.StartInfo.Arguments, " && ", args[i]);
}
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
backgroundWorker1.ReportProgress(20);
process.Start();
backgroundWorker1.ReportProgress(40);
System.IO.StreamWriter sIn = process.StandardInput;
sIn.WriteLine("ExternalCommandLineApp1.exe >> C:\\testoutput.txt");
backgroundWorker1.ReportProgress(60);
sIn.WriteLine("ExternalCommandLineApp1.exe >> C:\\testoutput.txt");
System.IO.StreamReader sOut = process.StandardOutput;
backgroundWorker1.ReportProgress(90);
sIn.WriteLine("EXIT");
outputWork = sOut.ReadToEnd();
process.Close();
backgroundWorker1.ReportProgress(100);
e.Result = outputWork;
done = true;
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
string output = e.Result as string;
//outputTextArea.Text = output;
}
}
This is not the best way as mentioned in other answers, but it still can work successfully.
You can open a file for reading/writing without blocking other reads/writes. Just use File.Open instead of helper methods and provide additional parameters (FileMode and FileShare)
Here is a complete example. Note that one thread keeps file opened for writing and second thread opens and closes file every time and reads all lines:
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string fileName = "c:\\_data\\temp.txt";
Task writer = new Task(() => {
using (FileStream fs = File.Open(fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite))
using (StreamWriter sw = new StreamWriter(fs))
{
for (int i = 0; i < 50; i++ )
{
sw.WriteLine(DateTime.Now.Millisecond.ToString());
sw.Flush();
Thread.Sleep(500);
}
}
});
Task reader = new Task(() => {
for (int i = 0; i < 50; i++)
{
Thread.Sleep(500);
Console.WriteLine("Read again");
if (File.Exists(fileName))
{
using (FileStream fs = File.Open(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
using (StreamReader r = new StreamReader(fs))
{
while (!r.EndOfStream)
{
Console.WriteLine(r.ReadLine());
}
}
}
}
});
writer.Start();
reader.Start();
writer.Wait();
reader.Wait();
}
}
}
The simplest way with what you've already got is to exploit the UserState you can pass with the BackgroundWorker.
In the backgroundWorker1_DoWork method, you can use
backgroundWorker1.ReportProgress(0, "Whatever text you want to send right now.");
And in backgroundWorker1_ProgressChanged, you can read the message and put it in the text box like this:
outputTextArea.AppendText((e.UserState as string) + "\r\n");
This is a bit inefficient, but it should be much safer and faster than your original solution anyway.
In .NET, you've got many options of passing data between threads. If you want to learn more about the concepts, problems and solutions of multi-threading, you can give this a go: http://www.albahari.com/threading/
You can get the Standard Output of processes using System.Diagnostics.Process StandardOutput property (it's a Stream).
http://msdn.microsoft.com/en-us/library/vstudio/system.diagnostics.process.standardoutput(v=vs.90).aspx
I suggest you use Windows Communications Foundation to do this.
Following is a complete example.
There are two helper classes that you would normally put into a class library for reuse, class WcfServiceHost<T> and class WcfServiceProxy<T>.
This is a console app which you should run from the command line twice, passing a parameter of monitor for the first instance you start, and worker for the second instance.
Run it from the command like like this (assuming the app is called ConsoleApp1.exe):
start ConsoleApp1.exe monitor
start ConsoleApp1.exe worker
and then look at the output. The monitor instance is waiting for progress reports from the worker. The worker instance is reporting the progress, effectively by calling a function in the monitor instance (RPC, or Remote Procedure Call).
Here's the complete code. You will need to reference System.ServiceModel:
using System;
using System.Diagnostics;
using System.ServiceModel;
using System.Threading;
namespace Demo
{
[ServiceContract]
interface IProgressReporter
{
[OperationContract]
void ReportProgress(double percentComplete, string message);
}
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
sealed class Monitor: IProgressReporter
{
public void ReportProgress(double percentComplete, string message)
{
Console.WriteLine("Monitor received progress - Completed {0}%: {1}", percentComplete, message);
if (percentComplete == 100)
{
Program.ReportFinished();
}
}
}
public sealed class WcfServiceHost<T>: IDisposable where T: class
{
public WcfServiceHost(T service, string wcfEndpointAddress)
{
_service = service;
_wcfEndpointAddress = wcfEndpointAddress;
var serviceHost = new ServiceHost(service);
serviceHost.AddServiceEndpoint(typeof(T), new NetNamedPipeBinding(), wcfEndpointAddress);
serviceHost.Open();
_serviceHost = serviceHost;
}
public T Service
{
get
{
return _service;
}
}
public string WcfEndpointAddress
{
get
{
return _wcfEndpointAddress;
}
}
/// <summary>Disposal.</summary>
public void Dispose()
{
if (_serviceHost != null)
{
try
{
_serviceHost.Close();
}
catch (Exception exception) // Don't allow exceptions to escape from Dispose().
{
Trace.WriteLine("There was an exception while closing the host: " + exception.Message);
}
}
}
private readonly T _service;
private readonly string _wcfEndpointAddress;
private readonly ServiceHost _serviceHost;
}
public sealed class WcfServiceProxy<T>: IDisposable where T: class
{
public WcfServiceProxy(string wcfEndpointAddress)
{
_wcfEndpointAddress = wcfEndpointAddress;
_channelFactory = new ChannelFactory<T>(new NetNamedPipeBinding(), _wcfEndpointAddress);
_service = _channelFactory.CreateChannel();
_comms = _service as ICommunicationObject;
if (_comms == null)
{
throw new InvalidOperationException("proxy does not implement ICommunicationObject.");
}
}
public T Service
{
get
{
return _service;
}
}
public string WcfEndpointAddress
{
get
{
return _wcfEndpointAddress;
}
}
public void Dispose()
{
closeComms();
closeChannelFactory();
}
private void closeComms()
{
try
{
_comms.Close();
}
catch (CommunicationException exception) // Not closed - call Abort to transition to the closed state.
{
Debug.WriteLine("CommunicationException while closing ICommunicationObject: " + exception.Message);
_comms.Abort();
}
catch (TimeoutException exception) // Not closed - call Abort to transition to the closed state.
{
Debug.WriteLine("TimeoutException while closing ICommunicationObject: " + exception.Message);
_comms.Abort();
}
catch (Exception exception) // Not closed - call Abort to transition to the closed state.
{
Trace.WriteLine("Unexpected exception while closing ICommunicationObject: " + exception.Message);
_comms.Abort();
}
}
private void closeChannelFactory()
{
try
{
_channelFactory.Close();
}
catch (CommunicationException exception) // Not closed - call Abort to transition to the closed state.
{
Debug.WriteLine("CommunicationException while closing ChannelFactory: " + exception.Message);
_channelFactory.Abort();
}
catch (TimeoutException exception) // Not closed - call Abort to transition to the closed state.
{
Debug.WriteLine("TimeoutException while closing ChannelFactory: " + exception.Message);
_channelFactory.Abort();
}
catch (Exception exception) // Not closed - call Abort to transition to the closed state.
{
Trace.WriteLine("Unexpected exception while closing ChannelFactory: " + exception.Message);
_channelFactory.Abort();
}
}
private readonly T _service;
private readonly string _wcfEndpointAddress;
private readonly ChannelFactory<T> _channelFactory;
private readonly ICommunicationObject _comms;
}
internal static class Program
{
static void Main(string[] args)
{
if (args.Length > 0 && args[0] == "worker")
runWorker();
else
runMonitor();
Console.WriteLine("\nEnded. Press a key to exit.");
Console.ReadKey();
}
public static void ReportFinished()
{
finished.Set();
}
static void runMonitor()
{
using (new WcfServiceHost<IProgressReporter>(new Monitor(), SERVICE_PIPE_NAME))
{
finished.WaitOne();
}
}
static void runWorker()
{
using (var proxy = new WcfServiceProxy<IProgressReporter>(SERVICE_PIPE_NAME))
{
for (int i = 0; i <= 100; ++i)
{
Thread.Sleep(100);
Console.WriteLine("Worker reporting progress: Completed {0}%: {1}", i, i);
proxy.Service.ReportProgress(i, i.ToString());
}
}
}
private static ManualResetEvent finished = new ManualResetEvent(false);
private const string SERVICE_PIPE_NAME = "net.pipe://localhost/MyServicePipeName";
}
}
thanks to you i managed to do what i wanted ^^
Since it took me quite some time to search/debug, I share my solution.
I used a temporary text file, so it's not very "professional" but it works.
To run the process, you have to call :
string[] args = { "/c cmd1", "cmd2" , "cmd3"};
backgroundWorker1.RunWorkerAsync(args);
(sync on a button pressed event for example)
public partial class Form1 : Form
{
string fileName = "c:\\temp\\tempoutput.txt";
public Form1()
{
InitializeComponent();
backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler
(backgroundWorker1_ProgressChanged);
}
void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
// This function fires on the UI thread so it's safe to edit the UI control directly
progressBar1.Value = e.ProgressPercentage;
readTempFile();
//outputTextArea.Text = "Processing......" + progressBar1.Value.ToString() + "%";
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
// command line
string[] args = e.Argument as string[];
backgroundWorker1.ReportProgress(2);
try
{
FileStream fs = File.Open(fileName, FileMode.OpenOrCreate, FileAccess.Write, FileShare.ReadWrite);
StreamWriter sw = new StreamWriter(fs);
sw.WriteLine("### Starting the process : ###");
sw.Flush();
System.Diagnostics.Process process = new System.Diagnostics.Process();
process.StartInfo.WorkingDirectory = "WorkdirPath";
process.StartInfo.UseShellExecute = false;
process.StartInfo.FileName = "cmd.exe";
// create the command line
int nArgs = args.Length;
if (nArgs > 0)
{
process.StartInfo.Arguments = args[0];
}
for (int i = 1; i < nArgs; i++)
{
process.StartInfo.Arguments = String.Concat(process.StartInfo.Arguments, " && ", args[i]);
}
process.StartInfo.CreateNoWindow = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
backgroundWorker1.ReportProgress(5);
process.Start();
backgroundWorker1.ReportProgress(10);
System.IO.StreamWriter sIn = process.StandardInput;
System.IO.StreamReader sOut = process.StandardOutput;
backgroundWorker1.ReportProgress(15);
int timeCount = 15;
string tempOut = "";
while (!sOut.EndOfStream)
{
tempOut = sOut.ReadLine();
sw.WriteLine(tempOut);
sw.Flush();
if (timeCount < 90)
{
// increasing the progress bar value.
//timeCount += 1;
}
backgroundWorker1.ReportProgress(timeCount);
}
sw.WriteLine("Closing process");
sw.Flush();
process.Close();
backgroundWorker1.ReportProgress(100);
}
catch (System.IO.IOException exept)
{
Console.WriteLine(exept.Message);
return;
}
}
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
readTempFile();
}
private void readTempFile()
{
try
{
FileStream fs = File.Open(fileName, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);
StreamReader r = new StreamReader(fs);
string output = r.ReadToEnd();
outputTextArea.Text = output;
}
catch (System.IO.IOException exept)
{
Console.WriteLine(exept.Message);
return;
}
}
}

Windows service not triggering scheduled task

I have an XML file which contains scheduling dates. I want to create a service that will read the date and time from the XML file and trigger (call my application) on that time.
I tried a lot but the service doesn't not trigger my application so I made a console application to replicate my service which work perfectly.
Also, on my service, on Start/Stop I am creating a log file which does seem to be working it just appears to be my trigger that doesn't.
protected override void OnStart(string[] args)
{
TraceService("start service");
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timer.Interval = 60000;
timer.Enabled = true;
}
protected override void OnStop()
{
timer.Enabled = false;
TraceService("stopping service");
}
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
TraceService(" Varun Another entry at " + DateTime.Now);
}
private void TraceService(string content)
{
FileStream fs = new FileStream(#"d:\Varun-Pc start up.txt", FileMode.OpenOrCreate, FileAccess.Write);
StreamWriter sw = new StreamWriter(fs);
sw.BaseStream.Seek(0, SeekOrigin.End);
sw.WriteLine(content);
sw.Flush();
sw.Close();
connect();
string xmldata = "";
SqlDataAdapter da = new SqlDataAdapter("select * from Schedualer_Master", cn);
DataSet mds = new DataSet();
da.Fill(mds);
for (int i = 0; i < mds.Tables[0].Rows.Count; i++)
{
xmldata = "";
xmldata = mds.Tables[0].Rows[i]["XML_Data"].ToString();
TaskScheduler.TriggerItem newItem = TaskScheduler.TriggerItem.FromXML(xmldata);
newItem.Enabled = true;
_taskScheduler.AddTrigger(newItem); // set item into trigger
_taskScheduler.Enabled = true;
}
object sender = new object();
EventArgs e = new EventArgs();
_taskScheduler._triggerTimer_Tick(sender, e);
}
And this is my trigger function
public void _triggerTimer_Tick(object sender, EventArgs e)
{
_triggerTimer.Stop();
foreach (TriggerItem item in TriggerItems)
if (item.Enabled)
{
while (item.TriggerTime <= DateTime.Now)
{
item.RunCheck(DateTime.Now);
System.Diagnostics.Process.Start("E:\\SqlBackup_Programs\\console-backup\\Backup_Console_App 22July Latest\\Backup_Console_App\\Backup_Console_App\\bin\\Debug\\Backup_Console_App");
}
}
_triggerTimer.Start();
}

Issue in c# Window service

In my window service when I run window service from manage ,ScheduledService file does not contain "Get Connection". I think there is problem in GetConnectionOfReportServer, it may it take more time.
When I debug it is working fine.
Code Example
protected override void OnStart(string[] args)
{
TraceService("start service");
timer = new System.Timers.Timer(1000);
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timer.Interval = 90000;
timer.Enabled = true;
}
protected override void OnStop()
{
TraceService("stopping service");
}
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
time_elapsed();
TraceService("Another entry at " + DateTime.Now);
}
private void time_elapsed()
{
TraceService("Call susseccfully");
GetConnectionOfReportServer();//The problem is here.
TraceService("Get Connection");
DailyReportFile = getReportFrmServer(reportName, param);
}
public void GetConnectionOfReportServer()
{
TraceService("I am in GetConnectionOfReportServer "); //**Edit part**
try
{
NetworkCredential credential = new NetworkCredential("administrator", "epass#123");
this.reportViewer1.ServerReport.ReportServerCredentials.NetworkCredentials = credential;
this.reportViewer1.ProcessingMode = Microsoft.Reporting.WinForms.ProcessingMode.Remote;
this.reportViewer1.ServerReport.ReportServerUrl = new Uri(#"http://xxx.xxx.xxx.xxx/ReportServer");
}
catch (Exception ex)
{
}
}
private void TraceService(string content)
{
FileStream fs = new FileStream(#"c:\ScheduledService.txt", FileMode.OpenOrCreate, FileAccess.Write);
StreamWriter sw = new StreamWriter(fs);
sw.BaseStream.Seek(0, SeekOrigin.End);
sw.WriteLine(content);
sw.Flush();
sw.Close();
}
Edit Method
public void GetConnectionOfReportServer()
{
TraceService("I am in GetConnectionOfReportServer.");
try
{
TraceService("I am in Try.");
//NetworkCredential credential = new NetworkCredential("administrator", "espl#123","");
NetworkCredential credential = new NetworkCredential("administrator", "esmart#123");
this.reportViewer1.ServerReport.ReportServerCredentials.NetworkCredentials = credential;
//select where the report should be generated with the report viewer control or on the report server using the SSRS service.
this.reportViewer1.ProcessingMode = Microsoft.Reporting.WinForms.ProcessingMode.Remote;
this.reportViewer1.ServerReport.ReportServerUrl = new Uri(#"http://xxx.xxx.xxx.xxx/ReportServer");
TraceService("I am atTry end");
}
catch (Exception ex)
{
TraceService(ex.StackTrace);
}
finally
{
TraceService("I am in finally block");
}
}
But when I am seeing my "ScheduledService File"
start service
Call susseccfully
Find punch
Yes have to send
Yes have to send,
I am in GetConnectionOfReportServer.
I am in Try. // After this line It should be print "I am at Try end"
Call susseccfully.
After it again call OnElapsedTime event.

C# Windows Service Timer app config change in runtime

I'm making some Windows Services in c# and i need to read some variables from a config file like files and paths. I also have a variable that controls (it should) the timer interval. The problem is, every time a change data in the config file, that data is not fetched and, for example, if i change the file name i get an error saying that the file does not exist (and i checked the name and the path) or if i change the time interval nothing happens. Can someone help me please?
System.Timers.Timer timer;
CallWebServices call;
int time;
public Planview_SEB_Pervasive()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
call = new CallWebServices();
startPervasive();
}
protected override void OnStop()
{
timer.Enabled = false;
call.InsertLog("PV/S&B Win Service", "Serviço parado", "");
}
private void startPervasive()
{
try
{
try
{
//Vai buscar o tempo ao app.config
time = Convert.ToInt32(ConfigurationManager.AppSettings.Get("TimeElapsedInMinutes"));
}
catch (Exception ex)
{
//Em caso de falha ficam 5 minutos
call.InsertLog("PV/S&B Win Service StartPervasive (time)", ex.Message, "");
time = 5;
}
this.timer = new System.Timers.Timer();
timer.Enabled = true;
timer.AutoReset = true; //Necesário para que o srviço se repita
timer.Interval = 1000 * 60 * time; //Cálculo para minutos
timer.Elapsed += new ElapsedEventHandler(Elapsed);
}
catch (Exception ex)
{
call.InsertLog("PV/S&B Win Service StartPervasive", ex.Message, "");
OnStop();
}
}
protected void Elapsed(Object sender, ElapsedEventArgs e)
{
try
{
timer.Interval = Convert.ToInt32(ConfigurationManager.AppSettings.Get("TimeElapsedInMinutes"));
StartProcess();
}
catch (Exception ex)
{
call.InsertLog("PV/S&B Win Service Elapsed", ex.Message, "");
}
}
private static void StartProcess()
{
try
{
string directory = ConfigurationManager.AppSettings.Get("WorkingDirectory");
string file = ConfigurationManager.AppSettings.Get("FileToRun");
//Execução dos processo (ficheiro)
Process process = new Process();
process.StartInfo.WorkingDirectory = directory;
process.StartInfo.FileName = directory + #"\" + file;
process.StartInfo.Arguments = "";
process.StartInfo.UseShellExecute = false;
process.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
process.StartInfo.CreateNoWindow = false;
process.StartInfo.RedirectStandardOutput = false;
process.Start();
}
catch (Exception ex)
{
throw ex;
}
}
You could implement a FileSystemWatcher that monitors the directory where the app.config is stored in. When it is updated you will get an event in your application notifying you that something has changed. When that occurs you can reload the app.config and refresh your values.
Link: FileSystemWatcher Class

Dispatcher timer not running

I'm trying to execute some Python scripts from my WPF app. The scripts are generating the log files and the code in the Tick event is reading them and displaying that as it is in a textbox.
My issue here is that, that LaunchProcess fires successfully, but the UI freezes. I have an indefinite progress bar, which too does not start animating. I'm a beginner with WPF and there is something very small I have to do to get this code working. I'm not getting any error/warnings. The scripts run fine and in the end I get to know the result too. But during the run, the UI of my app freezes.
private void LaunchProcess(string paramStr)
{
Process myProcess = new Process();
StartProgressBar();
try
{
dispatcherTimer = new DispatcherTimer();
dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick);
dispatcherTimer.Interval = new TimeSpan(0, 0, 0);
dispatcherTimer.Start();
myProcess.StartInfo.UseShellExecute = false;
// You can start any process
myProcess.StartInfo.FileName = "C:\\Python32\\python.exe";
myProcess.StartInfo.Arguments = "\""+paramStr+"\"";
myProcess.StartInfo.CreateNoWindow = true;
myProcess.StartInfo.RedirectStandardOutput = true;
myProcess.StartInfo.RedirectStandardError = true;
myProcess.Start();
myProcess.WaitForExit();
// This code assumes the process you are starting will terminate itself.
// Given that is is started without a window so you cannot terminate it
// on the desktop, it must terminate itself or you can do it programmatically
// from this application using the Kill method.
dispatcherTimer.Stop();
}
catch
{
MessageBox.Show("Process Launch Failed!!", "Failure", MessageBoxButton.OK, MessageBoxImage.Error);
}
}
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
//txtOutPut.Text = "";
txtOutPut.Text += "\n" + DateTime.Now.ToString();
if (File.Exists(scriptPath+"\\log.txt"))
{
//File.Copy("C:\\FlashAuto\\Execution_Logs\\log.txt", "C:\\FlashAuto\\Temp\\log.txt", true);
TextReader readLogs = new StreamReader(scriptPath + "\\log.txt");
string line = readLogs.ReadLine();
while (line != null)
{
txtOutPut.Text += "\n" + line;
line = readLogs.ReadLine();
txtOutPut.ScrollToEnd();
}
//CountLines = txtExecLog.LineCount - 1;
readLogs.Close();
// Forcing the CommandManager to raise the RequerySuggested event
txtOutPut.ScrollToEnd();
CommandManager.InvalidateRequerySuggested();
readLogs.Dispose();
}
else
{
txtOutPut.Text += "log file not found at: " + DateTime.Now.ToString();
}
}
In case you call LaunchProcess from the UI thread it will obviously be blocked at myProcess.WaitForExit().
You might simply remove the myProcess.WaitForExit() and dispatcherTimer.Stop() calls from the launch method and check if the process is still running in the timer Tick handler.
private void dispatcherTimer_Tick(object sender, EventArgs e)
{
if (myProcess.WaitForExit(0)) // check with timeout zero
{
dispatcherTimer.Stop();
}
... // all your code
}
Calling LaunchProcess method asynchronously would resolve your UI Freeze Issue
public void LaunchProcessAsynchrousCall(string paramStr)
{
ThreadStart displayContentHandler = delegate()
{
LaunchProcess(paramStr)
};
Thread thread = new Thread(displayContentHandler);
thread.IsBackground = true;
thread.Start();
}

Categories

Resources