I have a 10 second timer checking for updates. I have tried putting "check for updates" in the timer routine. I tried "checking for updates" in a background worker . I have tried async "checking for updates". All throw "Cannot bind to deployment that is not installed". After that, I get a new exception, "Object reference not set to an instance of an object". The exception is not necessarily on the 1st check for updates. I have had it run for hours before throwing an exception. After that, it will no longer retrieve an update. If I can't fix the issue, I would like to clear the error. Every 10 seconds out of a hat. I write to a log and/or restart the computer on the main thread.
Private Sub tmrAppUpdate_Tick(sender As Object, e As EventArgs) Handles tmrAppUpdate.Tick
If bwAutoUpdates.IsBusy Then Return 'if updates busy...leave
bwAutoUpdates.RunWorkerAsync() 'check for updates
End Sub
''' <summary>check for and get automatic updates</summary>
Private Sub bwAutoUpdates_DoWork(sender As Object, e As DoWorkEventArgs) Handles bwAutoUpdates.DoWork
e.Result = {"ok", ""} 'default message
Try
Dim updateCheck = ApplicationDeployment.CurrentDeployment 'updates
Dim info = updateCheck.CheckForDetailedUpdate() 'get update info
If info.UpdateAvailable Then 'if updates available...
updateCheck.Update() 'download updates
e.Result = {"restart", "Automatic Update ReStart: "} 'error, error message
End If '
Catch ex As InvalidOperationException 'error
e.Result = {"err", "bw ioe: " & ex.Message} 'error, error message
Catch ex As DeploymentDownloadException 'error
e.Result = {"err", "bw dde: " & ex.Message} 'error, error message
Catch ex As InvalidDeploymentException 'error
e.Result = {"err", "bw ide: " & ex.Message} 'error, error message
Catch ex As TrustNotGrantedException 'error
e.Result = {"err", "bw tnge: " & ex.Message} 'error, error message
Catch ex As Exception 'error
e.Result = {"err", "bw ax: " & ex.Message} 'error, error message
End Try '
End Sub
Private Sub bwAutoUpdates_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles bwAutoUpdates.RunWorkerCompleted
Dim result = CType(e.Result, Array).OfType(Of String)
If result(1).Length > 0 Then writeLog(result(1)) 'write to log!
Select Case result(0) 'what are we going to do?
Case "ok" : Return 'everything ok
Case "restart" : Application.Restart() 'restart
Case "err" 'errors
End Select
End Sub
The new code is crashing. In poking around, I discovered that this problem has been lurking for 10 years. I don't know why everyone isn't aware of it.
Microsoft Discussion
"A privilege that the service requires to function properly does not exist in the service account configuration. You may use the Services Microsoft Management Console (MMC) snap-in (services.msc) and the Local Security Settings MMC snap-in (secpol.msc) to view the service configuration and the account configuration. (Exception from HRESULT: 0x80070511)"
For the past couple of weeks I have fooled with automatic updates. It has bugs and fails if your app checks for updates often. I have included a link to the full project. You can download it, run it for a couple of days and watch it fail (usually within a couple of hours). When it fails, there seems to be no way to clear the error without a restarting. I have seen reports of this bug going back 10 years. If you find a fix, please let me know. Thanks Sandy
vb.net AutomaticUpdates
"Improved solution"
Imports System.ComponentModel
Imports System.Deployment.Application
Imports System.Deployment.Application.ApplicationDeployment
Public Class frmMain
Private lngUpdateSize As Long = 0
Dim WithEvents ad As ApplicationDeployment
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
lblRev.Text = getRev()
End Sub
Private Sub UpdateApplication()
If ApplicationDeployment.IsNetworkDeployed Then '
ad = ApplicationDeployment.CurrentDeployment '
ad.CheckForUpdateAsync() 'any updates...anyone?
End If
End Sub
Private Sub adUpdate_CheckForUpdateProgressChanged(ByVal sender As Object, ByVal e As
DeploymentProgressChangedEventArgs) Handles ad.CheckForUpdateProgressChanged
Const fmt = "{0:F1}K of {1:F1}K downloaded." 'string format
txtUpdateStatus.Text = String.Format(fmt, e.BytesCompleted / 1024, e.BytesTotal /
1024)
End Sub
Private Sub adUpdate_CheckForUpdateCompleted(ByVal sender As Object, ByVal e As
CheckForUpdateCompletedEventArgs) Handles ad.CheckForUpdateCompleted
If e.Cancelled Then 'if update canceled
lblMsg.Text = "The update was cancelled." 'display message
Return 'leave
ElseIf e.Error IsNot Nothing Then 'if there was an error
MessageBox.Show("ERROR") 'display message
Return 'leave
End If '
If e.UpdateAvailable Then 'if updates available
lngUpdateSize = e.UpdateSizeBytes 'get download size
Dim msg = "" 'holder for message
If Not e.IsUpdateRequired Then 'update flag set
msg = "Optional update, Installing now!" 'required message
Else 'optional update
msg = "Mandatory update, Installing now!" 'optional message
End If
lblMsg.Text = msg 'display message
lblMsg.Refresh() 'make we see message
Threading.Thread.Sleep(2000) 'give chance to see message
BeginUpdate() '
End If
End Sub
Private Sub BeginUpdate()
ad = ApplicationDeployment.CurrentDeployment '
ad.UpdateAsync() 'we have them...install em
now!!!
End Sub
Private Sub adUpdate_UpdateProgressChanged(ByVal sender As Object, ByVal e As
DeploymentProgressChangedEventArgs) Handles ad.UpdateProgressChanged
Const fmt = "{0:F1}K out of {1:F1}K downloaded - {2:F1}% complete"
Dim strProgress = String.Format(fmt, e.BytesCompleted / 1024, e.BytesTotal / 1024,
e.ProgressPercentage)
txtUpdateStatus.Text = strProgress
End Sub
Private Sub adUpdate_UpdateCompleted(ByVal sender As Object, ByVal e As
AsyncCompletedEventArgs) Handles ad.UpdateCompleted
If e.Cancelled Then 'if update canceled
lblMsg.Text = "The update was cancelled." 'display message
Return 'leave
ElseIf e.Error IsNot Nothing Then 'if there was an error
MessageBox.Show("ERROR") 'display message
Return 'leave
End If '
lblMsg.Text = "App finished updating, Restarting now!" 'display message
lblMsg.Refresh() 'make sure displayed
Threading.Thread.Sleep(2000) 'chance to see the message
Application.Restart() 'kill app and restart
End Sub
Private Sub tmrUpdate_Tick(sender As Object, e As EventArgs) Handles tmrUpdate.Tick
UpdateApplication() 'time to check for updates
End Sub
Function getRev() As String
If IsDebug() Then Return "Debug Mode" 'if debug...return
Return CurrentDeployment.CurrentVersion.ToString 'revision
End Function
Function IsDebug() As Boolean
Return Debugger.IsAttached 'return debug mode
End Function
End Class
I created a solution that might help. Basically I look at the modified date of the posted ".application" file. if the date changes, then updates pending. This example is not ftp or http, local only. It prevents CheckForUpdateAsync() from getting hammered (from what I have read is the cause of the problem). Hopes this helps...Sandy
Private Sub UpdateApplication()
If IsNetworkDeployed = False Then Return 'if not deployed...leave
Dim fName = CurrentDeployment.UpdateLocation.ToString 'full deployment path
fName = Replace(fName, "file:", Nothing) 'remove
Dim modD = CStr(File.GetLastWriteTime(fName)) 'get file modified
If modD = My.Settings.fileModified Then Return 'if files match...leave
My.Settings.fileModified = modD 'save modified date
ad = CurrentDeployment 'get current deployment
ad.CheckForUpdateAsync() 'any updates...anyone?
writeLog("check for updates") 'log it!
End Sub
Related
I have a process that works well when it's running against small files but gives an "Message=Managed Debugging Assistant 'ContextSwitchDeadlock' : 'The CLR has been unable to transition from COM context 0xa5b8e0 to COM context 0xa5b828 for 60 seconds." error when running against large files. I'm pretty new to VB and did some investigating and found that using Application.DoEvent seemed to be recommended. I was hoping that someone could show me an example of how to use that. If I'm executing a Sub called "Process1", how would I use the DoEvent to prevent it from timing out. Ideally I'd like to add a progress bar as well but I have ot idea on that one either. I'd appreciate any help. Please keep it simple as I'm new to VB/VS.
This is the comment from my first question showing the code. Process1 calls a sub named ArchDtlCopyFile1 which scrolls through the values in a list view, copying the files named in the items to a different location. It then calls ArchDtlCheckCopy1 to scroll through the list view again to ensure that the copy was done. It then decides if the source file should be deleted and do it if required. Finally it inserts a row in an Access table documenting the change made.
Private Sub Process1()
If ReturnCode = 0 Then
ArchDtlCopyFile1()
Else
' MessageBox.Show("Error code coming in is: " & CStr(ReturnCode))
End If
If ReturnCode = 0 Then
ArchDtlCheckCopy1()
Else
' MessageBox.Show("Error code for check copy is: " & CStr(ReturnCode))
End If
End Sub
Private Sub ArchDtlCopyFile1()
intLVIndex = 0
' Copy the file from the source computer onto the NAS
Do While intLVIndex < intMaxFileIndex
Try
' Select the row from the LVFiles ListView, then move the first column (0) into strSourceFilePath and the last
' column (3) into strDestFilePath. Execute the CopyFile method to copy the file.
LVFiles.Items(intLVIndex).Selected = True
strSourceFilePath = LVFiles.SelectedItems(intLVIndex).SubItems(0).Text
strDestFilePath = LVFiles.SelectedItems(intLVIndex).SubItems(3).Text
My.Computer.FileSystem.CopyFile(strSourceFilePath, strDestFilePath, overwrite:=False)
Catch ex As Exception
' Even if there's an error with one file, we should continue trying to process the rest of the files
Continue Do
End Try
intLVIndex += 1
Loop
End Sub
Private Sub ArchDtlCheckCopy1()
intLVIndex = 0
intLVError = 0
' ' Check each file was copied onto the NAS
Do While intLVIndex < intMaxFileIndex
' Select the row from the LVFiles ListView, then move the last column (3) into strDestFilePath.
' Use the FileExists method to ensure the file was created on the NAS. If it was, call the
' ADetDelete Sub to delete the source file from the user's computer.
LVFiles.Items(intLVIndex).Selected = True
strSourceFilePath = LVFiles.SelectedItems(intLVIndex).SubItems(0).Text
strDestFilePath = LVFiles.SelectedItems(intLVIndex).SubItems(3).Text
strSourceFile = LVFiles.SelectedItems(intLVIndex).SubItems(1).Text
Try
If My.Computer.FileSystem.FileExists(strDestFilePath) Then
' Archive file was created so go ahead and delete the source file
'If strSourceFile = myCheckFile Then
' strDestFile = LVFiles.SelectedItems(intLVIndex).SubItems(3).Text
'End If
If RBArchive.Checked = True Then
ArchDtlDeleteFile(strSourceFilePath)
End If
PrepareDtlVariables()
ADtlAddRow()
Else
MessageBox.Show("File not found. " & strDestFilePath)
End If
Catch ex As Exception
ErrorCode = "ARC6"
MessageCode = "Error while checking file copy"
ReturnCode = 8
End Try
intLVIndex += 1
Loop
End Sub
Here's a simplified example:
Imports System.ComponentModel
Imports System.IO
Public Class Form1
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
BackgroundWorker1.WorkerReportsProgress = True
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Button1.Enabled = False
BackgroundWorker1.RunWorkerAsync()
End Sub
Private Sub BackgroundWorker1_DoWork(sender As Object, e As DoWorkEventArgs) Handles BackgroundWorker1.DoWork
For i As Integer = 1 To 20
BackgroundWorker1.ReportProgress(i) ' you can pass anything out using the other overloaded ReportProgress()
System.Threading.Thread.Sleep(1000)
Next
End Sub
Private Sub BackgroundWorker1_ProgressChanged(sender As Object, e As ProgressChangedEventArgs) Handles BackgroundWorker1.ProgressChanged
' you can also use e.UserState to pass out ANYTHING
Label1.Text = e.ProgressPercentage
End Sub
Private Sub BackgroundWorker1_RunWorkerCompleted(sender As Object, e As RunWorkerCompletedEventArgs) Handles BackgroundWorker1.RunWorkerCompleted
MessageBox.Show("Done!")
Button1.Enabled = True
End Sub
End Class
I am trying to download a file, and then run some adb commands. However when downloading, i could not get it to update the progress bar using
downloadFile(url,filename)` command.
A bit of searching it said that the command was blocking the UI thread, so i decided to use Task.Run() (a solution to my previous post to run ADB Commands when it blocked the UIThread).
This made no difference. Another solution that i found is to use
downloadFileAsync(url, filename)
The progress bar is updating!
But, the ADB commands are running before the file is downloaded! They are declared after, but they are still being run before the file is downloaded, which I don't want.
Here is the code:
Private Sub btnFlashRecovery_Click(sender As Object, e As EventArgs) Handles btnFlashRecovery.Click
'Insert ommited Code here (removed to simplify question)
'id is variable obtained from a previous code that was ommited here
Dim fileName As String = "downloads/twrp-" & id & ".img"
DownloadFile(url, fileName)
'run the right commands
LabelToOutput = txtBoxRecovery
Dim commands(3, 3) As String
commands = {{"adb", "reboot bootloader", "Rebooting to bootloader"},
{"fastboot", "flash recovery" & "downloads/twrp-3.1.1-0.img", "Flashing recovery: (make sure device is plugged, otherwise it will not output anything)"},
{"fastboot", "reboot", "Rebooting device"}
}
'Task to run after
Task.Run(Sub() runComands(commands))
End Sub
Private Sub UpdateProgressBar(ByVal a As Integer)
If Me.InvokeRequired Then
Dim args() As String = {a}
Me.Invoke(New Action(Of String)(AddressOf UpdateProgressBar), args)
Return
End If
ProgressBar1.Value = CInt(a)
End Sub
Public Sub DownloadFile(urlAddress As String, location As String)
Using webClient = New WebClient()
AddHandler webClient.DownloadFileCompleted, AddressOf Completed
AddHandler webClient.DownloadProgressChanged, AddressOf ProgressChanged
Try
' Start downloading the file
webClient.DownloadFileAsync(New Uri(urlAddress), location)
Catch ex As Exception
MessageBox.Show(ex.Message)
End Try
End Using
End Sub
' The event that will fire whenever the progress of the WebClient is changed
Private Sub ProgressChanged(sender As Object, e As DownloadProgressChangedEventArgs)
'Console.WriteLine(e.ProgressPercentage)
' Update the progressbar percentage only when the value is not the same.
UpdateProgressBar(e.ProgressPercentage)
End Sub
' The event that will trigger when the WebClient is completed
Private Sub Completed(sender As Object, e As AsyncCompletedEventArgs)
If e.Cancelled = True Then
MessageBox.Show("Download has been canceled.")
Else
MessageBox.Show("Download completed!")
End If
End Sub
Do it like this:
'Need Async keyword with the method
Private Async Sub btnFlashRecovery_Click(sender As Object, e As EventArgs) Handles btnFlashRecovery.Click
'Insert ommited Code here (removed to simplify question)
'id is variable obtained from a previous code that was ommited here
Dim fileName As String = "downloads/twrp-" & id & ".img"
'You need to AWAIT the result of the task
Await Task.Run(Sub() DownloadFile(url, fileName))
'run the right commands
LabelToOutput = txtBoxRecovery
Dim commands(3, 3) As String
commands = { {"adb", "reboot bootloader", "Rebooting to bootloader"},
{"fastboot", "flash recovery" & "downloads/twrp-3.1.1-0.img", "Flashing recovery: (make sure device is plugged, otherwise it will not output anything)"},
{"fastboot", "reboot", "Rebooting device"}
}
'Task to run after
'Await here, too, to allow the UI to remain responsive
Await Task.Run(Sub() runComands(commands))
End Sub
In my project im using inputsimulator and it works great when visual studio is ran as an administrator, but when i build it into a .exe it doesn't work even when i run it as administrator. here's my code
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
AutoSaveTimer.Enabled = True
Try
System.Threading.Thread.Sleep(50)
GameConnection.SendKeyTo(Keys.OemSemicolon)
System.Threading.Thread.Sleep(2000)
GameConnection.SendKeyTo(Keys.K)
System.Threading.Thread.Sleep(50)
GameConnection.SendKeyTo(Keys.Enter)
Catch AutoSaveExeption As GameException
If AutoSaveExeption.GameErrorCode = GameError.GAME_ERR_SENDMSG Then
' Send message error - connection to Game lost.
'
MessageBox.Show("cant make a connection.... can't autosave sadly", AppTitle, MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
SimConnectionBar.BackColor = Color.Red
End If
End Try
End Sub
it does send focus to the window i specify but it doesn't send the keystrokes
Try using SetForegroundWindow before sending any input to ensure your game does in fact have focus.The call to SetForegroundWindow should be made in your method just before sending the input.
<DllImport("user32.dll")> _
Public Shared Function SetForegroundWindow(hWnd As IntPtr) As Boolean
End Function
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click `
AutoSaveTimer.Enabled = True
Try
'Find the handle to the game. This can do it by searching for the process.
Dim p As System.Diagnostics.Process() = System.Diagnostics.Process.GetProcessesByName("notepad")
'search for process notepad
If p.Length > 0 Then
'check if window was found
'bring notepad to foreground
SetForegroundWindow(p(0).MainWindowHandle)
End If
System.Threading.Thread.Sleep(50)
GameConnection.SendKeyTo(Keys.OemSemicolon)
System.Threading.Thread.Sleep(2000)
GameConnection.SendKeyTo(Keys.K)
System.Threading.Thread.Sleep(50)
GameConnection.SendKeyTo(Keys.Enter)
Catch AutoSaveExeption As GameException
If AutoSaveExeption.GameErrorCode = GameError.GAME_ERR_SENDMSG Then
' Send message error - connection to Game lost.
'
MessageBox.Show("cant make a connection.... can't autosave sadly", AppTitle, MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
SimConnectionBar.BackColor = Color.Red
End If
End Try
end sub
I'm currently using this code, (which is working) but I'm not satisfied with how it looks... Is there a more professional way to do it ?
Here's the code I use now :
Private Sub BackgroundWorker_DoWork(sender As Object, e As System.ComponentModel.DoWorkEventArgs) Handles BackgroundWorker.DoWork
Try
If BackgroundWorker.CancellationPending Then
e.Cancel = True
Exit Sub
End If
LatestVersion = Web.DownloadString(UpdateLink)
If BackgroundWorker.CancellationPending Then
e.Cancel = True
Exit Sub
End If
If LatestVersion.Contains(InstalledVersion) Then
e.Result = UP_TO_DATE
Else
e.Result = OUTDATED
End If
Web.Dispose()
Catch ex As Exception
e.Result = ex.Message
End Try
End Sub
As you can see, I'm repeating two times the same condition. But imagine if there was more code, I should have repeat it more times...
My problem is that I would like to exit the Sub at anytime, as long as the BackgroundWorker.CancellationPending property is set to True.
I'm using the same condition two times because I wanna check if the operation has been canceled before, and after downloading of my string (I don't wanna wait for the string to be downloaded whereas I've already canceled the operation... it's a waste of time).
Should I use a While statement ? If yes, how ?
Don't use BackgroundWorker and this problem goes away. The code probably should be (mixture of VB and C#):
//Instance field:
CancellationTokenSource cts = ...;
//Update method
var downloadTask = HttpClient().DownloadString(UpdateLink, cts.Token);
await Task.WhenAll(downloadTask, cts.Token); //Wait with timeout
LatestVersion = await downloadTask;
If LatestVersion.Contains(InstalledVersion) Then
ShowResult(UP_TO_DATE);
Else
ShowResult(OUTDATED);
End If
And if you want to cancel, signal cts.
Also, error handling is missing. This is easy to test for and add.
I've found another solution. By the way, I've renamed Web by WebClient...
Here's my code :
Private Sub Form1_Load() Handles Form1.Load
AddHandler WebClient.DownloadStringCompleted, AddressOf WebClient_DownloadStringCompleted
End Sub
Private Sub BackgroundWorker_DoWork() Handles BackgroundWorker.DoWork
WebClient.DownloadStringAsync(New Uri(UpdateLink))
End Sub
Private Sub WebClient_DownloadStringCompleted(sender As Object, e As System.Net.DownloadStringCompletedEventArgs)
Dim Output As String = Nothing
If Not e.Cancelled Then
LatestVersion = e.Result
If LatestVersion.Contains(InstalledVersion) Then
Output = UP_TO_DATE
Else
Output = OUTDATED
End If
End If
End Sub
And, to cancel the operation, I run WebClient.CancelAsync().
I latched onto the Catia using:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
Dim boolCatAlive As Boolean
boolCatAlive = False
Try
Dim myCatia As INFITF.Application
myCatia = Interaction.GetObject(vbNullString, "CATIA.Application")
boolCatAlive = True
Catch ex As Exception
boolCatAlive = False
End Try
Select Case boolCatAlive
Case True
'continue loading app, do my stuff
Case Else
'end this now
MsgBox("No running CATIA instance detected, please start a new CATIA instance and re-run this program.", MsgBoxStyle.Critical, "Error")
End
End Select
End Sub
So that is a simple boolean switch at the form loading that decides whether the app is going to load or not.
This works ok, but is doing the check only once when the app is started. Is there a way to continually detect CATIA status, so that - if a user exits CATIA in the middle of my app running - app gets notified and realises that the CATIA COM link is no longer alive?
I could also use that to detect selection changes for example?
You can Check it All the time by using a timer.Add a timer and specify the same code in its TICK event.sorry to Post this as an answer.I don't have enough reputation to post comment.
http://vb.net-informations.com/gui/timer-vb.htm
This link will be helpfull to you.
Thanks, it works fine.
I put this code inside Tick event, set timer to enabled, and use 1000ms interval to check every 1 second for CATIA link.
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Dim boolCatAlive As Boolean
boolCatAlive = False
Try
Dim myCatia As INFITF.Application
myCatia = Interaction.GetObject(vbNullString, "CATIA.Application")
boolCatAlive = True
Catch ex As Exception
boolCatAlive = False
End Try
End Sub
I would recommend to ask the actual Catia Object in timer instead of getting new object. Assuming you have Global CatiaApp variable
Put in the timer something like this
Try
If CatiaApp.Name.Length > 0 Then
'catia is alive
End If
Catch ex As Exception
'catia is down
CatiaApp = Nothing
End Try
You get an exception if Name.Length fails which signal that catia is down