# Starting an external process asynchronously

## Starting an external process asynchronously

Hello,

in my Fortran program, I want to start an external process and directly return to my program, not waiting for its completion.
Thus, as I understand it, the compiler routines RUNQQ, SYSTEM or SYSTEMQQ are not suitable for this problem.

I have read about the possibility to use the Windows-Routine CreateProcess instead and implemented the following function:

subroutine start_help()
c-----------------------------------------------------------------------
c
c.... Purpose: start an external process
c-----------------------------------------------------------------------
use Kernel32
implicit none
INTEGER(BOOL) :: res, bIH
INTEGER(DWORD) :: dCF
INTEGER(LPVOID) :: lpE
CHARACTER(len=500) :: fcis, fcis1
TYPE( T_SECURITY_ATTRIBUTES ) tPA, tTA
TYPE( T_PROCESS_INFORMATION ) tPI
TYPE( T_STARTUPINFO ) tSI
bIH = FALSE ! inherit handles [bool] dCF = NULL ! creation flags [dword]
lpE = NULL ! environment [lpStr]

+AcroRd32.exe"C
fcis1 = "/s /o C:\\path\\to\\my.pdf"C
res = CreateProcess(fcis,fcis1,tPA,tTA,bIH,dCF,lPE,NULL,tSI,tPI) if (res .eq. 0) then
write(16,*) "Error! Could not create process.",GetLastError()
end if
return
end

This routine works fine when calling it in a blank test program, which does nothing but call this routine.

However, as soon as I implement it to my larger program, it somehow refuses to work at all.
I tried adding a break point to the subroutine, but somehow the debugger just skips the whole routine, even when setting the break point to its call-statement and proceding with single steps.

The routine is called though, as test and error output is written just fine.

CreateProcess seems to fail too, as there is no process opened, even with other executables. The GetLastError error code is 0.

I am using Visual Studio 2010 with Intel(R) Visual Fortran Compiler XE 13.0.0.089 [Intel(R) 64]. I have used the same compiler for both programs.
No external libraries are used, OpenMP is activated but the routine and its calls are outside of parallel regions.

4 Beiträge / 0 neu
Nähere Informationen zur Compiler-Optimierung finden Sie in unserem Optimierungshinweis.

Some of the arguments (the derived type ones) passed to CreateProcess don't look like they are being initialised. The values of those arguments will be random garbage in a larger program which may cause odd things to happen (in a smaller program their values may be somewhat consistent, to the extent that things seem to work, but there be dragons near). Most of those arguments you don't need to supply anything other than a NULL pointer for, unless you are doing fancy stuff.

This snippet doesn't do what you want - it explicitly waits for the process to terminate - but should give you an idea of how to use CreateProcess. If you obliterate the wait_result, bool_result and success_flag assignment statements towards the end of the procedure (leave the cleanup bit!) then things should carry on asynchronously. It is an internal procedure in a main program - while I don't see any host associated stuff in this section of code there may be the odd declaration missing.


!*****************************************************************************

!!

!> Execute a child program, determine whether it succeeded or failed based

!! on the process exit code.

!!

!! @param[in]     command_name      The name of the executable file for the

!! program to execute.

!!

!! @param[in]     command_line      The command line to execute.  Typically

!! the first argument would be the same as @a command_name.

!!

!! @param[out]    success_flag      Flag to indicate whether successful

!! termination of the command was detected.  This is based on the process

!! exit code being zero.
SUBROUTINE check_return_code(command_name, command_line, success_flag)
USE IFWIN
!---------------------------------------------------------------------------

! Arguments
CHARACTER(*), INTENT(IN) :: command_name

CHARACTER(*), INTENT(IN) :: command_line

LOGICAL, INTENT(OUT) :: success_flag
!---------------------------------------------------------------------------

! Local variables
INTEGER(BOOL) :: bool_result

TYPE(T_STARTUPINFO) :: startup_info

TYPE(T_PROCESS_INFORMATION) :: proc_info

INTEGER(DWORD) :: wait_result

INTEGER(DWORD) :: process_code
!***************************************************************************
CALL ZeroMemory(LOC(startup_info), SIZEOF(startup_info))

startup_info%cb = SIZEOF(startup_info)
bool_result = CreateProcess(  &

command_name // ACHAR(0),  &   ! LPCTSTR lpApplicationName

command_line // ACHAR(0),  &   ! LPTSTR lpCommandLine

0,  &                 ! LPSECURITY_ATTRIBUTES lpProcessAttributes

1_BOOL,  &            ! BOOL bInheritHandles

0_DWORD,  &           ! DWORD dwCreationFlags

0,  &                 ! LPVOID lpEnvironment

0,  &                 ! LPCTSTR lpCurrentDirectory

startup_info,  &      ! LPSTARTUPINFO lpStartupInfo,

proc_info )           ! LPPROCESS_INFORMATION lpProcessInformation
wait_result = WaitForSingleObject(proc_info%hProcess, INFINITE)

bool_result = GetExitCodeProcess(proc_info%hProcess, LOC(process_code))

success_flag = process_code == 0
! Cleanup.

bool_result = CloseHandle(proc_info%hProcess)

END SUBROUTINE check_return_code



Note that I don't go in for this 'string'C business - I prefer to stick with the standard fortran approach to creating a null terminated string.

(Edit to further note that I don't have some sort of bizarre vertical spacing convention - that's just the forum software botching things.)

Thanks, that was exactly the problem. :) Works just fine now.

Until Execute_Command_Line appears in ifort, could you use one of those ifort system functions to start a background process? The start command of cmd shell, or the usual background "&" of bash and similar shells, might perform your task.

## Kommentar hinterlassen

Bitte anmelden, um einen Kommentar hinzuzufügen. Sie sind noch nicht Mitglied?