I have a Ruby application I'm installing (along with a packaged ruby interpreter) under Program Files on Windows 7 with an NSIS-built installer. In order to debug it, I edited one of the files to add some debugging statements. After that, I uninstalled the package and ran a new version of the installer which includes a new copy of the edited file, without debugging statements.
Now, I can't get the new copy to load into ruby. If I run type <filename> in cmd.exe, or open the file in Notepad.exe or Firefox, I see the new version. If I run ruby -e "puts File.read('<filename>')", or open the file in emacs, I see the old version.
If, in Windows Explorer, I copy the file to a new filename, everything can see the new contents at that filename. If I delete the original file and rename the copy to replace the original, the split personality returns.
This situation survives a reboot, so it's not a simple matter of a file being accidentally held open.
What on earth is going on here? Is there some aspect of the install process that might be checkpointing the file in a way I can revert, or at least switch off while I'm debugging the installer?
update
If I run ruby -e "puts File.read('<filename>')" in a console that is run as administrator, I see the correct, new contents. How should I be managing this file?
I think it has to do with UAC file system virtualization. Check whether your file exists in C:\Users\<username>\AppData\Local\VirtualStore. If it does, delete it from the VirtualStore.
The fact you see the correct file when running Administrator console proves that it's because of virtualization: UAC virtualization is turned off for elevated processes.
In general, do not put files you plan to change a lot in Program Files. From Vista onward, there is an interesting way things work to "allow" you to write to a protected file, but it really gets stored in your app data directories, not actually in Program Files. So, utilities that go through the Windows API find the "new" version of the file correctly, but utilities that are more low-level (ruby.exe) only find the existing version. If you navigate to that folder, do you see a "Compatibility Files" button right above the contents? Press that and you'll see your updated version.
Scott Hanselman wrote a good article about this when it was introduced in Vista.
You can only write to the real file when you're logged on as Administrator.
Related
I have a fairly large application (~750k LOC) that I distribute using the Package and Deployment Wizard. I fully understand that it would be nice to migrate to .NET (that ain't happening - see the code size above), and that the PDW is deeply flawed. However, for the most part I've made it work well for my end users, by customizing the Setup1 application, writing a menu-driven wrapper for the Setup application, and by running it in silent mode. (Note that the problem I'm about to describe occurred even before I started using silent mode.)
The issue I'm having is that my application requires quite a few auxiliary files, which I've added to the PDW project in the "Included files" section. When a user does a clean installation (either from scratch, or after un-installing a previous installation), everything works fine. However, if they simply run the installer to update the existing installation, the executable file and any OCXs I've updated get copied over the previous versions just fine, but my auxiliary files don't - I have to have the user manually delete them, and then the Setup1 program will re-install them as it should.
I've checked in the Setup.lst file, and all of the files are listed there, with their current date stamps. In fact, in my "BuildAll.bat" file, I do the Windows equivalent of a "touch" (copy /b "TheFile.dat" +,,) to force the date stamp to be current. However, if the file exists on the target machine, it won't be over-written even though it's older. There are no errors reported, either visibly or in the .LOG file (which is required if using the silent option).
A couple of additional points: Some of the auxiliary files are themselves VB6 applications - just the .exe files. Those do get copied correctly if they're newer than the existing files. Other than being files with internal versioning information, there's no difference between them and the other auxiliary files (which are things like media files, or text-based .txt or .dat files).
So, what's going on, and how do I fix it (besides moving to Inno or some other solution that won't work for me...)? Thanks in advance for any help!
~~
Mark Moulding
I have written my own screensaver, which makes use of additional files located at the same directory as the screensaver executable (.scr file).
If I right-click on the screensaver and select 'Test', all is well, those extra files are found.
But if I right-click and click on 'Install' to install the screensaver, it seems to not be able to find those files anymore.
Does the installation process make another copy of screensaver, or maybe change the working directory? If so, what directory is it in?
It's a Windows 7 desktop.
So far I have searched in Windows folder, Program Files, Program Files (x86).
UPDATE:
So, I added the following bit of code to determine the executable's location.
System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName
It appears that the screensaver is running from the directory where I put it, from the original file. However, after installing it, the only way I can reach files in the same folder from the executable is if I use full paths. If I run it as Test, I can simply use filenames only.
This should be a clue as to what is going on, I think. The above function, if I run it as Test, returns long file names, but if I run it as Installed, it returns short file names. I think that when Installed, it runs as some kind of a special process, or maybe a child process, which also interferes with file access.
What is going on?
I added a piece of code to determine the current working directory, and found that when running the screensaver in Installed mode, the current working directory becomes C:\Windows\system32, which would of course explain how files are referenced.
Environment.CurrentDirectory
I have made an installer (using Inno Setup) for my software, which is finally installed in
C:\Program Files (x86)\MyApp\myapp.exe
as usual on Windows platform, and it works perfectly.
A problem comes when my software tries to write its config file here :
C:\Program Files (x86)\MyApp\myapp.cfg
here a Permission denied error arrives !
The only solution I have found is "Run software as administrator", but I don't like this solution : I don't want to ask the final user to have to do "Run as adminstrator" each time they will use the software.
Is there a clean solution for having the right to write in C:\Program Files (x86)\MyApp\myapp.cfg without asking the final user to "run as administrator" ?
As #TLama said, never ever try to write to the application folder. That was never the recommended practice and since Vista Microsoft has disabled it (by first allowing you to write but actually redirecting the writing to another directory, a functionality which in later OS versions seems to have been removed - and good thing too as it was making support hellish).
To retrieve a known folder path, use SHGetFolderPath function. Depending on whether the application data is shared among all users or just used by the user running the app, you should call SHGetFolderPath either with CSIDL_COMMON_APPDATA or with CSIDL_LOCAL_APPDATA respectively. Avoid writing directly in those folders but create subfolders like <your company>\<your app> and use those instead.
Note that SHGetFolderPath has been deprecated and SHGetKnownFolderPath should be used in lieu of it but only if you don't need compatibility with Windows versions prior to Vista.
For completeness sake, this thread also describes how to import SHGetFolderPath into Python.
Update: Corrected to avoid using environment variables and SHGetFolderPath instead per comments by #RemyLebeau #TLama
My installer requires there be two files in the same directory in order for it to install.
The installer (.msi file)
An organization specific config file that the installer copies. (This file is customized by the organization and then distributed to it's end users).
Since there are two files, the file has to be distributed as a zip file. Which presents the issue of if a user tries running the .msi without actually extracting the zip... only the msi file gets extracted. I am able to detect the issue in the install process and tell the user they need to unzip the file... but you know how noone actually reads error messages.
So, I'd like to make it more foolproof and so i was wondering if there was a simple tool that i could let my customers (ie the organization) be able to make modifications to the config file and when finished create a .exe file which when clicked would extract to a temp folder and then run the msi. I know there are solutions for this which require commercial software. I'm wondering if a simple freeware tool exists that can do this.
Edit: Accepted Solution Notes:
The one issue i ran into is the iexpress wasn't designed to be used for .msi files. As a result on the step that asks you for the Install Program. It's a combo box which if you had added a .exe file in the previous step could just select the .exe file from. Instead you have to manually type in
msiexec /i yourinstaller.msi
I was very pleased to find such a simple solution that's built in to windows. The only way this could be better is if it allowed for wildcards so that your iexpress project would be able to handle changes in the msi file's name which occur with each version. And defaulting the Install Program to the .msi file. These minor inconveniences are offset by the fact that end user wouldn't need to install any new software to create the package so I have stopped looking for other tools.
You could try using iexpress.
It enables you to package up a set of files which can be extracted, with the option of running an installation command automatically after extraction. It also has options to enable you to prompt users about things, show a EULA, restart the computer, etc..
I believe it comes as part of Windows (part of IE?) - try running iexpress.exe from the run dialog to get the UI.
The Wix project has a bootstrapper and packager for dealing with this kind of thing.
I've used wix a lot but haven't really looked at the bootstrapper/packager much - last time I had a quick look it wasn't really usable but that was a long time ago so it may be better now.
I'm guessing that the config file is something like a properties file, and that you want users to set the values of the properties "foo" and "bar". You don't need a separate tool to update the file.
I would do this:
Put one or more dialogs in the install that ask the user what the values of foo and bar should be, and set a couple public properties accordingly.
Write a custom action that writes the config file out to whatever location you want, including whatever values you want for foo and bar. This would be pretty easy in vbscript.
Put the custom action somewhere in the execute sequence (ideally as a deferred execution action, since you're making changes to the system).
Add an entry to the RemoveFile table, so the config file is removed on uninstall (assuming you don't want it to be left behind.)
Add an entry to the LaunchCondition table, to prevent users from doing a silent install. Or if you want silent install to be allowed, make the names of the public properties that hold the config data known, and make them part of the LaunchCondition. You would block "msiexec /i myapp.msi", but you could choose to allow "msiexec /i myapp.msi FOO=Something BAR=SomethingElse".
I have a Windows service application on Vista SP1 and I've found that users are renaming its executable file (while it's running) and then rebooting, thus causing it to fail to start on next bootup because the service manager can no longer find the exe file since it's been renamed.
I seem to recall that with older versions of Windows you couldn't do this because the OS placed a lock on the file. Even with Vista SP1 I still cannot copy over the existing file when it's running - Windows reports that the file is in use - makes sense. So why should I be allowed to rename it? What happens if Windows needs to page in a new code page from the exe but the file has been renamed since it was started? I ran Process Monitor while renaming the exe file, etc, but Process Mon didn't report anything strange and just logged changing the filename like any other file.
Does anyone know what's going on here behind the scenes? It's seem counter intuitive that Windows would allow a running process' filename (or its dependent DLLs) to be changed. What am I missing here?
your concept is wrong ... the filename is not the center of the file-io universe ... the handle to the open file is. the file is not moved to a different section of disk when you rename it, it's still in the same place and the part of the disk the internal data structure for the open file is still pointing to the same place. bottom line is that your observations are correct. you can rename a running program without causing problems. you can create a new file with the same name as the running program once you've renamed it. this is actually useful behavior if you want to update software while the software is running.
As long as the file is still there, Windows can still read from it - it's the underlying file that matters, not its name.
I can happily rename running executables on my XP machine.
The OS keeps an open handle to the .exe file,. Renaming the file simply changes some filesystem metadata about the file, without invalidating open handles. So when the OS goes to page in more code, it just uses the file handle it already has open.
Replacing the file (writing over its contents) is another matter entirely, and I'm guessing the OS opens with the FILE_SHARE_WRITE flag unset, so no other processes can write to the .exe file.
Might be a stupid question but, why do users have access to rename the file if they are not suppose to rename the file? But yeah, it's allowed because, as the good answers point out, the open handle to the file isn't lost until the application exits. And there are some uses for it as well, even though I'm not convinced updating an application by renaming its file is a good practice.
You might consider having your service listen to changes to the directory that your service is installed in. If it detects a rename, then it could rename itself back to what it's supposed to be.
There are two aspects to the notion of file here:
The data on the disk - that's the actual file.
The file-name (could be several or none) which you can give that data - called directory entries.
What you are renaming is the directory entry, which still references the same data. Windows doesn't care about your doing so, as it still can access the data when it needs to. The running process is mapped to the data, not the name.