Our Winform app consists of a Main.exe and a Launcher.exe. The purpose of the Launcher app is to check for updated versions of the Main.exe.
If it finds no updates it launches Main.exe using System.Diagnostics.Process.Start
If it finds an update, it copies the new Main.exe into position and launches Main.exe the same way (in this case it will be a fresh copy of Main.exe).
Here's the Process.Start code:
Dim p As New ProcessStartInfo
p.FileName = "Main.exe"
p.WindowStyle = ProcessWindowStyle.Normal
Process.Start(p)
This code executes whether or not there's been an update and always successfully fires up Main.exe.
However our Main.exe, if it's being run for the first time (ie. after an update), will error on any line which references the My namespace, such as My.Settings or My.Computer.FileSystem
For example this line will cause an error:
Msgbox(My.Computer.FileSystem.SpecialDirectories.Desktop)
Here's the error:
System.IO.DirectoryNotFoundException:
Could not find special directory
'Desktop'. at
Microsoft.VisualBasic.FileIO.SpecialDirectories.GetDirectoryPath(String
Directory, String DirectoryNameResID)
at
Microsoft.VisualBasic.FileIO.SpecialDirectories.get_Desktop()
at
Microsoft.VisualBasic.MyServices.SpecialDirectoriesProxy.get_Desktop()
But while this example refers to Desktop remember it can't find any of the SpecialDirectories. It's not restricted to Desktop.
But only the first time it's run (ie. immediately after an update). Thereafter it will run fine.
If the process failed more spectacularly, to do with file system issues, locks or threads, it would be more understandable. But why just this "minor" problem with the My namespace?
I realise now it was nothing to do with the copied file and everything to do with a badly implemented System.Security.Principal.WindowsImpersonationContext.
Amazing how these things become clear 5 minutes after posting.
Related
Im developing a system using vb2022 its almost done but today the changes I made doesn't reflect on run time.
For example I added a button but when I run the program the button will not show.
Same as the code, i can write code but it doesnt reflect on run time
Plus im trying to change the startup form into form 2 (initial is form 1) but it doesn't reflect.
What should I do? I didn't change anything I just opened the file and write code. But suddenly this happened.
Most likely your build is failing and VS is automatically running the old output. When that happens, VS will prompt you whether to run the old output or not by default, but many people tell VS not to prompt them again without actually reading the dialogue. Use the Build menu to build your project/solution and pay attention to the Output and Error List windows to see whether it failed or not.
It may be that the compilation is succeeding but VS simply can't overwrite the output files because they are locked, which does happen sometimes. In that case, just delete the entire obj and bin folders from your project folder. You may need to close VS to do so. The next time you build, new output will be created and run.
If this happens regularly then you should probably repair VS and, if it continues after that, reinstall.
My problem :
I made a program and i have this program for example now under this directory : "C:\Program Files (x86)\AppName", now in the program i'm saving some images in my program directory, but since this is in the C drive, it's giving me a access denied error, now i made the program to always run in administrative mode and that worked just fine, but also there is in my program a feature to auto-start my program when the system starts up using a registry key, but when the "always run in administrative mode" is ON, the program will not start even though there is a start-up key in the registry, and when the "always run in administrative mode" is OFF, it will start.
What I have tried so far :
I tried making an another executable file that will start when the system starts up and then it will run my main program and close it self and i knew that will work but now every time i start my computer, the User Access Control prompt ask me if i trust this program even and that is not very user-friendly.
So i searched and i found that i can create scheduled task but i didn't find a lot of examples and but i tried creating one manually and it did work as wanted!
But here is a code which didn't work :
Imports Microsoft.Win32.TaskScheduler
Using ts As New TaskService("\\RemoteServer")
'Create a new task definition and assign properties
Dim td As TaskDefinition = ts.NewTask()
td.RegistrationInfo.Description = "Does something"
'Create a trigger that will fire the task at this time every other day
td.Triggers.Add(New DailyTrigger() With {
Key.DaysInterval = 2
})
'Create an action that will launch Notepad whenever the trigger fires
td.Actions.Add(New ExecAction("notepad.exe", "c:\test.log", Nothing))
'Register the task in the root folder
ts.RootFolder.RegisterTaskDefinition("Test", td)
End Using
And the problem with the code is :
It couldn't find the TaskService and it has no use of the TaskScheduler library!
Hope someone have some previous experience with that who can help me!
To answer your question:
To use that code you've got to download the Managed Task Scheduler Wrapper first. Then to make it run with administrative privileges you've got to set the RunLevel to TaskRunLevel.Highest on your TaskDefinition:
td.Principal.RunLevel = TaskRunLevel.Highest
However like Plutonix says you shouldn't be writing files to the directory of your program (as that's usually located in the restricted %ProgramFiles% folder).
Instead, use the %ProgramData% directory. You can get the path to it from your code via Environment.GetFolderPath():
Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)
'Example:
Dim ConfigPath As String = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "AppName")
Dim ImagePath As String = Path.Combine(ConfigPath, "MyImage.png")
If Directory.Exists(ConfigPath) = False Then Directory.CreateDirectory(ConfigPath)
if I have two or more running python console applications at the same time of same application, but executed several times by hand or any other way.
Is there any method from python code itself to stop all extra processes, close console window and keep running only one
The solution I would use would be to have a lockfile created in the tmp directory.
The first instance would start, check for the existence of the file, create the file since it is not there, then run; the following instances will start, check for the existence of the file, then quit since it's there. The original instance would remove the lockfile as its last instruction. NOTE: If the app runs into an error and does not execute the instruction to remove the lockfile, you would need to manually remove it else the app will always see the file.
I've seen on other threads that some suggest using the ps command and look for your app's name, which would work; however, if your app will ever run on Windows, you would need to use tasklist.
Okay, this is one that has me stumped beyond belief. I have a program that is to be installed on different machines that is supposed to execute a batch file after it has completed a specific task. The batch file is configured via our webservice by the user, and the application pulls this path string down and then executes the file at that path. Should be pretty simple/straightforward, right?
The code:
Private Function ExecuteBatchFile(batchFilePath As String) As String
Try
Dim psi As New ProcessStartInfo(batchFilePath)
psi.RedirectStandardError = True
psi.RedirectStandardOutput = True
psi.CreateNoWindow = False
psi.UseShellExecute = False
Dim process As Process = process.Start(psi)
process.WaitForExit()
ExecuteBatchFile = process.ExitCode
Catch ex As Exception
StrAppStatus = "Error within execution of batch file: " & ex.Message
LogMe(StrAppStatus)
Return "Fail"
End Try
End Function
Now, for the tricky part. This code works perfectly when running in the dev environment. I have yet to have an issue. HOWEVER, when the application is installed on any computer (including the same one the IDE is installed on), when it gets to the step in it's overall process that calls this function, it does not actually launch the batch file. Keep in mind, it never throws an exception, on either side. It also does not return an exitcode to that string, as i have other logging to track that as well.
There are only two possibilities I can think of in this case. Either A:) there is a permissions issue where the application is not allowed to launch batch files on the computer it is installed on, or B:) this sub is called by a thread that was spun off from the main thread (i.e. using the MyThread = New System.Threading.Thread(AddressOf TheMainLoop) MyThread.Start() command).
Still the fact that it works 100% of the time during the compile and run phase in the IDE but not after an install is blowing my mind.
EDIT 1:
Just did a test where I placed a button on the main form itself, and the click event does the same thing as the earlier function, and it works, even after an install. This leads me to believe that it will only work if it is launched using the main thread... What do you all think?
EDIT 2:
The batch file is a very simple test batch that opens a text file, and I know that the batch file and path are both fine, because when compiled it works fine. Also, edit 1 was stating that I created a simple button that executes the same code from above, and it works fine after an install. Since that was done on the main thread, and the code from earlier was done in a separate thread spun off from the original, I was wondering if that was the cause of the issue.
The other crazy thing is that my logging catches if the file launches or not, and it almost acts as if it is launching when I have that original issue. Bah, this whole thing is just nuts.
EDIT 3:
Added the answer.
Thanks to tinstaafl, the answer was to change UseShellExecute to True. I had to remove the RedirectStandardError and RedirectStandardOutput lines, but I wasn't using them anyways. On that note, thank you everyone for your investigations, and if anyone has an idea as to why this happened, I am all ears.
I'm creating a self updating app where I have the majority of the code in a seperate DLL. It's command line and will eventually be run on Mono. I'm just trying to get this code to work in C# on windows at the command line.
How can I create a c# application that I can delete a supporting dll while its running?
AppDomain domain = AppDomain.CreateDomain("MyDomain");
ObjectHandle instance = domain.CreateInstance( "VersionUpdater.Core", "VersionUpdater.Core.VersionInfo");
object unwrap = instance.Unwrap();
Console.WriteLine(((ICommand)unwrap).Run());
AppDomain.Unload(domain);
Console.ReadLine();
at the ReadLine the VersionUpdater.Core.dll is still locked from deletion
The ICommand interface is in VersionUpdater.Common.dll which is referenced by both the Commandline app and VersionUpdater.Core.dll
The only way I've ever managed something similar is to have the DLL in a separate AppDomain to the assembly that is trying to delete it. I unload the other AppDomain and then delete the DLL from disk.
If you're looking for a way to perform the update, off the top of my head I would go for a stub exe that spawns the real AppDomain. Then, when that stub exe detects an update is to be applied, it quits the other AppDomain and then does the update magic.
EDIT: The updater cannot share DLLs with the thing it is updating, otherwise it will lock those DLLs and therefore prevent them from being deleted. I suspect this is why you still get an exception. The updater has to be standalone and not reliant on anything that the other AppDomain uses, and vice versa.
Unwrap will load the assembly of the object's type into the appdomain that calls it. One way around this is to create a type in your "base" assembly that calls command.run, then load that into your new appdomain. This way you never have to call unwrap on an object from a type in a different assembly, and you can delete the assembly on disk.
When I built a self-updating app, I used the stub idea, but the stub was the app itself.
The app would start, look for updates. If it found an update, it would download a copy of the new app to temp storage, and then start it up (System.Diagnostics.Process.Start()) using a command-line option that said "you are being updated". Then the original exe exits.
The spawned exe starts up, sees that it is an update, and copies itself to the original app directory. It then starts the app from that new location. Then the spawned exe ends.
The newly started exe from the original app install location starts up - sees the temp file and deletes it. Then resumes normal execution.
You can always use MOVEFILE_DELAY_UNTIL_REBOOT to delete on reboot. This is most likely the least hackey way todo this sort of thing, by hackey I ususally see things like; loading up new DLL's or injecting to explorer.exe even patching a system dll to get loaded into another process, etc...
MoveFileEx From MSDN;
lpNewFileName [in, optional] The new
name of the file or directory on the
local computer.
When moving a file, the destination
can be on a different file system or
volume. If the destination is on
another drive, you must set the
MOVEFILE_COPY_ALLOWED flag in dwFlags.
When moving a directory, the
destination must be on the same drive.
If dwFlags specifies
MOVEFILE_DELAY_UNTIL_REBOOT and
lpNewFileName is NULL, MoveFileEx
registers the lpExistingFileName file
to be deleted when the system
restarts. If lpExistingFileName refers
to a directory, the system removes the
directory at restart only if the
directory is empty.