Old 16th November 2015, 12:11   #1
unisev
Junior Member
 
Join Date: Nov 2015
Posts: 7
Question %ProgramFiles% shortcut icon location on 64-bit Windows

Hello,

Here is a part of my code :
code:

ReadRegStr $0 HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\Patio" Path

CreateShortCut "$DESKTOP\SwitchPatio.lnk" "$0switch.cmd" "" "$0Switch\switch.ico"



Doing that, my customized icon is well used, but with this path :

%programfile%\Patio\Switch\switch.ico

How can I be sure that the path will be the true absolute path without %ProgramFile% ??

UniseV

Last edited by Anders; 17th November 2015 at 21:25. Reason: Changed title
unisev is offline   Reply With Quote
Old 16th November 2015, 19:19   #2
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,275
ExpandEnvStrings

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 16th November 2015, 22:22   #3
unisev
Junior Member
 
Join Date: Nov 2015
Posts: 7
Thank you Anders,

This did not solve my problem, since my var ($0) did not contain the environment variables (%ProgramFiles%)... even if my finally created shortcut, contain this environment variables .

This is not a big problem since the icon is well shown, the problem just appear when you try to manually change the icon shortcut...



Not a big problem
unisev is offline   Reply With Quote
Old 17th November 2015, 00:00   #4
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,275
Sorry, I somehow thought your App Paths entry had %ProgramFiles% in it.

If Windows adds it and then later has a problem with it then I'd call that a bug in Windows.

Is this a 64-bit system by any chance? I have seen problems with %programfiles% there in the past...

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 17th November 2015, 07:58   #5
unisev
Junior Member
 
Join Date: Nov 2015
Posts: 7
This is Win10 64-bit, the very last version (1511)

I don't know how 'NSIS-CreateShortCut' do the trick but when I do it in VBS the bug do not occurs, so is this really a Windows bug ?

There is in fact 2 bugs :
  • %ProgramFiles% is not expected, the absolute path is enough
  • It takes %ProgramFiles% instead of %ProgramFiles(x86)%
unisev is offline   Reply With Quote
Old 17th November 2015, 21:04   #6
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,275
Just to be clear, NSIS does not change c:\program files\... to %ProgramFiles%\..., it does some minor checking to make sure the path is valid and then just calls IShellLink::SetIconLocation. VBS has the exact same bug when you execute the script with the 32-bit version of wscript.exe.

This bug exists in the 32-bit IShellLink implementation when running under WOW64. Windows tries to be clever and sees that the path is inside %ProgramFiles% and therefore in addition to storing the path we used in SetIconLocation it also adds a EXP_SZ_ICON_SIG block to the .lnk. This is not a problem when running on 32-bit Windows but it becomes a problem on 64-bit Windows if you view the shortcut properties (created by a 32-bit program) in a 64-bit program! When a 32-bit IShellLink::SetIconLocation references something in the 64-bit Program Files folder then %ProgramFiles% does not match and it falls back to storing %SystemDrive%\Program Files\ which is actually better and works everywhere.




PHP Code:
RequestExecutionLevel admin
!include x64.nsh
Section
!if "${NSIS_PTR_SIZE}4
!error "Must be compiled as 32-bit!"
!endif
${
IfNot} ${RunningX64}
MessageBox mb_IconStop "Must be 32-bit app on 64-bit Windows!"
Quit
${EndIf}
DetailPrint ProgramFiles32=$ProgramFiles32
DetailPrint ProgramFiles64
=$ProgramFiles64

FileOpen 
$"$ProgramFiles32\lnktest32.cmd" a
FileClose 
$0
File 
"/oname=$ProgramFiles32\lnktest32.ico" "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico"
FileOpen $"$ProgramFiles64\lnktest64.cmd" a
FileClose 
$0
File 
"/oname=$ProgramFiles64\lnktest64.ico" "${NSISDIR}\Contrib\Graphics\Icons\modern-uninstall.ico"

/* If you uncomment these then the icon in lnktestvbs32.lnk will point to 
** "%SystemDrive%\Program Files (x86)\lnktest32.ico" and 
** not (the broken in 64-bit processes) "%ProgramFiles%\lnktest32.ico"
System::Call 'KERNEL32::SetEnvironmentVariable(t "ProgramFiles", t "c:\*invalid*\?path?")i'
System::Call 'KERNEL32::SetEnvironmentVariable(t "ProgramFiles(x86)", t "c:\*invalid*\?path?")i'
System::Call 'KERNEL32::SetEnvironmentVariable(t "ProgramW6432", t "c:\*invalid*\?path?")i'
#*/

