I have an msi. In it I have several config files (a.config, etc) and exes (jux.exe, etc).
In my msi I created a custom actions - commit for one of the exe (jux.exe). I make the installerclass false.
The idea is for the msi to call jux.exe right after install.
jux can start ok until it tries to validate the existence of some of the files (jex.exe, jax.exe etc.) and reading files inside the msi (a.config, b.config etc). seems like jux.exe cant find the files.
Should I not use commit? ideas?
It's most likely failing because you are making assumptions about the locations of the files, and they are incorrect. Your exe is being run from an msiexec.exe with the system account and an unknown working directory. It is not being run from an interactive user shell with explorer setting the working directory and running it with your credentials. If your code just tries to open a.config without specifying the full exact path then it won't find it.
All VS custom actions run after everything is installed, so you got lucky there. You don't need a Commit custom action - an install custom action will work too. That will also be called after all the files are installed. It's not clear why you want to validate the existence of the files - there's no point. An MSI install either works and installs everything or fails, rolls back and restores the system to its previous state. So there's no point in checking that it installed files.
There's no good way around this problem using this project type. It simply fails to expose full control over when to schedule your custom action and boils it down to overly simplistic choices. If I was you I'd factor this custom action out into a WiX merge module and then merge that into your VDPROJ installer (or go full WiX).
Related
Okay, so I've been building a c# activeX control and have run into EVERY issue in the book during the process...That being said, I have everything squared up now except the installer
Before I can delve into the issue itself, I need to explain how my setup process is working and why I have chosen this route.
I have a signed CAB file that stores my setup exe, which is loaded through a web page using an object tag
The setup exe is an InstallShield LE project which has my project embedded inside of it (i.e. the files to be installed are a part of the final setup binary)
The CAB file has an INF file in it which tells the caller to run the setup exe to install the control
This process runs just fine and launches the setup application, which then does successfully install the control. However, near the end of the setup process users who are NOT administrators receive an error message stating the following:
An error occurred while copying file myINFFile.inf
Cannot copy file to destination directory.
Click Retry to retry the operation or click Cancel to
(yea, it just cuts off after the word 'to')
If you hit retry it does nothing but repeat the error over and over until you hit cancel. If you hit cancel it says something to the effect of 'Would you like setup to continue in spit of this error?', which then goes on to successfully install the control.
As this error only happens to users with limited permissions I believe the issue is that the cab extraction process cannot extract the inf file to the location it's trying to extract it to...it's just very annoying because this file serves no other purpose, especially during the installation process, but I cannot figure out why the issue is happening or how to work around it...
Use process explorer (by Microsoft/SysInternals) to see what files are written.
My guess is that you did not author setup properly to allow per-user install of you ActiveX control.
(by Robert Petz) If you add the following hook to the INF file it runs correctly and extracts the cab to a allowed location:
[Deployment]
InstallScope=user
First off hi all, and thanks for the many times searching here has helped me out or taught me something.
I've made a custom HUD for a game I play, and am working on an installer in C#, inspired by another HUD for the same game. It downloads and overwrites all the script files to the existing directory:
C:\Program Files (x86)\Steam\steamapps\me\team fortress 2\tf
[I don't have any control over which folder to use unfortunately, since I'm modifying files which Valve installed]
In order to delete folders, add folders, or copy files, I've had to use an app manifest to increase the user permissions every time the exe is launched:
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
Somehow, the installer I've been inspired by is installing to the same folder that I am, without forcing a UAC prompt.
His app only shows a security warning, but if I uncheck the "always check" checkbox, I can run it over and over again without having to verify any special permissions:
http://www.trishtech.com/img_art_a/win7_publisher_not_verified_0.jpg>">
Any suggestions on how I can make my app more seamless like his? I've contacted the author of the other app, and he says he is also using C#, but doesn't know of anything special he's doing to make this work.
EDIT: A few things I know we're doing differently, just in case they make a difference somehow:
I'm using a file browser to decide where to put my files, so the app can be run from anywhere.
He's just outputting them to the same directory as the exe, requiring the exe to be put in the destination folder.
I'm using ILMerge to bundle SharpZipLib with my app.
He's just leaving the dll in his zip file next to the exe.
If you are trying to write to "C:\Program Files (x86)" then you need admin rights. It follows that the other app must not be creating files there, but to a directory that is not protected by UAC.
If your files are per user, then you can create a subfolder in the appdata folder and save the files there.
Convention is to create a folder to indentity the company and another to identity the product,
eg
var dir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)
+ "\\MyCompanyName\\MyApplicationName";
He's just outputting them to the same directory as the exe, requiring the exe to be put in the destination folder.
I don't think that will be it. The same exe directory should be no different, you either have permissions or you don't.
The "normal" response would be, write to a directory you have permission to. But this is not always possible.
If you ran your application as a service it would popup just the once I think under Windows, but this does not seem right for your use case.
I don't think there will be any proper way to suppress such a message, its like a catch 22 situation. To do something you cannot do, you need to get permission (so elevate user -> UAC popup).
I'm marking sgmoore's answer as the right one, although my own case seemed to be something a bit stranger and I want to document that too.
I've stripped down my program to the basics and done a lot of experimenting. I figured out that for some reason, he and I actually can copy files and create folders into that directory. Maybe it's something special about the steamapps folder, or maybe it's just a bug that's making it actually work in this limited case, when it shouldn't normally for "real" programs.
What was actually requires the UAC prompt, strangely, was running the exe from the \Bin\Debug\ folder where my project was initially generating it. If I move my exe somewhere else and then run it, it works fine. If I run his exe from my \Bin\Debug\ folder, his doesn't work either. I haven't been able to figure out why that is.
Something else I noticed is that when my app is going to succeed without an exception, it doesn't prompt with the security warning when I launch it. It just silently opens and then works. Any time it does display the security warning, it fails.
I guess the protocol would be to turn those two issues into new questions, but it seems at this point it's probably well into edgecase/hack territory since all of you agree that this shouldn't even be working at all.
I'm going to build my program back out and see if I can still get it to work with full functionality under these weird circumstances, or whether I'll have to reenable the UAC elevation.
I've built against the release profile and this creates an executable build within the release directory in my project.
How do I best distribute to clients from this executable? There are a lot of files within this folder which don't appear when installed through the installer, such as the mainifest and one called application.exe.xml (which is confusing when Windows hides the extension in Windows Explorer).
Are these all necessary? Can I just send the executable? Or will I need to send with all the files? Is there a way to build without all these files?
You must send the EXE file and any DLL file that you reference locally. If you use COM references and the like, you need to register them during the installation. The same thing for the GAC I think, but I haven't used that for stand-alone applications myself.
The application.exe.config file contains the application settings (a copy of app.config). If you don't use settings or the user doesn't typically care about them, you can omit the file, and it will use the default values you built the application with.
The vshost files are not needed (if you have them). They are used by Visual Studio's debugger. The .pdb files contain debug data used to facilitate DLL file to source matching. Unless you plan on attaching a debugger to the application, there is no point sending those.
Usually, in an XCopy deployment you have to deploy (literally copy all files deployment with no setup/installer program) the content of the output folder (like debug or release) without:
*.pdb - debug symbols
*.xml - xml documentation
?vshost? - Visual Studio hosting files
In fact, it anyway also depends on your specific application. As a developer, you need to know what you are producing; in case you are using an xml file which is not the result of the .NET documentation compiler, but a static file copied in the output folder, then do not forget to deploy it.
A last note: developers usually disable the option to hide file extensions in Windows Explorer ;-)
You need to understand what an installer does or why an installer is important.
An installer takes care of the basic environment. The installer can carry dependent assemblies/modules along with the application. It can also check if you need something before you run, like .NET on the target machine. It can also create the shortcuts on the desktop or start menu. Plus it also provides adequate options on the target machine to uninstall it.
If you wish to ship the executable alone, you might miss out some assemblies that the executable depends on. The target machine may or may not have the correct .NET version installed.
Use the program: HM NIS EDIT from HM Soft.
Build your project
Run NIS EDIT
Make a new script from the wizard (Ctrl + W)
Run all the steps
Select all the .dll and .exe files
Build a setup file
I am using a custom action during install to write a text file to my install directory. When I uninstall, that file is not removed nor is the corresponding install directory. However everything else is uninstalled properly.
I understand the reason that WIX cannot uninstall this file using the uninstaller, I'm just wondering what's the best way to call into a "clean up" action on uninstall which in which I can manually delete the directory/file?
You could include a RemoveFile element in whatever component your text file is most closely associated. When that component is uninstalled, the text file will be deleted as well.
<RemoveFile Id="CleanUpLogFile" On="uninstall" Name="log.txt"/>
You could install an empty text file and then have the custom action write to the file instead of creating it.
In general, I would suggest to stay away from custom actions as much as possible (they can get quite messy when dealing with install, uninstall, patching, repair, etc.) You may want to consider having your application itself configure the file on first run or have an additional configuration app that is executed on first run.
you can always run a console app for example that removes the file through code. You would just add that project only to the uninstall custom actions.
Out of curiosity what is the nature of the text file? In similar situations where the text file is an install log I'd recommend logging to a temp directory or a location that is not under Program Files (such as the Program/AppData folders - C:\ProgramData\Manufacturer\ on windows 7 for instance).
This approach bypasses this issue completely eliminating the need to create custom clean up scripts or actions.
We have an application that we wish to install just a basic shell for. As the users use it, it will download and install the necessary dlls for actions that need to take place (imagine a wizard application scenario with several possible paths). Currently, everything is installed for all possible paths through the shell app.
For about 3 months out of the year, the dlls used for the possible paths go through a high churn rate with updates, so we wish to start ensuring the users have the most recent version of these dlls. The idea is that after all their selections are made, we'd make a web check to see what dlls are required for their selection and check to make sure they have the most recent version of those files.
All of this we have a plan for on how to do it. The problem I'm fighting is what is the most appropriate way to "install" these files. ClickOnce is not an option...too much legacy stuff here. Our app is installed in "Program Files" which obviously has restrictions for writing random files into the program's install folder under Vista and later.
Right now I see the options as the following:
On install mark the install directory as writable for the "Everyone" group. I haven't actually tested to see if this would work yet, or if Vista does something different in this scenario.
Split the download portion out into a second app that we can have prompt for elevated privileges so that it can download and install these files.
I'm leaning towards the second option since that maintains the security aspect of the Program Files folder. Others in the group lean towards the first option because they just don't want to have to worry about things. Or is there some other option I'm missing?
The app is a .NET app, though it has some requirements of third party dlls that are not managed assemblies.
As long as the dlls you want to load are managed, there are several ways to do this.
One way is to designate an Environment.SpecialFolder path such as AppData and dynamically load assemblies into your appdomain from there. RssBandit does this for plugins, there is a special directory that loads dlls and searches for specific interface implementations, loads them into a temporary appdomain, and then calls them from the app. You could take this one step further by using an IoC library like ninject or structuremap.
you could also try MEF, the new extensibility framework coming out in C# 4.
Personally, I like what Firefox/xul apps do. It's a hybrid of your two proposed solutions, I suppose. They have an updater.exe that lives in the install directory. I assume that means that the install directory is made writable during install so that they can run the update application. However, having never deployed a application in this manner, I can't tell you how much of a headache (or not) it is.
An alternative which you haven't mentioned, and may not know about, is using the .Net download cache. When you attempt to load an assembly you can give it a code base to load from. If you set the codebase to a web url (i.e. http://mywebhost/mycoolapp/) .Net will download the assembly from that url if it's not found in the download cache. It will also grab the latest version of the assembly from the web url if there is one.
This approach can be a pain as you'll likely have to deal with CAS security issues if your app needs elevated permissions. However, it is nice not having to write code to download the latest versions of your assemblies for you. If you want more information, I can find some resources and give more detailed examples.
The way I handle it is to have an update.exe installed into program files next to the main .exe file.
Then, on app startup, I have the app download an xml file off of the web and save it in the App Data folder. This file contains the latest versions of the dlls and has a simple Filename, Version structure.
Run through the list of filenames and if you don't have the dll locally or you have an older version, then add the needed dll to an update list.
After you generate your update list. Fire off the Updater.exe with a command line list of the files to be updated. You don't have to write them to program files but I do. On Vista, my updater pops up the UAC prompt correctly (as it should to maintain Program Files' security).
The updater then downloads the files to Program Files and restarts the main app.
One problem with firing off the second app is that you have to give it a manifest with "AsAdministrator" set in it.
This isn't hard to do, but once the updater is done and retriggers the main app, it cannot start the main app with normal privileges. An exe running as administrator can only start other exe's as administrator also, even if "AsInvoker" is set in the manifest. I don't know why you can't restrict it back to normal rights...you can only elevate permissions for some reason...