I have an application that runs on my computer and the computers of my colleagues at work. I sometimes push out updates for this application and want the application to detect this automatically (perhaps via database) and shut down and re-open to install the new updates.
I know how I can close an application, but don't know how I can re-open it because when it's not running, I don't know how to execute any code...
ClickOnce handles updating an application very well. I don't see a problem here, if the user finds that the application is not working (because you have made a change server-side, that warrants them to update the client), they will restart the application and be prompted by the ClickOnce update mechanism to say an update is available (if this has been set up), once the application starts again.
The only way you could tell whether the application was due for an update, whilst the application in question is still running, is to poll the ClickOnce deployment file on the server and compare the version number against the current deployment. Not advisable.
Edit:
Another way to ensure that your users always have the most up-to-date version, is to not include a persistent deployment file and make the user always run from the launch page on your website. This would only dish out the latest and greatest version.
How about creating a small update app. When your application detects an update it launches the update app and closes itself. The update app downloads and installs the update and then relaunches the main app and closes itself.
Alternatively if the application can update itself when it opens, why does it need to shutdown? Can't it just release any resources it's using etc and perform the update.
The process you really need to have is something like this:
Application detects an update is required and executes an Update Application and then exits itself
Update application downloads and installs the update
Update application restarts the "main" application
The "Update application" may need administrative privileges to run if you're updating files on a Vista/Windows7 machine due to UAC, so you'd probably want to embed a manifest to help solve that.
To start another process, the code you'll want to execute is System.Diagnostics.Process.Start(), for example:
Process p = new Process();
p.StartInfo.FileName = "C:\\Windows\\System32\cmd.exe";
p.Start();
If you are using ClickOnce (and your tag suggests you are?) then you can configure it so your application checks for updates on start-up.
I had a similar problem, but mine was related to unmanageable memory leak that I couldn't find on an app that has to run 24/7. With the customer I agreed that safe time to restart the app was 03:00AM if the memory consumption was over the defined value.
I tried Application.Restart, but since it seems to use some mechanism that starts new instance while it is already running, I went for another scheme. I used the trick that file system handles persist until process that created them dies. So, from The Application, i dropped the file to the disk, and didn't Dispose() the handle. I used the file to send 'myself' executable and starting directory also (to add flexibility).
Code:
_restartInProgress = true;
string dropFilename = Path.Combine(Application.StartupPath, "restart.dat");
StreamWriter sw = new StreamWriter(new FileStream(dropFilename, FileMode.Create, FileAccess.ReadWrite, FileShare.ReadWrite));
sw.WriteLine(Application.ExecutablePath);
sw.WriteLine(Application.StartupPath);
sw.Flush();
Process.Start(new ProcessStartInfo
{
FileName = Path.Combine(Application.StartupPath, "VideoPhill.Restarter.exe"),
WorkingDirectory = Application.StartupPath,
Arguments = string.Format("\"{0}\"", dropFilename)
});
Close();
Close() at the end would initiate app shutdown, and file handle I used for StreamWriter here would be held open until process really dies. Then...
Restarter.exe comes into action. It TRIES to read the file in exclusive mode, preventing it to gain access until main app wasn't dead, then starts main app, deletes the file and exists. I guess that it can't be simpler:
static void Main(string[] args)
{
string filename = args[0];
DateTime start = DateTime.Now;
bool done = false;
while ((DateTime.Now - start).TotalSeconds < 30 && !done)
{
try
{
StreamReader sr = new StreamReader(new FileStream(filename, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite));
string[] runData = new string[2];
runData[0] = sr.ReadLine();
runData[1] = sr.ReadLine();
Thread.Sleep(1000);
Process.Start(new ProcessStartInfo { FileName = runData[0], WorkingDirectory = runData[1] });
sr.Dispose();
File.Delete(filename);
done = true;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Thread.Sleep(1000);
}
}
Related
I have an app that runs DirectX 11 that plays a scene and generates an mp4.
I am trying to launch it through Process.Start so that I can manage the process and force it to timeout if it crashed or doesn't close correctly.
When I test the function on my local Win10 machine it works perfectly, and when I run it through CL or a .BAT file on the WinServ2012R2 machine it works perfectly too.
However when I try to run it through the Process.Start function on the server machine it fails to open DirectX
var startInfo = new System.Diagnostics.ProcessStartInfo($"{AppLocation}", $"{Parameters}")
{
WindowStyle = System.Diagnostics.ProcessWindowStyle.Normal,
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = false,
WorkingDirectory = $"{DirectoryName}",
Verb = "runas"
};
var loop = 0;
while (!System.IO.File.Exists($"{FileLocation}"))
{
loop++;
using (var p = System.Diagnostics.Process.Start(startInfo))
{
Logger.Info("Process Running....");
if (!p.WaitForExit(300000))
{
p.Kill();
}
if (loop >= 5)
break;
}
}
Edit: The DirectX error is: DXGI_ERROR_NOT_CURRENTLY_AVAILABLE
0x887A0022
It’s probably something about the environment.
If the parent process is a normal Win32 console or GUI app running inside a desktop of that server, put something like Sleep( 60000 ); in the first line of your main() or WinMain function, and use Process Explorer to find differences between manual launch which works, and programmatic launch which fails. Check the “Image”, “Security” and “Environment” tabs of the processes.
If the parent process is a system service, it’s more complicated. Services generally run under another user account and you gonna need some setup to allow the service, or a child process launched by the service, to access GPU.
Another possible reason is anti-virus or anti-malware breaking things.
P.S. Note you have minor bugs in your code.
One thing, when you detect timeouts, Process.Kill is asynchronous, you need to wait afterwards.
Another one, you specifying RedirectStandardOutput = true but you don't consume that stream. If the child process prints a lot of text it will eventually stall waiting for the parent process to consume the data buffered in that pipe. If you don’t care about output, don’t redirect these streams. If you do care, redirect and consume the data as soon as it printed, either on a separate thread or with async/await.
link app with windows process so that when user terminated or end the process it says used by another process and also need to insert it into system file like shutdown file using c sharp so that my app never end or terminates
i tried that material but not usefull
this.ShowInTaskbar = false;
I also tried that code in click:
WindowsImpersonationContext ctx = null;
if (!WindowsIdentity.GetCurrent().IsSystem)
{
ctx = WindowsIdentity.Impersonate(System.IntPtr.Zero);
}
string thisuser = WindowsIdentity.GetCurrent().Name;
But have a look at image it is still present in process, what I want is that my process never stops.
what I want is that my process never stops.
To ensure that your process is always running and is started when Windows boots it's easiest to create a windows service instead. It will probably still show up somewhere in task manager and could be killed manually by the user. But windows will try to keep it running.
How to create a service:
https://msdn.microsoft.com/en-us/library/zt39148a(v=vs.110).aspx
And if you need other programs to communicate with your service I find it easy to use a WCF service instead.
https://msdn.microsoft.com/en-us/library/bb386386.aspx
i'm trying to find the most generic way to understand if a file is being "used" by any application.
this is true also for applications like notepad/onenote/notepad++ (which don't lock the file).
i'm handling the opening of the files through my app (using Process.Start), and i need to delete the file when the user finishes working on it.
what i managed to come up until now is the following:
"MSWord like applications" - which has a lock on the file constantly, thus - i know that it's currently being used - and the delete will fail.
"Notepad/MSPaint like application" - which opens a file in a distinct process, and have a lock on the hosting folder - i can check who's locking the folder, and compare the PID to the PID i received when opening the file
"OneNote" like applications - which is problematic as when i open the file - i get different PID (i guess that the process opens, and then it sends the file to the single main onenote process). BUT - i can then check it by name and not PID (not the best, but ok) - as i found out onenote also has some kind of lock on the directory.
the only issue here is that i'll have to wait until the process is closed, then delete the file.
i'm totally lost about "Notepad++" applications or similar to them.
notepad++ doesn't have any lock on the file or folder, and it uses single process.
i 'm not sure how to handle this scenario, when doing Process.Start i don't even have a name of the process. (i can check the registry maybe to see who's the default app that opens the file)...
so, any other directions?
thanks!
== EDIT ==
well, currently i've decided about the following logic, unless there's a flaw in it:
When opening an appliction (Process.Start) - save the PID and the application path. then wait 1 second (or something else i'll think about) - try to get the process by PID - if it exists, this is indeed the PID i want to wait on. if not, then i'll go by process path/name
check if the file is locked by regular lock (by any application) - if so, then don't delete the file yet.
if the file is not locked, check who's locking the folder - then compare it to the PID i have. if the PID doesn't exist (and it's indeed the PID i want to wait on) - then delete the file. if it exists - don't delete the file.
If when starting the process after 1 second the PID doesn't exist, and no lock on the folder/file - i'll just wait until the process ends
that's the idea i think
I am guessing you are trying to do this,
static void ShowFile(string fileToShow) {
using (Process proc = new Process()) {
ProcessStartInfo psi = new ProcessStartInfo(fileToShow);
psi.UseShellExecute = true;
proc.StartInfo = psi;
proc.Start();
proc.WaitForExit();
}
}
But, maybe you should do this
static void ShowFile(string fileToShow) {
using (Process proc = new Process()) {
ProcessStartInfo psi = new ProcessStartInfo(#"C:\Program Files (x86)\Notepad++\notepad++.exe", "-multiInst " + fileToShow);
psi.UseShellExecute = false;
proc.StartInfo = psi;
proc.Start();
proc.WaitForExit();
}
}
And then when your function returns, you can delete your temp file.
I understand that you might not know if the system already has notepad++ installed and its path, etc. In that case you can try to use the path for notepad.exe which comes with windows.
The thing is, there is no perfect solution to what you are looking. To put it in other words, no file viewer/editor is guaranteed to
Use a specific locking mechanism
Keep handle open to the file or directory containing it
Not communicate using DDE, etc
You can find out the default application registered to open your file, but you don't know if it starts as a single instance or a multi-instance app or they communicate using DDE, etc
I am creating a complex service on Windows 7, which starts off by loading an .exe application. The only way to achieve this was to enable to "Interactive Services Detection" service in services.msc.
As a test application, I added the following code which simply opens the system calculator. It works, however not as intended. I first get the following message when starting the service:
When clicking "View this message", it loads the calculator as it is supposed to, but opens a blue full screen mode, and contains the calculator within it.
My question is basically the following: How can I make the application display automatically, and not have to prompt the user to "view the message", and more importantly, how can I get the application to display normally, rather than in this "interactive services detection" sandbox?
This is the code of my sample service:
public partial class OpenCalculator : ServiceBase
{
public Process process;
public OpenCalculator()
{
this.ServiceName = "Open Calculator";
InitializeComponent();
}
protected override void OnStart(string[] args)
{
start_calc();
}
protected override void OnStop()
{
process.Kill();
}
protected void start_calc()
{
try
{
process = new Process();
process.StartInfo.FileName = #"C:\Windows\system32\calc.exe";
process.StartInfo.CreateNoWindow = true;
process.StartInfo.ErrorDialog = false;
process.StartInfo.RedirectStandardError = true;
process.StartInfo.RedirectStandardInput = true;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.WindowStyle = System.Diagnostics.ProcessWindowStyle.Hidden;
process.Start();
using (StreamWriter writer = File.AppendText("C:\\Users\\scaruana\\Desktop\\test.txt"))
{
writer.WriteLine(process);
}
}
catch (Exception ex)
{
using (StreamWriter writer = File.AppendText("C:\\Users\\scaruana\\Desktop\\test.txt"))
{
writer.WriteLine(ex.Message);
}
}
}
}
Services run in session 0, whose desktop you cannot see. Interactive desktops are hosted in other sessions. So, for instance, the first interactive logon runs in session 1. This means that services cannot directly show UI on an interactive desktop.
In older versions of Windows (XP and earlier), the first interactive logon shared session 0 with services. And so when you enabled the allow service to interact with desktop option in the service control manager, the service could show UI on an interactive desktop. However, all that ended with Vista because it was a security risk.
So, you need to start a new process and specifically force it onto the desktop of an logged in interactive user. That is not easy to do. This MSDN blog article covers your options: Launching an interactive process from Windows Service in Windows Vista and later.
Now, that's how you go about starting a new process from a service, and putting the new process onto an interactive desktop. But that is almost certainly the wrong way to solve your problem. As you can see by reading the linked article, doing it that way is complex. The standard solution to your problem is to run an interactive process on the logged in user's desktop. This remains hidden until your service needs to show UI. The service then communicates with the desktop app using your preferred IPC mechanism, and then the desktop app shows the UI.
This question has been the cause of great frustration, and I have finally solved my problem. Yes, I have managed to make a service load a GUI application, even though everyone says that it is impossible. There is a warning though - the "fix" can be considered as exploiting a loophole in Windows, as the code which I used basically passes the Vista and Windows 7 UAC. Essentially, the application is always executed with full rights and bypasses the UAC.
If anyone has this same problem, what you need to do is iterate through a list of logged in users on the PC, and choose to open the UI application in this session (which has the user's desktop), rather than in session 0 where the service is supposed to be running (and which does not have a desktop).
For some people, this might not be a solution as it is not secure. But in my case, security is not a main concern, and I just needed it to work (had to be a service by force).
Hope this helps anyone who has the same problem that I had.
I have been trying to implement something like this, but it will time out on the wait for exit?
My objective is to open the file on the client's machine in notepad. The below code is what i originally had, but just learned taht this will only work on the server ,not the client.
public JsonResult Index()
{
System.Diagnostics.Process proc = new System.Diagnostics.Process();
proc.EnableRaisingEvents = false;
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.FileName = "notepad";
proc.StartInfo.Arguments = #"\\share\test.XML";
proc.Start();
proc.WaitForExit();
}
Is there a way to do this?
All i am trying to do is open the test.xml file on a client's machine.
The code you have there will execute on the server side; not on the client-side. You can't open a file (or execute a program for that matter) on the client machine, from a browser. That would be a major security issue if a browser could do that.
Best thing you can do is either create a hyperlink to the file in the format file:///drive:/file.xml
Your code will start the notepad application and open the test.xml file in correctly
The notepad application will left open till it is close because you are using the WaitForExit method.
The WaitForExit method instructs the Process component to wait indefinitely for the associated process to exit.
Do you really want to use the WaitForExit in your MVC action
Please read the Remarks taken from MSDN for WaitForExit
The WaitForExit() overload is used to make the current thread wait
until the associated process terminates. This method instructs the
Process component to wait an infinite amount of time for the process
and event handlers to exit. This can cause an application to stop
responding. For example, if you call CloseMainWindow for a process
that has a user interface, the request to the operating system to
terminate the associated process might not be handled if the process
is written to never enter its message loop.
Note: In the .NET Framework version 3.5 and earlier versions, the WaitForExit() overload waited for MaxValue milliseconds (approximately
24 days), not indefinitely. Also, previous versions did not wait for
the event handlers to exit if the full MaxValue time was reached.
my weight the same and so I resolved using this
using System.Xml;
XmlTextReader reader = new XmlTextReader(
Server.MapPath("mycompany.xml"));
reader.WhitespaceHandling = WhitespaceHandling.None;
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.Load(reader);
reader.Close();
lbNodes.Items.Add("XML Document");
XmlNode xnod = xmlDoc.DocumentElement;
AddWithChildren(xnod, 1);
the complete example you can see here
http://www.codeproject.com/Articles/4902/Reading-an-XML-file-using-NET