How to stop logcat from logging and close adb programmatically? - c#

I am writing a small C# application to collect logcat files for an app that's running on an Android device connected to the computer.
I can easily start logcat and get it to log the desired lines to a particular text file. But every command that I've tried to stop logcat from logging doesn't work.
I've tried my solutions also when running my app with admin rights.
Here is my code:
static void Main(string[] args)
{
string choice;
string clearLogging = #"adb logcat -c";
string startLogging = #"adb logcat MyApp_LoggingTag:V AndroidRuntime:E *:S > C:\logcat.txt";
string adbDir = #"C:\Users\me\AppData\Local\Android\android-sdk\platform-tools\";
string clearCommand = adbDir + clearLogging;
string startLoggingCommand = adbDir + startLogging;
ProcessStartInfo startInfo = new ProcessStartInfo("cmd.exe", "/K " + clearCommand);
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
startInfo.RedirectStandardInput = true;
//Tried giving the cmd process elevated rights and then use logcat -c - didn't work
//startInfo.Verb = "runas";
Process logcatRunner = Process.Start(startInfo);
//This works!
logcatRunner.StandardInput.WriteLine(startLoggingCommand);
Console.WriteLine("Logging has started.");
Console.Write("Press Enter to stop logging....");
Console.ReadLine();
//-c doesn't work
//logcatRunner.StandardInput.WriteLine(clearCommand);
//Tried killing adb via the logcatRunner process - doesn't work.
//logcatRunner.StandardInput.WriteLine(#"taskkill -f /im ""adb.exe""");
//Tried killing my process - doesn't work - adb is still running and logcat is still writing logs
//logcatRunner.Kill();
Console.WriteLine("Logging has stopped.");
Console.Write(#"Enter any key");
choice = Console.ReadLine();
}
adb is still running after I close the above application.
So my question is, having started adb and logcat successfully, how do I close both of them programmatically?

Doing this with your approach is complicated. You create cmd process and then start another process (adb) there. To kill adb you need to send CTRL+C to cmd, but it's not that easy because of CreateNoWindow=true. I'd suggest another approach and run adb directly, redirecting its output:
string adbPath = #"G:\Android\android-sdk\platform-tools\adb.exe";
ProcessStartInfo startInfo = new ProcessStartInfo(adbPath, "logcat MyApp_LoggingTag:V AndroidRuntime:E *:S");
startInfo.CreateNoWindow = true;
startInfo.UseShellExecute = false;
startInfo.RedirectStandardOutput = true;
// if you don't want to recreate it each time - choose another file mode, like FileMode.Append
using (var fs = new FileStream(#"C:\logcat.txt", FileMode.Create, FileAccess.Write, FileShare.Read)) {
using (var writer = new StreamWriter(fs)) {
Process logcatRunner = new Process();
logcatRunner.StartInfo = startInfo;
logcatRunner.EnableRaisingEvents = true;
logcatRunner.OutputDataReceived += (sender, args) => {
// Data null indicates end of output stream - don't write it
if (args.Data != null) {
writer.Write(args.Data);
// flush immediately if needed
writer.Flush();
}
};
logcatRunner.Start();
logcatRunner.BeginOutputReadLine();
Console.WriteLine("Logging started, press any key to stop");
Console.ReadKey();
logcatRunner.CancelOutputRead();
logcatRunner.Kill();
logcatRunner.WaitForExit();
}
}

Related

C# RedirectStandardOutput from third party terminal stops at first character

I'm trying to redirect the output from a third party terminal (accoreconsole.exe).
The output is redirected to a richtextbox.
If I manually type in the accoreconsole.exe from cmd I see the whole output but when I try to start it from my project it's stops at the first letter of the first row.
The first row where the output stops at letter R:
Redirect stdout (file: C:\Users\Marcus\AppData\Local\Temp\accc207883).
When I send something like "ipconfig" it work as it should.
I tried to send the output to a .txt file and that worked. But when I tried to apply the text from the .txt file to my textbox it stops at the same letter (R). If I manually opend the .txt file and just save it I can apply it to the textbox.. Wierd?
Any ideas? :) Thanks!
Manually from cmd:
Microsoft Windows [Version 10.0.19043.1348]
(c) Microsoft Corporation. All rights reserved.
C:\Users\Marcus>"C:\Program Files\Autodesk\AutoCAD 2018\accoreconsole.exe"
Redirect stdout (file: C:\Users\Marcus\AppData\Local\Temp\accc207883).
AcCoreConsole: StdOutConsoleMode: processed-output: enabled,auto
AutoCAD Core Engine Console - Copyright 2017 Autodesk, Inc. All rights reserved. (O.72.0.0)
Execution Path:
C:\Program Files\Autodesk\AutoCAD 2018\accoreconsole.exe
Version Number: O.72.0.0 (UNICODE)
Usage:
AcCoreConsole.exe [/i <input dwg>] /s <script>[/product <product>] [/l <language>] [/isolate <userid> <userDataFolder>] [/readonly] [/p[rofile] <profile>]
Example:
AcCoreConsole.exe /i 8th_floor.dwg /s test.scr /l en-US
C:\Users\Marcus>
Output from my project:
Microsoft Windows [Version 10.0.19043.1348]
(c) Microsoft Corporation. All rights reserved.
C:\Users\Marcus\source\repos\Test_Read_Console_Live\Test_Read_Console_Live\bin\Debug>"C:\Program Files\Autodesk\AutoCAD 2018\accoreconsole.exe"
R
My project code:
using System;
using System.Diagnostics;
using System.Windows.Forms;
namespace Test_Read_Console_Live
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
run();
}
public void run()
{
Process cmd = new Process()
{
StartInfo = new ProcessStartInfo("cmd")
{
RedirectStandardInput = true,
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden
}
};
cmd.Start();
cmd.StandardInput.WriteLine(#"""C:\Program Files\Autodesk\AutoCAD 2018\accoreconsole.exe""");
cmd.StandardInput.Flush();
cmd.StandardInput.Close();
string output = cmd.StandardOutput.ReadToEnd();
cmd.WaitForExit();
cmd.Close();
richTextBox1.Text = output;
}
}
}
Here is a snippet of code I had for calling a DOS-based command terminal program.
Whatever the "exeToRun" program is, such as your AcCoreConsole.exe, and
var info = new ProcessStartInfo();
// call the DOS command, ensure the path to
// your exe file being called.
info.FileName = Path.Combine(Environment.CurrentDirectory, exeToRun);
info.Arguments = stringOfCommandArguments;
info.RedirectStandardInput = true;
info.UseShellExecute = false;
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
// dont "SHOW" the black popup window in background making things look
// like popup, popup, popup for each call going out to device.
info.WindowStyle = ProcessWindowStyle.Hidden;
// the "CreateNoWindow" actually prevents the black DOS window from showing.
info.CreateNoWindow = true;
p.StartInfo = info;
p.Start();
var sb = new StringBuilder();
try
{
while (!p.StandardOutput.EndOfStream)
sb.AppendLine(p.StandardOutput.ReadLine());
while (!p.StandardError.EndOfStream)
sb.AppendLine(p.StandardError.ReadLine());
}
catch
{
sb.AppendLine("Error/Timeout getting results of request.");
}
So, after the process.Start, I did a loop of capturing both standardOutput and standardError streams that are part of the process object. Hopefully this can get you over the hump you are working on.
Now, in the string builder, I can assess, write out and debug for later assessment. You can split into your own capture, but again, hopefully just the piece(s) you may be missing.
One can also use the dedicated event handlers to process the output and error streams asynchronously:
var startInfo = new ProcessStartInfo();
startInfo.FileName = "app.exe";
startInfo.UseShellExecute = false;
var p = new Process();
p.StartInfo = startInfo;
// Gather standard output in a string buffer
var outSb = new StringBuilder();
startInfo.RedirectStandardOutput = true;
p.OutputDataReceived += new DataReceivedEventHandler((sender, e) => { outSb.AppendLine(e.Data); });
// Gather standard error in a string buffer
startInfo.RedirectStandardError = true;
var errSb = new StringBuilder();
p.ErrorDataReceived += new DataReceivedEventHandler((sender, e) => { errSb.AppendLine(e.Data); });
p.Start();
p.BeginOutputReadLine();
p.BeginErrorReadLine();
p.WaitForExit();
var allOutputLines = outSb.ToString();
var allErrorLines = errSb.ToString();

