- NSIS Discussion
- problem with icons, CreateShortcut on 64-bit Windows and "C:\Program Files (x86)"
Archive: problem with icons, CreateShortcut on 64-bit Windows and "C:\Program Files (x86)"
o___O
24th February 2011 23:30 UTC
problem with icons, CreateShortcut on 64-bit Windows and "C:\Program Files (x86)"
I've creating an NSIS package and noticed that when a program is installed to the legacy 32-bit folder on 64-bit Windows 7 Ultimate SP1, that "C:\Program Files (x86)" is being translated either by NSIS or Windows to the environmental variable "%ProgramFiles%" which resolves to the 64-bit version of Program Files. Where I'm running into a problem is with CreateShortcut and the custom icon setting. Here's my code for starters:
CreateShortcut "$SMPROGRAMS\${APP_NAME}\${APP_NAME}.lnk" "$INSTDIR\online.exe" "" "$INSTDIR\online.exe" "" "" "" "Launches PSOBB"
CreateShortcut "$SMPROGRAMS\${APP_NAME}\Visit schtserv.com.lnk" "http://www.schtserv.com/" "" "$INSTDIR\online.exe" "" "" "" "Visit the SCHTHACK website"
CreateShortcut "$SMPROGRAMS\${APP_NAME}\Register a game account.lnk" "http://www.schtserv.com/bbregister.php" "" "$INSTDIR\online.exe" "" "" "" "You need an account to play PSOBB"
CreateShortcut "$SMPROGRAMS\${APP_NAME}\Community forums and support.lnk" "http://schtserv.com/forum/" "" "$INSTDIR\online.exe" "" "" "" "Join the community"
CreateShortcut "$SMPROGRAMS\${APP_NAME}\Readme.txt.lnk" "$INSTDIR\readme.txt" "" "" 0 "" "" "o_o"
Now if I install the program anywhere inside "C:\Program Files (x86)" and inspect the shortcuts above (right-click->Properties), and choose "Change Icon" it will prompt an error that says "Windows cannot find the file %ProgramFiles%\<installfolder>\online.exe." I did a test and found that if I placed a copy of online.exe in the 64-bit Program Files folder that the shortcut icon was found by Windows Explorer, and I did another test and found that the field was properly filled in if any folder other than C:\Program Files (x86) (such as C:\newtest) was used. What I think is NSIS has some type of code that is converting Program Files path by default to the environmental variable %ProgramFiles%. This might work on 32-bit Windows, but 64-bit Windows uses different folders for 32-bit and 64-bit and this causes the icon path at least for CreateShortcut to be resolved improperly in Windows Explorer (64-bit version).
What I also found is that in some cases the icon on the shortcuts will default back to the missing shortcut icon and you have to reset the icon manually on the shortcut for it to work again, which is how I discovered this problem. It does this every time after a reboot on the first shortcut in the code, the other ones are a bit different (URLs/Internet shortcuts) that don't seem to reset as often (so far). I'm still trying to fix this problem but thought I'd report about my findings, it's obviously a bug that needs fixing somewhere.
NSIS 2.46...
Zinthose
24th February 2011 23:48 UTC
:eek: Removed public display of stupid...
o___O
24th February 2011 23:55 UTC
These are shortcuts being installed to the Start Menu Programs folder, ala internal NSIS Constant $SMPROGRAMS. I also found that it makes no difference what InstallDir is, the user can change directories to C:\Program Files (x86) during the installation, or manually select C:\Program Files (x86) and it will convert the shortcut icon path to %ProgramFiles%. As I said I believe NSIS detects "C:\Program Files (x86)" in $INSTDIR and converts it to %ProgramFiles%... unless it is some internal calls of Windows doing it (which NSIS executes), which is definitely possible.
o___O
25th February 2011 00:10 UTC
Edit, scratch part of what I said before.
This was my InstallDir:
InstallDir "$PROGRAMFILES32\${APP_NAME}"
I changed it to
InstallDir "C:\PSOBB-installer\${APP_NAME}"
Rebuild...
Actually, I'll just post my entire script for you to test with some test files. I think the behavior I described with %ProgramFiles% variable only occurs if $PROGRAMFILES is initially used in InstallDir, this doesn't happen after changing InstallDir like I did above, and then manually select "C:\Program Files (x86)" as the installation location.
Here's my script & test files to make it work if you wanna take a look and try it: http://strags.com/d2/nsis.zip
Zinthose
25th February 2011 00:18 UTC
Kodama,
!define APP_NAME "My App"
>OutFile lnkTest.exe
InstallDir "$PROGRAMFILES\${APP_NAME}"
>Section
SetOutPath $INSTDIR
File/oname=online.exe "C:\WINDOWS\NOTEPAD.EXE"
CreateDirectory "$SMPROGRAMS\${APP_NAME}"
CreateShortcut "$SMPROGRAMS\${APP_NAME}\${APP_NAME}.lnk" "$INSTDIR\online.exe" "" "$INSTDIR\online.exe" "" "" "" "Launches PSOBB"
>SectionEnd
>
I ran this on my Windows XP x64 system and it works fine.
o___O
25th February 2011 00:41 UTC
Did you check the Change Icon function to determine if the path was set correctly? Didn't work on Win7Ult x64.. BUT the icon does show up properly, at least right after install. Problem I have run into, is that it might default back to the broken shortcut icon after awhile, which shows up on the next screen.
http://strags.com/i/myapp.png
http://strags.com/i/myapp.png
http://strags.com/i/myapp2.png
http://strags.com/i/myapp2.png
o___O
25th February 2011 00:47 UTC
If I go and put a copy of online.exe (for your example) in C:\Program Files\My App, it will find it without changing the shortcut. It won't work ever without being manually updated if it's in C:\Program Files (x86) under these exact circumstances. I used the same code as you...
Zinthose
25th February 2011 01:04 UTC
AH! not I see the problem... I'm going to perform some tests to see what can be done about this.
o___O
25th February 2011 01:07 UTC
Let me know what you find...
Anders
25th February 2011 09:28 UTC
NSIS does not touch your strings, blame the windows shortcut API. At least for you main apps shortcut, try not setting the icon directly and just use "" as the icon path
Edit: Another option would be to remove the SLDF_HAS_EXP_ICON_SZ flag and datablock after the shortcut has been created:
CreateShortcut "$temp\test.lnk" "c:\windows\system32\calc.exe" "" "c:\windows\explorer.exe" 1
System
::Call 'OLE32::CoCreateInstance(g "{00021401-0000-0000-c000-000000000046}",i 0,i 1,g "{000214ee-0000-0000-c000-000000000046}",*i.r1)i'
>${If} $1 <> 0
System::Call '$1->0(g "{0000010b-0000-0000-C000-000000000046}",*i.r2)'
${If} $2 <> 0
System::Call '$2->5(w "$temp\test.lnk",i 2)i.r0'
${If} $0 = 0
System::Call '$1->0(g "{45e2b4ae-b1c3-11d0-b92f-00a0c90312e1}",*i.r3)i.r0'
${If} $3 <> 0
System::Call '$3->5(i 0xA0000007)i.r0'
System::Call '$3->6(*i.r4)i.r0'
${If} $0 = 0
IntOp$4 $4 & 0xffffBFFF
System::Call '$3->7(ir4)i.r0'
${If} $0 = 0
System::Call '$2->6(i0,i0)'
${EndIf}
${EndIf}
System::Call $3->2()
${EndIf}
${EndIf}
System::Call $2->2()
${EndIf}
System::Call $1->2()
${EndIf}
After I do this, (on XP) the change shortcut icon dialog displays c:\windows\explorer.exe and not %SystemRoot%\explorer.exe
Zinthose
25th February 2011 16:17 UTC
As usual... Awesome work Anders :up:
I Wrapped your code up into a function/macro for easy implementation so I can add it to my own packages. I have been packaging for 64bit XP for some time but never noticed the issue. Worse yet no one has complained yet. :eek:
/******************************************************************************
WORKAROUND - FixShortcut
This snippet was developed to address an issue with Windows
x64 incorectly redirecting the shortcuts icon from $PROGRAMFILES32
to $PROGRAMFILES64.
See Forum post: http://forums.winamp.com/newreply.php?do=postreply&t=327806
Example:
CreateShortcut "$SMPROGRAMS\My App\My App.lnk" "$INSTDIR\My App.exe" "" "$INSTDIR\My App.exe"
${lnkX64IconFix} "$SMPROGRAMS\My App\My App.lnk"
Original Code by Anders - http://forums.winamp.com/member.php?u=70852
******************************************************************************/
>!ifndef ___lnkX64IconFix___
!verbose push
!verbose 0
!include "LogicLib.nsh"
!include "x64.nsh"
!define ___lnkX64IconFix___
!define lnkX64IconFix `!insertmacro _lnkX64IconFix`
!macro _lnkX64IconFix _lnkPath
!verbose push
!verbose 0
${If} ${RunningX64}
DetailPrint "WORKAROUND: 64bit OS Detected, Attempting to apply lnkX64IconFix"
Push "${_lnkPath}"
Call lnkX64IconFix
${EndIf}
!verbose pop
!macroend
Function lnkX64IconFix ; _lnkPath
Exch$5
Push$0
Push$1
Push$2
Push$3
Push$4
System
::Call 'OLE32::CoCreateInstance(g "{00021401-0000-0000-c000-000000000046}",i 0,i 1,g "{000214ee-0000-0000-c000-000000000046}",*i.r1)i'
${If} $1 <> 0
System::Call '$1->0(g "{0000010b-0000-0000-C000-000000000046}",*i.r2)'
${If} $2 <> 0
System::Call '$2->5(w r5,i 2)i.r0'
${If} $0 = 0
System::Call '$1->0(g "{45e2b4ae-b1c3-11d0-b92f-00a0c90312e1}",*i.r3)i.r0'
${If} $3 <> 0
System::Call '$3->5(i 0xA0000007)i.r0'
System::Call '$3->6(*i.r4)i.r0'
${If} $0 = 0
IntOp$4 $4 & 0xffffBFFF
System::Call '$3->7(ir4)i.r0'
${If} $0 = 0
System::Call '$2->6(i0,i0)'
DetailPrint "WORKAROUND: lnkX64IconFix Applied successfully"
${EndIf}
${EndIf}
System::Call $3->2()
${EndIf}
${EndIf}
System::Call $2->2()
${EndIf}
System::Call $1->2()
${EndIf}
Pop $4
Pop$3
Pop$2
Pop$1
Pop$0
FunctionEnd
!verbose pop
>!endif
Zinthose
25th February 2011 19:28 UTC
FYI: Wiki Article Created
MSG
25th February 2011 20:00 UTC
That URL in the comment is broken. You should probably point to: http://forums.winamp.com/showthread.php?t=327806
o___O
25th February 2011 20:24 UTC
Originally posted by Anders
NSIS does not touch your strings, blame the windows shortcut API. At least for you main apps shortcut, try not setting the icon directly and just use "" as the icon path
Edit: Another option would be to remove the SLDF_HAS_EXP_ICON_SZ flag and datablock after the shortcut has been created:
After I do this, (on XP) the change shortcut icon dialog displays c:\windows\explorer.exe and not %SystemRoot%\explorer.exe
Neither of these are suitable alternatives, though. The shortcuts I want to specify the icon on are Internet links, the default icon is just ugly and doesn't go with the program. Secondly, NSIS must be involved in this process somehow, because if InstallDir is set to "C:\${APP_NAME}" by default rather than "$PROGRAMFILES32\${APP_NAME}" - one can manually select the "C:\Program Files (x86)" folder during installation and not have this problem (shortcut icon path is correct, icons never vanish). I think the problem has to do with how NSIS is resolving $PROGRAMFILES or handling these Constants and the environmental variables internally (might be specific to InstallDir directive or when or how these variables are used)... Give it another look.
Zinthose
25th February 2011 21:10 UTC
Internet shortcuts are even easier to tweak as they are just ini files.
[InternetShortcut]
URL=http://download.microsoft.com/download/8/8/8/888f34b7-4f54-4f06-8dac-fa29b19f33dd/msxml3.msi
IDList=
IconFile=C:\WINDOWS\system32\accwiz.exe
HotKey=0
IconIndex=5
[{000214A0-0000-0000-C000-000000000046}]
Prop3=19,2
Do somthing like this..
WriteINIStr "$SMPROGRAMS\${APP_NAME}\My Web Site.url" "InternetShortcut" "IconFile" "$INSTDIR\online.exe"
>WriteINIStr "$SMPROGRAMS\${APP_NAME}\My Web Site.url" "InternetShortcut" "IconIndex" 5
>
...and it "Should" fix it.
EDIT: Or just read the Wiki article Stu Posted.. :D
Anders
25th February 2011 22:32 UTC
Originally posted by o___O
I think the problem has to do with how NSIS is resolving $PROGRAMFILES or handling these Constants and the environmental variables internally (might be specific to InstallDir directive or when or how these variables are used)... Give it another look.
InstallDir does not do anything special, $PROGRAMFILES is resolved using a documented shell function and nsis itself does not use environment variables IIRC.
o___O
2nd March 2011 10:12 UTC
I found more information out about this issue. From the manual:
4.8.1.21 InstallDir
definstdir
Sets the default installation directory. See the variables section for variables that can be used to make this string (especially $PROGRAMFILES). Note that the part of this string following the last \ will be used if the user selects 'browse', and may be appended back on to the string at install time (to disable this, end the directory with a \ (which will require the entire parameter to be enclosed with quotes). If this doesn't make any sense, play around with the browse button a bit.
So the problem is with this behavior in NSIS when InstallDir doesn't end with a \. Disable this feature and the icons and shortcuts are fine.
So..
InstallDir "$PROGRAMFILES32\SCHTHACK PSOBB" has the problem.
InstallDir "$PROGRAMFILES32\SCHTHACK PSOBB\" (disables behavior) doesn't have the problem.
It seems to be something going wrong in this feature when it enumerates and appends "SCHTHACK PSOBB" to the directory selection. For example, a user will choose "C:\Program Files (x86)" as the directory rather than a sub directory, and NSIS will fill in the sub directory to match the last string of InstallDir after the last \, in this case "SCHTHACK PSOBB," making it auto to C:\Program Files (x86)\SCHTHACK PSOBB\. For some reason this breaks CreateShortcut icon association and perhaps other functions in NSIS. What it looks like is Windows is looking in the 64-bit Program Files directory for the icon when this function is enabled, even though the program is really in the 32-bit Program Files folder, which I think is the result of this features functionality mixing up the 64-bit and 32-bit Program Files folders or how it resolves them.
Anders
2nd March 2011 13:11 UTC
Originally posted by o___O
making it auto to C:\Program Files (x86)\SCHTHACK PSOBB\.
Are you sure about this? $instdir will normally strip off the \ at the end.
Try:
strcpy $instdir "c:\temp\"
MessageBox mb_ok $instdir
>
Zinthose
2nd March 2011 14:59 UTC
I'm going to have to confirm with Anders.
I modified the test script and the issue remains.
Can you provide a script that shows the working vs non?
"My App"
>OutFile lnkTest.exe
ShowInstDetails show
InstallDir "$PROGRAMFILES32\${APP_NAME}\"
Page directory
Page instfiles
Section
SetOutPath "
$INSTDIR"
File /oname=online.exe "C:WINDOWSNOTEPAD.EXE"
CreateDirectory "$SMPROGRAMS${APP_NAME}"
CreateShortcut "$SMPROGRAMS${APP_NAME}${APP_NAME}.lnk" "$INSTDIRonline.exe" "" "$INSTDIRonline.exe" "" "" "" "Launches PSOBB"
SectionEnd
>