Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (WinAPI, Konsole) » fork/dup2/execv Ersatz unter Windows gesucht

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
05.10.2005, 15:55 Uhr
virtual
Sexiest Bit alive
(Operator)


Das folgende ist ein Stück Source von mir, wie ich ihn unter UNIX verwende (ohne Fehlerbehandlung)

Was es macht, ist im Prinzip ein Programm starten, aber eben nicht nur das, sondern zwei Dateihandles aufmachen, eines um die Ausgabe des Kommandos zu lesen, und eines um die Eingabe des Kommandos zu steuern. (Ist ein alter Hut, aber für Windowser möglicherweise ein wenig unbekannt)

Frage: wie mache ich das unter Windows? CreateProcess erlaubt mir wohl nicht, die Dateihandles umzuleiten. Auf temp. Dateien oder eine DOS Box habe ich keine Lust.


C++:
int run_command(
    const char* cmd,
    char* args[],
    int in,
    int out) {

    /* Do fork */
    switch(fork()) {
    case -1:
        /* fork failed */
        return -1;

    case 0:
        /* Execute the command. */

        /* stdin umleiten */
        close(0);
        dup2(in, 0);

        /* stdout umleiten. */
        close(1);
        dup2(out, 1);

        /* Programm ausführen */
        execv(cmd, args);
        return 0;
    default:
        close(in);
        close(out);
        break;
    }
}


--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)

Dieser Post wurde am 05.10.2005 um 15:56 Uhr von virtual editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
05.10.2005, 16:01 Uhr
FloSoft
Medialer Over-Flow
(Administrator)


CreateProcess erlaubt schon die Dateihandles umzuleiten, dafür ist die STARTUPINFO struktur da, dort flags auf STARTF_USESTDHANDLES setzen und bei CreateProcess TRUE für Inherithandles.

achja bsp gibts dazu auch:


Zitat:


Platform SDK: DLLs, Processes, and Threads
Creating a Child Process with Redirected Input and Output


The example in this topic demonstrates how to create a child process from a console process. It also demonstrates a technique for using anonymous pipes to redirect the child process's standard input and output handles. Note that named pipes can also be used to redirect process I/O.


The CreatePipe function uses the SECURITY_ATTRIBUTES structure to create inheritable handles to the read and write ends of two pipes. The read end of one pipe serves as standard input for the child process, and the write end of the other pipe is the standard output for the child process. These pipe handles are specified in the SetStdHandle function, which makes them the standard handles inherited by the child process. After the child process is created, SetStdHandle is used again to restore the original standard handles for the parent process.

The parent process uses the other ends of the pipes to write to the child process's input and read the child process's output. The handles to these ends of the pipe are also inheritable. However, the handle must not be inherited. Before creating the child process, the parent process must use DuplicateHandle to create a duplicate of the application-defined hChildStdinWr global variable that cannot be inherited. It then uses CloseHandle to close the inheritable handle. For more information, see Pipes.

The following is the parent process.


C++:
#include <stdio.h>
#include <windows.h>

#define BUFSIZE 4096

HANDLE hChildStdinRd, hChildStdinWr, hChildStdinWrDup,
   hChildStdoutRd, hChildStdoutWr, hChildStdoutRdDup,
   hInputFile, hSaveStdin, hSaveStdout;

BOOL CreateChildProcess(VOID);
VOID WriteToPipe(VOID);
VOID ReadFromPipe(VOID);
VOID ErrorExit(LPTSTR);
VOID ErrMsg(LPTSTR, BOOL);

DWORD main(int argc, char *argv[])
{
   SECURITY_ATTRIBUTES saAttr;
   BOOL fSuccess;

// Set the bInheritHandle flag so pipe handles are inherited.

   saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
   saAttr.bInheritHandle = TRUE;
   saAttr.lpSecurityDescriptor = NULL;

   // The steps for redirecting child process's STDOUT:
   //     1. Save current STDOUT, to be restored later.
   //     2. Create anonymous pipe to be STDOUT for child process.
   //     3. Set STDOUT of the parent process to be write handle to
   //        the pipe, so it is inherited by the child process.
   //     4. Create a noninheritable duplicate of the read handle and
   //        close the inheritable read handle.

// Save the handle to the current STDOUT.

   hSaveStdout = GetStdHandle(STD_OUTPUT_HANDLE);

// Create a pipe for the child process's STDOUT.

   if (! CreatePipe(&hChildStdoutRd, &hChildStdoutWr, &saAttr, 0))
      ErrorExit("Stdout pipe creation failed\n");

// Set a write handle to the pipe to be STDOUT.

   if (! SetStdHandle(STD_OUTPUT_HANDLE, hChildStdoutWr))
      ErrorExit("Redirecting STDOUT failed");

// Create noninheritable read handle and close the inheritable read
// handle.

    fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdoutRd,
        GetCurrentProcess(), &hChildStdoutRdDup , 0,
        FALSE,
        DUPLICATE_SAME_ACCESS);
    if( !fSuccess )
        ErrorExit("DuplicateHandle failed");
    CloseHandle(hChildStdoutRd);

   // The steps for redirecting child process's STDIN:
   //     1.  Save current STDIN, to be restored later.
   //     2.  Create anonymous pipe to be STDIN for child process.
   //     3.  Set STDIN of the parent to be the read handle to the
   //         pipe, so it is inherited by the child process.
   //     4.  Create a noninheritable duplicate of the write handle,
   //         and close the inheritable write handle.

