Last active
April 4, 2017 09:32
-
-
Save Filarius/71fb73c32aca2aef82271d30c94f5202 to your computer and use it in GitHub Desktop.
C# Console Apps Wrapper
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Text; | |
using System.IO; | |
using System.Diagnostics; | |
using System.Threading; | |
namespace Helper | |
{ | |
class Wrapper | |
{ | |
public Process _proc; | |
private ProcessStartInfo _procInfo; | |
public MemoryStream _readStream; | |
public MemoryStream _errorStream; | |
public MemoryStream _writeStream; | |
public Boolean IgnoreInput; | |
private Thread _tread, _twrite, _terror; | |
private Object rLocker, wLocker, eLocker; | |
private bool _isRun; | |
private int _charBlock = 1024000 / sizeof(char); | |
private int _byteBlock = 1024000; | |
public Wrapper(string Path, string args) | |
{ | |
IgnoreInput = false; | |
rLocker = new Object(); | |
eLocker = new Object(); | |
wLocker = new Object(); | |
_errorStream = new MemoryStream(_byteBlock * 2); | |
_readStream = new MemoryStream(_byteBlock * 2); | |
_writeStream = new MemoryStream(_byteBlock * 2); | |
_procInfo = new ProcessStartInfo(Path, args); | |
_procInfo.CreateNoWindow = true; | |
_procInfo.UseShellExecute = false; | |
_procInfo.RedirectStandardError = true; | |
_procInfo.RedirectStandardInput = true; | |
_procInfo.RedirectStandardOutput = true; | |
_proc = new Process(); | |
_proc.StartInfo = _procInfo; | |
_isRun = false; | |
} | |
~Wrapper() | |
{ | |
Stop(); | |
} | |
public void Start() | |
{ | |
if (_isRun) return; | |
_isRun = true; | |
_proc.Start(); | |
_proc.PriorityClass = ProcessPriorityClass.BelowNormal; | |
// low CPU solution to check if process is alive | |
(new Thread( | |
() => | |
{ | |
while (true) | |
{ | |
try | |
{ | |
if (_proc.HasExited) // HasExited is expensive operation ! | |
{ | |
_isRun = false; | |
break; | |
} | |
} | |
catch | |
{ | |
_isRun = false; | |
break; | |
}; | |
Wait(1000); | |
} | |
} | |
) | |
).Start(); | |
_twrite = new Thread( | |
() => | |
{ | |
IntractBytes(_writeStream, _proc.StandardInput.BaseStream, wLocker); | |
} | |
); | |
_twrite.Start(); | |
_tread = new Thread( | |
() => | |
{ | |
ExtractBytes(_proc.StandardOutput.BaseStream, _readStream, rLocker); | |
} | |
); | |
_tread.Start(); | |
_terror = new Thread( | |
() => | |
{ | |
ExtractBytes(_proc.StandardError.BaseStream, _errorStream, eLocker); | |
} | |
); | |
_terror.Start(); | |
} | |
public void Stop() | |
{ | |
(new Thread(() => | |
{ | |
if (_isRun) | |
{ | |
_isRun = false; | |
} | |
try { _tread.Abort(); } catch { } | |
try { _terror.Abort(); } catch { } | |
try { _twrite.Abort(); } catch { } | |
try | |
{ | |
if (!_proc.HasExited) | |
{ | |
Console.WriteLine("Killing " + _proc.ProcessName); | |
_proc.Kill(); | |
_proc.Close(); | |
} | |
} | |
catch | |
{ } | |
_readStream.Close(); | |
_errorStream.Close(); | |
_writeStream.Close(); | |
}) | |
).Start(); | |
} | |
public void Wait() | |
{ | |
System.Threading.Thread.Sleep(1); | |
} | |
public void Wait(int ms) | |
{ | |
System.Threading.Thread.Sleep(ms); | |
} | |
/* | |
private void WaitFor(ref bool flag) | |
{ | |
System.Threading.Thread.Sleep(1); | |
while (flag) | |
{ | |
System.Threading.Thread.Sleep(1); | |
} | |
} | |
*/ | |
private string BArrToString(byte[] data) | |
{ | |
string reply = ""; | |
if (data != null) | |
{ | |
reply = System.Text.Encoding.ASCII.GetString(data); | |
} | |
return reply; | |
} | |
private byte[] BArrFromString(String data) | |
{ | |
return Encoding.ASCII.GetBytes(data); | |
} | |
private void ExtractBytes(Stream input, Stream output, Object locker) | |
{ | |
while (IsRunning) | |
{ | |
if (output.Position < _byteBlock) | |
{ | |
byte[] buf = new byte[_byteBlock]; | |
int i = 0; | |
try | |
{ | |
i = input.Read(buf, 0, _byteBlock); | |
} | |
catch | |
{ | |
break; | |
} | |
if (i > 0) | |
{ | |
lock (locker) | |
{ | |
output.Write(buf, 0, i); | |
} | |
} | |
} | |
} | |
} | |
private void IntractBytes(Stream input, Stream output, Object locker) | |
{ | |
while (IsRunning) | |
{ | |
if (input.Position == 0) | |
{ | |
Wait(100); | |
continue; | |
} | |
byte[] buf; | |
int pos; | |
lock (locker) | |
{ | |
pos = (int)input.Position; | |
buf = new byte[pos]; | |
input.Position = 0; | |
int i = input.Read(buf, 0, pos); | |
input.Position = 0; | |
} | |
try | |
{ | |
output.Write(buf, 0, pos); | |
output.Flush(); | |
} | |
catch | |
{ | |
break; | |
} | |
} | |
} | |
public void WriteString(String data) | |
{ | |
throw new Exception("Not Implemented"); | |
} | |
private byte[] GetStreamData(MemoryStream stream) | |
{ | |
if (stream.Position > 0) | |
{ | |
int pos = (int)stream.Position; | |
byte[] data = new byte[pos]; | |
stream.Position = 0; | |
int i = stream.Read(data, 0, pos); | |
if (i < stream.Position) | |
{ | |
throw new Exception("Somewhy stream readed not at full length"); | |
} | |
stream.Position = 0; | |
return data; | |
} | |
return null; | |
} | |
private void SetStreamData(MemoryStream stream, byte[] data) | |
{ | |
int i = 0; | |
while ((i + 1) < data.Length) | |
{ | |
int len = (_byteBlock * 2) - (int)stream.Position - 1; | |
if (len <= 0) | |
{ | |
continue; | |
} | |
int cnt = data.Length - i - 1; | |
if (len > cnt) | |
{ | |
len = cnt; | |
} | |
len = len + 1; | |
byte[] buf = new byte[len]; | |
Buffer.BlockCopy(data, i, buf, 0, len); | |
i += len; | |
lock (wLocker) | |
{ | |
stream.Write(buf, 0, buf.Length); | |
} | |
} | |
} | |
public byte[] Read() | |
{ | |
lock (rLocker) | |
{ | |
return GetStreamData(_readStream); | |
} | |
} | |
public string ReadString() | |
{ | |
if (Monitor.TryEnter(rLocker)) | |
{ | |
return BArrToString(Read()); | |
} | |
else | |
{ | |
return ""; | |
}; | |
} | |
public byte[] Error() | |
{ | |
lock (eLocker) | |
{ | |
return GetStreamData(_errorStream); | |
} | |
} | |
public string ErrorString() | |
{ | |
if (Monitor.TryEnter(eLocker, 1000)) | |
{ | |
try | |
{ | |
return BArrToString(Error()); | |
} | |
catch | |
{ | |
return ""; | |
} | |
finally | |
{ | |
Monitor.Exit(eLocker); | |
} | |
} | |
else | |
{ | |
return ""; | |
} | |
/* | |
if (Monitor.TryEnter(eLocker)) | |
{ | |
return BArrToString(Error()); | |
} | |
else | |
{ | |
return ""; | |
} | |
*/ | |
} | |
public void Write(byte[] data) | |
{ | |
SetStreamData(_writeStream, data); | |
} | |
public void Write(String data) | |
{ | |
Write(BArrFromString(data)); | |
} | |
public void WriteFlush() | |
{ | |
_proc.StandardInput.BaseStream.Flush(); | |
} | |
public Boolean IsRunning | |
{ | |
get | |
{ | |
try | |
{ | |
//return (!_proc.HasExited); // operataion is too heavy !! | |
return _isRun; | |
} | |
catch | |
{ | |
return false; | |
} | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment