从 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=],而不是 $R0R0r10$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}