为什么System :: Call在32位计算机中运行32位安装程序时却返回“ 0”,而在64位计算机中运行它却在NSIS中返回空白

时间:2019-01-25 16:40:42

标签: nsis

我使用NSIS创建了一个32位安装程序,该安装程序可以在32位或64位计算机上运行。

下面的代码在32位计算机上使用System :: Call和相应的函数IsSplashScreenDisabled()调用DLL(Profile.dll)时工作正常。此函数返回false并显示消息框。它按预期工作。

但是当我在64位计算机上运行时,同一安装程序System :: Call没有返回“ 0”,而是显示空白“”。所以我没有收到消息框。

如果我将“ $ PROGRAMFILES32”更改为“ $ PROGRAMFILES64”,那么它也会显示空白“”,而不显示消息框。

因此,在这里,我需要您对System :: Call为什么在32位/ 64位安装程序以及32位或64位计算机上以不同方式工作的建议或想法。

!include LogicLib.nsh

InstallDir $PROGRAMFILES32\MyAppTest

Page components
Page directory
Page instfiles

UninstPage uninstConfirm
UninstPage instfiles

Section
SetOutPath $INSTDIR
  File E:\TestNullSoft\Profile.dll

System::Call 'KERNEL32::AddDllDirectory(w "$INSTDIR")'

 System::Call "$INSTDIR\Profile.dll::IsSplashScreenDisabled() i.r0 ?e" 
  Pop $1 
  ${If} $0 = 0

    MessageBox MB_OK|MB_ICONEXCLAMATION "Splash Screen Is Disabled.$\r$\nRolling back the installation..." IDOK

  ${EndIf}
SectionEnd

下面是IsSplashScreenDisabled()函数

BOOL IsSplashScreenDisabled()
{
    BOOL    bResult = FALSE;
    DWORD   dwSplashScreen(0);
    RegistryObj regObj(SPE_DALI_SETTINGS_REG_PATH);

    if (regObj.Get(SPE_SETTINGS_ENABLE_SPLASH_SCREEN, dwSplashScreen))
    {
        bResult = (BOOL) !dwSplashScreen;
    }

    return  bResult;
}

1 个答案:

答案 0 :(得分:0)

System::Call解析字符串的方式存在缺陷,如果字符串包含(..),它将解析为函数参数,并且无法加载.DLL并且调用失败。在64位Windows上,$ ProgramFiles32包含(x86)作为路径的一部分,这会触发漏洞。

有两种方法可以解决此问题:

A)

结合使用SetOutPathAddDllDirectory以确保可以从相对路径加载.DLL:

SetOutPath $InstDir
System::Call 'KERNEL32::AddDllDirectory(w "$INSTDIR")'
File MyFile.dll

System::Call 'MyFile::MyFunction()i.r0'

SetOutPath将该路径作为当前目录,而AddDllDirectory将该目录添加到要加载的有效目录列表中。

B)

手动加载.DLL并直接调用地址:

SetOutPath $InstDir
System::Call 'KERNEL32::AddDllDirectory(w "$INSTDIR")'
File MyFile.dll

System::Call 'KERNEL32::LoadLibrary(t "$InstDir\MyFile.dll")p.r1'
${If} $1 P<> 0
    System::Call 'KERNEL32::GetProcAddress(pr1,m "MyFunction")p.r2'
    ${If} $2 P<> 0
        System::Call '::$2()i.r0'
    ${EndIf}
    System::Call 'KERNEL32::FreeLibrary(pr1)'
${EndIf}