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

Why System::Call is returning "0" when running 32-bit installer in 32-bit machine but when running it in 64-bit machine returning blank in NSIS

我已经使用 NSIS 创建了一个 32 位安装程序,在 32 位或 64 位机器上都应该 运行。

下面的代码在使用 System::Call 和相应函数 IsSplashScreenDisabled() 调用 DLL (Profile.dll) 的 32 位机器上运行良好。此函数 returns false 并显示消息框。它按预期工作。

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

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

因此,我需要您的建议或想法,了解为什么 System::Call 在 32-bit/64-bit 安装程序和 32 位或 64 位机器上的工作方式不同。

!include LogicLib.nsh

InstallDir $PROGRAMFILES32\MyAppTest

Page components
Page directory
Page instfiles

UninstPage uninstConfirm
UninstPage instfiles

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

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

 System::Call "$INSTDIR\Test.dll::IsSplashDisabled() i.r0 ?e" 
  Pop  
  ${If} [=13=] = 0
    
    MessageBox MB_OK|MB_ICONEXCLAMATION "Splash s Disabled.$\r$\nRolling back the installation..." IDOK

  ${EndIf}
SectionEnd


BOOL IsSplashDisabled()
{
    BOOL    bResult = FALSE;
    DWORD   dwSplashScreen(0);
    RegistryObj regObj(SETTINGS_REG_PATH);
    
    if (regObj.Get(SPLASH_SCREEN, testSplashScreen))
    {
        bResult = (BOOL) !testSplashScreen;
    }

    return  bResult;
}

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}  P<> 0
    System::Call 'KERNEL32::GetProcAddress(pr1,m "MyFunction")p.r2'
    ${If}  P<> 0
        System::Call '::()i.r0'
    ${EndIf}
    System::Call 'KERNEL32::FreeLibrary(pr1)'
${EndIf}