Manual check for updates with WPF ClickOnce - c#

I do not want to used the default behavior of ClickOnce, which presents a dialog window, checking for updates, I want to check for update manually
After search on the internet I found:
try
{
var deploy = ApplicationDeployment.CurrentDeployment;
if (deploy.CheckForUpdate())
MessageBox.Show("There is a new update");
else
MessageBox.Show("You using the latest version");
}
catch (Exception e2)
{
MessageBox.Show(e2.ToString());
}
When I install the application and want to check for update I got the error:
system.deployment.application.trustnotgrantedexception: user has refused to grant required permissions to the application
Could you help please.
Thanks in advance.

Right Click on your project. Select Properties. Then go to publish Tab. Click updates. Then uncheck "The application should check for updates".
I'm not really sure why you are getting that error, but I'm also using the same approach. Checking manually for updates. But my application is deployed on a server. I have this timer that checks for new updates every 15 mins.
Here's how I do it.
private void InstallUpdateSyncWithInfo()
{
if (!isNewUpdateMessageShown)
{
try
{
if (ApplicationDeployment.IsNetworkDeployed)
{
ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
ad.UpdateCompleted += new AsyncCompletedEventHandler(ad_UpdateCompleted);
//ad_UpdateCompleted is a private method which handles what happens after the update is done
UpdateCheckInfo info = ad.CheckForDetailedUpdate();
if (info.UpdateAvailable)
{
//You can create a dialog or message that prompts the user that there's an update. Make sure the user knows that your are updating the application.
ad.UpdateAsync();//Updates the application asynchronously
}
}
}
catch (Exception ex)
{
ex.Log();
}
}
}
void ad_UpdateCompleted(object sender, AsyncCompletedEventArgs e)
{
//Do something after the update. Maybe restart the application in order for the update to take effect.
}
EDIT
I have updated my answer. You can copy and paste this one and adjust it based on your app needs.
On my previous answer, I'm opening a new window that tells the users that there's an update then have the user choose if he or she wants to update the application.

Related

How to detect when a user is adding or removing a program in WPF C#

My WPF app is like a MacBook dock which displays apps. I want to update the applications list within my app whenever the user installs or uninstalls a program.
What would be a good way to capture that add/remove program event?
As most people flagged for too broad I'm going to elaborate further:
I haven't tried anything yet. The only thing I'm thinking of is rescanning the registry every now and then to see if the program list has changed. This will work for sure, however, that's my backup option for now and I'm looking for a better solution.
By installed app I mean an application which has a registry key associated with it in either of these locations and therefore it shows up in the add/remove programs window.
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall
By uninstalled app I mean - a program you uninstalled from the add/remove program window.
Solved it. When you add or remove a program(install/uninstall) Windows writes events in the Event Log(Event Viewer) under WindowsLogs/Application. You can listen to when a new log entry is added using EventLog.EntryWritten
EventLog eLog = new EventLog();
eLog.Log = "Application"; //MsiInstaller events are written in Application
eLog.EntryWritten += Log_NewInstallUninstallOccured; //Add the event and remove it when you want to stop listening
eLog.EnableRaisingEvents = true; // Enable event raising
private void Log_NewInstallUninstallOccured(object sender, EntryWrittenEventArgs e)
{
if (e.Entry.Source == "MsiInstaller") //MsiInstaller is the source responsible for installation related events
{
if(e.Entry.Message.Contains("Installation completed successfully."))
{
Console.WriteLine("Installation Occured");
}
else if (e.Entry.Message.Contains("Removal completed successfully."))
{
Console.WriteLine("Removal Occured");
} else
{
Console.WriteLine("Other Installation Event Occured");
}
}
}
Sources:
How to tell which user installed or uninstalled an app in Windows
EventLog Class
EventLog.EntryWritten Event

Unpacking a .cab file and then closing the running process on windows CE 6.0 with .net mobile 3.5

I have a windows CE 6.0 program that uses a .cab file for installation. it incorporates the guide from http://msdn.microsoft.com/en-us/library/aa446487.aspx to support automatic self-updates.
the program can check for updates just fine, it downloads the update like it should, but when I try to make it unpack the .cab file it just downloaded, it fails.
this is my code:
void ResponseReceived(IAsyncResult res)
{
try
{
_mResp = (HttpWebResponse)_mReq.EndGetResponse(res);
}
catch (WebException ex)
{
MessageBox.Show(ex.ToString(), "Error");
return;
}
// Allocate data buffer
_dataBuffer = new byte[DataBlockSize];
// Set up progrees bar
_maxVal = (int)_mResp.ContentLength;
pgbDownloadBar.Invoke(new EventHandler(SetProgressMax));
// Open file stream to save received data
_mFs = new FileStream(#"\Application\CCOptimizerSetup.cab",
FileMode.Create);
// Request the first chunk
_mResp.GetResponseStream().BeginRead(_dataBuffer, 0, DataBlockSize,
OnDataRead, this);
}
void OnDataRead(IAsyncResult res)
{
// How many bytes did we get this time
int nBytes = _mResp.GetResponseStream().EndRead(res);
// Write buffer
_mFs.Write(_dataBuffer, 0, nBytes);
// Update progress bar using Invoke()
_pbVal += nBytes;
pgbDownloadBar.Invoke(new EventHandler(UpdateProgressValue));
// Are we done yet?
if (nBytes > 0)
{
// No, keep reading
_mResp.GetResponseStream().BeginRead(_dataBuffer, 0,
DataBlockSize, OnDataRead, this);
}
else
{
// Yes, perform cleanup and update UI.
_mFs.Close();
_mFs = null;
Invoke(new EventHandler(AllDone));
}
}
private void AllDone(object sender, EventArgs e)
{
Cursor.Current = Cursors.Default;
DialogResult dialogresult = MessageBox.Show(#"CCOptimizer has finished downloading. Open now?", "Download complete", MessageBoxButtons.OKCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
switch (dialogresult)
{
case DialogResult.OK:
Application.Exit();
Dispose();
Close();
Invoke(new EventHandler(StartProcess));
break;
case DialogResult.Cancel:
Form1 oForm = new Form1();
oForm.Show();
Hide();
break;
}
}
private void StartProcess(object sender, EventArgs e)
{
Process.Start(#"\Application\CCOptimizerSetup.cab", null);
}
It doesn't work though. wherever I place the invocation of StartProcess(), either it just shuts down with no message or I get an error during unpacking that one of the files i'm trying to update is still in use. During debugging, it just stops the program. If I try on an installed version, it very briefly flashes a window, then locks up the machine with the WaitCursor rotating and needs a reboot, although it can install just fine afterwards.
How can I close the current program and open a .cab file without having to reboot the machine?
You've got a flaw in your update logic, probably that the app you want to update is the thing checking for updates (it's not entirely clear from the question, but the behavior suggest this is the case).
An application cannot directly update itself because, for what should be fairly obvious reasons, you cannot replace the assemblies that are already loaded and running.
There are, generally speaking, two ways that I have used to get around this. Both require a second executable (which in many case I already have as a watchdog app anyway).
Instead of directly launching your application, launch some "updater" application first. That application can check for updates, inform the user, download, and install/overwrite the target application because it's not yet running. The updater then runs the target application when it's done, or if no update steps are required.
Instead of directly launching your application, launch some "bootstrap" application first. The bootstrap looks in local temporary storage for any update files, executes them if they exist, and then runs the normal application. Have the application itself check for updates and pull them to the temporary storage location. When updates have been pulled, have it shutdown and restart the bootstrap, which then will apply the update.

Is it possible to navigate from webbrowser NavigationFailed event?

private void webBrowser_NavigationFailed(object sender, NavigationFailedEventArgs e)
{
Debug.WriteLine("Navigation Failed");
if (!Utils.IsNetworkAvailable())
{
MessageBoxResult result = MessageBox.Show("Please go to Settings and enable your network connection.",
"No network connection", MessageBoxButton.OK);
if (result == MessageBoxResult.OK)
{
Dispatcher.BeginInvoke(() =>
NavigationService.Navigate(new Uri("/TutorialPage.xaml", UriKind.Relative))); //TODO: Doesnt work
}
}
}
Is this posible? i want go to previous xaml page not webpage.
Thank you in advance.
I've tried your code and it runs ok. Here is my simple example. You can Navigate in NavigationFailedEvent - the problem is that you never get there.
As I've tried the problem mostly concerns Emulator - probably due to how internet connection is realized. For example:
web.Navigate(new Uri(#"http://nosite.azd", UriKind.Absolute));
this Navigation hadn't failed on my Emulator (I was redirected somewhere), but as I've tested it on the Device - it failed.
So try to test your App on device. But IMO it will be much better to check for the internet connection before Navigating (Loading Webbrowser) rather that waiting Navigation to Fail (it can be an additional check up).
Also you don't need to Navigate via Dispatcher as your code runs on main thread.

SqlDependency in a Windows Service not firing

I am trying to monitor a database table for changes using the SqlDependency class. Though I must be missing something. I have followed all of the examples that I see online and I have reviewed all the questions on this site. I just don't see what I am missing. Here are the initial commands that I ran on the database to enable the service broker and create the queue and service.
CREATE QUEUE ScheduleChangeQueue
GO
CREATE SERVICE ScheduleChangeService ON QUEUE ScheduleChangeQueue ([http://schemas.microsoft.com/SQL/Notifications/PostQueryNotification])
GO
ALTER DATABASE [database] SET ENABLE_BROKER
On the C# side, I have created a class that has a single static Setup method that is called to initiate the process. Here is the code for that:
public class SqlDependencyManager
{
private static bool DoesUserHavePermission()
{
var success = false;
try
{
Program.Log.Info("Retrieving SqlPermission to establish dependency...");
var clientPermission = new SqlClientPermission(System.Security.Permissions.PermissionState.Unrestricted);
// this will throw an error if the user does not have the permissions
clientPermission.Demand();
success = true;
Program.Log.Info("SqlPermission established. Continue setting up dependency.");
}
catch (Exception ex)
{
Program.Log.Error(ex, "SqlPermission not able to be established.");
}
return success;
}
public static void Setup()
{
if (!DoesUserHavePermission())
{
return;
}
var connectionString = ConfigurationManager.ConnectionStrings["ShowMakerPro"].ConnectionString;
// You must stop the dependency before starting a new one.
// You must start the dependency when creating a new one.
SqlDependency.Stop(connectionString);
SqlDependency.Start(connectionString);
using (var cn = new SqlConnection(connectionString))
{
using (var cmd = cn.CreateCommand())
{
cmd.CommandType = CommandType.Text;
//cmd.CommandText = "SELECT MAX(LastChangeTime) FROM Schedule WHERE ChannelID IN ( SELECT ID FROM Channels WHERE Type = 1 ) AND StartTime BETWEEN (GETDATE() - 7) AND (GETDATE() + 30)";
cmd.CommandText = "SELECT LastChangeTime FROM dbo.Schedule";
cmd.Notification = null;
// Creates a new dependency for the SqlCommand. Then creates attaches handler for the notification of data changes
new SqlDependency(cmd).OnChange += SqlDependency_OnChange;
cn.Open();
cmd.ExecuteReader();
}
}
Program.Log.Info("SQL Dependency set. Now monitoring schedule table for changes.");
}
private static void SqlDependency_OnChange(object sender, SqlNotificationEventArgs e)
{
if (e.Type == SqlNotificationType.Change)
{
// this will remove the event handler since the dependency is only for a single notification
((SqlDependency)sender).OnChange -= SqlDependency_OnChange;
ScheduleOutputterService.BuildSchedules();
Program.Log.Info("SQL Dependency triggered schedule rebuild. Resetting SqlDependency to monitor for changes.");
Setup();
}
}
}
I see the code get setup ok and the OnChange method is fired once for the Subscribe but then I never see it fire after that. I manually go into the database and change the LastChangeTime field hoping that it will force the firing of the event but nothing happens.
Can someone please shed some light on where I am screwing up? I see some people saying on line that this works fine in a windows form but they are also having some problems while in a service.
So I finally figured out the answer to my question and I thought I should list all the steps I took to get to this point so someone else coming along behind me will also have another place to look for answers since I seemed unable to find all of my answers in one place.
First off, I noticed in my situation that as soon as the subscription was set the OnChange event would fire right away. That is why I put in the check for change type so I could ignore those events. It turns out that ignoring those events was not a good thing because those events were actually trying to tell me something. Doing a search on my values directed me here:
http://msmvps.com/blogs/siva/archive/2011/11/22/subtle-sqldependency-notification-issue.aspx
This was very valuable because it helped me to see that there must have been a problem with some of my options in the database. Upon further inspection I noticed that my database was set to SQL Server 2000 compatibility. That is obviously my first problem because this is a 2005 and greater feature. So I tried to change my settings to the high version. This worked ok but then I still noticed that I was receiving the same event. So then I checked my database settings and I found that they were not set to match the options required to run service broker. You can see all the required option settings here:
http://msdn.microsoft.com/en-us/library/ms181122(v=SQL.100).aspx
After I inspected all these and tried to do some workarounds to get the right settings all squared away the setup was still failing. But this time it was failing because the updates would not save. It turned out that the client had triggers on the table in question and it's database settings that were being used to execute the trigger were in conflict with the needed settings to run QueryNotifications.
So long story short, the client decided that they did not want to change all the triggers that were being used so they abandoned the effort. But I learned a lot about how to troubleshoot SqlDependency and ServiceBroker. Hopefully these few links I provided will be helpful for someone else. A couple more links that were very helpful were mentioned in the comments but I am going to repost them in this answer so you can have some other items to review.
http://rusanu.com/2006/06/17/the-mysterious-notification/
http://rusanu.com/2005/12/20/troubleshooting-dialogs/

Remote Process Execution

My scenerio is connection to remote machine with C#.Net, and listing all processes with that remote computer. I can kill a process, or start a new process at remote. The problem is, when I execute a new process on remote, I can see the process on task manager, but it doesnt apeear on windows screen. Any idea why its not appearing on windows, but appearing on task manager/ process. Here is my execution code
private void btnStartNew_Click(object sender, EventArgs e)
{
object[] arrParams = { txtNewProcess.Text.Trim()};
try
{
manageClass = new ManagementClass(myScope, new ManagementPath("Win32_Process"), new ObjectGetOptions());
manageClass.InvokeMethod("Create", arrParams);
btnConnect_Click(sender, e);
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
My Scope is :
myScope = new ManagementScope(#"\ROOT\CIMV2", connOptions);
the problem is about administrator permissions
Shouldn't the ManagementPath be something like \ComputerName\Root\CIMV2 instead of just \ROOT\CIMV2 ?
If you have trouble with authentication, then you need to check the DCOM configuration on the target machine.
On the target machine, run dcomcnfg from the command prompt.
Expand Component Services\Computers\My Computer\DCOM Config
Find Windows Management Instruction, identified with GUID 8BC3F05E-D86B-11D0-A075-00C04FB68820 (you can see this in the details view).
Edit the properties and then add the username you are trying to login with under the permissions tab.
You may need to reboot the service for the changes to take effect.

Categories

Resources