// Save the handle to the current STDIN.

   hSaveStdin = GetStdHandle(STD_INPUT_HANDLE);

// Create a pipe for the child process's STDIN.

   if (! CreatePipe(&hChildStdinRd, &hChildStdinWr, &saAttr, 0))
      ErrorExit("Stdin pipe creation failed\n");

// Set a read handle to the pipe to be STDIN.

   if (! SetStdHandle(STD_INPUT_HANDLE, hChildStdinRd))
      ErrorExit("Redirecting Stdin failed");

// Duplicate the write handle to the pipe so it is not inherited.

   fSuccess = DuplicateHandle(GetCurrentProcess(), hChildStdinWr,
      GetCurrentProcess(), &hChildStdinWrDup, 0,
      FALSE,                  // not inherited
      DUPLICATE_SAME_ACCESS);
   if (! fSuccess)
      ErrorExit("DuplicateHandle failed");

   CloseHandle(hChildStdinWr);

// Now create the child process.
  
   fSuccess = CreateChildProcess();
   if (! fSuccess)
      ErrorExit("Create process failed");

// After process creation, restore the saved STDIN and STDOUT.

   if (! SetStdHandle(STD_INPUT_HANDLE, hSaveStdin))
      ErrorExit("Re-redirecting Stdin failed\n");

   if (! SetStdHandle(STD_OUTPUT_HANDLE, hSaveStdout))
      ErrorExit("Re-redirecting Stdout failed\n");

// Get a handle to the parent's input file.

   if (argc > 1)
      hInputFile = CreateFile(argv[1], GENERIC_READ, 0, NULL,
         OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, NULL);
   else
      hInputFile = hSaveStdin;

   if (hInputFile == INVALID_HANDLE_VALUE)
      ErrorExit("no input file\n");

// Write to pipe that is the standard input for a child process.

   WriteToPipe();

// Read from pipe that is the standard output for child process.

   ReadFromPipe();

   return 0;
}

BOOL CreateChildProcess()
{
   PROCESS_INFORMATION piProcInfo;
   STARTUPINFO siStartInfo;
   BOOL bFuncRetn = FALSE;

// Set up members of the PROCESS_INFORMATION structure.

   ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );

// Set up members of the STARTUPINFO structure.

   ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
   siStartInfo.cb = sizeof(STARTUPINFO);

// Create the child process.
    
   bFuncRetn = CreateProcess(NULL,
      "child",       // command line
      NULL,          // process security attributes
      NULL,          // primary thread security attributes
      TRUE,          // handles are inherited
      0,             // creation flags
      NULL,          // use parent's environment
      NULL,          // use parent's current directory
      &siStartInfo,  // STARTUPINFO pointer
      &piProcInfo);  // receives PROCESS_INFORMATION
  
   if (bFuncRetn == 0) {
      ErrorExit("CreateProcess failed\n");
      return 0;
   } else {
      CloseHandle(piProcInfo.hProcess);
      CloseHandle(piProcInfo.hThread);
      return bFuncRetn;
      }
   }
}

VOID WriteToPipe(VOID)
{
   DWORD dwRead, dwWritten;
   CHAR chBuf[BUFSIZE];

// Read from a file and write its contents to a pipe.

   for (;;)
   {
      if (! ReadFile(hInputFile, chBuf, BUFSIZE, &dwRead, NULL) ||
         dwRead == 0) break;
      if (! WriteFile(hChildStdinWrDup, chBuf, dwRead,
         &dwWritten, NULL)) break;
   }

// Close the pipe handle so the child process stops reading.

   if (! CloseHandle(hChildStdinWrDup))
      ErrorExit("Close pipe failed\n");
}