Command won't run in Command Prompt

When users click on a button, I want it to run the logon script(launching from server), but each computer in different servers, so I get the server name. But the netlogon.StartInfo.Arguments = slnres + #"/c \netlogon\logon.cmd"; line is not working as it should be. It should run the logon.cmd on the PC(mapping network drivers, printers, etc), and then the CMD should close.
private void MapNetwork_Click(object sender, EventArgs e)
{
Process sln = new Process();
sln.StartInfo.UseShellExecute = false;
sln.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
sln.StartInfo.FileName = "cmd.exe";
sln.StartInfo.Arguments = "/c echo %logonserver%";
sln.StartInfo.RedirectStandardOutput = true;
sln.Start();
string slnres = sln.StandardOutput.ReadToEnd();
label1.Text = slnres;
Process netlogon = new Process();
netlogon.StartInfo.UseShellExecute = false;
netlogon.StartInfo.FileName = "cmd.exe";
netlogon.StartInfo.Arguments = slnres + #"/c \netlogon\logon.cmd";
netlogon.Start();
}
A couple things:
You don't need to run a command prompt to get an environment variable. You can use Environment.GetEnvironmentVariable.
Your Arguments property for your call to logon.cmd is being constructed into this:
\\myserver/c \netlogon\logon.cmd
When I think you want this:
/c \\myserver\netlogon\logon.cmd
So make sure you put slnres at the right place in your string. Your code should look like this:
private void MapNetwork_Click(object sender, EventArgs e)
{
string slnres = Environment.GetEnvironmentVariable("logonserver");
label1.Text = slnres;
Process netlogon = new Process();
netlogon.StartInfo.UseShellExecute = false;
netlogon.StartInfo.FileName = "cmd.exe";
netlogon.StartInfo.Arguments = "/c " + slnres + #"\netlogon\logon.cmd";
netlogon.Start();
}
i am a little confused about your question and i am not rly sure if i understand you correctly. some time ago i made a program where i had to run few powershell commands, so i made a class for it. redirected to your button it would look like that:
(and remember you need the fqdn to your file location => Reading File From Network Location)
using System.Diagnostics;
//class lvl scope vars
string output;
string ErrorOutput;
private void MapNetwork_Click(object sender, EventArgs e)
{
//define process arguments
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.FileName = #"cmd.exe";
startInfo.Arguments = #"FQDN path to your file on the server; exit";
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
startInfo.RedirectStandardOutput = true;
startInfo.RedirectStandardError = true;
//start process
Process process = new Process();
process.StartInfo = startInfo;
process.Start();
process.WaitForExit();
//outpunt handling
if (string.IsNullOrEmpty(ErrorOutput))
{
return output;
}
else
{
return ErrorOutput;
}
}
first of all i would check if your application is able to open the file one the shared network location. (server available? access rights to server? serer mapped?)
after that you can check if he is able to start the file locally. (does it need admin rights to run the *.cmd, *.bat file)
now you can check if your application runs it correctly.

