Как использовать System :: Call и MessageBox при вызове метода C++ dll из сценария NSIS

Мое требование - мне нужно проверить, «присутствует ли устройство, прежде чем мы попытаемся отключить собственное питание» в системе.

Для этого мне нужно вызвать функцию ниже, которая есть в 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»?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
315
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы используете неправильный регистр. 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 с помощью Зависимость Уокер, он должен выглядеть так: 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}

Я не знаю, почему он показывает «Возвращаемое значение» как ошибку. Пожалуйста, помогите мне, в чем может быть причина. Кроме того, «DetailPrint» не показывает никаких сообщений. Где я могу увидеть сообщение DetailPrint?

Yar 18.10.2018 08:58

DetailPrint отображается на странице InstFiles при вызове из раздела. Я еще раз посмотрю на код и посмотрю, смогу ли я обнаружить какие-нибудь проблемы.

Anders 18.10.2018 10:12

Возможно, я отредактирую свой ответ каким-нибудь новым кодом, который вы можете попробовать.

Anders 18.10.2018 12:09

Спасибо Андерсу за подробное объяснение. Когда я запустил свой проект из Visual Studio, я смог загрузить DLL и функцию. В любом случае я протестирую dll один раз с помощью dependency walker и подтвердю. Замечательно, что вы предоставили сценарий для ручного запуска, чтобы проверить, загружаются ли DLL и функция или нет. Я протестирую это, и это определенно поможет мне продолжить.

Yar 18.10.2018 18:02

Это больше не вопрос NSIS, вам нужно спросить кого-нибудь еще.

Anders 19.10.2018 10:57

Другие вопросы по теме