VOID ReadFromPipe(VOID)
{
   DWORD dwRead, dwWritten;
   CHAR chBuf[BUFSIZE];
   HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);

// Close the write end of the pipe before reading from the
// read end of the pipe.

   if (!CloseHandle(hChildStdoutWr))
      ErrorExit("Closing handle failed");

// Read output from the child process, and write to parent's STDOUT.

   for (;;)
   {
      if( !ReadFile( hChildStdoutRdDup, chBuf, BUFSIZE, &dwRead,
         NULL) || dwRead == 0) break;
      if (! WriteFile(hSaveStdout, chBuf, dwRead, &dwWritten, NULL))
         break;
   }
}

VOID ErrorExit (LPTSTR lpszMessage)
{
   fprintf(stderr, "%s\n", lpszMessage);
   ExitProcess(0);
}



The code for the child process.


C++:
#include <windows.h>
#define BUFSIZE 4096

VOID main(VOID)
{
   CHAR chBuf[BUFSIZE];
   DWORD dwRead, dwWritten;
   HANDLE hStdin, hStdout;
   BOOL fSuccess;

   hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
   hStdin = GetStdHandle(STD_INPUT_HANDLE);
   if ((hStdout == INVALID_HANDLE_VALUE) ||
      (hStdin == INVALID_HANDLE_VALUE))
      ExitProcess(1);

   for (;;)
   {
   // Read from standard input.
      fSuccess = ReadFile(hStdin, chBuf, BUFSIZE, &dwRead, NULL);
      if (! fSuccess || dwRead == 0)
         break;

   // Write to standard output.
      fSuccess = WriteFile(hStdout, chBuf, dwRead, &dwWritten, NULL);
      if (! fSuccess)
         break;
   }
}




--
class God : public ChuckNorris { };

Dieser Post wurde am 05.10.2005 um 16:03 Uhr von FloSoft editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
05.10.2005, 16:05 Uhr
virtual
Sexiest Bit alive
(Operator)


Besten dank, ich habe das f**cking "STARTF_USESTDHANDLES" vergessen. jetzt fluppt es sogar!
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
003
05.10.2005, 16:14 Uhr
Guybrush Threepwood
Gefürchteter Pirat
(Operator)


Nur als Anmerkung:
Unter Windows gibt es _dup, _dup2 in der io.h und _execv in der process.h nur fork konnte ich in der MSDN nicht finden.
Da gibts dann aber bestimmt auch einen Ersatz ohne Winapi für...leider weiß ich nicht was es macht um danach zu gucken.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
004
05.10.2005, 16:19 Uhr
virtual
Sexiest Bit alive
(Operator)


@Guybrush
Nee fork gibt es unter Windows 100% nicht, auch keinen Ersatz dafür. Das ist ein echtes UNIX schätzchen :

fork geht hin und macht aus einen Prozess zwei. Dh fork duppliziert wirklich alles, was mit dem prozess zu tun hat (Speicher, Handles, usw.) und läßt es einfach parallel zu dem bereits existierenden Prozess weiterlaufen. die von mir gepostete Routine ist der übliche Weg, aus einem Programm ein anderes zu starten: denn execv macht unter UNIX auch was anderes als unter UNIX: Unter UNIX ersetzt execv einfach den aktuellen Prozess, unter Windows macht execv sowas wie fork und execv zusammen unter UNIX machen würden.
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
005
05.10.2005, 16:24 Uhr
Guybrush Threepwood
Gefürchteter Pirat
(Operator)



Zitat von virtual:
@Guybrush
unter Windows macht execv sowas wie fork und execv zusammen unter UNIX machen würden.

und das kannste aber trotzdem nicht nehmen?
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
006
05.10.2005, 16:29 Uhr
virtual
Sexiest Bit alive
(Operator)


Nein, CreateProcess ist schon richtig:

Ich möchte sowohl Ein- alsauch Ausgabe vom Prozess direct über Handles steuern, das leistet execv nicht (ich mache also sowas wie popen, aber eben für ein- und ausgabe gleichzeitig)
--
Gruß, virtual
Quote of the Month
Ich eß' nur was ein Gesicht hat (Creme 21)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
007
05.10.2005, 16:59 Uhr
FloSoft
Medialer Over-Flow
(Administrator)



Zitat von virtual:
Besten dank, ich habe das f**cking "STARTF_USESTDHANDLES" vergessen. jetzt fluppt es sogar!

manchmal hilfts halt doch die msdn/google zu befragen
--
class God : public ChuckNorris { };
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (WinAPI, Konsole) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: