redirecting stdout with WineLib

Ferenc Wagner wferi at afavant.elte.hu
Thu Mar 25 11:00:20 CST 2004


Eric Pouech <pouech-eric at wanadoo.fr> writes:

> Ferenc Wagner a écrit :
>
>> Hacking away on winetest I encountered the following
>> problem: under Windows and Wine (running cross compiled
>> binaries) it's possible to redirect the stdout of a child
>> process with CreateProcess using STARTF_USESTDHANDLES.
>> However, if I CreateProcess an .exe.so from the WineLib
>> version, the redirection is ignored.  The create_process
>> function in process.c acts on this option in both cases, but
>> I didn't investigate further.  Does anybody have an idea why
>> this happens?
>
> which winelib pgm did you used ?

winetest.  Apply the enclosed patch to get the version I
have.

> did you check that the program was actually using the
> inherited handles (thru the standard headers) and wasn't
> opening itself the handles ?

Sorry, I don't understand this.  What headers do you mean?

> (btw kernel/tests/process.c just implemnents what you
> describe (on a winelib app - the test app itself) and
> works just fine here, the inherited handle being a pipe)

Then I may be misusing the pipe api.  I would be grateful if
you had a look at the patched program and point out my
mistakes.  Meanwhile I check out the process test program.

(The Makefile.in patch is simply for faster compilation.
Half of the rest has already been submitted but not
committed.)

Feri.

Index: Makefile.in
===================================================================
RCS file: /home/wine/wine/programs/winetest/Makefile.in,v
retrieving revision 1.24
diff -u -r1.24 Makefile.in
--- Makefile.in	24 Mar 2004 23:40:06 -0000	1.24
+++ Makefile.in	25 Mar 2004 16:48:20 -0000
@@ -20,22 +20,22 @@
 
 TESTS = \
 	advapi32 \
-	comctl32 \
-	gdi32 \
-	kernel32 \
-	msvcrt \
-	netapi32 \
-	ntdll \
-	oleaut32 \
-	rpcrt4 \
-	shell32 \
-	shlwapi \
-	urlmon \
-	user32 \
-	wininet \
-	winmm \
-	winspool.drv \
-	ws2_32
+	comctl32
+#	gdi32 \
+#	kernel32 \
+#	msvcrt \
+#	netapi32 \
+#	ntdll \
+#	oleaut32 \
+#	rpcrt4 \
+#	shell32 \
+#	shlwapi \
+#	urlmon \
+#	user32 \
+#	wininet \
+#	winmm \
+#	winspool.drv \
+#	ws2_32
 
 @MAKE_PROG_RULES@
 
Index: main.c
===================================================================
RCS file: /home/wine/wine/programs/winetest/main.c,v
retrieving revision 1.8
diff -u -r1.8 main.c
--- main.c	24 Mar 2004 23:40:06 -0000	1.8
+++ main.c	25 Mar 2004 16:48:20 -0000
@@ -56,7 +56,7 @@
 };
 
 static struct wine_test *wine_tests;
-static struct rev_info *rev_infos;
+static struct rev_info *rev_infos = NULL;
 
 static const char *wineloader;
 
@@ -226,44 +226,68 @@
                                test->exename);
 }
 
+HANDLE
+my_popen (char *cmd)
+{
+    HANDLE pipeRead, pipeWrite;
+    SECURITY_ATTRIBUTES sa;
+    STARTUPINFO si;
+    PROCESS_INFORMATION pi;
+
+    sa.nLength = sizeof sa;
+    sa.lpSecurityDescriptor = NULL;
+    sa.bInheritHandle = TRUE;
+    if (!CreatePipe (&pipeRead, &pipeWrite, &sa, 0))
+        report (R_FATAL, "Can't create pipe: %d", GetLastError ());
+
+    GetStartupInfo (&si);
+    si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
+    si.wShowWindow = SW_HIDE;
+    si.hStdOutput = pipeWrite;
+    if (!CreateProcess (NULL, cmd, NULL, NULL, TRUE, 0,
+                        NULL, NULL, &si, &pi))
+        report (R_FATAL, "Can't execute '%s': %d", cmd, GetLastError ());
+    CloseHandle (pi.hThread);
+    CloseHandle (pi.hProcess);
+    CloseHandle (pipeWrite);
+    return pipeRead;
+}
+
 void
 get_subtests (const char *tempdir, struct wine_test *test, int id)
 {
-    char *subname;
-    FILE *subfile;
-    size_t subsize, bytes_read, total;
-    char *buffer, *index;
+    size_t total;
+    char buffer[8192], *index;
     const char header[] = "Valid test names:", seps[] = " \r\n";
-    int oldstdout;
-    const char *argv[] = {"wine", NULL, NULL};
     int allocated;
 
-    subname = tempnam (0, "sub");
-    if (!subname) report (R_FATAL, "Can't name subtests file.");
-    oldstdout = dup (1);
-    if (-1 == oldstdout) report (R_FATAL, "Can't preserve stdout.");
-    subfile = fopen (subname, "w+b");
-    if (!subfile) report (R_FATAL, "Can't open subtests file.");
-    if (-1 == dup2 (fileno (subfile), 1))
-        report (R_FATAL, "Can't redirect output to subtests.");
-    fclose (subfile);
+    HANDLE pipe;
+    DWORD bytes_read;
+
+    test->subtest_count = 0;
 
     extract_test (test, tempdir, id);
-    argv[1] = test->exename;
-    if (test->is_elf)
-        spawnvp (_P_WAIT, wineloader, argv);
-    else
-        spawnvp (_P_WAIT, test->exename, argv+1);
-    subsize = lseek (1, 0, SEEK_CUR);
-    buffer = xmalloc (subsize+1);
+    pipe = my_popen (test->exename);
 
-    lseek (1, 0, SEEK_SET);
     total = 0;
-    while ((bytes_read = read (1, buffer + total, subsize - total))
-               && (signed)bytes_read != -1)
-            total += bytes_read;
-    if (bytes_read)
-        report (R_FATAL, "Can't get subtests of %s", test->name);
+    while (ReadFile (pipe, buffer+total, sizeof buffer-1-total,
+                     &bytes_read, NULL)) {
+        if (bytes_read == 0) {  /* FIXME for Wine */
+            SetLastError (ERROR_BROKEN_PIPE);
+            break;
+        }
+        total += bytes_read;
+        if (total >= sizeof buffer-1) {
+            report (R_ERROR, "Subtest list of %s is bigger than %d bytes",
+                    test->name, sizeof buffer);
+            return;
+        }
+    }
+    if (GetLastError () != ERROR_BROKEN_PIPE)
+        report (R_FATAL, "Can't get subtests of %s: %d",
+                      test->name, GetLastError ());
+    CloseHandle (pipe);
+
     buffer[total] = 0;
     index = strstr (buffer, header);
     if (!index)
@@ -273,7 +297,6 @@
 
     allocated = 10;
     test->subtests = xmalloc (allocated * sizeof(char*));
-    test->subtest_count = 0;
     index = strtok (index, seps);
     while (index) {
         if (test->subtest_count == allocated) {
@@ -287,13 +310,7 @@
     test->subtests = xrealloc (test->subtests,
                                test->subtest_count * sizeof(char*));
     free (buffer);
-    close (1);
-    if (-1 == dup2 (oldstdout, 1))
-        report (R_FATAL, "Can't recover old stdout.");
-    close (oldstdout);
-    if (remove (subname))
-        report (R_FATAL, "Can't remove subtests file.");
-    free (subname);
+
 }
 
 /* Return number of failures, -1 if couldn't spawn process. */
@@ -335,8 +352,6 @@
     SetErrorMode (SEM_FAILCRITICALERRORS);
 
     if (!(wineloader = getenv("WINELOADER"))) wineloader = "wine";
-    if (setvbuf (stdout, NULL, _IONBF, 0))
-        report (R_FATAL, "Can't unbuffer output.");
 
     tempdir = tempnam (0, "wct");
     if (!tempdir)
Index: util.c
===================================================================
RCS file: /home/wine/wine/programs/winetest/util.c,v
retrieving revision 1.4
diff -u -r1.4 util.c
--- util.c	19 Mar 2004 19:15:23 -0000	1.4
+++ util.c	25 Mar 2004 16:48:20 -0000
@@ -19,6 +19,7 @@
  *
  */
 #include <windows.h>
+#include <unistd.h>
 #include <errno.h>
 
 #include "winetest.h"
@@ -39,26 +40,14 @@
     return p;
 }
 
-void xprintf (const char *fmt, ...)
-{
-    va_list ap;
-
-    va_start (ap, fmt);
-    if (vprintf (fmt, ap) < 0)
-        report (R_FATAL, "Can't write logs: %d", errno);
-    va_end (ap);
-}
-
-char *vstrmake (size_t *lenp, va_list ap)
+char *vstrfmtmake (size_t *lenp, const char *fmt, va_list ap)
 {
-    char *fmt;
     size_t size = 1000;
     char *p, *q;
     int n;
 
     p = malloc (size);
     if (!p) return NULL;
-    fmt = va_arg (ap, char*);
     while (1) {
         n = vsnprintf (p, size, fmt, ap);
         if (n < 0) size *= 2;   /* Windows */
@@ -75,6 +64,14 @@
     return p;
 }
 
+char *vstrmake (size_t *lenp, va_list ap)
+{
+    const char *fmt;
+
+    fmt = va_arg (ap, const char*);
+    return vstrfmtmake (lenp, fmt, ap);
+}
+
 char *strmake (size_t *lenp, ...)
 {
     va_list ap;
@@ -85,6 +82,26 @@
     if (!p) report (R_FATAL, "Out of memory.");
     va_end (ap);
     return p;
+}
+
+void xprintf (const char *fmt, ...)
+{
+    va_list ap;
+    size_t size;
+    ssize_t written;
+    char *buffer, *head;
+
+    va_start (ap, fmt);
+    buffer = vstrfmtmake (&size, fmt, ap);
+    head = buffer;
+    va_end (ap);
+    while ((written = write (1, head, size)) < size) {
+        if (written == -1)
+            report (R_FATAL, "Can't write logs: %d", errno);
+        head += written;
+        size -= written;
+    }
+    free (buffer);
 }
 
 char *




More information about the wine-devel mailing list