Launching Click Once Application - File Not Found - c#

I have a basic service that will be used to run a ClickOnce application every x minutes, however when i run Process.Start() i am receiving an exception that the file cannot be found.
Code
private void OnElapsedTime(object source, ElapsedEventArgs e)
{
WriteToFile("Timer ticked");
CheckProcess(GetProcessName());
}
public void CheckProcess(string ProcessName)
{
WriteToFile(ProcessName);
try
{
Process.Start(ProcessName);
WriteToFile("It ran");
}
catch (Exception ex)
{
WriteToFile(ex.ToString());
}
}
public string GetProcessName()
{
string ProcessName = string.Concat("%AppData%\\Microsoft\\Windows\\Start Menu\\Programs\\", PublisherName, "\\", ProductName, ".appref-ms");
return ProcessName;
}
The error i receive is:
%AppData%\Microsoft\Windows\Start Menu\Programs\PubName\ProdName.appref-ms
System.ComponentModel.Win32Exception (0x80004005): The system cannot find the file specified
at System.Diagnostics.Process.StartWithShellExecuteEx(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start()
at System.Diagnostics.Process.Start(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start(String fileName)
If i run the ProcessName retrieved in explorer then the application launches successfully. Value of ProcessName is :
C:\Users\xxx\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\PubName\ProdName.appref-ms
Is there something i am missing in order to start the file?

Windows Services are the programs which will runs even before a user logged into it's Account. This is Windows Service purpose, and by this definition you haven't access to specific User Environment Variables (Like %AppData%) because you aren't in the User Session so your address will be translated to something Odd if you write it into a .txt you will see the result.
Windows Services (By your definitions) will run by LocalSystem, LocalService or NetworkService. Go to TaskManager->Services->Open Services and watch Log On As Column.
So you must use a general path which be access-able through your service.
Most terrifying solution is to force your Service to wait for a user login and impersonate his token.
I will Prefer to choose a better place.
There is a way to debug and see your Service bugs (In UserSession) in VisualStudio.
Change your Program.cs to something like:
static void Main()
{
#if DEBUG
var MainService = new MainService();
MainService.OnDebug();
#else
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new MainService()
};
ServiceBase.Run(ServicesToRun);
#endif
}
and Add OnDebug function to your Service:
public void OnDebug()
{
OnStart(null);
}
if you debug your project in this way you will see that your service is working As Expected !!!

Related

Unable to start C# windows service from my PC

I try to start my own Windows service on C# based.
I try to run with sc.exe create Service.exe but when I want to run this service I have bugs #1026 (Description: The process was terminated due to an unhandled exception.) and #1000. (Faulting application name: Timesync.exe, version: 1.0.0.0, time stamp: 0xf1683f8e
Faulting module name: KERNELBASE.dll, version: 10.0.22621.674, time stamp: 0x160a2aa8) Now I try to this service with InstallUtil.exe but we I can't. Because I have this error: Exception occurred while initializing the installation:
System.BadImageFormatException: Could not load file or assembly 'file:Service.exe' or one of its dependencies. The module was expected to contain an assembly manifest..
Here is my code:
Timer Schedular;
public Service1()
{
InitializeComponent();
if (!EventLog.SourceExists("Timesync"))
EventLog.CreateEventSource("Timesync", "TimesyncLog");
eventLog1.Source = "Timesync";
eventLog1.Log = "TimesyncLog";
}
protected override async void OnStart(string[] args)
{
System.Diagnostics.Debugger.Launch();
eventLog1.WriteEntry("Timesync was started", EventLogEntryType.Information);
await this.ScheduleService();
}
public void onDebug()
{
OnStart(null);
}
private async void SchedularCallback(object e)
{
await this.ScheduleService();
}
private async Task ScheduleService()
{
try
{
}
catch (Exception ex)
{
eventLog1.WriteEntry("Timesync was be here on catch state", EventLogEntryType.Information);
//Stop the Windows Service.
using (ServiceController serviceController = new ServiceController("Timesync"))
{
serviceController.Stop();
}
}
}
Program.cs
internal class Program
{
static void Main(string[] args)
{
//In Release this section is used. This is the "normal" way.
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
Console.WriteLine("The application was be here");
}
}
I can't understand how to resolve my bug and how to run this service.
If it possible, please help. :)
Any chance you are trying to use 32bit library in x64 solution or vice versa. I usually get badimageformat when I don't set Platform target in project build settings.
So if left on Any CPU and the system is x64, and if I use some dependent library which is 32bit. Service will try to run as x64 but fails because of this 32 library. So in our case solution is to set Platform target to x86.

