windows service won't execute [closed] - c#

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I have a simple service with .net using c#. When I deploy the serivce, I know that it's running because I can see files being deleted. However, the only task that doesn't run is the send the file to printer task. I'm using admin account on the service and it still not doing anything. If I run this same code in visual studio under debug mode, the service runs just fine. please advise on what I'm doing wrong. Thank you so much everyone.
const string flagNoSplashScreen = "/s";
const string flagOpenMinimized = "/h";
var flagPrintFileToPrinter = string.Format("/t \"{0}\" \"{1}\"", pdfFileName, printerName);
var args = string.Format("{0} {1} {2}", flagNoSplashScreen, flagOpenMinimized, flagPrintFileToPrinter);
string processFilename = Microsoft.Win32.Registry.LocalMachine
.OpenSubKey("Software")
.OpenSubKey("Microsoft")
.OpenSubKey("Windows")
.OpenSubKey("CurrentVersion")
.OpenSubKey("App Paths")
.OpenSubKey("AcroRd32.exe")
.GetValue(String.Empty).ToString();
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.FileName = processFilename;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.Arguments = args;
p.Start();
p.StartInfo.WindowStyle = ProcessWindowStyle.Hidden;
//if (!p.WaitForExit(10000))
//{
// if (!p.HasExited)
// {
// p.Kill();
// }
//}
p.EnableRaisingEvents = true;
p.CloseMainWindow();
p.Close();

