"Fossies" - the Fresh Open Source Software Archive

Member "seed7/src/pcs_win.c" (31 Dec 2020, 35925 Bytes) of package /linux/misc/seed7_05_20210223.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "pcs_win.c" see the Fossies "Dox" file reference documentation.

    1 /********************************************************************/
    2 /*                                                                  */
    3 /*  pcs_win.c     Process functions which use the Windows API.      */
    4 /*  Copyright (C) 1989 - 2014  Thomas Mertes                        */
    5 /*                                                                  */
    6 /*  This file is part of the Seed7 Runtime Library.                 */
    7 /*                                                                  */
    8 /*  The Seed7 Runtime Library is free software; you can             */
    9 /*  redistribute it and/or modify it under the terms of the GNU     */
   10 /*  Lesser General Public License as published by the Free Software */
   11 /*  Foundation; either version 2.1 of the License, or (at your      */
   12 /*  option) any later version.                                      */
   13 /*                                                                  */
   14 /*  The Seed7 Runtime Library is distributed in the hope that it    */
   15 /*  will be useful, but WITHOUT ANY WARRANTY; without even the      */
   16 /*  implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR */
   17 /*  PURPOSE.  See the GNU Lesser General Public License for more    */
   18 /*  details.                                                        */
   19 /*                                                                  */
   20 /*  You should have received a copy of the GNU Lesser General       */
   21 /*  Public License along with this program; if not, write to the    */
   22 /*  Free Software Foundation, Inc., 51 Franklin Street,             */
   23 /*  Fifth Floor, Boston, MA  02110-1301, USA.                       */
   24 /*                                                                  */
   25 /*  Module: Seed7 Runtime Library                                   */
   26 /*  File: seed7/src/pcs_win.c                                       */
   27 /*  Changes: 2010, 2012 - 2014  Thomas Mertes                       */
   28 /*  Content: Process functions which use the Windows API.           */
   29 /*                                                                  */
   30 /********************************************************************/
   31 
   32 #define LOG_FUNCTIONS 0
   33 #define VERBOSE_EXCEPTIONS 0
   34 
   35 #include "version.h"
   36 
   37 #include "stdlib.h"
   38 #include "stdio.h"
   39 #include "string.h"
   40 #include "windows.h"
   41 #include "io.h"
   42 #include "fcntl.h"
   43 #include "wchar.h"
   44 #include "ctype.h"
   45 #include "errno.h"
   46 
   47 #include "common.h"
   48 #include "data_rtl.h"
   49 #include "os_decls.h"
   50 #include "heaputl.h"
   51 #include "striutl.h"
   52 #include "int_rtl.h"
   53 #include "rtl_err.h"
   54 
   55 
   56 #define MAXIMUM_COMMAND_LINE_LENGTH 32768
   57 
   58 typedef struct {
   59     uintType usage_count;
   60     fileType stdIn;
   61     fileType stdOut;
   62     fileType stdErr;
   63     /* Up to here the structure is identical to struct processStruct */
   64     HANDLE hProcess;
   65     HANDLE hThread;
   66     DWORD pid;
   67     boolType isTerminated;
   68     DWORD exitValue;
   69   } win_processRecord, *win_processType;
   70 
   71 typedef const win_processRecord *const_win_processType;
   72 
   73 #if DO_HEAP_STATISTIC
   74 size_t sizeof_processRecord = sizeof(win_processRecord);
   75 #endif
   76 
   77 #define to_hProcess(process)     (((const_win_processType) process)->hProcess)
   78 #define to_hThread(process)      (((const_win_processType) process)->hThread)
   79 #define to_pid(process)          (((const_win_processType) process)->pid)
   80 #define to_isTerminated(process) (((const_win_processType) process)->isTerminated)
   81 #define to_exitValue(process)    (((const_win_processType) process)->exitValue)
   82 
   83 #define to_var_hProcess(process)     (((win_processType) process)->hProcess)
   84 #define to_var_hThread(process)      (((win_processType) process)->hThread)
   85 #define to_var_pid(process)          (((win_processType) process)->pid)
   86 #define to_var_isTerminated(process) (((win_processType) process)->isTerminated)
   87 #define to_var_exitValue(process)    (((win_processType) process)->exitValue)
   88 
   89 #if POINTER_SIZE == 32
   90 typedef int32Type intPtrType;
   91 #elif POINTER_SIZE == 64
   92 typedef int64Type intPtrType;
   93 #endif
   94 
   95 
   96 
   97 #if ANY_LOG_ACTIVE
   98 static void printParameters (const const_rtlArrayType parameters)
   99 
  100   {
  101     memSizeType paramSize;
  102     memSizeType pos;
  103 
  104   /* printParameters */
  105     paramSize = arraySize(parameters);
  106     for (pos = 0; pos < paramSize; pos++) {
  107       printf(", \"%s\"",
  108              striAsUnquotedCStri(parameters->arr[pos].value.striValue));
  109     } /* for */
  110   } /* printParameters */
  111 #endif
  112 
  113 
  114 
  115 /**
  116  *  Fill the contents of a quoted part to be used by prepareCommandLine.
  117  *  This function does not create the surrounding quotations (").
  118  *  A string with the backslash logic of Windows commandline parameters
  119  *  is produced. 2 * N backslashes followed by a quotation (") means
  120  *  N backslashes and the end of the parameter. Note that in this case
  121  *  the quotation is written by prepareCommandLine. 2 * N + 1 backslashes
  122  *  followed by a quotation (") means N backslashes and the quotation
  123  *  is part of the parameter. N backslashes not followed by a quotation
  124  *  means just N backslashes.
  125  */
  126 static os_charType *copyQuotedPart (os_charType *sourceChar, os_charType *destChar,
  127     os_charType *beyondDest)
  128 
  129   {
  130     memSizeType countBackslash;
  131 
  132   /* copyQuotedPart */
  133     for (; *sourceChar != '\0' && destChar < beyondDest;
  134         sourceChar++, destChar++) {
  135       if (*sourceChar == '"') {
  136         if (&destChar[2] > beyondDest) {
  137           destChar = beyondDest;
  138         } else {
  139           *(destChar++) = '\\';
  140           *destChar = *sourceChar;
  141         } /* if */
  142       } else if (*sourceChar == '\\') {
  143         sourceChar++;
  144         countBackslash = 1;
  145         while (*sourceChar == '\\') {
  146           sourceChar++;
  147           countBackslash++;
  148         } /* while */
  149         /* fprintf(stderr, "countBackslash=" FMT_U_MEM "\n", countBackslash);
  150            fprintf(stderr, "sourceChar=%c\n", *sourceChar); */
  151         if (*sourceChar == '"' || *sourceChar == '\0') {
  152           countBackslash *= 2;
  153         } /* if */
  154         sourceChar--;
  155         if (countBackslash > MAXIMUM_COMMAND_LINE_LENGTH ||
  156             &destChar[countBackslash] > beyondDest) {
  157           destChar = beyondDest;
  158         } else {
  159           do {
  160             *(destChar++) = '\\';
  161             countBackslash--;
  162           } while (countBackslash != 0);
  163           destChar--;
  164         } /* if */
  165       } else {
  166         *destChar = *sourceChar;
  167       } /* if */
  168     } /* for */
  169     return destChar;
  170   } /* copyQuotedPart */
  171 
  172 
  173 
  174 /**
  175  *  Create a command line string that can be used by CreateProcessW().
  176  *  All parameters that contain a space or a quotation (") or a control
  177  *  character or a character byond ASCII are quoted. All other parameters
  178  *  are not quoted. The command line string must be freed with os_stri_free().
  179  *  @param err_info Unchanged if the function succeeds, and
  180  *                  MEMORY_ERROR if a memory allocation failed, and
  181  *                  RANGE_ERROR if the conversion of a parameter failed.
  182  *  @return a null terminated os_striType command line, or
  183  *          NULL if an error occurred.
  184  */
  185 static os_striType prepareCommandLine (const const_os_striType os_command_stri,
  186     const const_rtlArrayType parameters, errInfoType *err_info)
  187 
  188   {
  189     const_os_striType command_stri;
  190     memSizeType arraySize;
  191     memSizeType striSize;
  192     memSizeType pos;
  193     os_striType argument;
  194     os_charType *sourceChar;
  195     os_charType *destChar;
  196     os_charType *beyondDest;
  197     boolType quoteArgument;
  198     os_striType command_line;
  199 
  200   /* prepareCommandLine */
  201     logFunction(printf("prepareCommandLine(\"" FMT_S_OS "\"",
  202                        os_command_stri);
  203                 printParameters(parameters);
  204                 printf(", %d)\n", *err_info););
  205     arraySize = arraySize(parameters);
  206     if (unlikely(!os_stri_alloc(command_line, MAXIMUM_COMMAND_LINE_LENGTH - 1))) {
  207       *err_info = MEMORY_ERROR;
  208     } else {
  209       beyondDest = &command_line[MAXIMUM_COMMAND_LINE_LENGTH];
  210       if (USE_EXTENDED_LENGTH_PATH &&
  211           memcmp(os_command_stri, PATH_PREFIX, PREFIX_LEN * sizeof(os_charType)) == 0) {
  212         /* For extended path omit the prefix. */
  213         command_stri = &os_command_stri[PREFIX_LEN];
  214       } else {
  215         command_stri = os_command_stri;
  216       } /* if */
  217       /* fprintf(stderr, "\ncommand_stri=\"%ls\"\n", command_stri); */
  218 #ifdef USE_MODULE_NAME_FOR_CREATE_PROCESS
  219       /* Pelles C cannot start the compiler (POCC.EXE) without this fix. */
  220       {
  221         os_charType *lastPathDelimiter;
  222 
  223         lastPathDelimiter = os_stri_strrchr(command_stri, OS_PATH_DELIMITER);
  224         if (lastPathDelimiter != NULL) {
  225           command_stri = &lastPathDelimiter[1];
  226         } /* if */
  227       }
  228 #endif
  229       striSize = os_stri_strlen(command_stri);
  230       if (striSize > MAXIMUM_COMMAND_LINE_LENGTH - 2 ||
  231           &command_line[striSize] > beyondDest) {
  232         *err_info = MEMORY_ERROR;
  233         destChar = beyondDest;
  234       } else {
  235         command_line[0] = '\"';
  236         memcpy(&command_line[1], command_stri, sizeof(os_charType) * striSize);
  237         command_line[striSize + 1] = '\"';
  238         destChar = &command_line[striSize + 2];
  239       } /* if */
  240       for (pos = 0; pos < arraySize && *err_info == OKAY_NO_ERROR; pos++) {
  241         argument = stri_to_os_stri(parameters->arr[pos].value.striValue, err_info);
  242         if (argument != NULL) {
  243           /* fprintf(stderr, "argument[%d]=%ls\n", pos + 1, argument); */
  244           quoteArgument = FALSE;
  245           for (sourceChar = argument; *sourceChar != '\0'; sourceChar++) {
  246             if (*sourceChar <= ' ' || *sourceChar > '~' || *sourceChar == '"') {
  247               quoteArgument = TRUE;
  248             } /* if */
  249           } /* for */
  250           if (quoteArgument) {
  251             if (&destChar[2] > beyondDest) {
  252               destChar = beyondDest;
  253             } else {
  254               *(destChar++) = ' ';
  255               *(destChar++) = '"';
  256             } /* if */
  257             destChar = copyQuotedPart(argument, destChar, beyondDest);
  258             if (destChar >= beyondDest) {
  259               *err_info = MEMORY_ERROR;
  260             } else {
  261               *(destChar++) = '"';
  262             } /* if */
  263           } else {
  264             if (destChar < beyondDest) {
  265               *(destChar++) = ' ';
  266             } /* if */
  267             for (sourceChar = argument; *sourceChar != '\0' && destChar < beyondDest;
  268                  sourceChar++, destChar++) {
  269               *destChar = *sourceChar;
  270             } /* for */
  271           } /* if */
  272           os_stri_free(argument);
  273         } /* if */
  274       } /* for */
  275       if (destChar >= beyondDest) {
  276         *err_info = MEMORY_ERROR;
  277       } else {
  278         *destChar = '\0';
  279       } /* if */
  280       if (unlikely(*err_info != OKAY_NO_ERROR)) {
  281         os_stri_free(command_line);
  282         command_line = NULL;
  283       } else {
  284         /* fprintf(stderr, "command_line=%ls\n", command_line); */
  285       } /* if */
  286     } /* if */
  287     logFunction(printf("prepareCommandLine --> \"" FMT_S_OS "\"\n",
  288                        command_line););
  289     return command_line;
  290   } /* prepareCommandLine */
  291 
  292 
  293 
  294 /**
  295  *  Compare two processes.
  296  *  @return -1, 0 or 1 if the first argument is considered to be
  297  *          respectively less than, equal to, or greater than the
  298  *          second.
  299  */
  300 intType pcsCmp (const const_processType process1, const const_processType process2)
  301 
  302   {
  303     intType signumValue;
  304 
  305   /* pcsCmp */
  306     if (process1 == NULL) {
  307       if (process2 != NULL) {
  308         signumValue = -1;
  309       } else {
  310         signumValue = 0;
  311       } /* if */
  312     } else if (process2 == NULL) {
  313       signumValue = 1;
  314     } else if (to_pid(process1) < to_pid(process2)) {
  315       signumValue = -1;
  316     } else {
  317       signumValue = to_pid(process1) > to_pid(process2);
  318     } /* if */
  319     return signumValue;
  320   } /* pcsCmp */
  321 
  322 
  323 
  324 /**
  325  *  Check if two processes are equal.
  326  *  @return TRUE if both processes are equal,
  327  *          FALSE otherwise.
  328  */
  329 boolType pcsEq (const const_processType process1, const const_processType process2)
  330 
  331   { /* pcsEq */
  332     if (process1 == NULL) {
  333       return process2 == NULL;
  334     } else if (process2 == NULL) {
  335       return FALSE;
  336     } else {
  337       return to_pid(process1) == to_pid(process2);
  338     } /* if */
  339   } /* pcsEq */
  340 
  341 
  342 
  343 /**
  344  *  Return the exit value of the specified process.
  345  *  By convention, the value 0 indicates normal termination.
  346  *  @return the exit value of the specified process.
  347  */
  348 intType pcsExitValue (const const_processType process)
  349 
  350   {
  351     intType exitValue;
  352 
  353   /* pcsExitValue */
  354     if (unlikely(!to_isTerminated(process))) {
  355       raise_error(FILE_ERROR);
  356       exitValue = -1;
  357     } else {
  358       exitValue = (intType) to_exitValue(process);
  359     } /* if */
  360     return exitValue;
  361   } /* pcsExitValue */
  362 
  363 
  364 
  365 /**
  366  *  Free the memory referred by 'oldProcess'.
  367  *  After pcsFree is left 'oldProcess' refers to not existing memory.
  368  *  The memory where 'oldProcess' is stored can be freed afterwards.
  369  */
  370 void pcsFree (processType oldProcess)
  371 
  372   { /* pcsFree */
  373     logFunction(printf("pcsFree(" FMT_U32 ") (usage=" FMT_U ")\n",
  374                        (uint32Type) (oldProcess != NULL ? to_pid(oldProcess) : 0),
  375                        oldProcess != NULL ? oldProcess->usage_count : (uintType) 0););
  376     CloseHandle(to_hProcess(oldProcess));
  377     CloseHandle(to_hThread(oldProcess));
  378     FREE_RECORD(oldProcess, win_processRecord, count.process);
  379   } /* pcsFree */
  380 
  381 
  382 
  383 /**
  384  *  Compute the hash value of a process.
  385  *  @return the hash value.
  386  */
  387 intType pcsHashCode (const const_processType process)
  388 
  389   {
  390     intType hashCode;
  391 
  392   /* pcsHashCode */
  393     if (process == NULL) {
  394       hashCode = 0;
  395     } else {
  396       hashCode = to_pid(process);
  397     } /* if */
  398     return hashCode;
  399   } /* pcsHashCode */
  400 
  401 
  402 
  403 /**
  404  *  Test whether the specified process is alive.
  405  *  @return TRUE if the specified process has not yet terminated,
  406  *          FALSE otherwise.
  407  */
  408 boolType pcsIsAlive (const processType process)
  409 
  410   {
  411     DWORD exitCode = 0;
  412     boolType isAlive;
  413 
  414   /* pcsIsAlive */
  415     logFunction(printf("pcsIsAlive(" FMT_U32 ") (hProcess=" FMT_U_MEM ")\n",
  416                        (uint32Type) (process != NULL ? to_pid(process) : 0),
  417                        process != NULL ? (memSizeType) to_hProcess(process) : (memSizeType) 0););
  418     if (to_isTerminated(process)) {
  419       isAlive = FALSE;
  420     } else {
  421       if (GetExitCodeProcess(to_hProcess(process), &exitCode) != 0) {
  422         if (exitCode == STILL_ACTIVE) {
  423           if (WaitForSingleObject(to_hProcess(process), 0) == WAIT_OBJECT_0) {
  424             to_var_isTerminated(process) = TRUE;
  425           } /* if */
  426         } else {
  427           to_var_isTerminated(process) = TRUE;
  428         } /* if */
  429         isAlive = !to_isTerminated(process);
  430         if (!isAlive) {
  431           to_var_exitValue(process) = exitCode;
  432         } /* if */
  433       } else {
  434         logError(printf("pcsIsAlive: GetExitCodeProcess(" FMT_U_MEM ", 0) failed:\n"
  435                         "GetLastError=" FMT_U32 "\n",
  436                         (memSizeType) to_hProcess(process), (uint32Type) GetLastError());
  437                  printf("PID=" FMT_U32 "\n", (uint32Type) to_pid(process)););
  438         raise_error(FILE_ERROR);
  439         isAlive = TRUE;
  440       } /* if */
  441     } /* if */
  442     return isAlive;
  443   } /* pcsIsAlive */
  444 
  445 
  446 
  447 /**
  448  *  Kill the specified process.
  449  *  @exception FILE_ERROR It was not possible to kill the process.
  450  */
  451 void pcsKill (const processType process)
  452 
  453   { /* pcsKill */
  454     logFunction(printf("pcsKill(" FMT_U32 ") (hProcess=" FMT_U_MEM ")\n",
  455                        (uint32Type) (process != NULL ? to_pid(process) : 0),
  456                        process != NULL ? (memSizeType) to_hProcess(process) : (memSizeType) 0););
  457     if (unlikely(process == NULL)) {
  458       logError(printf("pcsKill: process == NULL\n"););
  459       raise_error(FILE_ERROR);
  460     } else if (unlikely(TerminateProcess(to_hProcess(process), 0) == 0)) {
  461       logError(printf("pcsKill: TerminateProcess(" FMT_U_MEM ", 0) failed:\n"
  462                       "GetLastError=" FMT_U32 "\n",
  463                       (memSizeType) to_hProcess(process), (uint32Type) GetLastError());
  464                printf("PID=" FMT_U32 "\n", (uint32Type) to_pid(process)););
  465       raise_error(FILE_ERROR);
  466     } /* if */
  467   } /* pcsKill */
  468 
  469 
  470 
  471 void pcsPipe2 (const const_striType command, const const_rtlArrayType parameters,
  472     fileType *childStdin, fileType *childStdout)
  473 
  474   {
  475     os_striType os_command_stri;
  476     os_striType command_line;
  477     SECURITY_ATTRIBUTES saAttr;
  478     HANDLE childInputRead = INVALID_HANDLE_VALUE;
  479     HANDLE childInputWrite = INVALID_HANDLE_VALUE;
  480     HANDLE childOutputRead = INVALID_HANDLE_VALUE;
  481     HANDLE childOutputWrite = INVALID_HANDLE_VALUE;
  482     STARTUPINFOW startupInfo;
  483     PROCESS_INFORMATION processInformation;
  484     int path_info = PATH_IS_NORMAL;
  485     errInfoType err_info = OKAY_NO_ERROR;
  486 
  487   /* pcsPipe2 */
  488     logFunction(printf("pcsPipe2(\"%s\"", striAsUnquotedCStri(command));
  489                 printParameters(parameters);
  490                 printf(")\n"););
  491     os_command_stri = cp_to_os_path(command, &path_info, &err_info);
  492     if (likely(os_command_stri != NULL)) {
  493       command_line = prepareCommandLine(os_command_stri, parameters, &err_info);
  494       if (likely(command_line != NULL)) {
  495         /* printf("pcsPipe2(%ls, %ls)\n", os_command_stri, command_line); */
  496         saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
  497         saAttr.bInheritHandle = TRUE;
  498         saAttr.lpSecurityDescriptor = NULL;
  499         if (unlikely(CreatePipe(&childInputRead,
  500                                 &childInputWrite, &saAttr, 0) == 0 ||
  501                      CreatePipe(&childOutputRead,
  502                                 &childOutputWrite, &saAttr, 0) == 0)) {
  503           logError(printf("pcsPipe2(\"%s\", ...): CreatePipe() failed.\n",
  504                           striAsUnquotedCStri(command)););
  505           err_info = FILE_ERROR;
  506         } else if (unlikely(SetHandleInformation(childInputWrite,
  507                                                  HANDLE_FLAG_INHERIT, 0) == 0 ||
  508                             SetHandleInformation(childOutputRead,
  509                                                  HANDLE_FLAG_INHERIT, 0) == 0)) {
  510           logError(printf("pcsPipe2(\"%s\", ...): SetHandleInformation() failed.\n",
  511                           striAsUnquotedCStri(command)););
  512           err_info = FILE_ERROR;
  513         } else {
  514           memset(&startupInfo, 0, sizeof(startupInfo));
  515           /* memset(&processInformation, 0, sizeof(processInformation)); */
  516           startupInfo.cb = sizeof(startupInfo);
  517           startupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
  518           startupInfo.wShowWindow = SW_HIDE;
  519           startupInfo.hStdInput = childInputRead;
  520           startupInfo.hStdOutput = childOutputWrite;
  521           startupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);;
  522           logMessage(printf("before CreateProcessW(\"" FMT_S_OS "\", \"" FMT_S_OS "\", ...)\n",
  523                             os_command_stri, command_line););
  524           if (CreateProcessW(os_command_stri,
  525                              command_line /* lpCommandLine */,
  526                              NULL /* lpProcessAttributes */,
  527                              NULL /* lpThreadAttributes */,
  528                              1  /* bInheritHandles */,
  529                              CREATE_UNICODE_ENVIRONMENT /* dwCreationFlags */,
  530                              NULL /* lpEnvironment */,
  531                              NULL /* lpCurrentDirectory */,
  532                              &startupInfo,
  533                              &processInformation) != 0) {
  534             CloseHandle(childInputRead);
  535             CloseHandle(childOutputWrite);
  536             *childStdin  = fdopen(_open_osfhandle((intPtrType) (childInputWrite), _O_TEXT), "w");
  537             *childStdout = fdopen(_open_osfhandle((intPtrType) (childOutputRead), _O_TEXT), "r");
  538             CloseHandle(processInformation.hProcess);
  539             CloseHandle(processInformation.hThread);
  540           } else {
  541             logError(printf("pcsPipe2: CreateProcessW(\"" FMT_S_OS "\", \"" FMT_S_OS "\", ...) failed.\n"
  542                             "GetLastError=" FMT_U32 "\n",
  543                             os_command_stri, command_line, (uint32Type) GetLastError());
  544                      printf("ERROR_FILE_NOT_FOUND=%d\n", (int) ERROR_FILE_NOT_FOUND););
  545             err_info = FILE_ERROR;
  546           } /* if */
  547           /* printf("after CreateProcessW\n"); */
  548         } /* if */
  549         os_stri_free(command_line);
  550       } /* if */
  551       os_stri_free(os_command_stri);
  552     } /* if */
  553     if (unlikely(err_info != OKAY_NO_ERROR)) {
  554       if (childInputRead != INVALID_HANDLE_VALUE) {
  555         CloseHandle(childInputRead);
  556       } /* if */
  557       if (childInputWrite != INVALID_HANDLE_VALUE) {
  558         CloseHandle(childInputWrite);
  559       } /* if */
  560       if (childOutputRead != INVALID_HANDLE_VALUE) {
  561         CloseHandle(childOutputRead);
  562       } /* if */
  563       if (childOutputWrite != INVALID_HANDLE_VALUE) {
  564         CloseHandle(childOutputWrite);
  565       } /* if */
  566       raise_error(err_info);
  567     } /* if */
  568     logFunction(printf("pcsPipe2 ->\n"););
  569   } /* pcsPipe2 */
  570 
  571 
  572 
  573 void pcsPty (const const_striType command, const const_rtlArrayType parameters,
  574     fileType *childStdin, fileType *childStdout)
  575 
  576   { /* pcsPty */
  577     pcsPipe2(command, parameters, childStdin, childStdout);
  578   } /* pcsPty */
  579 
  580 
  581 
  582 static HANDLE getHandleFromFile (fileType aFile, errInfoType *err_info)
  583 
  584   {
  585     int file_no;
  586     HANDLE fileHandle;
  587 
  588   /* getHandleFromFile */
  589     if (aFile == NULL) {
  590       fileHandle = CreateFile(NULL_DEVICE, GENERIC_READ | GENERIC_WRITE,
  591                               FILE_SHARE_READ | FILE_SHARE_WRITE,
  592                               NULL, OPEN_EXISTING, 0, NULL);
  593       if (unlikely(fileHandle == INVALID_HANDLE_VALUE)) {
  594         logError(printf("CreateFile(\"nul:\", ...) failed.\n"););
  595       } /* if */
  596     } else {
  597       file_no = fileno(aFile);
  598       if (unlikely(file_no == -1)) {
  599         logError(printf("getHandleFromFile(%d): fileno(%d) failed:\n"
  600                         "errno=%d\nerror: %s\n",
  601                         safe_fileno(aFile), safe_fileno(aFile),
  602                         errno, strerror(errno)););
  603         *err_info = FILE_ERROR;
  604         fileHandle = INVALID_HANDLE_VALUE;
  605       } else {
  606         fileHandle = (HANDLE) _get_osfhandle(file_no);
  607         if (unlikely(fileHandle == INVALID_HANDLE_VALUE)) {
  608           logError(printf("getHandleFromFile(%d): _get_osfhandle(%d) failed:\n"
  609                           "errno=%d\nerror: %s\n",
  610                           safe_fileno(aFile), safe_fileno(aFile),
  611                           errno, strerror(errno)););
  612           *err_info = FILE_ERROR;
  613         } /* if */
  614       } /* if */
  615     } /* if */
  616     return fileHandle;
  617   } /* getHandleFromFile */
  618 
  619 
  620 
  621 processType pcsStart (const const_striType command, const const_rtlArrayType parameters,
  622     fileType childStdin, fileType childStdout, fileType childStderr)
  623 
  624   {
  625     os_striType os_command_stri;
  626     os_striType command_line;
  627     STARTUPINFOW startupInfo;
  628     PROCESS_INFORMATION processInformation;
  629     int path_info = PATH_IS_NORMAL;
  630     HANDLE stdinFileHandle;
  631     HANDLE stdoutFileHandle;
  632     HANDLE stderrFileHandle;
  633     errInfoType err_info = OKAY_NO_ERROR;
  634     win_processType process = NULL;
  635 
  636   /* pcsStart */
  637     logFunction(printf("pcsStart(\"%s\"", striAsUnquotedCStri(command));
  638                 printParameters(parameters);
  639                 printf(", %d, %d, %d)\n",
  640                        safe_fileno(childStdin), safe_fileno(childStdout),
  641                        safe_fileno(childStderr)););
  642     stdinFileHandle = getHandleFromFile(childStdin, &err_info);
  643     stdoutFileHandle = getHandleFromFile(childStdout, &err_info);
  644     stderrFileHandle = getHandleFromFile(childStderr, &err_info);
  645     if (likely(err_info == OKAY_NO_ERROR)) {
  646       os_command_stri = cp_to_os_path(command, &path_info, &err_info);
  647       if (likely(os_command_stri != NULL)) {
  648         command_line = prepareCommandLine(os_command_stri, parameters, &err_info);
  649         if (likely(command_line != NULL)) {
  650           if (!ALLOC_RECORD(process, win_processRecord, count.process)) {
  651             err_info = MEMORY_ERROR;
  652           } else {
  653             memset(&startupInfo, 0, sizeof(startupInfo));
  654             /* memset(&processInformation, 0, sizeof(processInformation)); */
  655             startupInfo.cb = sizeof(startupInfo);
  656             startupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
  657             startupInfo.wShowWindow = SW_SHOWNORMAL;
  658             startupInfo.hStdInput = stdinFileHandle;
  659             startupInfo.hStdOutput = stdoutFileHandle;
  660             startupInfo.hStdError = stderrFileHandle;
  661             logMessage(printf("before CreateProcessW(\"" FMT_S_OS "\", \"" FMT_S_OS "\", ...)\n",
  662                               os_command_stri, command_line););
  663             if (CreateProcessW(os_command_stri,
  664                                command_line /* lpCommandLine */,
  665                                NULL /* lpProcessAttributes */,
  666                                NULL /* lpThreadAttributes */,
  667                                1  /* bInheritHandles */,
  668                                CREATE_UNICODE_ENVIRONMENT /* dwCreationFlags */,
  669                                NULL /* lpEnvironment */,
  670                                NULL /* lpCurrentDirectory */,
  671                                &startupInfo,
  672                                &processInformation) != 0) {
  673               /* printf("pcsStart: pProcess=" FMT_U_MEM "\n",
  674                   (memSizeType) (processInformation.hProcess)); */
  675               /* printf("pcsStart: PID=" FMT_U32 "\n", processInformation.dwProcessId); */
  676               memset(process, 0, sizeof(win_processRecord));
  677               process->usage_count = 1;
  678               process->hProcess = processInformation.hProcess;
  679               process->hThread  = processInformation.hThread;
  680               process->pid      = processInformation.dwProcessId;
  681               process->isTerminated = FALSE;
  682             } else {
  683               logError(printf("pcsStart: CreateProcessW(\"" FMT_S_OS "\", \"" FMT_S_OS "\", ...) failed.\n"
  684                               "GetLastError=" FMT_U32 "\n",
  685                               os_command_stri, command_line, (uint32Type) GetLastError());
  686                        printf("ERROR_FILE_NOT_FOUND=%d\n", (int) ERROR_FILE_NOT_FOUND););
  687               FREE_RECORD(process, win_processRecord, count.process);
  688               process = NULL;
  689               err_info = FILE_ERROR;
  690             } /* if */
  691             /* printf("after CreateProcessW\n"); */
  692           } /* if */
  693           os_stri_free(command_line);
  694         } /* if */
  695         os_stri_free(os_command_stri);
  696       } /* if */
  697     } /* if */
  698     if (childStdin == NULL && stdinFileHandle != INVALID_HANDLE_VALUE) {
  699       CloseHandle(stdinFileHandle);
  700     } /* if */
  701     if (childStdout == NULL && stdoutFileHandle != INVALID_HANDLE_VALUE) {
  702       CloseHandle(stdoutFileHandle);
  703     } /* if */
  704     if (childStderr == NULL && stderrFileHandle != INVALID_HANDLE_VALUE) {
  705       CloseHandle(stderrFileHandle);
  706     } /* if */
  707     if (unlikely(err_info != OKAY_NO_ERROR)) {
  708       raise_error(err_info);
  709     } /* if */
  710     logFunction(printf("pcsStart -> " FMT_U32 "\n",
  711                        (uint32Type) (process != NULL ? process->pid : 0)););
  712     return (processType) process;
  713   } /* pcsStart */
  714 
  715 
  716 
  717 processType pcsStartPipe (const const_striType command, const const_rtlArrayType parameters)
  718 
  719   {
  720     os_striType os_command_stri;
  721     os_striType command_line;
  722     SECURITY_ATTRIBUTES saAttr;
  723     HANDLE childInputRead = INVALID_HANDLE_VALUE;
  724     HANDLE childInputWrite = INVALID_HANDLE_VALUE;
  725     HANDLE childOutputRead = INVALID_HANDLE_VALUE;
  726     HANDLE childOutputWrite = INVALID_HANDLE_VALUE;
  727     HANDLE childErrorRead = INVALID_HANDLE_VALUE;
  728     HANDLE childErrorWrite = INVALID_HANDLE_VALUE;
  729     STARTUPINFOW startupInfo;
  730     PROCESS_INFORMATION processInformation;
  731     int path_info = PATH_IS_NORMAL;
  732     errInfoType err_info = OKAY_NO_ERROR;
  733     win_processType process = NULL;
  734 
  735   /* pcsStartPipe */
  736     logFunction(printf("pcsStartPipe(\"%s\"", striAsUnquotedCStri(command));
  737                 printParameters(parameters);
  738                 printf(")\n"););
  739     os_command_stri = cp_to_os_path(command, &path_info, &err_info);
  740     if (likely(os_command_stri != NULL)) {
  741       command_line = prepareCommandLine(os_command_stri, parameters, &err_info);
  742       if (likely(command_line != NULL)) {
  743         if (!ALLOC_RECORD(process, win_processRecord, count.process)) {
  744           err_info = MEMORY_ERROR;
  745         } else {
  746           /* printf("pcsStartPipe(%ls, %ls)\n", os_command_stri, command_line); */
  747           saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
  748           saAttr.bInheritHandle = TRUE;
  749           saAttr.lpSecurityDescriptor = NULL;
  750           if (unlikely(CreatePipe(&childInputRead,
  751                                   &childInputWrite, &saAttr, 0) == 0 ||
  752                        CreatePipe(&childOutputRead,
  753                                   &childOutputWrite, &saAttr, 0) == 0 ||
  754                        CreatePipe(&childErrorRead,
  755                                   &childErrorWrite, &saAttr, 0) == 0)) {
  756             logError(printf("pcsPipe2(\"%s\", ...): CreatePipe() failed.\n",
  757                             striAsUnquotedCStri(command)););
  758             err_info = FILE_ERROR;
  759           } else if (unlikely(SetHandleInformation(childInputWrite,
  760                                                    HANDLE_FLAG_INHERIT, 0) == 0 ||
  761                               SetHandleInformation(childOutputRead,
  762                                                    HANDLE_FLAG_INHERIT, 0) == 0 ||
  763                               SetHandleInformation(childErrorRead,
  764                                                    HANDLE_FLAG_INHERIT, 0) == 0)) {
  765             logError(printf("pcsPipe2(\"%s\", ...): SetHandleInformation() failed.\n",
  766                             striAsUnquotedCStri(command)););
  767             err_info = FILE_ERROR;
  768           } else {
  769             memset(&startupInfo, 0, sizeof(startupInfo));
  770             /* memset(&processInformation, 0, sizeof(processInformation)); */
  771             startupInfo.cb = sizeof(startupInfo);
  772             startupInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
  773             startupInfo.wShowWindow = SW_HIDE;
  774             startupInfo.hStdInput = childInputRead;
  775             startupInfo.hStdOutput = childOutputWrite;
  776             startupInfo.hStdError = childErrorWrite;
  777             logMessage(printf("before CreateProcessW(\"" FMT_S_OS "\", \"" FMT_S_OS "\", ...)\n",
  778                               os_command_stri, command_line););
  779             if (CreateProcessW(os_command_stri,
  780                                command_line /* lpCommandLine */,
  781                                NULL /* lpProcessAttributes */,
  782                                NULL /* lpThreadAttributes */,
  783                                1  /* bInheritHandles */,
  784                                CREATE_UNICODE_ENVIRONMENT /* dwCreationFlags */,
  785                                NULL /* lpEnvironment */,
  786                                NULL /* lpCurrentDirectory */,
  787                                &startupInfo,
  788                                &processInformation) != 0) {
  789               CloseHandle(childInputRead);
  790               CloseHandle(childOutputWrite);
  791               CloseHandle(childErrorWrite);
  792               memset(process, 0, sizeof(win_processRecord));
  793               process->usage_count = 1;
  794               process->hProcess = processInformation.hProcess;
  795               process->hThread  = processInformation.hThread;
  796               process->pid      = processInformation.dwProcessId;
  797               process->isTerminated = FALSE;
  798               process->stdIn  = fdopen(_open_osfhandle((intPtrType) (childInputWrite), _O_TEXT), "w");
  799               process->stdOut = fdopen(_open_osfhandle((intPtrType) (childOutputRead), _O_TEXT), "r");
  800               process->stdErr = fdopen(_open_osfhandle((intPtrType) (childErrorRead), _O_TEXT), "r");
  801             } else {
  802               logError(printf("pcsStartPipe: CreateProcessW(\"" FMT_S_OS "\", \"" FMT_S_OS "\", ...) failed.\n"
  803                               "GetLastError=" FMT_U32 "\n",
  804                               os_command_stri, command_line, (uint32Type) GetLastError());
  805                        printf("ERROR_FILE_NOT_FOUND=%d\n", (int) ERROR_FILE_NOT_FOUND););
  806               FREE_RECORD(process, win_processRecord, count.process);
  807               process = NULL;
  808               err_info = FILE_ERROR;
  809             } /* if */
  810             /* printf("after CreateProcessW\n"); */
  811           } /* if */
  812         } /* if */
  813         os_stri_free(command_line);
  814       } /* if */
  815       os_stri_free(os_command_stri);
  816     } /* if */
  817     if (unlikely(err_info != OKAY_NO_ERROR)) {
  818       if (childInputRead != INVALID_HANDLE_VALUE) {
  819         CloseHandle(childInputRead);
  820       } /* if */
  821       if (childInputWrite != INVALID_HANDLE_VALUE) {
  822         CloseHandle(childInputWrite);
  823       } /* if */
  824       if (childOutputRead != INVALID_HANDLE_VALUE) {
  825         CloseHandle(childOutputRead);
  826       } /* if */
  827       if (childOutputWrite != INVALID_HANDLE_VALUE) {
  828         CloseHandle(childOutputWrite);
  829       } /* if */
  830       if (childErrorRead != INVALID_HANDLE_VALUE) {
  831         CloseHandle(childErrorRead);
  832       } /* if */
  833       if (childErrorWrite != INVALID_HANDLE_VALUE) {
  834         CloseHandle(childErrorWrite);
  835       } /* if */
  836       if (process != NULL) {
  837         FREE_RECORD(process, win_processRecord, count.process);
  838         process = NULL;
  839       } /* if */
  840       raise_error(err_info);
  841     } /* if */
  842     logFunction(printf("pcsStartPipe -> " FMT_U32 "\n",
  843                        (uint32Type) (process != NULL ? process->pid : 0)););
  844     return (processType) process;
  845   } /* pcsStartPipe */
  846 
  847 
  848 
  849 /**
  850  *  Convert a 'process' to a string.
  851  *  The process is converted to a string with the process identifier (PID).
  852  *  @return the string result of the conversion.
  853  *  @exception MEMORY_ERROR Not enough memory to represent the result.
  854  */
  855 striType pcsStr (const const_processType process)
  856 
  857   {
  858     striType result;
  859 
  860   /* pcsStr */
  861     if (process == NULL) {
  862       result = CSTRI_LITERAL_TO_STRI("NULL");
  863       if (unlikely(result == NULL)) {
  864         raise_error(MEMORY_ERROR);
  865       } /* if */
  866     } else {
  867       result = intStr((intType) to_pid(process));
  868     } /* if */
  869     return result;
  870   } /* pcsStr */
  871 
  872 
  873 
  874 /**
  875  *  Wait until the specified child process has terminated.
  876  *  Suspend the execution of the calling process until the
  877  *  specified child has terminated.
  878  */
  879 void pcsWaitFor (const processType process)
  880 
  881   {
  882     DWORD exitCode = 0;
  883 
  884   /* pcsWaitFor */
  885     logFunction(printf("pcsWaitFor(" FMT_U32 ") (hProcess=" FMT_U_MEM ")\n",
  886                        (uint32Type) (process != NULL ? to_pid(process) : 0),
  887                        process != NULL ? (memSizeType) to_hProcess(process) : (memSizeType) 0););
  888     if (!to_isTerminated(process)) {
  889       if (WaitForSingleObject(to_hProcess(process), INFINITE) == WAIT_OBJECT_0) {
  890         if (GetExitCodeProcess(to_hProcess(process), &exitCode) != 0) {
  891           to_var_isTerminated(process) = TRUE;
  892           to_var_exitValue(process) = exitCode;
  893         } else {
  894           logError(printf("pcsWaitFor: GetExitCodeProcess(" FMT_U_MEM ", *) failed:\n"
  895                           "GetLastError=" FMT_U32 "\n",
  896                           (memSizeType) to_hProcess(process), (uint32Type) GetLastError());
  897                    printf("PID=" FMT_U32 "\n", (uint32Type) to_pid(process)););
  898           raise_error(FILE_ERROR);
  899         } /* if */
  900       } else {
  901         logError(printf("pcsWaitFor: WaitForSingleObject(" FMT_U_MEM ", INFINITE) failed:\n"
  902                         "GetLastError=" FMT_U32 "\n",
  903                         (memSizeType) to_hProcess(process), (uint32Type) GetLastError());
  904                  printf("PID=" FMT_U32 "\n", (uint32Type) to_pid(process)););
  905         raise_error(FILE_ERROR);
  906       } /* if */
  907     } /* if */
  908     logFunction(printf("pcsWaitFor -->\n"););
  909   } /* pcsWaitFor */