How to fix NullReferenceException occurring only on some computers

I create a setup file of a winform app using VS 2017 installer. When I test this setup file on my PC, the login runs fine. So I run this setup file on other PCs.
However, when I login the app in these PCs, the app say "Object reference not set to an instance of an object", though I am sure that the username and password were correct in the db.
I have seen What is a NullReferenceException, and how do I fix it?, but I do not think it is the null exception, because the installed app did not throw above error in my PC. This error only happens when I install the app in other PCs.
I also try replacing the .exe and .config files in folder of the installed app in other PCs with the same files of the app in my PC (which work well), and the app runs ok. But then I restart those PCs, and try to login the app, the same error happens.
This is the code for login. I believe that I have checked for the null exception properly. Am I right?
private void btnLogin_Click(object sender, EventArgs e)
{
try
{
var info = UsersBiz.Login(txtUserName.Text.Trim(), txtPassWord.Text);
if (info != null && info.user.Id > 0)
{
Constants.USERINFO = info;
this.Hide();
var frm = new frmMain();
frm.Show();
if (ckbRemember.Checked)
{
ManagementInventory.Properties.Settings.Default.User = txtUserName.Text;
ManagementInventory.Properties.Settings.Default.Pass = txtPassWord.Text;
ManagementInventory.Properties.Settings.Default.Save();
}
}
else
{
MessageBox.Show("UserName or Password not correct!");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
The most easy way would be to use visual studio debugger on the computer where the program runs. If there is no visual studio on that computer, consider using remote debugging. See how to start debugging on a remote computer
If for security reasons remote debugging is out of the question, consider to log the exception, especially the stack trace. If you know where it occurs, simply surround it with a try-catch
try
{
// Here are the statements that cause your ArgumentNullException
}
catch (ArgumentNullException exc)
{
// log the exception
}
If your program has no logging facility, consider adding something like NLOG. Another possibility is to append it to a text file.
void WriteExceptionToTextFile(Exception exc, string fileName)
{
using (var writer = File.AppendText(fileName))
{
writer.WriteLine("Exception {0}", exc.GetType());
write.WriteLine("Stack trace" + exc.StackTrace);
... // etc
}
}
If you don't know where the exception occurs, you can't try-catch it. In that case consider to catch the unhandled exception and log it:
See: catching unhandled exception
In your forms program is a file program.cs which contains the main:
public static void Main()
{
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.UnhandledException += OnUnhandledException;
...
}
static void OnUnhandledException(object sender, UnhandledExceptionEventArgs args)
{
Exception undhandledException = (Exception) args.ExceptionObject;
// TODO log the unhandled exception
}

Reading registry in windows service

I have made a windows service using VS2017 template and it have created two classes: Program.cs and Service1.cs:
Program.cs Main() function code is separated as below:
#if DEBUG
Service1 service = new Service1();
service.OnDebug();
System.Threading.Thread.Sleep(System.Threading.Timeout.Infinite);
#else
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new Service1()
};
ServiceBase.Run(ServicesToRun);
#endif
It helps me while I debug my service before release.
In Service1.cs class I have OnDebug() method:
public void OnDebug()
{
OnStart(null);
}
and OnStartMethod() looks like this:
protected override void OnStart(string[] args)
{
const string keyPath = "HKEY_CURRENT_USER\\Software\\MyKey";
string companyCardNumber = null;
while (companyCardNumber == null || companyCardNumber.Equals(""))
{
companyCardNumber = (string)Registry.GetValue(keyPath, "CompanyCardNumber", null);
if (companyCardNumber != null && !companyCardNumber.Equals(""))
{
break;
}
Debug.WriteLine("company card number in registry is empty or key doesn't exist");
System.Threading.Thread.Sleep(5000);
}
//more code...
}
Now the problem is that when i use DEBUG mode in VS it goes to //more code and program correctly read value from the registy. But when I switch to RELEASE mode and deploy service and then install, it loops in this while and after
companyCardNumber = (string)Registry.GetValue(keyPath, "CompanyCardNumber", null);
companyCardNumer doesn't have any value.
What causes this problem? Do I need any administrative privileges to read values from the registry? It would be weird, because as user I can modify registy. Another thing I noticed is state of service, because most services are launched, but mine is launching (if i can say that). But it's still working but companyCardNumber is empty.

Cannot evaluate expression because a native frame is on top of the call stack

I'm creating a simple window service and when I go to debug I get the error, "Cannot evaluate expression because a native frame is on top of the call stack.". Also, when I build the service in Release and run it just hangs.
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new MyService1() };
ServiceBase.Run(ServicesToRun);
}
Thats all that is in the Program.cs file, where it normally gets hung on the ServiceBase.Run(ServicesToRun) line.
Everything I've been able to find only relates to the expression not being evaluated because the code is optimized or having to deal with asp.net and response.redirect.
Code for the Service.
public TruckRateClearService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
tmrProcess.Enabled = true;
}
protected override void OnCustomCommand(int command)
{
base.OnCustomCommand(command);
if (command == 129)
{
OnStart(null);
}
}
protected override void OnStop()
{
tmrProcess.Enabled = false;
}
private void tmrProcess_Tick(object sender, EventArgs e)
{
tmrProcess.Enabled = false;
try
{
eventLog.WriteEntry("Clearing Truck Rates Start" + DateTime.Now.ToString());
TruckRateClearingAgent.Process();
eventLog.WriteEntry("Clearing Truck Rates Finished" + DateTime.Now.ToString());
}
catch (Exception ex)
{
eventLog.WriteEntry(ex.ToString(), EventLogEntryType.Error);
}
tmrProcess.Enabled = true;
}
internal void Run()
{
tmrProcess_Tick(tmrProcess, null);
}
The Internal Void Run() was added just recent on the suggestion in the comments by Eren Ersönmez. His idea has been very helpful for helping debug my logic until I can figure the rest out.
I was able to get the into the Native call stack and it sits on one location, 76F17094 ret. Now I have no idea what this is but maybe someone else will.
Also, when I start the service and look into attaching it to VS I'm noticing two instances of it. One is the normal .exe and another is a .vshost.exe. When I start other services I only see the .exe file in the Attach to process part of the debugger. Could this be because one is on the v4 Framework ( .vshost .exe service ) and another on the v2 ( single .exe service ) Framework?
I believe I got it working. It seems that the problem lied with the timer I was using. The original timer I was using was a System.Windows.Forms timer. I switched it to System.Timers.Timers and everything started working again. Still cant attach VS to it but I can debug it still by using the Internal Run() method. Thanks for all the help n.n
Your main problem is that you're trying to directly run a windows service exe. Windows services can only be started via Service Control Manager (SCM). In order to be able to debug in VS, I'd recommend something like this:
static void Main()
{
if (Environment.UserInteractive)
{
new MyService1().Run();
Thread.Sleep(Timeout.Infinite);
}
else
{
ServiceBase.Run(new ServiceBase[] { new MyService1() });
}
}
You'd create a MyService1.Run method which spawns a new thread that runs the service loop. Also, you'd call the same Run method from within the MyService1.Onstart.
This scheme runs it as a service when being started by SCM, but treats it like a normal exe when being debugged in VS (or being run directly as an exe outside VS).
The problem
This notification means that the thread is currently executing unmanaged code, and therefore cannot be used to evaluate the expression.
In some situations, you could wait for the call to return to managed code before evaluating the expression. Unfortunately, in this situation, that won't happen until you shut down the service.
An Alternative
You might consider overriding the ServiceBase.OnCustomCommand method and putting a breakpoint there so you can evaluate your expression.
protected override void OnCustomCommand(int command)
{
//Debugger.Break() <- or just put a breakpoint in here.
}
You can invoke the custom command as follows:
c:\>sc control YourServiceName 129
The exception you're seeing means that unmanaged code is throwing an exception, so the .NET debugger can't show you the usual useful details.
What are you doing in MyService1() ? Can you post the code inside it?
Also are you trying to debug the service by just starting it from the environment. That might not work.
I usually write something like this:
static void Main(params string[] args)
{
if (args.Length > 0 && args[0] == "/console")
{
// Run whatever your service calls here
}
else
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[] { new MyService1() };
ServiceBase.Run(ServicesToRun);
}
}
Then in the project properties under the Debug tab enter /console as the command line arguments. You should be able to step into the application and debug it. You can only debug a service by installing it first: http://msdn.microsoft.com/en-us/library/7a50syb3(v=vs.80).aspx

