2009-02-20 1 views
1

Возможно ли запустить синхронный процесс в VB6 (т. Е. Вызвать внешний .exe), дождаться его завершения и захватить возвращаемое значение?Могу ли я запустить синхронный процесс в VB6 и получить его возвращаемое значение?

У нас есть устаревший код (очевидно, в VB6), что нам нужно вызвать приложение .NET для выполнения некоторых сложных задач и на основе возвращаемого значения .NET app либо продолжить, либо сбой. Есть ли лучший способ сделать такое?

+0

Я интересно - есть ли что-то не так с моей идеей? Я прошу чисто из интереса. – Tomalak

+0

Причина, по которой я отметил другой ответ, был ответом на то, что у меня было аналогичное решение уже на месте, но не так полно, как этот (с возвратным значением тоже). Я определенно попробую тоже, так как это намного проще. Насколько я могу судить, ничего плохого - я вам сообщу. Благодаря!! – Pwninstein

+0

О, хорошо. :) Я просто царапал себе голову, что, на мой взгляд, я мог упустить из виду, что заставило вас пойти со сравнительно сложным способом Win32 API сделать что-то очень простое. – Tomalak

ответ

8

Ваш первый вариант, вероятно, должен заключаться в том, чтобы разоблачить интерфейс, чтобы открыть интерфейсы .NET для COM и использовать его (он намного чище), но если по какой-то причине вы должны сделать это через порожденный процесс, используйте этот код VB6 ,

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 WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long 
    Private Declare Function CreateProcessA Lib "kernel32" (ByVal lpApplicationName As Long, 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 Long, lpStartupInfo As STARTUPINFO, lpProcessInformation As PROCESS_INFORMATION) As Long 
    Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long 
    Private Declare Function GetExitCodeProcess Lib "kernel32" (ByVal hProcess As Long, lpExitCode As Long) As Long 

    Private Const NORMAL_PRIORITY_CLASS = &H20& 
    Private Const INFINITE = -1& 
    Private Const SW_HIDE = 0 
    Private Const SW_SHOWMINNOACTIVE = 7 

    Public Function ExecCmd(cmdline As String, workdir As String) As Integer 
     Dim proc As PROCESS_INFORMATION 
     Dim start As STARTUPINFO 
     Dim ret as Long 

     ChDrive Left(workdir, 1) & ":" 
     ChDir workdir 

     start.cb = Len(start) 
     start.wShowWindow = SW_SHOWMINNOACTIVE 

     Call CreateProcessA(0&, cmdline, 0&, 0&, 1&, NORMAL_PRIORITY_CLASS, 0&, 0&, start, proc) 
     Call WaitForSingleObject(proc.hProcess, INFINITE) 
     Call GetExitCodeProcess(proc.hProcess, ret) 
     Call CloseHandle(proc.hThread) 
     Call CloseHandle(proc.hProcess) 
     ExecCmd=ret 
    End Function 
+0

BTW: Я не заметил, когда я разместил это как уродливый этот код. Это из самых глубоких архивов кода, которые я написал/заимствовал, когда был еще молод и глуп. Он функциональный, но, вероятно, может использоваться для очистки пружин. – JohnFx

+0

похоже на то, что мы используем. Я рекомендую этот подход –

+0

Хорошо, я опубликовал слегка очищенную версию и протестировал ее в VB6. – JohnFx

2
' References: "Windows Script Host Shell Object Model" ' 
Function ExecuteCommand(cmd As String, ExpectedResult as Long) As Boolean 
    Dim shell As New IWshRuntimeLibrary.WshShell 
    Dim Result As Long 

    Result = shell.Run(Command:=cmd, WindowStyle:=WshHide, WaitOnReturn:=True) 

    ExecuteCommand = (Result = ExpectedResult) 
End Function 
0

Вы могли бы использовать:

Option Explicit 

Private Const INFINITE = &HFFFF& 
Private Const SYNCHRONIZE = &H100000 
Private Const PROCESS_QUERY_INFORMATION = &H400& 

Private Declare Function CloseHandle Lib "kernel32" (_ 
    ByVal hObject As Long) As Long 

Private Declare Function GetExitCodeProcess Lib "kernel32" (_ 
    ByVal hProcess As Long, _ 
    lpExitCode As Long) As Long 

Private Declare Function OpenProcess Lib "kernel32" (_ 
    ByVal dwDesiredAccess As Long, _ 
    ByVal bInheritHandle As Long, _ 
    ByVal dwProcessId As Long) As Long 

Private Declare Function WaitForSingleObject Lib "kernel32" (_ 
    ByVal hHandle As Long, _ 
    ByVal dwMilliseconds As Long) As Long 

Private Function SyncShell(_ 
    ByVal PathName As String, _ 
    ByVal WindowStyle As VbAppWinStyle) As Long 
    'Shell and wait. Return exit code result, raise an 
    'exception on any error. 
    Dim lngPid As Long 
    Dim lngHandle As Long 
    Dim lngExitCode As Long 

    lngPid = Shell(PathName, WindowStyle) 
    If lngPid <> 0 Then 
     lngHandle = OpenProcess(SYNCHRONIZE _ 
          Or PROCESS_QUERY_INFORMATION, 0, lngPid) 
     If lngHandle <> 0 Then 
      WaitForSingleObject lngHandle, INFINITE 
      If GetExitCodeProcess(lngHandle, lngExitCode) <> 0 Then 
       SyncShell = lngExitCode 
       CloseHandle lngHandle 
      Else 
       CloseHandle lngHandle 
       Err.Raise &H8004AA00, "SyncShell", _ 
          "Failed to retrieve exit code, error " _ 
         & CStr(Err.LastDllError) 
      End If 
     Else 
      Err.Raise &H8004AA01, "SyncShell", _ 
         "Failed to open child process" 
     End If 
    Else 
     Err.Raise &H8004AA02, "SyncShell", _ 
        "Failed to Shell child process" 
    End If 
End Function 
+0

Если вы хотите сделать это правильно без «замораживания пользовательского интерфейса», вам действительно нужно использовать таймер для опроса дочернего процесса для завершения.DoEvents - неприятный взлом с возможными негативными побочными эффектами, и его следует избегать. – Bob