Quintus
25th May 2011 01:21 UTC
AllUsers/CurrentUser install without elevation
I've got a game application that I'm trying to write an installer for. The game is an online game that has its own launcher/patcher and will need to apply frequent updates. Because of this, its desirable to install to a folder that doesn't require elevation to write to (otherwise the launcher/patcher would constantly have to request elevation to run)
Other applications in this situation have modified the traditional PerUser/AllUsers install paths to be:
* AllUsers = install to a common per-machine location (e.g., CSIDL_COMMON_APPDATA)
* PerUser = install to something like CSIDL_LOCAL_APPDATA
Microsoft even specifically addresses the problems posed by patching software here:
My preference would be to install to a location like:
- AllUsers
- Vista/Win7: C:\Users\Public\Games\
- XP: C:\Program Files\
- PerUser: C:\<profile>\My Documents\My Games\
This seems to be fairly irritating to implement. For starters, I haven't been able to get NSIS to reliably get me either the user's 'My Documents' folder or the 'Common' folder. I can get CSIDL_COMMON_APPDATA with something liek this:
System::Call 'shell32::SHGetSpecialFolderPath(i $HWNDPARENT, t .r1, i 46, i0)i.r0'
But that doesn't actually give me the path I want. It might *work*, but it's not optimal.
The SHGetSpecialFolderPath doesn't seem to work with the 'My Documents' folder. When I passin the CSIDL for that (12) - I get nothing... I can get it from the registry using
ReadRegStr $0 HKCU "SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders" Personal
But I've heard that the registry method may not be reliable in non-English Windows installations (I haven't verified that).
Finally - uninstallation can also be tricky. If a user installs (without privileges) in an AllUsers context to a folder like C:\Users\Public\ traditional installation/uninstallation tricks like writing registry keys/values to HKLM might not be available.
Does anybody have any experience with the kind of installer I'm talking about? I would really appreciate hearing from anybody who has been down this path before.
MSG
25th May 2011 06:02 UTC
Originally posted by Quintus
My preference would be to install to a location like:- AllUsers
- Vista/Win7: C:\Users\Public\Games\
- XP: C:\Program Files\
- PerUser: C:\<profile>\My Documents\My Games\
This seems to be fairly irritating to implement.
It's actually quite easy. Use nsDialogs to create a custom page asking for single/all user install, and use winver.nsh to distinguish between OS versions. Then simply do StrCpy $INSTDIR "Whatever Applies".
Originally posted by Quintus
For starters, I haven't been able to get NSIS to reliably get me either the user's 'My Documents' folder or the 'Common' folder.
It's all there in the manual...
http://nsis.sourceforge.net/Docs/Chapter4.html#4.2.3http://nsis.sourceforge.net/Docs/Chapter4.html#4.9.7.7Originally posted by Quintus
But I've heard that the registry method may not be reliable in non-English Windows installations (I haven't verified that).
The reliability problem occurs on any language Windows. Mostly on newly installed operating systems, actually. But either way, use the constants listed in the manual.
Originally posted by Quintus
Finally - uninstallation can also be tricky. If a user installs (without privileges) in an AllUsers context to a folder like C:\Users\Public\ traditional installation/uninstallation tricks like writing registry keys/values to HKLM might not be available.
A user-level user cannot install in an all users context. Only admins can. Use the userinfo plugin to verify whether you have admin access, and throw an error when you don't. Most people put it in .onInit, and add a "requestexecutionlevel admin" for graceful UAC handling.
Quintus
25th May 2011 23:26 UTC
For what it's worth, the only part that I was having trouble getting to work at all was extracting the public profile path for Vista/Win7. None of the standard NSIS constants resolve to the root of the public user profile folder (e.g., C:\Users\Public\).
After fishing around however, I found that in Vista/Win7, while there is not a CSIDL value that corresponds withe the public user profile, there is an environment variable %PUBLIC% that gets me what I want, so I now get the root for my AllUsers install on Vista/Win7 with the following:
ExpandEnvStrings $0 "%PUBLIC%\Games"
I have to be careful to only use the %PUBLIC% env. variable in Vista/Win7 (and I gracefully handle an empty result just in case), but for the most part I can just append my product-specific path on the end of that.
Anders
25th May 2011 23:30 UTC
There is no CLSIDL, but there is a knownfolder id. You need to use the system plugin to call that api tho. I use the API in some other example @ http://pastebin.com/MZeNijJJ you can just change the folder guid...