Debugging a Windows Service

I am making a Windows Service and I want to debug it.
This is the error I get when I try to debug it:
Cannot start service from the command line or a debugger. A Windows service must be first installed and then started with the Server Explorer, Windows Services Administrative TOll or the NET start command.
I have already installed my service using InstallUtil, but I am still facing problems.
Also, when I try to attach a process, my service goes into the running mode, it never starts debugging.
EDIT: DO we have to reinstall the Windows Service everytime we make a change or just building it would suffice?
In your OnStart use something like this:
#if DEBUG
if(!System.Diagnostics.Debugger.IsAttached)
System.Diagnostics.Debugger.Launch();
#endif
For the most use cases it's good enough to run the service as console application. To do this, I usually have the following startup code:
private static void Main(string[] args) {
if (Environment.UserInteractive) {
Console.WriteLine("My Service");
Console.WriteLine();
switch (args.FirstOrDefault()) {
case "/install":
ManagedInstallerClass.InstallHelper(new[] {Assembly.GetExecutingAssembly().Location});
break;
case "/uninstall":
ManagedInstallerClass.InstallHelper(new[] {"/u", Assembly.GetExecutingAssembly().Location});
break;
case "/interactive":
using (MyService service = new MyService(new ConsoleLogger())) {
service.Start(args.Skip(1));
Console.ReadLine();
service.Stop();
}
break;
default:
Console.WriteLine("Supported arguments:");
Console.WriteLine(" /install Install the service");
Console.WriteLine(" /uninstall Uninstall the service");
Console.WriteLine(" /interactive Run the service interactively (on the console)");
break;
}
} else {
ServiceBase.Run(new MyService());
}
}
This makes it easy not only to run and debug the service, but it can then also install and uninstall without needing the InstallUtil program.
This question has an excellent answer in making the service a console/service hybrid. See the answer from user marc_s. I don't want to duplicate the answer here.
I, personally for me, found the easiest solution is not change the code, by adding more mess and #if #else directives, but simply:
Compile your service binaries in DEBUG mode
Point installed service to DEBUG binaries
Run service
Use connect to process dialog of VS to connect to your running process
Enjoy.
The good thing on this that you don't change the code so it's exactly the same as your production binaries, which, I think, is kind of important.
Good luck.
One way that I've done it before was to insert a Debugger.Break() in the service on start method. Compile and install the service. When it starts it break and open the debug with dialog, from there you should be able to attach and debug.
The Debugger.Launch method is a good way but I prefer to create a class that does the processing and call it from the service, This can then also be called from a win forms app.
eg:
class ProcessingManager
{
public void Start()
{
//do processing
}
public void Stop()
{
//stop
}
}
then in your service / win forms app just create an instance of the processing class as a member variable and call the method on start and stop. It can be used in the service, or a win forms app with a start and stop button, which I find a lot quicker than attaching the debugger each time because you can set the windows application to start as default and add any breakpoints into the processing manager.
extract from service code:
namespace Service
{
public partial class Service : ServiceBase
{
#region Members
private ProcessingManager m_ProcessingManager = null;
#endregion Members
#region Constructor
/// <summary>
/// Constructor
/// </summary>
public Service()
{
InitializeComponent();
try
{
//Instantiate the processing manager
m_ProcessingManager = new ProcessingManager();
}
catch (Exception ex)
{
ErrorHandler.LogError(ex);
}
}
#endregion Constructor
#region Events
/// <summary>
/// Starts the processing
/// </summary>
/// <param name="args">Parameters</param>
protected override void OnStart(string[] args)
{
try
{
//Start the Processing
m_ProcessingManager.Start();
}
catch (Exception ex)
{
ErrorHandler.LogError(ex);
}
}
/// <summary>
/// Service Stopped
/// </summary>
protected override void OnStop()
{
try
{
//Stop Processing
m_ProcessingManager.Stop();
}
catch (Exception ex)
{
ErrorHandler.LogError(ex);
}
}
#endregion Events
}
}
Try following this guide
EDIT: Personally, I have a console application in the same project that does all the work. I then just have the service run the Main of the console application. It makes debugging easy especially when just developing.
For debugging or testing your service without installing it, make changes in Program.cs like this.
static class Program
{
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new MyService()
};
ServiceBase.Run(ServicesToRun);
}
}
Change it to:
static class Program
{
static void Main()
{
#if(!DEBUG)
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new MyService()
};
ServiceBase.Run(ServicesToRun);
#else
MyService myServ = new MyService();
myServ.Process();
// here Process is my Service function
// that will run when my service onstart is call
// you need to call your own method or function name here instead of Process();
#endif
}
}
What i always do is put a:
#if DEBUG
Thread.Sleep(20000)
#endif
in the OnStart. That gives me 20s to attach.
Quick and easy, just remember to wrap it in an #if DEBUG #endif :)

Categories

Resources