Let me layout the scenario.
We have a 3rd party application (say, app.exe installed to C:\App). It actually cannot run directly, it needs a configuration file passed to it as an argument: "C:\App\app.exe config.ini". Everyone already has shortcuts that contain the necessary arguments.
This application supports plugins, of which we have developed a few. In order to distribute said plugins, they need to be copied to each users C:\App\Plugin\ folder, so when a change is made I have to travel around to everyone's desk and make sure the update gets applied.
This was cumbersome, so I developed an application that will scan a network folder and compare it to it's internal db of files. If there are any changes, it copies the files over to the proper destination folder.
This wasn't seamless though, as the user would have to make sure app.exe was closed - run my updater, and then rerun app.exe. So I renamed the original app.exe to app_launcher.exe, and my updater to app.exe. I modified my updater application to support arguments and pass them through to app_launcher.exe when the update was done. Once app_launcher.exe has started the updater program closes.
I should note - the above actually works.
The problem comes from users who have the app shortcut pinned to the taskbar. Once the real app finally starts it gets it's own new icon on the taskbar instead of being grouped with the original shortcut. This actually makes sense as they are technically two different applications. The users however, don't like this.
I have done some research on this, and found some 3rd party programs that can allow you to group multiple programs (Bins/Fences). I DO NOT WANT THIS.
More research revealed something called the AppUserModelID, which intrigued me. After some playing around, I got my updater to set it's own AppUserModelID. The original app.exe didn't set it's AppUserModelID (found that out via ProcessHacker), but I was able to get the updater to start it with the same ID it was using via the CreateProcess method found in kernel32.dll.
This did NOT work. The updater started under it's own pinned icon, and the original app started a new icon. I tweaked the updater to stay open until the original app was closed to see if that made a difference. This time it started under it's own pinned icon, the original app started it's own, and then the updater window switched to be grouped with the original app under the new icon. So AppUserModelID did group them together, but not how I wanted.
I am using C# for the updater application, and cannot make changes to (or have changes made to) the original app.
How can I get these applications to group under the pinned shortcut? Is it even possible?
I think I may have found a solution, though it's a bit of a hack.
The problem comes from having the final application not matching the shortcut being run.
So rather than replacing the EXE and running the real one when done, I made sure the updater application would always run before the real exe.
The only caveat is that it also runs for EVERY exe on the system (via HKCR\exefile). The first parameter is now the path to the true executable, which if it matches the application it runs the updater. Once the updater finishes or if it is any other app, it runs it.
Not an ideal solution (as it could be detected as malware), but it should work for us.
Related
I have a windows app (written in C#...) that is installed on multiple remote workstations, the installation is being done by a MSI package.
An updated installation with changes to the program is being conducted from time to time, at this point, for each update, for each station we need to go to where the .MSI is located copy it and run it and only than start the app.
I would like that: whenever a user tries to start the app a background process will be initialized that will compare the installed version with the most recent version on the .msi location and if an update in needed will run the installation and than start the app.
The problem is that it can't be done from within the program since the program cannot be running when the installation/upgrade is taking place. Another consideration is that not all the stations operating at the same time so I can't schedule a timely upgrade, and it can't be done on stations boot since sometimes the updates needs to be done while the station is already operating(the station has several functions beside my app).
I have considered several approaches, it seems like a windows service could do the trick but I don't know if it could be "bound" to the initialize of the program and if it could suspend the program to do the necessary checks and updates and only than to restart the app.
I am open to all ideas so please don't feel obligated to my ideas...
at this point, for each update, for each station we need to go to where the .MSI
is located copy it and run it and only than start the app.
Fire the guy pretending to be a system administrator.
Unless you have done something odd in your installer - it should be doable with your standard software distribution package. Heck, I can roll out updates with active directory ONLY and no third party software as long as the MSI allows administrative no ui installs.
You try to fix a non-problem. Software distribution is a solved solution for the last 15 to 20 years. MSI was particularly created to handle this issue because other approaches demonstrated issues.
So, whoever pretends to be the administrator on your company needs to get his act together and be one. Do nothing (except making a good MSI) and let the admin do his job.
Everything else just creates a lot of problems (at least in the cost side). And it is totally not needed.
I'm updating my answer,
This is what we did....
Create the Installer / Package ( you can install for all users here)
Generate Bootstrapper (https://msdn.microsoft.com/en-us/library/ms165429.aspx
You can use this tool create bootstrapper (http://www.softpedia.com/get/Programming/Other-Programming-Files/Bootstrapper-Manifest-Generator.shtml)
Add dependencies and other conditions in bootstrapper
Set the URL for updates
This will solve your problem. I was too quick to answer but this how we did.
Thanks.
Some comments and answers about the assumptions in the question:
"I would like that: whenever a user tries to start the app a background process will be initialized that will compare the installed version with the most recent version on the .msi location and if an update in needed will run the installation and than start the app."
The only time this is likely to be a useful approach is when the MSI is at a company's web server. The web site can host a web api that you send your ProductCode, Version, Upgrade to and it reports whether there is an upgrade, patch etc, and a location to download it from. In a company domain, just use AD, as has been said.
"The problem is that it can't be done from within the program since the program cannot be running when the installation/upgrade is taking place."
Why? Windows Installer will show FilesInUse dialogs for the end user to close down the running app. So this situation is already dealt with, and I'm not sure where you see a problem.
"...and if it could suspend the program to do the necessary checks and updates and only than to restart the app."
This is exactly what Restart Manager is for. Integrate your app with RM and Windows Installer will allow you to close down the app (saving whatever data you need to recover) and then restart you afterwards so you can recover your data and the user sees a minimal interruption. One example:
http://www.codeproject.com/Articles/772868/Restart-Manager-Support-For-Windows-Application
So I think TomTom's point is valid - there is no need to re-invent what AD does, or worry about how to update programs that are running, or how to restart a program after an installer update because all these problems were solved years ago.
I need to update my executable with also the dll linked..
I've read about the AppDomainSetup.ShadowCopyFiles but I'm in trouble trying the right steps to do what I need
the question are:
the shadow copy I need to create only when I notify an update or each time I launch my executable?
what is the right step to copy and update the dlls and the .exe?
Creating a shadow copy is not going to update your application. The general sequence of auto-updating requires a third application that manages the process. It looks something like this.
Main application finds update and downloads update files to temp location
Main application launches updater application and terminates itself
Updater application copies update files over main application files
Updater application launches main application and terminates itself
Obviously there is going to be error handling logic built in to this. But that is the general idea. Shadow copies are nowhere in there.
Making use of the shadow copy feature of .NET is not a bad idea. It will allow you to update your assemblies without having to exit the application BUT you will need to restart the application in order to run the updated version. Shadow copy will simply allow you to overwrite the assemblies and nothing else.
Note that you cannot enable shadow copy on the default AppDomain. This means that you will need a loader that will create the AppDomain, and execute your application. Have a look at this answer for the steps you need to take and for a simple implementation.
If all you want to do is allow updates to be installed without having to exit the application then this is the simplest approach I can think of.
You should also have a look at Microsoft's ClickOnce technology. It solves a lot of the common problems of deploying and updating .NET GUI applications.
I need a deployment method that do following thing:
Auto-update, like click-once;
Install on all users, like Visual Studio Setup projects.
without admistratives privileges. (except the first times for the requirements)
Can install VB Powerpacks.
The problems is that I'm making a winforms program, that might need to be updated anytime, and that our computers are use by many users (our company run 24hours/days). And we don't want to update my program manually on our 80 computers, for each users!
Click-once could be great if we can do an install for all users (but yes, I already find that it's not possible).
I'M STUCK! Please help.
We use a system where the shortcut to launch our application actually launches an auto-updater. The updater checks the server for any update dlls, and if it finds them, it copies them to the local machine. After that (or if it didn't find any updates), it then launches the application.
This will only work if you have some way to force everyone to log out every now and then. We get around that by having the application watch for a specific file to be updated (the exe itself), and alerting the user every 5 minutes until they relaunch.
Question:
I need a DragAndDrop solution to download a file on drop in a folder of Windows Explorer for C# & .NET 4.0. It should not be necessary to have the file on the computer. The file will be big enough that the drag-time won't be enough to get the download done. I have found various questions, even accepted answers, but nothing that works. The very closest thing to something working is this demo project:
http://blogs.msdn.com/b/delay/archive/2009/11/16/creating-something-from-nothing-and-knowing-it-developer-friendly-virtual-file-implementation-for-net-refined.aspx
How to implement this code to download a file as part of the action of putting it to the drop place in Windows Explorer?
Web browsers solve this problem every day. Simplifying their model a little, do this:
Make a little program that performs your download given appropriate command line parameters. This little program should pop up a window with a progress bar and a cancel button.
Spawn this second program whenever the user "drops" something. This program will create the target file immediately and start filling it with data. It will maintain appropriate locks on the file until it is done downloading, at which point the "downloader" will exit.
If you're going to keep the "downloader" threads in the originating program, you will need some kind of download manager so that the user can get appropriate feedback on their downloads.
Okay, as Yahia said in the comments it's not possible without a proper shell extension for the different versions of Windows and .NET. You might have luck with the link I posted, but for me it crashes the Explorer and the developer thinks it works fine.
My honest opinion is with only .NET you can only do it with a FileSystemWatcher via copying special .temp-files, watching where they land, doing your task and replacing the .temp files when your task is done. Sad Windows.
Okay I've spent the afternoon researching and haven't had much luck finding the answer to this. I am trying to prevent an application from launching via some sort of dll or background application. It is to be used in monitoring application usage and licenses at my institution. I have found leads here regarding WqlEventQuery and also FileSystemWatcher. Neither of these solutions appear to work for me because:
With WqlEventQuery I was only able to handle an event after the process was created. Using notepad as a test, notepad was visible and accessible to me before my logic closed it. I attempted to Suspend/Resume the thread (I know this is unsafe but I was testing/playing) but this just hung the window until my logic finished.
With FileSystemWatcher I was not able to get any events from launching a .exe, only creating, renaming and deleting files.
The goal here is to not let the application launch at all unless my logic allows it to launch. Is this possible? The next best solution I came up with was forcing some type of modal dialog which does not allow the user to interact with anything, once the dialog is closed the application is killed. My concern here is killing the application nicely and handling applications with high overhead when they load such as Photoshop or something. This would also interfere with a feature I was hoping to have where the user could enter a queue until a license is available. Is this my best route? Any other suggestions?
Thanks
edit: To clarify this is not a virus or anything malicious. It's not about preventing access to a blacklist or allowing access through a whitelist. The idea is to check a database on a case by case basis for certain applications and see if there is a license available for use. If there is, let the app launch, if not display a dialog letting the user know. We also will use this for monitoring and keeping track if we have enough licenses to meet demand, etc. An example of one of these apps is SPSS which have very expensive licenses but a very limited pool of people using it.
Could you use
System.Diagnostics.Process.GetProcessesByName
in a loop to look for the process?
It might work if you don't use too aggressive a polling rate.
You are indeed close, take a look at the WMI Management Events. http://msdn.microsoft.com/en-us/library/ms186151%28VS.80%29.aspx
Sample code from Microsoft: http://msdn.microsoft.com/en-us/library/ms257355(VS.80).aspx
Subscribing to the appropriate event will provide your application with the appropriate information to perform what you described.
Not sure if this is a GOOD solution but you could do something like pass a key into main so that if the key is not present or valid the application shuts down. Then when you open the application in your code, just pass the key in. Someone would then have to know the key in order to start the application.
This is assuming you have access to the application in question's source code, which upon reading your question again, I'm not so sure of.
I assume you don't have source for the application you want to prevent from loading...
Have you considered using a system policy? That would be the best-supported way to prevent a user from launching a program.
You could have a service running that force-kills any app that isn't "whitelisted", but I can't say how well that would work.
I wonder if you are taking the wrong approach. Back in the day there was a Mac app that would prevent access to the desktop and had buttons to launch a set list of applications.
IDEA
What if you had a wrapper for the approved apps then only allow your wrapper to run on the computer?
I would expect there is some way of hooking an application launch, but can't help directly on that front.
You may be able to improve your current approach by detecting the application's window opening and hiding it (move it offscreen) so that the user can't attempt to interact with it while you are trying to shut it down.
However, another approach that may be possible (depending on your circumstances) would be to write an application launcher. This simply is a replacement for the shortcut to the application that checks your licencing conditions, and then does a Process.Start to launch the real .exe at that point. This would work well for any application. (I used a system like this for starting up applications with specialised environment settings and it works beautifully)
You could combine this with your current approach as a fall-back for "clever" users who manage to circumvent your launcher.
If my understanding is right you want to create an application what will prevent the computer user to start any other process except ones for a white-list.
If this is the case, monitor the process list of processes (in a while loop) using System.Diagnostics.Process (the GetProcesses method gives the list of all running ones)
Just kill the process when it starts.
Or if your machines have Windows 7 (Windows 2008??) you can use AppLocker. http://www.microsoft.com/windows/enterprise/products/windows-7/features.aspx#applocker Just let Windows prevent the startup.
You might want to look at this product: http://www.sassafras.com/licensing.html Personally I can't stand it, but that's because it does what you describe. Might save you some coding.
You could actually edit the registry so when you click a psd, your launcher gets called instead of photoshop. Your launcher then checks for licenses and if there is one starts photoshop with the path of the file.
This is a long shot but you may find it helpful.
Perceived Types and Application Registration
http://msdn.microsoft.com/en-us/library/cc144150(VS.85).aspx