How to close exit and restart program

I have a program and Im checking if there is an instance running, and if there is an instance running it should terminate the running program and run my app.. before I was just prompting the user that there is a running instance and just close the program. Now the user want the program to just terminate that instance and launch the app.
if (Process.GetProcessesByName(Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location)).Length > 1)
{
//MessageBox.Show("Another instance of the Program is Running", Global.ProgName, MessageBoxButton.OK, MessageBoxImage.Information);
//Environment.Exit(0);
foreach (var process in Process.GetProcessesByName(Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location)))
{
process.Kill();
}
Process.Start(Path.GetFileName(Assembly.GetEntryAssembly().Location));
}
if(Process.GetProcessesByName(System.IO.Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location)).Length > 1)
{
foreach (var process in Process.GetProcessesByName(System.IO.Path.GetFileNameWithoutExtension(Assembly.GetEntryAssembly().Location)))
{
if (process.Id != Process.GetCurrentProcess().Id)
{
process.Kill();
}
}
}
This code gets the processes which has same name with yours and kills the old ones, new one is the killer one.
It isn't clean, but you could use a shell command:
ProcessStartInfo Info = new ProcessStartInfo();
Info.Arguments = "/C ping 127.0.0.1 -n 4 && cd \"" + Application.StartupPath + "\" && filename.exe";
Info.WindowStyle = ProcessWindowStyle.Hidden;
Info.CreateNoWindow = true;
Info.FileName = "cmd.exe";
System.Timers.Timer t = new System.Timers.Timer(1000);
t.Elapsed += T_Elapsed;
t.Start();
Process.Start(Info);
private void T_Elapsed(object sender, ElapsedEventArgs e)
{
Application.Exit();
}
The shell command pings localhost 4 times to pass time, and during those pings, the program exits. The original shell command is still running after the program exits, so the program re-opens after the pings.

