首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >FileSystemObject调用正在执行..。太快了?

FileSystemObject调用正在执行..。太快了?
EN

Stack Overflow用户
提问于 2015-01-09 14:51:39
回答 1查看 141关注 0票数 0

我正在开发一个修改文件“就地”的系统。使用引号是因为实际过程如下:

  1. 将修改写入具有临时名称的新文件。
  2. 用".bak“扩展名移动源文件(重命名)
  3. 将(重命名)新文件移到源文件的名称。
  4. 删除中间文件。

此过程涉及使用PDFtk修改PDF文件。问题是,当我运行代码时,它有时会“跳过”一个步骤,有时会导致与前面某个步骤相关的错误没有发生。

当我使用调试器完成代码时,每次都能正常工作。如果我在每个文件系统调用之间添加以下代码,它也能工作。

代码语言:javascript
复制
Public Sub Wait(seconds As Integer)
Dim dTimer As Double

    dTimer = Timer
    Do While Timer < dTimer + seconds
        DoEvents
    Loop

End Sub

(信用:http://www.vbforums.com/showthread.php?442519-Wait-function&p=2732926&viewfull=1#post2732926)

我真的不想这样做,因为它增加了执行时间,而且我真的无法判断停顿时间对将要使用此应用程序的各种客户端来说“足够”多长时间。是否有更好的方法使上述功能正常工作?也许是因为根本不使用FileSystemObject

下面是我正在使用的代码:

代码语言:javascript
复制
If LCase$(inputFilename) = LCase$(outputFilename) Then
        ' Saving changes to original file.
        Set fso = New FileSystemObject
        tempPath = fso.GetParentFolderName(outputFilename) & "\" & _
            Format$(Now, "mm_dd_yyyy_hh_nn_ss") & ".pdf"
        ' Create temp file
        CreateSubsetFromPDF = Shell("""" & App.Path & "\pdftk"" """ & inputFilename & _
            """ cat " & pages & " output """ & tempPath & """", vbHide)
        ' Copy temp file to actual destination, overwriting.
        fso.CopyFile tempPath, outputFilename, True
        fso.DeleteFile tempPath
End If
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-01-09 15:27:40

我怀疑您的问题是,shell在启动(或未能启动)进程后立即返回。我建议使用API调用CreateProcess,并至少等待进程返回一个结果。我用得够多了,我已经为此创建了一个方法。有时,我需要等待几个小时才能运行生成的程序,所以我的方法使用无限等待。因为你只期望等待几秒钟,我会修改等待时间以适应你自己。等待的时间只是等待多久才会失败。否则,一旦生成的进程完成,它就会返回。

代码语言:javascript
复制
Private Type STARTUPINFO
   cb As Long
   lpReserved As String
   lpDesktop As String
   lpTitle As String
   dwX As Long
   dwY As Long
   dwXSize As Long
   dwYSize As Long
   dwXCountChars As Long
   dwYCountChars As Long
   dwFillAttribute As Long
   dwFlags As Long
   wShowWindow As Integer
   cbReserved2 As Integer
   lpReserved2 As Long
   hStdInput As Long
   hStdOutput As Long
   hStdError As Long
End Type

Private Type PROCESS_INFORMATION
    hProcess As Long
    hThread As Long
    dwProcessId As Long
    dwThreadID As Long
End Type

Private Declare Function WaitForSingleObjectEx Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long, ByVal bAlertable As Long) As Long
Private Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long, lpExitCode As Long) As Long
Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
Private Declare Function CreateProcessA Lib "kernel32" (ByVal lpApplicationName As String, ByVal lpCommandLine As String, ByVal _
    lpProcessAttributes As Long, ByVal lpThreadAttributes As Long, _
    ByVal bInheritHandles As Long, ByVal dwCreationFlags As Long, _
    ByVal lpEnvironment As Long, ByVal lpCurrentDirectory As String, _
    lpStartupInfo As STARTUPINFO, lpProcessInformation As _
    PROCESS_INFORMATION) As Long

Private Const INFINITE = -1&
Private Const NORMAL_PRIORITY_CLASS = &H20&
Private Const SW_SHOW = 5
Private Const STARTF_USESHOWWINDOW = &H1

Public Function ExecAndWait(ByVal Program As String, Optional ByVal Parms As Variant, _
                              Optional ByVal hStdOutput As Long) As Long
   Dim proc As PROCESS_INFORMATION
   Dim start As STARTUPINFO
   Dim RET As Long
   Dim strCommandLine As String
   Dim lExitCode As Long
   Dim lWaitTime As Long

   On Error GoTo errExecAndWait

   ' quote the commandline and parameters if necessary
   If InStr(Program, """") = 0 Then ' if quotes are found assume that any necessary quoting has already been done
      If InStr(Program, " ") > 0 Then
         'do not include any Program parms (" /parm" in the quotes
         If InStr(Program, " /") > 0 Then
            strCommandLine = Chr$(34) & Left$(Program, InStr(Program, " /") - 1) & Chr$(34) & Right$(Program, Len(Program) - InStr(Program, " /") + 1)
         Else
            strCommandLine = Chr$(34) & Program & Chr$(34)
         End If
      Else
         strCommandLine = Program
      End If
   Else
      strCommandLine = Program
   End If

   If Not IsMissing(Parms) Then
      If Len(Parms) > 0 Then
         If InStr(Program, """") = 0 Then ' if quotes are found assume that any necessary quoting has already been done
            If InStr(Parms, " ") > 0 Then
               strCommandLine = strCommandLine & " " & Chr$(34) & Parms & Chr$(34)
            Else
               strCommandLine = strCommandLine & " " & Parms
            End If
         Else
            strCommandLine = strCommandLine & " " & Parms
         End If
      End If
   End If

   start.dwFlags = STARTF_USESHOWWINDOW
   start.wShowWindow = SW_SHOW

   lWaitTime = INFINITE    'forever
   ' Initialize the STARTUPINFO structure:
   start.cb = Len(start)

   ' Start the shelled application:
   RET& = CreateProcessA(vbNullString, strCommandLine, 0&, 0&, 1&, _
                        NORMAL_PRIORITY_CLASS, 0&, vbNullString, start, proc)
   ' change the return value to 0 if the dll returned other than 0 else return the dll error
   If RET& = 0 Then   'error
      ExecAndWait = 0
      Err.Raise Err.LastDllError, strCommandLine, Translate_DLL_Error(Err.LastDllError)
   Else
      Call Sleep(2000)  ' Wait for the shelled application to get going:
      RET& = WaitForSingleObjectEx(proc.hProcess, lWaitTime, False)
      RET& = GetExitCodeProcess(proc.hProcess, lExitCode)
      ExecAndWait = RET&
      RET& = CloseHandle(proc.hProcess)
      RET& = CloseHandle(proc.hThread)
   End If

   Exit Function

errExecAndWait:
    Err.Raise Err.Number, Err.Source & ":ExecAndWait", Err.Description

End Function
票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/27863222

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档