I want my application to self-update if there is a different size executable available on the remote server. The problem I got is that when I kill the process to replace the application executable, nothing more happends - nothing more is executing after the eprocess.Kill() even though I am trying to freeze the thread during the file replacement process. Is there something I am doing wrong?
Here is my code:
Dim Request As System.Net.WebRequest
Dim Response As System.Net.WebResponse
Dim FileSize As Integer
Request = Net.WebRequest.Create("http://mywebsite.com/File.exe")
Request.Method = Net.WebRequestMethods.Http.Get
Response = Request.GetResponse
FileSize = Response.ContentLength
Dim mySize As New IO.FileInfo(Application.ExecutablePath)
If FileSize <> mySize.Length Then If File.Exists(tempPath & "\File_tmp.exe") Then
File.Delete(tempPath & "\File_tmp.exe")
End If
Patcher.DownloadFileAsync(New Uri("http://mywebsite.com/File.exe"), tempPath & "\File_tmp.exe") 'Patcher is defined before, you might think that its not working, but this is just a piece of code, and the new file is downloading properly. The described problem is
While Patcher.IsBusy
Threading.Thread.Sleep(100)
End While
Do While True
For Each eprocess As Process In Process.GetProcesses
If eprocess.ProcessName = "MyApplication" Then
eprocess.Kill()
End If
Next
File.Delete(Application.ExecutablePath)
'Copy downloaded file to the application executable path directory
File.Copy(tempPath & "\File_tmp.exe", Application.ExecutablePath)
Threading.Thread.Sleep(30) 'freeze thread...
Loop
End If
One way to handle this is make a separate(smaller exe) in your project that handles the downloading of the new version. First it would close the current version and since it's not tied to the original app the uploader app is still running, it downloads, then installs it and then launches the new version.
There is built in functionality to do this for you.
Have a look at ClickOnce. This negates the need to have a separate application to do the updating for you and allows you to specify a minimum and recommended version, whether the app checks for a new version before or after it starts, etc.
Some more links that may be of use:
http://msdn.microsoft.com/en-us/magazine/cc163973.aspx
http://www.codeproject.com/Articles/38546/Click-Once-Deployment-Technique
I say you write a function that creates a batch file which
downloads the new version of your exe
closes your app and overwrites your exe with the new.
Opens your app
Then your app on startup should look for a such batch file and erase it.
Make an updater whose work will be downloading the files from the remote server then copies/moves them into your main application directory.
I've been using this approach for a while now and it works fine.
Maybe this approach here will work for you https://www.codeproject.com/Articles/35787/VB-NET-Background-File-Downloader
Thought i would add my suggestion to the mix being that this is still the top result in google for stackoverflow.
Firstly.. I can not stand the ClickOnce Solution as it modifies to much of the project and requires other steps and so on.. So i ruled that out after 10 minutes of looking into it.
Also as for having another exe to handle the updates..This was not ideal for me either... So i had my main exe/setup install do all this for me.
Basically i have a website where i host the setup install files with a simple JSON data file to hold the version information. This is accessed via the application itself using a http request and json decoding to query the latest version and compare it against the apps current version.
If a new version is found, the application will download a copy of the new install and place it inside of the applications main directory in a temp folder/installers folder.
Once the download has completed, i execute the installer from within the application and dont waitforexit. The next like of code will trigger the applications save & exit functions.
At this point you have the install running but the main application has exited.. From here the installer can continue as normal and start the application on complete.
You can of course vary alot of things here like silent installs and so on.. but using this method, it allows me to get away with just the normal installer and app exe..
Related
(Visual Studio 2019)
It seems I have run into a snag.
My sample code is this.
Imports NAudio.Wave
Partial Class _Default
Inherits System.Web.UI.Page
Dim filename As String
filename = "G:\VS_Lessons\Media\Read\01. Got to Choose.mp3
Dim reader As New AudioFileReader(filename)
Dim duration As String = reader.TotalTime.ToString("mm\:ss")
reader.Dispose()
Label1.Text = duration
End Sub
End Class
This only happens when I am running the site LIVE and NOT from VS.
Running it through VS, it works as it supposed to.
Running it from a live URL it gives the following error.
Type 'AudioFileReader' is not defined
On this line
Dim reader As New AudioFileReader(filename)
Now, I tried to register the NAudio.dll using. (The NAudio.dll file is in the BIN folder of the website)
gacutil -i NAudio.dll
However, I get the following line
Failure adding assembly to the cache: Attempt to install an assembly without a strong name
I followed the steps in this article here
How to add Strong Name to an existing DLL and install to the GAC
But I get a FAILURE when trying to create the DLL file on STEP 5. (Maybe I am doing it wrong because I am not the owner of the file. Not really sure, this is the first time I have ever done anything like this and was trying everything I could find online)
Any assistance on this would be mighty grateful.
Wayne
The website has to be converted into an Application.
IIS | Web Site |
Right-click on the web site name or sub-folder name
And choose [Convert to Application]
Run the script, and it works.
Now, I have to do this on the live site, but first, I will do the local site, as it runs the same script, and I will get all the bugs out of it, then I can do the LIVE IIS site.
It Could Be Due To Partial Class Instead Of Public Class. Or You Haven't Downloaded Genuine DLL Version Of NAudio.
If Its Problem 1 ( Due To Use Of Partial Class ) Then Change To Public Class
If Its Problem 2 ( Use Of Non-Genuine NAudio DLL ) Then Download NAudio From Here
If Problem Still Persists, Then It Would Be For Windows Form Application.
Folks,
I'll been fighting this for a few weeks now. We have a proprietary corporate app running on thin clients in our organization. From this app we can apply VBA scripting behind the scenes to do simple functions. In the past adding buttons to open IE and direct them to certain web sites to enter data, open Calc and etc.
Recently I have been working the code below. It was developed on the Server using a RDP session which launches the full desktop and explorer.exe. What I have noticed that if explorer.exe isn't running then the code bombs at line in the function that reads "For Each oWin In oShApp.Windows " with "Run-time error '429'".
However if I script to start explorer.exe (which is bad because it enables the Start-bar and Task-bar) on the ThinClient which launches the desktop and full capabilities and it runs just fine as the Thin Client users that are logged in.
I have read a little bit about the "Limited Shell" that runs when using a remoteapp and not the full desktop and was wondering if there was anyway around it, without enable the start-menu and taskbar?
See the code below.
Thanks for the help, CreteIT
Private Sub cmdHomePage_Click()
Dim ie As Object
Dim sMatch As String
sMatch = "http://www.companyweb.com"
On Error Resume Next
Set ie = GetIEatURL(sMatch & "*")
On Error GoTo 0
If Not ie Is Nothing Then
ShowWindow ie.hwnd, 9
BringWindowToTop ie.hwnd
Else
Dim strHome
Dim strAPP
strHome = "c:\progra~1\intern~1\iexplore.exe www.companyweb.com"
strAPP = Shell(strHome, vbNormalFocus)
End If
End Sub
Function GetIEatURL(sMatch As String) As Object
Dim ie As Object, oShApp As Object, oWin As Object
Set oShApp = CreateObject("Shell.Application")
For Each oWin In oShApp.Windows
If TypeName(oWin.Document) = "HTMLDocument" Then
Set ie = oWin
If LCase(ie.LocationURL) Like LCase(sMatch) Then
Set GetIEatURL = ie
Exit For
End If
End If
Next
Set oShApp = Nothing
Set oWin = Nothing
End Function
I work on the RemoteApp team at Microsoft. I'm not quite clear whether you're running this script from an actual RemoteApp session or your own setup that has a different shell that replaces explorer.exe (or perhaps no shell at all), but either way the answer is about the same.
The Shell.Application ActiveX object your script is trying to instantiate appears to be implemented by the shell - typically explorer.exe. If that isn't running, the COM runtime won't be able to create an instance of the object, and when you try to activate it you'll get an error.
The obvious solution is to run explorer.exe but, as you observed, that also includes the taskbar and start menu, which you might not want. RemoteApp runs its own shell replacement (rdpshell.exe), but that doesn't implement Shell.Application, so just running your application under RemoteApp won't fix the problem.
There are a few potential solutions I can think of:
If you're not using RemoteApp, you could write your own replacement shell that does implement Shell.Application. This is quite a lot of work and there might not be a lot of documentation around on how to do it properly. If you already have a replacement shell, you might be able to extend it to implement Shell.Application.
You could use a different method to enumerate windows. Unfortunately this probably means Win32 (via the EnumWindows function), which isn't directly accessible from VB scripts; you might have to create an ActiveX object that implements the behavior you want, and invoke it from the script.
Similar to option 2 but more heavyweight - you could make that ActiveX object implement the whole Shell.Application interface - even though it isn't actually the shell - and register it on the remote machine. I can't guarantee you won't run into problems if you do this though; it isn't something I've tried before.
None of these solutions are ideal, unfortunately, but hopefully something lets you do what you need to.
I am using VB Express 2012 (VB.net) to make a game for educational use in schools that has .wav sound effects and .mp3 background music. My code is given below, and works fine on any personal computer, but hits a roadblock for computers where permission is not granted to write / delete files to the folder containing the application execute file due to my method for playing mp3's using WMPLib.WindowsMediaPlayer. Since wmp requires a URL to an external file for mp3 files (Why???), I have to write the mp3s from my.resource folder to the client computer to obtain a valid URL, then delete them upon closing the program. This fails if permission is not granted.
Is there another way to play an mp3 file from my.resources from the released application using the wmp.dll that does NOT require writing the file to the client computer? Streaming of some sort perhaps? I have never delved into that area before. By the way, it is unreasonable to convert my mp3s to wav files since the size of the application would be way too large. (I have many mp3s, although my code snippet only shows one as an example. Here's my Code:
For the sound effects I use
My.Computer.Audio.Play(My.Resources.soundeffect, AudioPlayMode.Background)
For the background music, in order for the songs to play uninterrupted by sound effects I added the wmp.dll reference and use the following code:
Dim WithEvents Player As New WMPLib.WindowsMediaPlayer
Player.settings.setMode("Loop", True)
Dim appPath As String
'get the location of application execute file
appPath = Application.StartupPath & "\" & "SongNameHere" & ".mp3"
'write the mp3 file to the folder containing the execute file so wmp accepts the URL
My.Computer.FileSystem.WriteAllBytes(appPath,My.Resources.ResourceManager.GetObject("SongNameHere"), False)
'assign the valid URL to the wmp player, it autostarts.
Player.URL = appPath
And, just in case it is important, on .formclosing I delete the songs with the following code:
My.Computer.FileSystem.DeleteFile(Application.StartupPath & "\" & "SongNameHere" & ".mp3")
Thank you to Mr. D. Digaetano for providing the following work around (key solution is bolded):
"...There is no native way to play a resource-packed MP3 file with .NET. It's not even allowed in C#.
The only way to get at the MP3 file is to create a stream that operates on the resource, but the Windows Media Player ActiveX object doesn't support streams as input.
Many people seem to use external DLLs like BASS, and then use the .NET wrapper code provided with those libraries to access their MP3s. However, I've used BASS in the past, and it's not free to use if you intend on selling your software. Also, my code that used it unpacked the MP3s to the current folder and just played them from there, which is what you wanted to avoid due to filesystem restrictions.
I'm not sure why Microsoft would forbid this, but if you read the second paragraph of the 'Remarks' section here, you'll see there's some resistance to bundling media files with your executables.
Perhaps the easiest solution is to get the MP3 files written to a directory that allows writes, such as a temporary folder. Try the following:
Imports System.IO
Dim tempDir As String = Path.GetTempPath() and see if you can
My.Computer.FileSystem.WriteAllBytes(tempDir, My.Resources.ResourceManager.GetObject("SongNameHere"), False)
---"
I am trying to get my vb.net application to look inside a folder on the web server and then let me know whether there are files in there or if the folder is empty...Would anybody know where i would begin? Thanks
Use the DirectoryInfo.EnumerateFiles() method.
Dim myDir as DirectoryInfo = new DirectoryInfo(pathToDir)
If (myDir.EnumerateFiles().Any())) Then
' Got files in direcotry!
End If
If you are also interested in finding out if there are directories within this one, there is also DirectoryInfo.EnumerateDirectories().
I would suggest you have a look at Directory.GetFiles
If your program is running on the web server, you can simply check whether Directory.GetFileSystemEntries(path) returns anything.
If your program is running on a client, you'll need to make a server-side script that calls Directory.GetFileSystemEntries and returns a value to the client.
I've got a Visual Basic App that tends to get severely messed up if the installation runs more than once. It seems the occasionally client mistakes the installer for the shortcut to it later on down the road, runs the installer again and it messes everything up. I can't for the life of me figure out why so I decided the easiest way would be to make it so the exe could only be run once on a machine otherwise it would just end. Any ideas?
Why don't you FIX the installer or whatever problems are happening rather than try to make some hack to avoid it...
Just my $.02
Have your installer place a file in the applications folder.
When runs again, check for that file, if it exists, display a "Already installed" popup and exit.
Assuming this is a VB6 question, you can use the built in App.PrevInstance.
Documentation: http://msdn.microsoft.com/en-us/library/aa268085(VS.60).aspx
App.Previnstance returns True if your application is already running.
In your Startup Form's load event or your Sub Main:
Private Sub Form_Load()
If App.PrevInstance = True Then
MsgBox "Already running"
'Do whatever you need to do before closing
End If
End Sub
If you want to go one step further and bring the previous instance to the foreground, you can check out these articles:
http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=21131&lngWId=1
http://support.microsoft.com/kb/185730
You could have the installer EXE file delete itself, well not directly while it's running but pass off a call to another service to delete it after it's done running.
I thought this was interesting so I Googled it, seems like some good info on this post:
http://www.autohotkey.com/forum/topic1572.html
If you are using .net then Mutex's are your friend here.
Never, ever use the Process.GetProcessesByName method. You'll only hate yourself later for using something that requires Admin priviliges
private bool CanIStart
{
try
{
MyAppMutex= new Mutex(false, "myAppMutex", out createdNew);
if(MyAppMutex.WaitOne(0,false))
{
return true;
}
else
{
MyAppMutex = null;
return false;
}
}
catch(ApplicationException ex)
{
// we couldn't create the mutex. // log the error if you care
return false;
}
}
Have the installer create a registry entry. Refuse to install (again) if the registry entry already exists.
Exactly how to achieve this will depend on the installer technology that you are using.
On the installer app
' Test eventual mark, settings in the registry.
if GetSetting("MyInstallerApp","Startup","BeenHere",0) = 1 then
MsgBox "This installer was ran once already... first run the un-installer."
End ' or some other code to properly exit the installer
EndIf
Call SaveSetting ("MyInstallerApp","Startup", "BeenHere", 1) 'leave a mark for future
On the uninstaller app (or the "uninstall" option of the installer)
' Allow future Installer to run again
Call DeleteSetting("MyInstallerApp", "Startup")
If you are using VB.NET with Visual Studio 2005 or 2008 you can check the 'Make Single Instance Application' option in the Windows Application Framework section of the Application tab in the project settings.
Maybe checking the running processes on the machine to tell you if another instance exists would help? See this thread for more info...
It strikes me that leaving an application around that shouldn't be run more than once is like leaving a big red button somewhere in someone's desk, that when pushed blows up the desk. Not cool.
Most installers have a feature to not offer repeat installation. Check that first - that seems like the best, most obvious solution.
What is severely messed up? How is running the installer a second time different from running it the first from your application's point of view? That should be addressed in your code as well.
You could check and see if the installed application files already exist. Assuming that is, you know where the application was installed to.