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.
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 $0 "$ProgramFiles32\lnktest32.cmd" a
FileClose $0
File "/oname=$ProgramFiles32\lnktest32.ico" "${NSISDIR}\Contrib\Graphics\Icons\modern-install.ico"
FileOpen $0 "$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 $0 "$Pluginsdir\lnktest.vbs" w
FileWrite $0 'Set lnk = WScript.CreateObject("WScript.Shell").CreateShortcut("$Temp\lnktestvbs32.lnk")$\r$\n'
FileWrite $0 'lnk.TargetPath = "$ProgramFiles32\lnktest32.cmd"$\r$\n'
FileWrite $0 'lnk.IconLocation = "$ProgramFiles32\lnktest32.ico, 0"$\r$\n'
FileWrite $0 'lnk.Save$\r$\n'
FileWrite $0 'Set lnk = WScript.CreateObject("WScript.Shell").CreateShortcut("$Temp\lnktestvbs64.lnk")$\r$\n'
FileWrite $0 'lnk.TargetPath = "$ProgramFiles64\lnktest64.cmd"$\r$\n'
FileWrite $0 'lnk.IconLocation = "$ProgramFiles64\lnktest64.ico, 0"$\r$\n'
FileWrite $0 '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...