Program update code issue - c#

Hey everyone.
I've developed a simple code to auto-update my program. The way it works is:
Program downloads a remote file that has the version string in it. If the version string is bigger than the program's, auto update initiates.
The program downloads the newest version of the program using a remote link with DownloadAsync.
The program creates a new batch file that kills the current app (The program itself), deletes the current program, and renames the new one to the application's name. Then, it runs the new updated application and deletes itself.
However, I'm facing an issue when the batch file is actually executed. Here is my code:
private void WC_Completed(object sender, AsyncCompletedEventArgs e)
{
StringBuilder Batch = new StringBuilder();
Batch.AppendLine("#echo off");
Batch.AppendLine("taskkill /IM " + Process.GetCurrentProcess().ProcessName + ".exe /F");
Batch.AppendLine("ping localhost > nul");
Batch.AppendLine("del /f " + (char)34 + Application.ExecutablePath + (char)34);
Batch.AppendLine("ren " + (char)34 + Application.StartupPath + #"\update.exe" + (char)34 + " " + Process.GetCurrentProcess().ProcessName + ".exe");
Batch.AppendLine((char)34 + Application.ExecutablePath + (char)34);
Batch.AppendLine("del %0");
File.WriteAllText(Application.StartupPath + #"\update.bat", Batch.ToString(), Encoding.Default);
Process.Start(Application.StartupPath + #"\update.bat");
}
For some reason, it doen't kill the current application, or it just takes too much, and the whole process is going crazy. It just runs the unupdated app because the renaming doesn't work, which causes a loop.
Can you please point out my error? I'm trying to see what's wrong!
Thank you!

There's an easier way to update a program if it consists of one executable file:
Rename a running executable using File.Move to something like my.exe.bak.
Put an updated executable in the place of the old one.
Launch the new copy using Process.Start("my.exe") and exit the old one.
Upon launch test if my.exe.bak exists and try to delete it. You won't succeed first time, but the backup will be deleted eventually.
This way you won't need any .bat trickery.
You can also enchance this algorithm by passing PID (Process ID) of the old instance to the new one through command line arguments and then using Process.GetProcessById(pid).WaitForExit(); to be able to delete my.exe.bak on the first launch and handle update process completion.

Related

C# open file with existing running process using system.diagnostics process

I initially thought that just maybe the process would use the existing process . but . it does not . the result of the following code starts 2 sepearte sessions of the CAD software - I need to open multiple files in one existing session of the CAD software .. I tried this first:
Process.Start(#"C:\Program Files\Autodesk\AutoCAD 2018\acad.exe",
"/product \"C3D\" " + #"C:\folder\1.dwg");
Process.Start(#"C:\Program Files\Autodesk\AutoCAD 2018\acad.exe",
"/product \"C3D\" " + #"C:\folder\2.dwg");
Then I did this, which works ... but I would still prefer to open a file in an existing process ... I guess the only way is to use interop ... but I would need to add an interop for each and every software app
Process.Start(#"C:\Program Files\Autodesk\AutoCAD 2018\acad.exe",
"/product \"C3D\""
+ " " + #"C:\folder\1.dwg"
+ " " + #"C:\folder\2.dwg"
+ " " + #"C:\folder\3.dwg"
);

Can you run an embedded .vbs file from a C# Windows Form?

I have been looking all over but cannot find a definitive answer/solution, or any solution I try fails. I am making a WinFormApp that calls an embedded .vbs file to script a program I use at work. This is what my Project Solution looks currently:
Project Solution
The test.vbs file is set as an embedded resource in its file properties. Here is the different code I have tried to use to run the script from the form:
private void button1_Click(object sender, EventArgs e)
{
string path = Path.Combine(Path.GetTempPath(), "test.vbs");
File.WriteAllBytes(path, Properties.Resources.Test);
Process.Start(path);
string path2 = Path.Combine(Path.GetTempPath(), "test.vbs");
System.Diagnostics.Process.Start(#"cscript //B //Nologo " + path2 + "");
}
Here is what my test.vbs file is:
dim thing
thing = "It did something!"
Wscript.Echo thing
The test.vbs file is primarily meant as a proof of concept to make sure I can at least run a .vbs file. The test.vbs file compiles fine outside of the WinForm.
Most of the time I receive 'The system cannot find the file specified' as the error message. I have read that it may be easier to just convert my .vbs file to C# but they are GUI scripting for SAP and all of SAP's libraries seem primarily set us for .vbs files.
I am still relatively new to C# so I may be way off with this so please tell me if I am. If there is another question that fixes my issue please link it.
Thank you for your time!
EDIT #1 Code compiles and seems to run.
string path2 = Path.Combine(Path.GetTempPath(), "test.vbs");
var startInfo = new ProcessStartInfo
{
WorkingDirectory = "" + path2 + "",
FileName = #"cscript"
};
However the script does not seem to be outputting to the cmd...
Your process start command is incorrect. Here is the correct version
System.Diagnostics.Process.Start("cscript", #"//B //Nologo " + path2 + "");

Set up Scheuled Task to create Excel File and send email with attachment in C# Console application

I had a problem where a scheduled task would not send out an email with an attachment in a C# console application. It took me a long time to figure out the solution (it is working now), so I wanted to share what the two issues were so others can find the solution easily.
There were two problems:
1) When saving the file to the directory I could not use a relative directory like:
DirectoryInfo currentDir = new DirectoryInfo(Directory.GetCurrentDirectory());
attachmentPath = currentDir.Parent.Parent.FullName + #"\Reports\" + startDate.ToString("yyyy.MM.dd") + " - " + endDate.ToString("yyyy.MM.dd") + ".xlsx";
I had to explicitly set the directory like:
attachmentPath = #"E:\reports\Excel Automated Reports\WebEx Daily Report\ExcelReportAutomation\Reports\" + startDate.ToString("yyyy.MM.dd") + " - " + endDate.ToString("yyyy.MM.dd") + ".xlsx";
After, I did that the file was being created and saved but still was not emailing it out. If I sent out an email without an attachment then the email would go out. The way to fix this issue is by setting the Start in (optional) option in the edit action for the scheduled task.
I repeat this is not a question but I am trying to lay out a solution for people who come across the same issue.

Directory.Move(): Access to Path is Denied

I'm writing this Windows Form Application in Visual Studio 2010 using C#.
There is a Execute button on the form, the user will hit the button, the program will generate some files and are stored in the Output folder (which is created by the program using Directory.CreateDirectory())
I want to create an Archive folder to save the output files from previous runs.
In the beginning of each run, I try to move the existing Output folder to the Archive folder, then create a new Output folder. Below is the function I ran to move directory.
static void moveToArchive()
{
if (!Directory.Exists("Archive")) Directory.CreateDirectory("Archive");
string timestamp = DateTime.Now.ToString("yyyyMMddHHmms");
try
{
Directory.Move("Output", "Archive\\" + timestamp);
}
catch(Exception e)
{
Console.WriteLine("Can not move folder: " + e.Message);
}
}
The problem I ran into confuses me a lot...
There are some times that I can successfully move the Output folder to archive, but sometimes it fails.
The error message I got from catching the exception is Access to path 'Output' is denied.
I have checked that all the files in the Output folder are not in use. I don't understand how access is denied sometimes and not all the times.
Can someone explain to me and show me how to resolve the problem?
--Edit--
After HansPassant comment, I modified the function a little to get the current directory and use the full path. However, I'm still having the same issue.
The function now looks like this:
static void moveToArchive()
{
string currentDir = Environment.CurrentDirectory;
Console.WriteLine("Current Directory = " + currentDir);
if (!Directory.Exists(currentDir + "\\Archive")) Directory.CreateDirectory(currentDir + "\\Archive");
string timestamp = DateTime.Now.ToString("yyyyMMddHHmms");
try
{
Directory.Move(currentDir + "\\Output", currentDir + "\\Archive\\" + timestamp);
}
catch(Exception e)
{
Console.WriteLine("Can not move folder: " + e.Message);
}
}
I printed out the current directory and it is just as what I was expecting, and I'm still having trouble using full path. Access to path 'C:\Users\Me\Desktop\FormApp\Output' is denied.
--Edit--
Thank you everyone for answering and commenting.
I think some of you miss this part so I'm going stress it a bit more.
The Directory.Move() sometimes work and sometimes fails.
When the function succeed, there was no problem. Output folder is moved to Archive
When the function fails, the exception message I got was Access to path denied.
Thank you all for the replies and help. I have figured out what the issue was.
It is because there was a file that's not completely closed.
I was checking the files that were generated, and missed the files the program was reading from.
All files that were generated were closed completely. It was one file I used StreamReader to open but didn't close. I modified the code and am now not having problem, so I figure that's were the issue was.
Thanks for all the comments and answers, that definitely help me with thinking and figuring out the problem.
See http://windowsxp.mvps.org/processlock.htm
Sometimes, you try to move or delete a file or folder and receive access violation or file in use - errors. To successfully delete a file, you will need to identify the process which has locked the file. You need to exit the process first and then delete the particular file. To know which process has locked a file, you may use one of the methods discussed in this article.
Using Process Explorer - download from http://download.sysinternals.com/files/ProcessExplorer.zip
Process Explorer shows you information about which handles and DLLs processes have opened or loaded.
Download Process Explorer from Microsoft site and run the program.
Click the Find menu, and choose Find Handle or DLL...
Type the file name (name of the file which is locked by some process.)
After typing the search phrase, click the Search button
You should see the list of applications which are accessing the file.
I bumped on the same problem recently. Using PE I'd figured that only process using that particular directory was explorer.exe. I'd opened few windows with explorer, one pointing to parent directory of one that I was about to move.
It appeared, that after I visited that sub-folder and then returned (even to root level!) the handle was still being kept by explorer, so C# was not able to modify it in any way (changing flags, attributes etc.).
I had to kill that explorer window in order to made C# operate properly.
File.SetAttributes(Application.dataPath + "/script", FileAttributes.Normal);
Directory.Move(Application.dataPath + "/script", Application.dataPath + "/../script");
This fixed my problem.
Try this:
If this does not solve, maybe check/change the antivirus, or the some other program is locking some file in or the folder.
static object moveLocker = new object();
static void moveToArchive()
{
lock (moveLocker)
{
System.Threading.Thread.Sleep(2000); // Give sometime to ensure all file are closed.
//Environment.CurrentDirectory = System.AppDomain.CurrentDomain.BaseDirectory;
string applicationPath = System.AppDomain.CurrentDomain.BaseDirectory;
string archiveBaseDirectoryPath = System.IO.Path.Combine(applicationPath, "Archive");
if (!Directory.Exists(archiveBaseDirectoryPath)) Directory.CreateDirectory(archiveBaseDirectoryPath);
String timestamp = DateTime.Now.ToString("yyyyMMddHHmms");
String outputDirectory = System.IO.Path.Combine(Environment.CurrentDirectory, "Output");
String destinationTS = System.IO.Path.Combine(archiveBaseDirectoryPath, timestamp);
try
{
Directory.Move(outputDirectory, destinationTS);
}
catch (Exception ex)
{
Console.WriteLine("Can not move folder " + outputDirectory + " to: " + destinationTS + "\n" + ex.Message);
}
}
}
I had the same problem, it failed sometimes but not all the time. I thought I'd wrap it in a Try Catch block and present the user with an Access Denied message and once I wrapped it in the Try Catch block it stopped failing. I can't explain why.
If existingFile.FileName <> newFileName Then
Dim dir As New IO.DirectoryInfo(existingFile.FilePath)
Dim path As String = System.IO.Path.GetDirectoryName(dir.FullName)
newFileName = path & "\" & newFileName
File.SetAttributes(existingFile.FilePath, FileAttributes.Normal)
Try
IO.File.Move(existingFile.FilePath, newFileName)
Catch ex As Exception
End Try
End If
I had a similar problem. Renamed many directories in a loop when following the certain template. From time to time the program crashed on different directories. It helped to add a sleep thread before Directory.Move. I need to create some delay.
But it slows down the copying process.
foreach (var currentFullDirPath in Directory.GetDirectories(startTargetFullDirectory, "*", SearchOption.AllDirectories))
{
var shortCurrentFolderName = new DirectoryInfo(currentFullDirPath).Name.ToLower();
if (shortCurrentFolderName.Contains(shortSourceDirectoryName))
{
// Add Thread.Sleep(1000);
Thread.Sleep(1000);
var newFullDirName = ...;
Directory.Move(currentFullDirPath, newFullDirName);
}
}

Alternatives ways to getting the properties of the file?

Background:
I have a file monitoring service that watches for changes in the files on the local system using the FileSystemWatcher class and i am handling for events like Created,Deleted,Renamed. When these events are triggered,I would simply want to GET THE PROPERTIES OF THE FILE such as FileName,FileSize,CreationTime,LastAccessTime,LastWriteTime using the FileSystemInfo class.
Problem:
While this service is running, I am unable to uninstall some programs for example (Microsoft Security Essentials). I have a feeling that these service is HANGING ON TO THE RESOURCES of the files marked for deletion because I can only uninstall those programs if only this service is running.
My Question is how can I GET THE PROPERTIES OF THE FILE (as specified above) in an ALTERNATIVE & efficient way without hanging on to the resources of the file ?
Here is my code using the FileSystemInfo
public void OnCreate/OnRenamed(object source, FileSystemEventArgs e)
{ FileInfo file = new FileInfo(e.FullPath);
String output = "<Event><TimeStamp>" + currentTime + "</TimeStamp>";
output += "<Name>" + action + "</Name>";
output += "<Properties><FileName>" + file.Name + "</FileName>";
output += "<FullPath>" + file.FullName + "</FullPath>";
output += "<FileSize>" + file.Length + "</FileSize>";
output += "<CreationTime>" + String.Format("{0:yyyyMMdd-HHmmss.fff}", file.CreationTime) + "</CreationTime>";
output += "<LastAccess>" + String.Format("{0:yyyyMMdd-HHmmss.fff}", file.LastAccessTime) + "</LastAccess>";
output += "<LastWriteTime>" + String.Format("{0:yyyyMMdd-HHmmss.fff}", file.LastWriteTime = DateTime.Now) + "</LastWriteTime></Properties></Event>";
}
Sincerely,
Derek
Using FileSystemInfo will not normally 'hang on' to these files. You have to first figure out what exactly is causing other programs to stuck during uninstallation. Use ProcessMonitor to see what files are being accessed during uninstallation. The tool is pretty self explanatory, you need to filter on file system activity. Read this or google around.
Try to experiment by taking out one thing at a time. I assume these programs get uninstalled successfully when your service is not running. This proves that it is indeed your service that is causing issues. First comment your FileSystemInfo code. See if the problem goes away. Then comment out FileSystemWatcher and see if it helps.
Update: looks like this is offending line:
file.LastWriteTime = DateTime.Now
Try to comment this assignement and see if it solves the problem:
file.LastWriteTime /* = DateTime.Now */
Was this a typo or you really need to write LastWriteTime?
What you could do is every interval check for LastAccessTime and LastWriteTime and do some quick math based on the interval and you can determine if the file was last accessed or modified within the interval time. If it was, do what you have to do. Just an idea...

Categories

Resources