VB.NET程序自复制生成update.exe后启动崩溃的技术问题求助
从你给出的错误栈和代码来看,崩溃的根源出在Updater.Initiate()方法的命令行解析逻辑上——具体是处理Environment.CommandLine时缺失了索引有效性判断,导致触发了非法的Substring调用。
为什么会崩溃?
错误信息里明确提到Length cannot be less than null,对应代码第19行:
Me.sFullname = sCmdLine.Substring(1, iPos - 1).Trim()
当你用Shell("update.exe")启动程序时,传递的命令行可能不带双引号(比如直接是update.exe),这时候sCmdLine.IndexOf("""", 2)会返回-1(从索引2开始找不到第二个双引号),计算iPos - 1就得到-2,而Substring的第二个参数(长度)不能为负数,直接抛出ArgumentOutOfRangeException。
而从资源管理器手动启动时,Windows会根据路径是否包含空格自动添加双引号,你的原始解析逻辑刚好能匹配到引号位置,所以不会出错。
解决方案
1. 替换程序路径获取方式,避开命令行解析坑
不要手动解析Environment.CommandLine来获取程序路径,.NET WinForms已经提供了更可靠的Application.ExecutablePath,直接返回当前程序的完整路径。修改Initiate()方法:
Private Sub Initiate() ' 直接用Application.ExecutablePath获取完整路径,无需解析命令行 Me.sFullname = Application.ExecutablePath Dim iPos2 = sFullname.LastIndexOf("\") Me.sExename = sFullname.Substring(iPos2 + 1).Trim() ' 安全解析命令行参数 Dim sCmdLine As String = Environment.CommandLine() Me.sArguments = "" If sCmdLine.StartsWith("""") Then ' 处理带引号的程序路径 Dim iPos = sCmdLine.IndexOf("""", 1) If iPos > -1 Then Me.sArguments = sCmdLine.Substring(iPos + 1).Trim() End If Else ' 处理不带引号的程序路径 Dim iPos = sCmdLine.IndexOf(" ") If iPos > -1 Then Me.sArguments = sCmdLine.Substring(iPos + 1).Trim() End If End If End Sub
2. 用Process.Start替代旧的Shell方法
Shell是VB6兼容的旧API,行为不够可控。改用Process.Start可以确保启动时的工作目录、参数传递更可靠:
Private Sub FakeUpdate() If Me.sArguments = "-fakeupdate" Then Dim targetPath = Path.Combine(Application.StartupPath, "update.exe") FileCopy(Me.sFullname, targetPath) ' 用Process.Start启动,确保工作目录与当前程序一致 Process.Start(targetPath) ' 如果需要当前程序退出,可添加:Application.Exit() End If End Sub
验证修改
做完以上修改后,无论是通过-fakeupdate参数触发启动,还是按钮点击启动update.exe,都不会再出现崩溃问题,同时保留了参数解析的功能。
内容的提问来源于stack exchange,提问作者LPChip