Unfortunately without you giving us an exception or stack trace we havent got much to go on here.
So, first of all, you need to find out which line of code fails when running as a "windows service" and not when you run the code "interactively".
One thing you could do is wrap your function with a try/catch clause and catch the exception and log it to a file.
In addition to that, another option would be for you to debug the code whilst it is running as a windows service and then put a breakpoint on the function in question and step through the code.
To do that, temporarily add the following code to the service:
static void Main(string[] args)
{
if (Debugger.IsAttached == false)
Debugger.Launch();
...
Then, make sure you have visual studio open with your solution loaded. Then, when you start your service, it will pop up a dialog and ask for you to either attach to an "existing instance" of visual studio or to "open a new instance". Select the option to attach to an "existing instance" with your code open, and then you will be able to step through the code as normal, set breakpoints, etc, only this time the code is running under the credentials of the service.
From here, you should be able to track down the code that fails while running as a service.

Related

How to uninstall a program using product code in C# code or via command line

I have an installer project for VS 2019 and it has a product code + update code available, so in my application I am using it to uninstall the application programatically. Everywhere I looked this appears to be the right way to call msiexec and provide the product code but all I get is a popup window with info style output for msiexec and error code 1603. Even running it myself via powershell it does the same thing so is this no longer the correct way to uninstall something via command line? I would be happy to get it working in command line and can easily update code as well but nothing is working at the moment.
Referenced several other forum posts, codeproject site solutions, maybe this info is just dated or no longer accurate? Checked here most recently How to uninstall MSI using its Product Code in c#
Process process = new Process();
process.StartInfo.FileName = "MsiExec.exe";
process.StartInfo.Arguments = " /x " + productCode + " /Qn";
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.UseShellExecute = false;
process.Start();
string output = process.StandardOutput.ReadToEnd();
string err = process.StandardError.ReadToEnd();
Debug.WriteLine(output);
Debug.WriteLine(err);
process.WaitForExit();
return (process.ExitCode == 0) ? true : false; //exit code 1603, popup appears from Start()

Having issues getting entire output from StandardOutput.ReadToEnd

At work we have a large number of on-site WES09 machines that are doing controls data gathering. Because we have thousands of these, upgrades are a pain. I have been slowly evolving a better process, and am currently working on a C# application to better manage these.
The machines are running File Based Write Filter, which has the effect that if PSEXEC had not been run on the machine before, it won't let it start. So I use WMIC to disable FBWF.
I am trying to add a status feature to see if FBWF is enabled, as I haven't always had 100% success with WMIC. Anyway, FBWF gives status output in the command window, but it's multiple lines. It seems when I use StandardOutput.ReadToEnd, it only gets the first line.
So here is what it looks like when you check FBWF status from PSEXEC:
FBWFOutput
When I run the C# Application I wrote, the output only gets this:
"\r\nPsExec v2.2 - Execute processes remotely\r\nCopyright (C)
2001-2016 Mark Russinovich\r\nSysinternals -
www.sysinternals.com\r\n\r\nFile-based write filter configuration for
the current session:\r\n"
I don't know why it stops there, I can't get the rest of it that actually says if it is enabled or not (which is the next line, of course).
Here is the relevant code piece, leaving out IP/User/Pass:
Process p = new Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardInput = true;
p.StartInfo.FileName = #"C:\temp\PSTools\PsExec.exe";
p.StartInfo.Arguments = #"\\" + RemotePCName + " -u " + Username + " -p " + Password + " fbwfmgr";
p.Start();
string output = p.StandardOutput.ReadToEnd();
string errormessage = p.StandardError.ReadToEnd();
I thought my issue might be the line break, but there looks to be two between the PsExec portion and the FBWF output, but otherwise am not sure what else to try. I spent a couple hours looking through other comments on issues with getting the output, but almost all were that the application would hang which is not an issue I am having.
Thank you in advance for the assistance, I am slowly learning C# and programming in general and this community has been a huge help!

Launching C# program from another C# program

Due to me having knowledge of launching apps I am aware that you have multiple ways of launching an application in C# .NET, but I'm running into a issue that occurs when attempting to launch a SDL2 application.
I have attempted the following using the Process class to:
Start the .exe file of the build.
Start the application using "cmd.exe /K" or "cmd.exe /c" followed by "exec" or "call" or "start" followed by "{path to file}" or "{path to batch file to launch the application}". Launching the application via a batch file and CMD works fine. But, whenever I attempt to even launch the application (even in a new instance of Command-Prompt launched from cmd.exe /? start cmd.exe ?params) it will yield no result.
What I can observe is that the application tries to open. It takes forever to launch into the Window mode (starting the 3D environment). After a timeout it will either, render a couple of frames of a blank window before closing or close immediately after opening the window.
So my question is, does anyone have succesfully made a launcher application for a SDL app written in C# .NET? Or knows a way to debug this behaviour? Because unfortunately, the app does not send out a error message and since SDL safely closes the application I can't observe a crash either.
Edit #1
I'm not doing anything fancy with parameters as there shouldn't be any. I already have another one functioning that launches a normal C# application as my launcher requires to open 2 programs. 1 SLD application, 1 COM:VBA controlling application.
Given:
string audioSpectrumProgram = "AudioSpectrum.exe";
string audioSpectrumBatchProgram = "AudioSpectrum.bat";
private void BtnLaunchPPTApp_OnClick()
{
//Powerpoint controlling application
pVBAApp = Process.Start(presenterProgram, $"\"{this.path}\" {this.audioFormatParams[0]} {((this.ckboxGenerate.Checked) ? "--create" : "")} lang={this.languageCodesParams[this.cboxLanguage.SelectedIndex]}");
}
Method 1:
private void BtnLaunchSDLApp_OnClick()
{
pVizualizer = Process.Start(audioSpectrumProgram); //file launched from local path (is correct)
}
Method 2:
pVizualizer = Process.Start(audioSpectrumBatchProgram); //file launched from local path (is correct)
Method 3:
ProcessStartInfo info = new ProcessStartInfo("cmd.exe");
FileInfo spectrumFileInfo = new FileInfo(audioSpectrumProgram);
if (spectrumFileInfo.Exists)
info.Arguments = $"/c \"{spectrumFileInfo.FullName}\"";
pVizualizer = Process.Start(info);
Method 4:
based on senario of method 3. You don't have to parse arguments using ProcessStartInfo.
pVizualizer = Process.Start($"cmd.exe /K call \"{spectrumFileInfo.FullName}\"") //to observe what happens to the application
Edit #2
Not affected by changing the UseShellExecute to true or false
private void btnOpenVisualizer_Click(object sender, EventArgs e)
{
FileInfo spectrumFileInfo = new FileInfo(audioSpectrumProgram);
ProcessStartInfo info = new ProcessStartInfo(spectrumFileInfo.FullName);
info.UseShellExecute = true;
pVizualizer = new Process();
pVizualizer.StartInfo = info;
pVizualizer.EnableRaisingEvents = true;
pVizualizer.Exited += new EventHandler(myProcess_Exited);
pVizualizer.Start();
}
private void myProcess_Exited(object sender, System.EventArgs e)
{
Console.WriteLine(
$"Exit time : {pVizualizer.ExitTime}\n" +
$"Exit code : {pVizualizer.ExitCode}\n"
);
}
A general way of analyzing startup issues is to use SysInternals Process Monitor.
Record the application that is not starting up properly. Use a filter for your application. Then go through all items which don't have SUCCESS in the result column. Typically you want to do that bottom-up, since the last error is the one stopping your application from loading.
Like this you'll find common startup issues like:
missing DLLs or other dependencies
old DLLs or DLLs loaded from wrong location (e.g. registered COM components)
wrong working directory, e.g. access to non-existent config files
Ok For Future reference:
Pathing to the files can be correct and everything might be in order but if you are using DLLs for imports. Change the process's working directory.
The project will run, libs can "sometimes" be found but can cause a weird unknown bug like this one. So the most optimal way of running another C# instance with SDL or any other kind of library:
private void RunSDLProgram()
{
FileInfo spectrumFileInfo = new FileInfo("pathToFile.exe");
ProcessStartInfo info = new ProcessStartInfo(spectrumFileInfo.FullName);
info.RedirectStandardOutput = true;
info.RedirectStandardError = true;
info.UseShellExecute = false;
info.WorkingDirectory = spectrumFileInfo.DirectoryName;
pVizualizer = new Process();
pVizualizer.StartInfo = info;
pVizualizer.EnableRaisingEvents = true;
pVizualizer.Exited += new EventHandler(myProcess_Exited);
pVizualizer.Start();
}
private void myProcess_Exited(object sender, System.EventArgs e)
{
Console.WriteLine(
$"Exit time : {pVizualizer.ExitTime}\n" +
$"Exit code : {pVizualizer.ExitCode}\n" +
$"output : {pVizualizer.StandardOutput}\n" +
$"err : {pVizualizer.StandardError}\n"
);
}
Running a batch file will look at it's own directory and makes all references local, but it won't alter the working directory. (already had my suspicions about changing the work directory but I didn't see a way to call 2 opperations in process.start("cmd.exe");)

How do I force standard output on a C# Process when UseShellExecute == false?

I am running processes from C# using the following code;
private static void ExecuteShellCMD(string workingDir, string commandWithArgs, bool bWait = true)
{
ProcessStartInfo info = new ProcessStartInfo();
info.Verb = "runas";
info.FileName = "cmd.exe";
info.WorkingDirectory = workingDir;
info.Arguments = "/C " + commandWithArgs;
info.UseShellExecute = false;
using (Process myProcess = Process.Start(info))
{
if (bWait)
{
myProcess.WaitForExit();
}
int ExitCode = myProcess.ExitCode;
//Log exit code here.
}
}
It loads an elevated command window and executes the code/bat file I pass it, but without logging anything to the console. This doesn't appear to be consistent on other machines, and has worked in the past on my machine, and I wondered if anyone had any ideas about how I can consistently make this Process just print logs into the command window the process makes.
I can see logs if I set UseShellExecute = true but then can't use Verb without accepting the elevation prompt which is undesirable.
I have tried looking for solutions around the web, and I am aware that I can redirect the output using other settings. Most of the questions and tutorials on this subject seem to deal with redirecting the ouput to somewhere else but I want to be able to keep track of the progress in the command window itself.
Perhaps I have missed an command line argument or similar?
Turns out this was actually a bug in Unity Hub. The process and output were working fine, however when ran from a Unity instance that was launched from Unity Hub it took control of the output and didn't release it. This was solved by just launching Unity directly and a bug report has been filed against Unity hub.

get git command line return value using c#

I want to run git commands from c#. below is the coded I had written and it does execute the git command but I am not able to capture the return value. When I manually run it from command line this is the output I get.
When I run from the program the only thing I get is
Cloning into 'testrep'...
Rest of the info is not capture, but the command is executed successfully.
class Program
{
static void Main(string[] args)
{
ProcessStartInfo startInfo = new ProcessStartInfo("git.exe");
startInfo.UseShellExecute = false;
startInfo.WorkingDirectory = #"D:\testrep";
startInfo.RedirectStandardInput = true;
startInfo.RedirectStandardOutput = true;
startInfo.Arguments = "clone http://tk1:tk1#localhost/testrep.git";
Process process = new Process();
process.StartInfo = startInfo;
process.Start();
List<string> output = new List<string>();
string lineVal = process.StandardOutput.ReadLine();
while (lineVal != null)
{
output.Add(lineVal);
lineVal = process.StandardOutput.ReadLine();
}
int val = output.Count();
process.WaitForExit();
}
}
From the manual page for git clone:
--progress
Progress status is reported on the standard error stream by default when it is attached to
a terminal, unless -q is specified. This flag forces progress status even if the standard
error stream is not directed to a terminal.
The last three lines in the output when running git clone interactively are sent to standard error, not standard output. They won't show up there when you run the command from your program, however, since it's not an interactive terminal. You could force them to appear, but the output isn't going to be anything usable for a program to parse (lots of \rs to update the progress values).
You are better off not parsing the string output at all, but looking at the integer return value of git clone. If it's nonzero, you had an error (and there will probably be something in standard error that you can show to your user).
Have you tried libgit2sharp? The documentation is not complete, but it is pretty easy to use and there's a nuget package for it. You can always look at the test code to see about usage as well. A simple clone would be like this:
string URL = "http://tk1:tk1#localhost/testrep.git";
string PATH = #"D:\testrep";
Repository.Clone(URL, PATH);
Fetching changes is easy as well:
using (Repository r = new Repository(PATH))
{
Remote remote = r.Network.Remotes["origin"];
r.Network.Fetch(remote, new FetchOptions());
}
Once you call process.WaitForExit() and the process has terminated, you can simply use process.ExitCode which will get you the value that you want.
Your code Looks OK.
this is git problem.
git clone git://git.savannah.gnu.org/wget.git 2> stderr.txt 1> stdout.txt
stderr.txt is empty
stdout.txt:
Cloning into 'wget'...
It looks like git not uses standard console.write() like output you can see it when it writes percentage it's all in one line not like:
10%
25%
60%
100%
process.StandardError.ReadToEnd() + "\n" + process.StandardOutput.ReadToEnd();

Categories

Resources