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