Windows Service fails to execute mshtml.dll

I have a Windows Application which uses mshtml.dll. It works fine within my Windows Form application.
When I use the same code within my Windows Service app then it fails. My Service runs as an Administrator.
below is the code I use:
private string PrintUsingPrinterExe(string Command)
{
System.Diagnostics.ProcessStartInfo procStartInfo = new System.Diagnostics.ProcessStartInfo("cmd", "/c " + Command);
// The following commands are needed to redirect the standard output.
// This means that it will be redirected to the Process.StandardOutput StreamReader.
procStartInfo.RedirectStandardOutput = true;
procStartInfo.UseShellExecute = false;
// Do not create the black window.
procStartInfo.CreateNoWindow = true;
// Now we create a process, assign its ProcessStartInfo and start it
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.StartInfo = procStartInfo;
proc.Start();
//StreamWriter streamWriter = proc.StandardInput;
//StreamReader outputReader = proc.StandardOutput;
//StreamReader errorReader = proc.StandardError;
//while (!outputReader.EndOfStream)
//{
// string text = outputReader.ReadLine();
// streamWriter.WriteLine(text);
//}
//while (!errorReader.EndOfStream)
//{
// string text = errorReader.ReadLine();
// streamWriter.WriteLine(text);
//}
//streamWriter.Close();
proc.WaitForExit(12000);
// Get the output into a string
string result = proc.StandardOutput.ReadToEnd();
if (!proc.HasExited)
{
proc.Kill();
}
// Display the command output.
return result;
}
command is : PRINTHTML.EXE url="http://www.google.com" printername="Brother HL-2270DW series" title="" header="" footer=""
Under event Log I find this:
Faulting module path: C:\Windows\SYSTEM32\mshtml.dll
So, how could it be possible that same DLL works just fine under winForm app and does not work under Windows Service.
BTW, same service runs fine on Windows 7.
so issue is Windows 10 + mshtml.dll + Windows Service

How to continuously output console application to text file in C#

I am trying to open up a hidden console application with arguments, and basically log it's output into a file continuously until it is stopped.
I have tried using a memory stream and writing it into the file, and it did seem to work for a bit. Now I am trying to take advantage of the DataRecievedEvent so I can further process the output. Right now I am not getting any output.
Here is how I am opening the console application:
StreamWriter writer = new StreamWriter("tsharkfieldoutput.txt", true)
private void capturePackets(int device)
{
string path =
string.Format("-i " + device +
" -O SNMP -T fields -e snmp.value.oid -e snmp.VarBind -e snmp.variable_bindings -e snmp.value.octets -e snmp.name -R udp src " +
destPort);
string tshark = #"C:\Program Files\Wireshark\tshark.exe";
ProcessStartInfo ps = new ProcessStartInfo();
ps.FileName = tshark;
ps.CreateNoWindow = true;
ps.WindowStyle = ProcessWindowStyle.Hidden;
ps.UseShellExecute = false;
ps.CreateNoWindow = true;
ps.RedirectStandardOutput = true;
ps.Arguments = path;
Process process = new Process();
process.StartInfo = ps;
process.Start();
process.OutputDataReceived += new DataReceivedEventHandler(tshark_OutputDataReceived);
//Not using stream reader any more.
//StreamReader myStreamReader = process.StandardOutput;
writer.Write("Begin tshark output- " + DateTime.Now + " - " + Environment.NewLine);
}
private void tshark_OutputDataReceived(object sender, DataReceivedEventArgs arg)
{
string tsharkline = arg.Data; //arg.Data contains the output data from the process...
writer.Write(tsharkline);
}
I think the issue is that your reference to the process is going out of scope at the end of function capturePackets. You will either need to give the process variable the same scope as the writer or wait in the capturePackets function until the process exits using the WaitForExit() method. Although the process that you create continues to run, when the reference to it goes out of scope (via the process variable), the events will stop being processed.

Categories