从 NSIS 脚本调用 C++ dll 方法时如何使用 System::Call 和 MessageBox
How to use System::Call and MessageBox when calling the C++ dll method from the NSIS script
我的要求是我需要从系统测试“在我们尝试禁用本机电源之前设备是否存在”。
为此,我需要调用 testutil.dll
中的以下函数
BOOL IsTherePower()
下面是调用此函数的 NSIS 脚本:
Name "PowerTest"
OutFile "PowerTest.exe"
InstallDir $PROGRAMFILES\PowerTest
Section "PowerTest(required)"
SectionIn RO
DetailPrint "PowerTest"
; Set output path to the installation directory. Here is the path C:\Program Files\PowerTest
SetOutPath $INSTDIR
; Give the dll path
File E:\Code\Source\Validatepower.exe
File E:\Code\Source\testutil.dll
File E:\Code\Source\ntutil.dll
File E:\Code\Source\dlgdll.dll
System::Call "$INSTDIR\testutil.dll::IsTherePower() i.r0"
Pop [=11=]
MessageBox MB_OK "Return value = $R0, lasterr = [=11=]"
IntCmp $R0 1 OkToInstall CancelInstall
CancelInstall:
Abort "Not allowed to install"
OkToInstall:
Do the install
使用上面的代码,当我 运行 应用程序时,我得到“Return value=, lasterr = error”。我不确定为什么我得到“Return 值”空白(空)。我在这里错过了什么吗?
我写了“System::Call”和“MessageBox”,但不确定它们在做什么。
在这里我想知道 System::Call 中的“i.r0”是什么
还有什么是“Pop $0”?
您使用了错误的寄存器。 r0
在系统语法中是 [=13=]
,而不是 $R0
(R0
和 r10
是 $R0
)。 System::Call "$INSTDIR\drvutil.dll::IsUPSPresent() i.r0"
将 INT32 return 值放入 [=13=]
然后你用 Pop
覆盖 [=13=]
并且你的堆栈恰好是空的。
如果您需要调用 GetLastError()
,那么您必须附加 ?e
选项:
System::Call "$INSTDIR\drvutil.dll::IsUPSPresent() i.r0 ?e" ; Pushes error code on top of the stack
Pop ; Get error code
DetailPrint "Return=[=10=] LastError="
?e
将最后一个错误推送到 the stack 并且 Pop
提取堆栈中的顶部项目。
我可以确认我的代码有效,我在虚拟 .DLL 上进行了测试。如果它对您不起作用,则 System::Call
无法加载 .DLL 或找到导出的函数。最可能的问题是您没有在 .DLL 中正确导出函数。
用 Dependency Walker 检查你的 .DLL,它应该看起来像这样:
没有
您也可以尝试在 NSIS 中手动验证它:
!include LogicLib.nsh
Section
SetOutPath $InstDir
File drvutil.dll
System::Call 'KERNEL32::LoadLibrary(t "$InstDir\drvutil.dll")p.r8 ?e'
Pop
${If} P<> 0
MessageBox MB_OK 'Successfully loaded "$InstDir\drvutil.dll" @ '
System::Call 'KERNEL32::GetProcAddress(pr8, m "IsUPSPresent")p.r9 ?e'
Pop
${If} P<> 0
MessageBox MB_OK 'Successfully found "IsUPSPresent" @ '
${Else}
MessageBox MB_ICONSTOP 'Unable to find "IsUPSPresent", error '
${EndIf}
System::Call 'KERNEL32::FreeLibrary(pr8)'
${Else}
MessageBox MB_ICONSTOP 'Unable to load "$InstDir\drvutil.dll", error '
${EndIf}
我的要求是我需要从系统测试“在我们尝试禁用本机电源之前设备是否存在”。
为此,我需要调用 testutil.dll
中的以下函数BOOL IsTherePower()
下面是调用此函数的 NSIS 脚本:
Name "PowerTest"
OutFile "PowerTest.exe"
InstallDir $PROGRAMFILES\PowerTest
Section "PowerTest(required)"
SectionIn RO
DetailPrint "PowerTest"
; Set output path to the installation directory. Here is the path C:\Program Files\PowerTest
SetOutPath $INSTDIR
; Give the dll path
File E:\Code\Source\Validatepower.exe
File E:\Code\Source\testutil.dll
File E:\Code\Source\ntutil.dll
File E:\Code\Source\dlgdll.dll
System::Call "$INSTDIR\testutil.dll::IsTherePower() i.r0"
Pop [=11=]
MessageBox MB_OK "Return value = $R0, lasterr = [=11=]"
IntCmp $R0 1 OkToInstall CancelInstall
CancelInstall:
Abort "Not allowed to install"
OkToInstall:
Do the install
使用上面的代码,当我 运行 应用程序时,我得到“Return value=, lasterr = error”。我不确定为什么我得到“Return 值”空白(空)。我在这里错过了什么吗?
我写了“System::Call”和“MessageBox”,但不确定它们在做什么。 在这里我想知道 System::Call 中的“i.r0”是什么 还有什么是“Pop $0”?
您使用了错误的寄存器。 r0
在系统语法中是 [=13=]
,而不是 $R0
(R0
和 r10
是 $R0
)。 System::Call "$INSTDIR\drvutil.dll::IsUPSPresent() i.r0"
将 INT32 return 值放入 [=13=]
然后你用 Pop
覆盖 [=13=]
并且你的堆栈恰好是空的。
如果您需要调用 GetLastError()
,那么您必须附加 ?e
选项:
System::Call "$INSTDIR\drvutil.dll::IsUPSPresent() i.r0 ?e" ; Pushes error code on top of the stack
Pop ; Get error code
DetailPrint "Return=[=10=] LastError="
?e
将最后一个错误推送到 the stack 并且 Pop
提取堆栈中的顶部项目。
我可以确认我的代码有效,我在虚拟 .DLL 上进行了测试。如果它对您不起作用,则 System::Call
无法加载 .DLL 或找到导出的函数。最可能的问题是您没有在 .DLL 中正确导出函数。
用 Dependency Walker 检查你的 .DLL,它应该看起来像这样:
没有
您也可以尝试在 NSIS 中手动验证它:
!include LogicLib.nsh
Section
SetOutPath $InstDir
File drvutil.dll
System::Call 'KERNEL32::LoadLibrary(t "$InstDir\drvutil.dll")p.r8 ?e'
Pop
${If} P<> 0
MessageBox MB_OK 'Successfully loaded "$InstDir\drvutil.dll" @ '
System::Call 'KERNEL32::GetProcAddress(pr8, m "IsUPSPresent")p.r9 ?e'
Pop
${If} P<> 0
MessageBox MB_OK 'Successfully found "IsUPSPresent" @ '
${Else}
MessageBox MB_ICONSTOP 'Unable to find "IsUPSPresent", error '
${EndIf}
System::Call 'KERNEL32::FreeLibrary(pr8)'
${Else}
MessageBox MB_ICONSTOP 'Unable to load "$InstDir\drvutil.dll", error '
${EndIf}