Мое требование - мне нужно проверить, «присутствует ли устройство, прежде чем мы попытаемся отключить собственное питание» в системе.
Для этого мне нужно вызвать функцию ниже, которая есть в 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 $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 = error». Я не уверен, почему я получаю пустое поле «Возвращаемое значение» (null). Я что-то здесь пропустил?
Я написал «System :: Call» и «MessageBox», но не уверен, что они делают. Здесь я хочу узнать, что такое «i.r0» из System :: Call. А также что такое «Pop $ 0»?
Вы используете неправильный регистр. r0
в системном синтаксисе - это $0
, а не $R0
(R0
и r10
- это $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
помещает последнюю ошибку в стек, а Pop
извлекает верхний элемент в стеке.
Я могу подтвердить, что мой код работает, я тестировал фиктивный .DLL. Если это не работает для вас, значит, System::Call
не может загрузить .DLL или найти экспортированную функцию. Наиболее вероятная проблема заключается в том, что вы неправильно экспортировали функцию в свой .DLL.
Проверьте свой .DLL с помощью Зависимость Уокер, он должен выглядеть так:
нет
Вы также можете попробовать проверить это вручную в 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}
DetailPrint отображается на странице InstFiles при вызове из раздела. Я еще раз посмотрю на код и посмотрю, смогу ли я обнаружить какие-нибудь проблемы.
Возможно, я отредактирую свой ответ каким-нибудь новым кодом, который вы можете попробовать.
Спасибо Андерсу за подробное объяснение. Когда я запустил свой проект из Visual Studio, я смог загрузить DLL и функцию. В любом случае я протестирую dll один раз с помощью dependency walker и подтвердю. Замечательно, что вы предоставили сценарий для ручного запуска, чтобы проверить, загружаются ли DLL и функция или нет. Я протестирую это, и это определенно поможет мне продолжить.
Это больше не вопрос NSIS, вам нужно спросить кого-нибудь еще.
Я не знаю, почему он показывает «Возвращаемое значение» как ошибку. Пожалуйста, помогите мне, в чем может быть причина. Кроме того, «DetailPrint» не показывает никаких сообщений. Где я могу увидеть сообщение DetailPrint?