I've been trying to create an updater app for my .NET application that gets called when an update is detected using a text file that includes the version info. I've created the said updater but it has some problems. When the file is downloaded, it seems like the anti virus software corrupts the file and it can't be opened. Sometimes the updater doesn't run at all and throws an exception ("The underlying connection was closed: The connection was closed unexpectedly.") which seems to also be caused by the local anti virus software. I figured maybe I could download the file in binary format and create the executable locally, but I am not completely sure on how I would do that (or if it would even work). I am still very much a beginner in a lot of areas. So my question is.. how can I efficiently download an update for my application without triggering the anti- virus?
My code:
public Updater()
{
InitializeComponent();
DownloadInfo.RemoteURI = "http://mywebserver.com/Application.exe";
DownloadInfo.NewExecutableName = "update.exe";
DownloadInfo.ExecutableName = "Application.exe";
DownloadInfo.LocDest = AppDomain.CurrentDomain.BaseDirectory;
InvokeUpdate();
}
private void InvokeUpdate()
{
Thread thr = new Thread(() => GetUpdate());
thr.Start();
}
private void GetUpdate()
{
Process[] proc = Process.GetProcessesByName("Application");
if (proc.Length != 0)
proc[0].Kill();
Util.DownloadFile(new Uri(DownloadInfo.RemoteURI), DownloadInfo.LocDest + DownloadInfo.NewExecutableName);
if (File.Exists(DownloadInfo.LocDest + DownloadInfo.ExecutableName))
File.Replace(DownloadInfo.LocDest + DownloadInfo.NewExecutableName, DownloadInfo.LocDest + DownloadInfo.ExecutableName, DownloadInfo.LocDest + "backup.exe");
else
File.Move(DownloadInfo.LocDest + DownloadInfo.NewExecutableName, DownloadInfo.LocDest + DownloadInfo.ExecutableName);
try
{
File.Delete(DownloadInfo.LocDest + "backup.exe");
}
catch { }
try
{
Process.Start(DownloadInfo.LocDest + DownloadInfo.ExecutableName);
}
catch { };
Invoke((MethodInvoker)(() => this.Close()));
}
And my DownloadFile method from my util class..
public static void DownloadFile(Uri remoteURI, string localDest)
{
try
{
using (WebClient webclient = new WebClient())
{
webclient.DownloadFile(remoteURI, localDest);
}
}
catch { }
}
Related
I'm relatively new to software development for the Hololens 2 and have a pretty big problem I've been messing around with for a long time and I'm slowly running out of ideas.
My project looks like this. I've written a Unity application to capture data and store it in a database (sqlite). A Xamarin.Forms UWP application is supposed to take the data from the database and use it to paint charts for better visualisation. The big problem is, both apps need to be able to access the same database on the Hololens 2. I thought that I could be the database on a usb stick and both apps could access the usb stick. In the Xamarin app and in the Unity app "removable storage" is enabled. In the Xamarin App I have made the file extension known under Appmanifest declaration. I am trying to get the connection with the following commands:
namespace ARScoliosis.XamarinApp.UWP.Services
{
public class DatabasePath : IDatabasePath
{
public async Task<string> GetLocalFilePath()
{
var messageDialog = new MessageDialog("No Usb connection has been found.");
StorageFolder externalDevices = KnownFolders.RemovableDevices;
if(externalDevices == null)
{
messageDialog.Commands.Add(new UICommand("No Devices", null));
}
StorageFolder usbStick = (await externalDevices.GetFoldersAsync()).FirstOrDefault(); <---According to debugging it stops here and jumps to optionsBuilder.UseSqlite($"Filename={databasePath}");
if (usbStick == null)
{
messageDialog.Commands.Add(new UICommand("No UsbStick", null));
}
var usbStickFolder = await usbStick.CreateFolderAsync("DB", CreationCollisionOption.OpenIfExists);
if (usbStickFolder == null)
{
messageDialog.Commands.Add(new UICommand("No Folder", null));
}
var file = await usbStickFolder.CreateFileAsync("Database.db", CreationCollisionOption.OpenIfExists);
if(file == null)
{
messageDialog.Commands.Add(new UICommand("No File", null));
}
//var success = await Launcher.LaunchFileAsync(file);
return file.ToString();
}
My dbcontext file looks something like this:
namespace XamarinApp.Authentication
{
public partial class DBContext : DbContext
{
public DBContext()
{
this.Database.EnsureCreated(); <--- Microsoft.Data.Sqlite.SqliteException: "SQLite Error 14: 'unable to open database file'."
this.Database.Migrate();
}
public virtual DbSet<ItemData> ItemDatas { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
var databasePath = DependencyService.Get<IDatabasePath>().GetLocalFilePath();
optionsBuilder.UseSqlite($"Filename={databasePath}");
}
}
namespace XamarinApp.Helpers
{
public interface IDatabasePath
{
Task<string> GetLocalFilePath();
}
}
Unfortunately this code does not find the Usb stick on the Hololens, i think. When I look in file explorer, I see the stick with all its data. In the Unity App, the stick is also not found, although I use the same code here, only slightly modified.
Does anyone know where my error lies, why I can't access the USB stick with either of the two apps? Has anyone tried something similar and knows how to do it?
i would like to thank you in advance for your help.
Thank you very much.
****Hi Hernando - MSFT,
Please excuse my late reply. i had somehow forgotten. I have found a way where I can find my database on the usb stick.
public static async Task<string> GetUsbStick()
{
StorageFolder UsbDrive = (await Windows.Storage.KnownFolders.RemovableDevices.GetFoldersAsync()).FirstOrDefault();
if (UsbDrive == null)
{
throw new InvalidOperationException("Usb Drive Not Found");
}
else
{
IReadOnlyList<StorageFile> FileList = await UsbDrive.GetFilesAsync();
var Path = UsbDrive.Path.Replace('\\','/');
foreach (StorageFile File in FileList)
{
var DBFound = File.Name.Contains("test.db");
if (DBFound == true)
{
return Path + File.Name;
}
}
throw new InvalidOperationException("DataBaseNotFound");
}
}
There I get the exact path for the database output. Only that somehow brings nothing. I cannot open it in the next step. "Sqlite cant open database" it says.
public static async Task<int> Init()
{
try
{
DatabasePath = await GetUsbStick();
StrConnDatabase = "Data Source" + "=" + DatabasePath + ";Mode=ReadWrite;";
}
catch (Exception io)
{
IsInit = false;
throw new InvalidOperationException(io.Message);
}
finally
{
//Try to Open Database to Read
using (var db = new Microsoft.Data.Sqlite.SqliteConnection(StrConnDatabase))
{
try
{
db.Open(); //<- here it breaks off
db.Close();
IsInit = true;
}
catch (Exception io)
{
throw new InvalidOperationException(io.Message);
}
}
}
return 1; // Succes
}
What could be the reason that this does not work?
is there a way to create a working copy within the app, which is then written back to the usb stick?
KnownFolders.RemovableDevices doesn't be supported on the HoloLens, for more information please see:Known folders. It is recommended to take a try at File pickers to pick one file manually.
I want the embedded GeckoFx 60 to download a file and then open it with the default app.
By default it seems like GeckoFx does not do anything when the client requests to download a file.
To handle the download request I enabled an event handler:
LauncherDialog.Download += LauncherDialog_Download;
Then I found two possibilities to download or open a file via the HelperAppLauncher.
This one saves the requested file to a temp folder and opens it:
private void LauncherDialog_Download(object sender, LauncherDialogEvent e)
{
// direct open, file will be stored in C:\Users\Username\AppData\Local\Temp\
e.HelperAppLauncher.LaunchWithApplication(null, false);
}
I did not find a way to configure the save path. This other possible solution allows me to set the save path myself:
private void LauncherDialog_Download(object sender, LauncherDialogEvent e)
{
nsILocalFileWin objTarget = Xpcom.CreateInstance<nsILocalFileWin>("#mozilla.org/file/local;1");
var downloadPath = #Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments) + "\\CustomFolder\\" + e.Filename;
using (nsAString tmp = new nsAString(downloadPath))
{
objTarget.InitWithPath(tmp);
}
e.HelperAppLauncher.SaveToDisk(objTarget, false);
Task.Run(() =>
{
Thread.Sleep(3000);
System.Diagnostics.Process.Start(downloadPath);
});
}
That Task.Run() works, but is quite ugly and error prone. I could not find a better solution though. I tried adding a WebProgressListener like this:
var webProgressListener = new WebProgressListener();
webProgressListener.OnStatusChangeCallback+= OnStatusChangeCallback;
e.HelperAppLauncher.SetWebProgressListener(webProgressListener);
webProgressListener.IsListening is true, but my method OnStatusChangeCallback is never called. Am I doing something wrong? Is there a newer way?
How can I get notified that the download is completed?
Or how do I set the path for LaunchWithApplication?
Not the best solution but here is my solution :
Task.Run(() =>
{
long sizefirst = 0;
while (true)
{
Thread.Sleep(1000);
if (File.Exists(downloadPath))
{
if (sizefirst == 0)
{
sizefirst = new FileInfo(downloadPath).Length;
continue;
}
long len_now = new FileInfo(downloadPath).Length;
if (len_now > sizefirst)
{
sizefirst = len_now;
continue;
}
else
{
System.Diagnostics.Process.Start(downloadPath);
break;
}
}
}
});
IDE: VS 2010, Windows service .net 4.0
I created a simple windows service, and tested this service with this code:
protected override void OnStart(string[] args)
{
using (System.IO.StreamWriter file = new System.IO.StreamWriter(#"F:\22Yardz_Pro\" + "error.txt", true))
{
file.WriteLine("Service is working \n");
}
//ReceiveMsmqMessage();
}
here in installer I have set
serviceProcessInstaller1. Account = Local System
Then I have changed my code to
** protected override void OnStart(string[] args)
{
using (System.IO.StreamWriter file = new System.IO.StreamWriter(#"F:\MyProj\" + "error.txt", true))
{
file.WriteLine("Service is working \n");
}
ReceiveMsmqMessage();
}
private static void ReceiveMsmqMessage()
{
//string MsmqPath = System.Configuration.ConfigurationManager.AppSettings["MsmqPath"];
MessageQueue queue = new MessageQueue(#".\Private$\MyProjQ");
System.Messaging.Message myMessage = queue.Receive();
myMessage.Formatter = new XmlMessageFormatter(new String[] { "System.String,mscorlib" });
string message = (myMessage.Body.ToString());
string labelName = myMessage.Label;
using (System.IO.StreamWriter file = new System.IO.StreamWriter(#"F:\MyProj\" + "error.txt", true))
{
file.WriteLine("Service started " + message + " \n");
}
}**
Can you tell me why my msmq code is not working, I have tested sapratly this code in working fine in winForms project also this is working in debugging mode but When I install service using cmd and after going in services.msc, when I start this service I am getting error
The _MsmqTesting service on local computer has started and then stopped. Some services stop automatically if there are not in use by other services or programs
Can you suggest me what mistake I am doing??
Finally It worked, I put my code in Try catch block, and In catch block I have written the exception message in txt File, So got to know that my queue was not accessible for Local or system user, so I changed my queue accessibility and it worked.
I am using visual studio 2010 and I am having a .DWG file which I want to open in autocad. Till now I have used this.
Process p = new Process();
ProcessStartInfo s = new ProcessStartInfo("D:/Test File/" + fileName);
p.StartInfo = s;
p.Start();
But what I want is to close the file inside the Autocad but not the autocad itself. (Means atocad.exe should be kept running).
Till now I hve used this but its closing the acad.exe not the file.
foreach (Process Proc in Process.GetProcesses())
{
if (Proc.ProcessName.Equals("acad"))
{
Proc.CloseMainWindow();
Proc.Kill();
}
}
Take the Autocad .NET libraries from Autodesk Sites (http://usa.autodesk.com/adsk/servlet/index?id=773204&siteID=123112)
Then you will be able to use Application and Document classes.
They will give you full control over opening and closing documents within the application.
You can find many articles on that, and can ask further questions.
AutoCAD does have an api. there are 4 assemblys. Two for in-process and two for COM.
inprocess :
acdbmgd.dll
acmgd.dll
COMInterop :
Autodesk.Autocad.Interop.dll
Autodesk.Autocad.Interop.Common.dll
this is a method that will open a new instance of AutoCAD or it will connect to an existing running instance of AutoCAD.
you will need to load these .dlls into your project references.
using Autodesk.AutoCAD.Interop;
using Autodesk.AutoCAD.Interop.Common;
namespace YourNameSpace {
public class YourClass {
AcadApplication AcApp;
private const string progID = "AutoCAD.Application.18.2";// this is AutoCAD 2012 program id
private string profileName = "<<Unnamed Profile>>";
private const string acadPath = #"C:\Program Files\Autodesk\AutoCAD 2012 - English\acad.exe";
public void GetAcApp()
{
try
{
AcApp = (AcadApplication)Marshal.GetActiveObject(progID);
} catch {
try {
var acadProcess = new Process();
acadProcess.StartInfo.Arguments = string.Format("/nologo /p \"{0}\"", profileName);
acadProcess.StartInfo.FileName = (#acadPath);
acadProcess.Start();
while(AcApp == null)
{
try { AcApp = (AcadApplication)Marshal.GetActiveObject(progID); }
catch { }
}
} catch(COMException) {
MessageBox.Show(String.Format("Cannot create object of type \"{0}\"",progID));
}
}
try {
int i = 0;
var appState = AcApp.GetAcadState();
while (!appState.IsQuiescent)
{
if(i == 120)
{
Application.Exit();
}
// Wait .25s
Thread.Sleep(250);
i++;
}
if(AcApp != null){
// set visibility
AcApp.Visible = true;
}
} catch (COMException err) {
if(err.ErrorCode.ToString() == "-2147417846"){
Thread.Sleep(5000);
}
}
}
}
}
closeing it is as simple as
Application.Exit();
and forgive the code. its atrocious, this was one of my first methods when i just started developing...
I doubt you will be able to do this unless AutoCAD has an API that you can hook into and ask it to close the file for you.
Your c# app can only do things to the process (acad.exe) , it doesn't have access to the internal operations of that process.
Also, you shouldn't use Kill unless the process has become unresponsive and certainly not immediately after CloseMainWindow.
CloseMainWindow is the polite way to ask an application to close itself. Kill is like pulling the power lead from the socket. You aren't giving it the chance to clean up after itself and exit cleanly.
There is one other possibility - this will only work if your C# code is running on the same machine as the AutoCAD process and it is not really recommended, but, if you are really stuck and are prepared to put up with the hassle of window switching you can send key strokes to an application using the SendKeys command.
MSDN articles here:
http://msdn.microsoft.com/EN-US/library/ms171548(v=VS.110,d=hv.2).aspx
http://msdn.microsoft.com/en-us/library/system.windows.forms.sendkeys.send.aspx
Using this you could send the key strokes to simulate the user using the menu commands to close the file.
To perform the closing of file, best way out is to follow the steps at this ObjectARX SDK for c# and change the following code with the below code.
[CommandMethod("CD", CommandFlags.Session)]
static public void CloseDocuments()
{
DocumentCollection docs = Application.DocumentManager;
foreach (Document doc in docs)
{
// First cancel any running command
if (doc.CommandInProgress != "" &&
doc.CommandInProgress != "CD")
{
AcadDocument oDoc =
(AcadDocument)doc.AcadDocument;
oDoc.SendCommand("\x03\x03");
}
if (doc.IsReadOnly)
{
doc.CloseAndDiscard();
}
else
{
// Activate the document, so we can check DBMOD
if (docs.MdiActiveDocument != doc)
{
docs.MdiActiveDocument = doc;
}
int isModified =
System.Convert.ToInt32(
Application.GetSystemVariable("DBMOD")
);
// No need to save if not modified
if (isModified == 0)
{
doc.CloseAndDiscard();
}
else
{
// This may create documents in strange places
doc.CloseAndSave(doc.Name);
}
}
}
I am monitoroing a folder using FileSystemWatcher and deleting the files created under the folder. But my application is throwing me an exception:
File is being used by another application
ifsXmlFileWatcher.Path = "D:\\";
ifsXmlFileWatcher.IncludeSubdirectories = false;
ifsXmlFileWatcher.EnableRaisingEvents = true;
ifsXmlFileWatcher.Created += new FileSystemEventHandler(IfsFileUpload);
private void IfsFileUpload(object sender, System.IO.FileSystemEventArgs e)
{
try
{
{
File.Delete(e.FullPath);
}
}
catch (Exception exp)
{
MessageBox.Show(exp.Message);
}
}
What might be the problem?
I guess it's a timing problem. The FileSystemWatcher fires it's Created event immediately when the file was created. This does not mean that all content is written to the file and it is closed again. So it's just accessed by the process who created it because this process has not finished writing to it yet.
TO delete it you have to wait until writing has finished.
Problem as you know "File is being used by another application".
So it may be your own application using it or some other application in your environment using it. Possible solution can be
You can keep trying deleting it certain number of times i try here as 5 times and then give up/write event somewhere or show message. I posted similar answer here where someone needs to make sure file copied is success How to know that File.Copy succeeded?
private void IfsFileUpload(object sender, System.IO.FileSystemEventArgs e)
{
bool done = false;
string file = e.FullPath;
int i = 0;
while (i < 5)
{
try
{
System.IO.File.Delete(file);
i = 5;
done = true;
}
catch (Exception exp)
{
System.Diagnostics.Trace.WriteLine("File trouble " + exp.Message);
System.Threading.Thread.Sleep(1000);
i++;
}
}
if (!done)
MessageBox.Show("Failed to delte file " + file);
}