NSIS ExecDos插件 - IsDone功能适用于某些计算机,但不适用于其他计算机

时间:2012-01-07 12:07:22

标签: installer nsis

我有一个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 个答案:

答案 0 :(得分:3)

我不知道确切的问题是什么,但您可能应该解决脚本的其他一些问题:

  • 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参数永远不会被推送到堆栈,因此函数最终会出现无效参数?

要对此进行调试,您应该能够将{d'}的调用替换为System::Call 'kernel32::WaitForSingleObject(i $DatabaseUpdate_ProcessHandle ,i 0)i.r0',并将$ 0中的值与return values listed on MSDN进行比较。