从NSIS脚本调用C ++ dll方法时如何使用System :: Call和MessageBox

时间:2018-10-12 11:02:54

标签: nsis

我的要求是我需要从系统中测试“如果存在UPS设备,然后再尝试禁用本机电源管理”。

为此,我需要调用drvutil.dll中的以下函数

BOOL IsUPSPresent()

下面是调用该函数的NSIS脚本:

Name "UPSTest"

OutFile "UPSTest.exe"

InstallDir $PROGRAMFILES\UPSTest

Section "UPSTest (required)"

  SectionIn RO

  DetailPrint "Testing UPS"

  ; Set output path to the installation directory. Here is the path C:\Program Files\UPSTest
  SetOutPath $INSTDIR

  ; Give the dll path
  File E:\Code\PCPE\Install\pcpe301\Common\ValidateUPS.exe
  File E:\Code\PCPE\Install\pcpe301\Common\drvutil.dll
  File E:\Code\PCPE\Install\pcpe301\Common\ntutil.dll
  File E:\Code\PCPE\Install\pcpe301\Common\pdcdll.dll

  System::Call "$INSTDIR\drvutil.dll::IsUPSPresent() i.r0"
  Pop $0
  MessageBox MB_OK "Return value = $R0, lasterr = $0"
  IntCmp $R0 1 OkToInstall CancelInstall

  CancelInstall:
  Abort "Not allowed to install"
  OkToInstall:
   Do the install

使用上面的代码,当我运行应用程序时,我得到“返回值=,lasterr =错误”。我不确定为什么我会得到“返回值”空白(空)。我在这里想念任何东西吗?

我写了“ System :: Call”和“ MessageBox”,但不确定它们在做什么。 在这里,我想知道System :: Call的“ i.r0”是什么 还有什么是“ Pop $ 0”?

1 个答案:

答案 0 :(得分:1)

您使用了错误的寄存器。系统语法中的r0$0,而不是$R0R0r10$R0)。 System::Call "$INSTDIR\drvutil.dll::IsUPSPresent() i.r0"将INT32返回值放在$0中,然后用$0覆盖Pop,而堆栈恰好为空。

如果您需要致电GetLastError(),则必须附加?e选项:

System::Call "$INSTDIR\drvutil.dll::IsUPSPresent() i.r0 ?e" ; Pushes error code on top of the stack
Pop $1 ; Get error code
DetailPrint "Return=$0 LastError=$1"

?e将最后一个错误压入the stack,而Pop则提取堆栈中的第一项。

我可以确认我的代码可以工作,我在一个虚拟的.DLL上进行了测试。如果它对您不起作用,则System::Call无法加载.DLL或找到导出的函数。最可能的问题是您没有将函数正确导出到.DLL中。

使用Dependency Walker检查您的.DLL,应该看起来像这样: Correct

不是

Incorrect

您也可以尝试在NSIS中手动进行验证:

!include LogicLib.nsh

Section
SetOutPath $InstDir
File drvutil.dll
System::Call 'KERNEL32::LoadLibrary(t "$InstDir\drvutil.dll")p.r8 ?e'
Pop $7
${If} $8 P<> 0
    MessageBox MB_OK 'Successfully loaded "$InstDir\drvutil.dll" @ $8'
    System::Call 'KERNEL32::GetProcAddress(pr8, m "IsUPSPresent")p.r9 ?e'
    Pop $7
    ${If} $9 P<> 0
        MessageBox MB_OK 'Successfully found "IsUPSPresent" @ $9'
    ${Else}
        MessageBox MB_ICONSTOP 'Unable to find "IsUPSPresent", error $7'
    ${EndIf}
    System::Call 'KERNEL32::FreeLibrary(pr8)'
${Else}
    MessageBox MB_ICONSTOP 'Unable to load "$InstDir\drvutil.dll", error $7'
${EndIf}