Go Back   Winamp & Shoutcast Forums > Developer Center > NSIS Discussion

Reply
Thread Tools Search this Thread Display Modes
Old 24th February 2011, 23:30   #1
o___O
Junior Member
 
Join Date: Mar 2002
Posts: 27
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:

Quote:
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...
o___O is offline   Reply With Quote
Old 24th February 2011, 23:48   #2
Zinthose
Senior Member
 
Join Date: May 2009
Posts: 152
Removed public display of stupid...
Zinthose is offline   Reply With Quote
Old 24th February 2011, 23:55   #3
o___O
Junior Member
 
Join Date: Mar 2002
Posts: 27
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 is offline   Reply With Quote
Old 25th February 2011, 00:10   #4
o___O
Junior Member
 
Join Date: Mar 2002
Posts: 27
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
o___O is offline   Reply With Quote
Old 25th February 2011, 00:18   #5
Zinthose
Senior Member
 
Join Date: May 2009
Posts: 152
Kodama,
PHP Code:
!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.
Zinthose is offline   Reply With Quote
Old 25th February 2011, 00:41   #6
o___O
Junior Member
 
Join Date: Mar 2002
Posts: 27
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/myapp2.png
o___O is offline   Reply With Quote
Old 25th February 2011, 00:47   #7
o___O
Junior Member
 
Join Date: Mar 2002
Posts: 27
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...
o___O is offline   Reply With Quote
Old 25th February 2011, 01:04   #8
Zinthose
Senior Member
 
Join Date: May 2009
Posts: 152
AH! not I see the problem... I'm going to perform some tests to see what can be done about this.
Zinthose is offline   Reply With Quote
Old 25th February 2011, 01:07   #9
o___O
Junior Member
 
Join Date: Mar 2002
Posts: 27
Let me know what you find...
o___O is offline   Reply With Quote
Old 25th February 2011, 09:28   #10
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,339
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:
PHP Code:
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} $<> 0
    System
::Call '$1->0(g "{0000010b-0000-0000-C000-000000000046}",*i.r2)'
    
${If} $<> 0
        System
::Call '$2->5(w "$temp\test.lnk",i 2)i.r0'
        
${If} $0
            System
::Call '$1->0(g "{45e2b4ae-b1c3-11d0-b92f-00a0c90312e1}",*i.r3)i.r0'
            
${If} $<> 0
                System
::Call '$3->5(i 0xA0000007)i.r0'
                
System::Call '$3->6(*i.r4)i.r0'
                
${If} $
                    IntOp 
$$0xffffBFFF
                    System
::Call '$3->7(ir4)i.r0'
                    
${If} $
                        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

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 25th February 2011, 16:17   #11
Zinthose
Senior Member
 
Join Date: May 2009
Posts: 152
As usual... Awesome work Anders
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.
PHP Code:
/******************************************************************************
    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} $<> 0
            System
::Call '$1->0(g "{0000010b-0000-0000-C000-000000000046}",*i.r2)'
            
${If} $<> 0
                System
::Call '$2->5(w r5,i 2)i.r0'
                
${If} $0
                    System
::Call '$1->0(g "{45e2b4ae-b1c3-11d0-b92f-00a0c90312e1}",*i.r3)i.r0'
                    
${If} $<> 0
                        System
::Call '$3->5(i 0xA0000007)i.r0'
                        
System::Call '$3->6(*i.r4)i.r0'
                        
${If} $
                            IntOp 
$$0xffffBFFF
                            System
::Call '$3->7(ir4)i.r0'
                            
${If} $
                                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 is offline   Reply With Quote
Old 25th February 2011, 19:28   #12
Zinthose
Senior Member
 
Join Date: May 2009
Posts: 152
FYI: Wiki Article Created
Zinthose is offline   Reply With Quote
Old 25th February 2011, 20:00   #13
MSG
Major Dude
 
Join Date: Oct 2006
Posts: 1,892
That URL in the comment is broken. You should probably point to: http://forums.winamp.com/showthread.php?t=327806
MSG is offline   Reply With Quote
Old 25th February 2011, 20:24   #14
o___O
Junior Member
 
Join Date: Mar 2002
Posts: 27
Quote:
Originally Posted by Anders View Post
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.
o___O is offline   Reply With Quote
Old 25th February 2011, 21:10   #15
Afrow UK
Moderator
 
Afrow UK's Avatar
 
Join Date: Nov 2002
Location: Surrey, England
Posts: 8,434
http://nsis.sourceforge.net/CreateIn...o_%26_function

Stu
Afrow UK is offline   Reply With Quote
Old 25th February 2011, 21:10   #16
Zinthose
Senior Member
 
Join Date: May 2009
Posts: 152
Internet shortcuts are even easier to tweak as they are just ini files.
code:
[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..
PHP Code:
WriteINIStr "$SMPROGRAMS\${APP_NAME}\My Web Site.url" "InternetShortcut" "IconFile" "$INSTDIR\online.exe"
WriteINIStr "$SMPROGRAMS\${APP_NAME}\My Web Site.url" "InternetShortcut" "IconIndex" 
...and it "Should" fix it.


EDIT: Or just read the Wiki article Stu Posted..
Zinthose is offline   Reply With Quote
Old 25th February 2011, 22:32   #17
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,339
Quote:
Originally Posted by o___O View Post
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 the registry and nsis itself does not use environment variables IIRC.

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 2nd March 2011, 10:12   #18
o___O
Junior Member
 
Join Date: Mar 2002
Posts: 27
I found more information out about this issue. From the manual:

Quote:
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.
o___O is offline   Reply With Quote
Old 2nd March 2011, 13:11   #19
Anders
Moderator
 
Anders's Avatar
 
Join Date: Jun 2002
Location: ${NSISDIR}
Posts: 5,339
Quote:
Originally Posted by o___O View Post
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:
PHP Code:
strcpy $instdir "c:\temp\"
MessageBox mb_ok 
$instdir 

IntOp $PostCount $PostCount + 1
Anders is offline   Reply With Quote
Old 2nd March 2011, 14:59   #20
Zinthose
Senior Member
 
Join Date: May 2009
Posts: 152
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?
PHP Code:
!define APP_NAME "My App"
OutFile lnkTest.exe
ShowInstDetails show

InstallDir 
"$PROGRAMFILES32\${APP_NAME}\"

Page directory
Page instfiles

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 
Zinthose is offline   Reply With Quote
Reply
Go Back   Winamp & Shoutcast Forums > Developer Center > NSIS Discussion

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