Inject MSI Property at Compile-Time: Difference between revisions

From NSIS Wiki
Jump to navigationJump to search
(Initial Release)
(Undo revision 19493 by Zinthose (talk))
 
Line 1: Line 1:
{{PageAuthor|Zinthose}}
{{PageAuthor|Zinthose}}
== About ==
== About ==
This snippet was developed to address an issue with Windows x64 incorrectly redirecting the shortcuts icon from $PROGRAMFILES32 to $PROGRAMFILES64.
This macro provides a compile-time ability to inject Microsoft Installer Database file properties at compile time.  It uses a dynamically created VBScript to open the MSI file and read the property then creates the requested property value.
[http://forums.winamp.com/newreply.php?do=postreply&t=327806 See forum post]


== Macro ==
== Macro ==
<highlight-nsis>/******************************************************************************
<highlight-nsis>/********************
     WORKAROUND - FixShortcut
     !MSIPropertyGet
         This snippet was developed to address an issue with Windows
         This macro provides a compile-time ability to inject Microsoft Installer Database file properties at compile time.
        x64 incorrectly redirecting the shortcuts icon from $PROGRAMFILES32
          
         to $PROGRAMFILES64.
   
    See Forum post: http://forums.winamp.com/newreply.php?do=postreply&t=327806
   
     Example:
     Example:
         CreateShortcut "$SMPROGRAMS\My App\My App.lnk" "$INSTDIR\My App.exe" "" "$INSTDIR\My App.exe"
         ${!MSIPropertyGet} "SomePackage.ProductName"   "SomePackage.msi" "ProductName"
         ${lnkX64IconFix} "$SMPROGRAMS\My App\My App.lnk"
         ${!MSIPropertyGet} "SomePackage.ProductVersion" "SomePackage.msi" "ProductVersion"
          
          
    Original Code by Anders [http://forums.winamp.com/member.php?u=70852]
        !define DisplayName `${SomePackage.ProductName} v${SomePackage.ProductVersion}`
  ******************************************************************************/
        OutFile Test.exe
!ifndef ___lnkX64IconFix___
        Name `${DisplayName} Special Build`
     !verbose push
        Section
        SectionEnd
  ********************/
!verbose push
!verbose 0
!define !MSIPropertyGet `!insertmacro _!MSIPropertyGet`
!macro _!MSIPropertyGet _DefineToCreate _MSIFilePath _PropertyToRead
     !verbose Push
     !verbose 0
     !verbose 0
   
     !if `${_DefineToCreate}` == ``
     !include "LogicLib.nsh"
        !define __DefineToCreate `${_PropertyToRead}`
    !include "x64.nsh"
     !else
   
        !define __DefineToCreate `${_DefineToCreate}`
     !define ___lnkX64IconFix___
     !endif
    !define lnkX64IconFix `!insertmacro _lnkX64IconFix`
    !ifdef `${__DefineToCreate}`
     !macro _lnkX64IconFix _lnkPath
         !verbose 1
        !verbose push
         !error "!MSIPropertyGet: Value previously defined! [${__DefineToCreate}=${${__DefineToCreate}}]"
         !verbose 0
     !else
         ${If} ${RunningX64}
         !tempfile MSIPropertyGet_VBScript
            DetailPrint "WORKAROUND: 64bit OS Detected, Attempting to apply lnkX64IconFix"
         !appendfile `${MSIPropertyGet_VBScript}` `Set A=WScript.Arguments:Set B=CreateObject("WindowsInstaller.Installer").OpenDatabase(A(2),0)`
            Push "${_lnkPath}"
         !appendfile `${MSIPropertyGet_VBScript}` `.OpenView("SELECT Value FROM Property WHERE Property='"&A(3)&"'"):B.Execute:Set C=CreateObjec`
            Call lnkX64IconFix
        !appendfile `${MSIPropertyGet_VBScript}` `t("Scripting.Filesystemobject"):Set D=C.OpenTextFile(A(0),2,1):D.WriteLine "!define $\`"&A(1)`
        ${EndIf}
        !appendfile `${MSIPropertyGet_VBScript}` `&"$\` $\`"&B.Fetch.StringData(1)&"$\`":D.Close`
        !verbose pop
        !tempfile MSIPropertyGet_Result
     !macroend
        !system `WScript.exe "${MSIPropertyGet_VBScript}" //B //E:VBSCRIPT //T:30 "${MSIPropertyGet_Result}" "${__DefineToCreate}" "${_MSIFilePath}" "${_PropertyToRead}"` = 0
   
        !include "${MSIPropertyGet_Result}"
    Function lnkX64IconFix ; _lnkPath
        !delfile `${MSIPropertyGet_VBScript}`
         Exch $5
        !delfile `${MSIPropertyGet_Result}`
         Push $0
        !undef MSIPropertyGet_VBScript
        Push $1
        !undef MSIPropertyGet_Result
        Push $2
        !ifndef `${__DefineToCreate}`
        Push $3
             !error "!MSIPropertyGet: Value was not defined! [${__DefineToCreate}] Ensure the MSI file exists and is not locked from reading"
        Push $4
         !else if `${${__DefineToCreate}}` == ``
        System::Call 'OLE32::CoCreateInstance(g "{00021401-0000-0000-c000-000000000046}",i 0,i 1,g "{000214ee-0000-0000-c000-000000000046}",*i.r1)i'
            !warning "!MSIPropertyGet: Value is a zero length string! [${__DefineToCreate}=${${__DefineToCreate}}]"
         ${If} $1 <> 0
         !endif
            System::Call '$1->0(g "{0000010b-0000-0000-C000-000000000046}",*i.r2)'
    !endif
            ${If} $2 <> 0
     !undef __DefineToCreate
                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
     !verbose pop
!endif</highlight-nsis>
!macroend
!verbose pop</highlight-nsis>
[[Category:Compile-Time Macros]]
[[Category:Compile-Time Macros]]

Latest revision as of 19:22, 25 February 2011

Author: Zinthose (talk, contrib)


About

This macro provides a compile-time ability to inject Microsoft Installer Database file properties at compile time. It uses a dynamically created VBScript to open the MSI file and read the property then creates the requested property value.

Macro

/********************
    !MSIPropertyGet
        This macro provides a compile-time ability to inject Microsoft Installer Database file properties at compile time.
 
    Example:
        ${!MSIPropertyGet} "SomePackage.ProductName"    "SomePackage.msi" "ProductName"
        ${!MSIPropertyGet} "SomePackage.ProductVersion" "SomePackage.msi" "ProductVersion"
 
        !define DisplayName `${SomePackage.ProductName} v${SomePackage.ProductVersion}`
        OutFile Test.exe
        Name `${DisplayName} Special Build`
        Section
        SectionEnd
 ********************/
!verbose push
!verbose 0
!define !MSIPropertyGet `!insertmacro _!MSIPropertyGet`
!macro _!MSIPropertyGet _DefineToCreate _MSIFilePath _PropertyToRead
    !verbose Push
    !verbose 0
    !if `${_DefineToCreate}` == ``
        !define __DefineToCreate `${_PropertyToRead}`
    !else
        !define __DefineToCreate `${_DefineToCreate}`
    !endif
    !ifdef `${__DefineToCreate}`
        !verbose 1
        !error "!MSIPropertyGet: Value previously defined! [${__DefineToCreate}=${${__DefineToCreate}}]"
    !else
        !tempfile MSIPropertyGet_VBScript
        !appendfile `${MSIPropertyGet_VBScript}` `Set A=WScript.Arguments:Set B=CreateObject("WindowsInstaller.Installer").OpenDatabase(A(2),0)`
        !appendfile `${MSIPropertyGet_VBScript}` `.OpenView("SELECT Value FROM Property WHERE Property='"&A(3)&"'"):B.Execute:Set C=CreateObjec`
        !appendfile `${MSIPropertyGet_VBScript}` `t("Scripting.Filesystemobject"):Set D=C.OpenTextFile(A(0),2,1):D.WriteLine "!define $\`"&A(1)`
        !appendfile `${MSIPropertyGet_VBScript}` `&"$\` $\`"&B.Fetch.StringData(1)&"$\`":D.Close`
        !tempfile MSIPropertyGet_Result
        !system `WScript.exe "${MSIPropertyGet_VBScript}" //B //E:VBSCRIPT //T:30 "${MSIPropertyGet_Result}" "${__DefineToCreate}" "${_MSIFilePath}" "${_PropertyToRead}"` = 0
        !include "${MSIPropertyGet_Result}"
        !delfile `${MSIPropertyGet_VBScript}`
        !delfile `${MSIPropertyGet_Result}`
        !undef MSIPropertyGet_VBScript
        !undef MSIPropertyGet_Result
        !ifndef `${__DefineToCreate}`
            !error "!MSIPropertyGet: Value was not defined! [${__DefineToCreate}] Ensure the MSI file exists and is not locked from reading" 
        !else if `${${__DefineToCreate}}` == ``
            !warning "!MSIPropertyGet: Value is a zero length string! [${__DefineToCreate}=${${__DefineToCreate}}]"
        !endif
    !endif
    !undef __DefineToCreate
    !verbose pop
!macroend
!verbose pop