InitPluginsDir
FileOpen 
$"$Pluginsdir\lnktest.vbs" w
FileWrite 
$'Set lnk = WScript.CreateObject("WScript.Shell").CreateShortcut("$Temp\lnktestvbs32.lnk")$\r$\n'
FileWrite $'lnk.TargetPath = "$ProgramFiles32\lnktest32.cmd"$\r$\n'
FileWrite $'lnk.IconLocation = "$ProgramFiles32\lnktest32.ico, 0"$\r$\n'
FileWrite $'lnk.Save$\r$\n'
FileWrite $'Set lnk = WScript.CreateObject("WScript.Shell").CreateShortcut("$Temp\lnktestvbs64.lnk")$\r$\n'
FileWrite $'lnk.TargetPath = "$ProgramFiles64\lnktest64.cmd"$\r$\n'
FileWrite $'lnk.IconLocation = "$ProgramFiles64\lnktest64.ico, 0"$\r$\n'
FileWrite $'lnk.Save$\r$\n'
FileClose $0
ExecWait 
'"$SysDir\wscript.exe" "$Pluginsdir\lnktest.vbs"'
MessageBox mb_ok "Done?"
Delete "$ProgramFiles32\lnktest32.cmd"
Delete "$ProgramFiles32\lnktest32.ico"
Delete "$ProgramFiles64\lnktest64.cmd"
Delete "$ProgramFiles64\lnktest64.ico"
Quit
SectionEnd 
Don't ask me why 64-bit Explorer is able to display the icon...

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 18th November 2015, 11:15   #7
unisev
Junior Member
 
Join Date: Nov 2015
Posts: 7
Thank you for this complete and precise answer !

So juste to be sure, this can only happen on 64bit systems when .LNK is created by a 32bit process, am I right ?

Is there a simple way to evolve my package to a 64bit one ? is there a real good reason to do this ?
unisev is offline   Reply With Quote
Old 18th November 2015, 12:00   #8
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,275
It seems like this only happens when you try to change the icon so not a big deal IMHO. If you want to force the icon to never use a environment path when resolving the icon you can try this (NSIS 3+ probably):

PHP Code:
!include LogicLib.nsh
!include Win\COM.nsh
!define /ifndef STGM_READWRITE 2
Function Shortcut_RemoveExpandIconPath
Exch 
$9
Push 
$0
Push 
$1
!insertmacro ComHlpr_CreateInProcInstance ${CLSID_ShellLink} ${IID_IPersistFiler0 ""
${If} $<> 0
    
${IPersistFile::Load} $'("$9",${STGM_READWRITE})i.r1'
    
${If} $0
        
${IUnknown::QueryInterface} $'("${IID_IShellLinkDataList}",.r1)'
        
${If} $<> 0
            
${IShellLinkDataList::RemoveDataBlock} $'(${EXP_SZ_ICON_SIG}).r9'
            
${IUnknown::Release} $""
            
${If} $0
                
${IPersistFile::Save} $'(p0,1)'
            
${EndIf}
        ${EndIf}
    ${EndIf}
    ${
IUnknown::Release} $""
${EndIf}
Pop $1
Pop 
$0
Pop 
$9
FunctionEnd

Section 
Push $Temp
\lnktestvbs32.lnk
Call Shortcut_RemoveExpandIconPath
SectionEnd 
Quote:
Originally Posted by unisev View Post

So juste to be sure, this can only happen on 64bit systems when .LNK is created by a 32bit process, am I right ?
Pretty much. There are probably also some corner cases where it can happen if you change %ProgramFiles% etc.

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 18th November 2015, 16:15   #9
unisev
Junior Member
 
Join Date: Nov 2015
Posts: 7
Wink

Quote:
Originally Posted by Anders View Post
It seems like this only happens when you try to change the icon so not a big deal IMHO.
You're totally right, thank you very much.
unisev is offline   Reply With Quote
Old 1st March 2016, 08:45   #10
joewinograd
Junior Member
 
Join Date: Mar 2016
Posts: 5
W7 Pro 64-bit
NSIS 3.0 b3

Hi Anders,

I would like to solve this problem, but I don't know how to apply your fix to my script. I am an NSIS newbie and have been using this sample script for all of my NSIS installers:

http://nsis.sourceforge.net/A_simple...nd_uninstaller

It has served me very well and I would like to continue using it. Can you please explain how I would incorporate your fix for the 64-bit Windows icon problem (%ProgramFiles%) into that sample script? Thanks for very much! Regards, Joe
joewinograd is offline   Reply With Quote
Old 3rd April 2016, 01:08   #11
joewinograd
Junior Member
 
Join Date: Mar 2016
Posts: 5
Hi Folks,
I haven't heard back from Anders on this. Can anyone else help me to get this fixed? Thanks very much!
joewinograd is offline   Reply With Quote
Old 3rd April 2016, 12:37   #12
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,275
Quote:
Originally Posted by joewinograd View Post
Hi Folks,
I haven't heard back from Anders on this. Can anyone else help me to get this fixed? Thanks very much!
There is no one true fix.

If you want to try the SetEnvironmentVariable hack then just add those three System::Call lines to the top of your first section. However, this might also change the behavior of any child processed you start from your installer.

If you want to try the Shortcut_RemoveExpandIconPath code then just copy the function and add the Push and Call instructions after your call to CreateShortcut (Change the path used in the Push of course)

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 3rd April 2016, 16:46   #13
joewinograd
Junior Member
 
Join Date: Mar 2016
Posts: 5
Hi Anders,
The Shortcut_RemoveExpandIconPath method worked perfectly! Thank you very much for that. I really appreciate it! Regards, Joe
joewinograd is offline   Reply With Quote
Reply
Go Back   Winamp & Shoutcast Forums > Developer Center > NSIS Discussion

Tags
winbug, wow64

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump