Плагин NSIS ExecDos - функция IsDone работает на некоторых компьютерах, но не на других - PullRequest
2 голосов
/ 07 января 2012

У меня есть установщик NSIS, который использует плагин ExecDOS для вызова инструмента командной строки, который запускает сценарии SQL. ExecDos вызывается в асинхронном режиме, и затем я зацикливаюсь на обновлении индикатора выполнения и вызываю функцию IsDone, пока инструмент командной строки не завершит работу.

Проблема, с которой я сталкиваюсь, заключается в том, что на некоторых компьютерах проверка IsDone ошибочно сообщает о завершении процесса, когда он на самом деле все еще выполняется, и поэтому он продолжается в фоновом режиме после завершения программы установки. Я не могу найти ничего общего между компьютерами, на которых он не работает, поэтому я надеюсь, что у кого-то есть какие-то идеи или они могут обнаружить ошибку в моем коде.

Function UpdateDatabase
  !insertmacro SetBannerText "Updating database" 0 0        
  !insertmacro Log "About to update the database"

  StrCpy $UpdateDatabase_PreviousScriptNumber 0      

  SetShellVarContext all         

  Push "ExecDos::End" # Add a marker for the loop to test for.
  ExecDos::exec /NOUNLOAD /ASYNC '"$ComSpec" /S /C ""$INSTDIR\Database\Tool\DatabaseResetTool.Console.exe" -sp="$INSTDIR\Database\Scripts" -cs="Data Source=$DatabaseServer;Initial Catalog=$Database;User ID=sa;Password=*********;Persist Security Info=true;MultipleActiveResultSets=True;Language=English" -eoe"' '' '$APPDATA\Company\$ApplicationPrefix\Database Update.log'
  Pop $DatabaseUpdate_ProcessHandle       
Loop:    
  ExecDos::isdone /NOUNLOAD $DatabaseUpdate_ProcessHandle
  Pop $DatabaseUpdate_Done    

  StrCpy $0 "$APPDATA\Company\$ApplicationPrefix\Database Update.log" 
  StrCpy $1 "$TEMP\Database Update.log"
  StrCpy $2 0
  System::Call 'kernel32::CopyFile(t r0, t r1, b r2) ?e'

  ${LineRead} "$TEMP\Database Update.log" "-2" $DatabaseUpdate_LogFileLine

  ${StrTok} $DatabaseUpdate_LogFileLineEndPart $DatabaseUpdate_LogFileLine "(" "L" "1"    
  ${StrTok} $DatabaseUpdate_ScriptNumber $DatabaseUpdate_LogFileLineEndPart "/" "0" "1"    
  ${StrTok} $DatabaseUpdate_ScriptCountUnprocessed $DatabaseUpdate_LogFileLineEndPart "/" "1" "1"    
  ${StrTok} $DatabaseUpdate_ScriptCount $DatabaseUpdate_ScriptCountUnprocessed ")" "0" "1"

  ${If} $DatabaseUpdate_ScriptNumber != ""
  ${AndIf} $DatabaseUpdate_ScriptCount != ""        
    FloatOp::D $DatabaseUpdate_ScriptNumber $DatabaseUpdate_ScriptCount        
    FloatOp::M $0 100                           

    ${If} $UpdateDatabase_PreviousScriptNumber != $DatabaseUpdate_ScriptNumber                                               
        !insertmacro SetBannerText "Updating database$\r$\n$\r$\nRunning script $DatabaseUpdate_ScriptNumber of $DatabaseUpdate_ScriptCount" 0 $0
        StrCpy $UpdateDatabase_PreviousScriptNumber $DatabaseUpdate_ScriptNumber
    ${EndIf}                                              
  ${EndIf}       

  Sleep 200

  StrCmp $DatabaseUpdate_Done "0" Loop Done
Done:
  Push "$TEMP\Database Update.log"
  Push "exception"
  Call FileSearch
  Pop $0
  Pop $1     

  ${If} $0 != "0"
    StrCpy $InstallError 1
    !insertmacro LogError "Database update failed. Please review the 'Database Update.log' to see the detail error message" ""        
  ${EndIf}       
FunctionEnd

1 Ответ

3 голосов
/ 10 января 2012

Я не знаю, в чем именно проблема, но у вас есть другие проблемы с вашим скриптом, которые вы, вероятно, должны исправить:

  • System::Call 'kernel32::CopyFile(t r0, t r1, b r2) ?e' b не является допустимым типом системного плагина, используйте i. ?e выталкивает в стек, вы никогда не выталкиваете это значение и не проверяете, успешно ли выполнено копирование. Замените его на System::Call 'kernel32::CopyFile(t r0, t r1, i 0)i.r0' и отметьте ${If} $0 = 0 ...deal with error

  • Вы используете $ ComSpec и "", которые, как я полагаю, предназначены для решения проблем с квотами cmd.exe, ExecDos использует каналы, поэтому перенаправление должно работать без внесения cmd.exe в миксы. Попробуйте выполнить только ExecDos::exec /NOUNLOAD /ASYNC '"$INSTDIR\Da...

  • Вы на самом деле не контролируете все файлы в $ Temp, используйте $ Pluginsdir в качестве пустого места

  • Вы никогда не проверяете и не тестируете Push "ExecDos::End"

Некоторые другие вещи, которые вы могли бы исследовать:

  • SetShellVarContext all преобразует $ APPDATA в общие данные appdata / programdata, поэтому убедитесь, что вы являетесь администратором.
  • Попробуй поспать подольше ...
  • Возможно ли, что значение ?e, которое вы никогда не выскальзываете, заканчивается заполнением стека, так что параметр isdone никогда не помещается в стек, так что функция заканчивается неверным параметром?

Для отладки вы можете заменить вызов isdone на System::Call 'kernel32::WaitForSingleObject(i $DatabaseUpdate_ProcessHandle ,i 0)i.r0' и сравнить значение в $ 0 с возвращаемыми значениями, перечисленными в MSDN .

...