我使用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;
}
答案 0 :(得分:0)
System::Call
解析字符串的方式存在缺陷,如果字符串包含(..)
,它将解析为函数参数,并且无法加载.DLL并且调用失败。在64位Windows上,$ ProgramFiles32包含(x86)
作为路径的一部分,这会触发漏洞。
有两种方法可以解决此问题:
A)
结合使用SetOutPath
和AddDllDirectory
以确保可以从相对路径加载.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}