Hello,
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?
Ferenc Wagner a écrit :
Hello,
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 ? did you check that the program was actually using the inherited handles (thru the standard headers) and wasn't opening itself the handles ? (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) A+
Eric Pouech pouech-eric@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 *
Ferenc Wagner wferi@afavant.elte.hu writes:
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?
The Windows std handles get redirected but not the Unix ones, so if the Winelib app is using Unix stdio functions the redirection won't have any effect.
Alexandre Julliard julliard@winehq.org writes:
Ferenc Wagner wferi@afavant.elte.hu writes:
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?
The Windows std handles get redirected but not the Unix ones, so if the Winelib app is using Unix stdio functions the redirection won't have any effect.
Unfortunately this is exactly what the ok() and trace() macros do in the tests. In the light of this I'm surprised that the cross compiled binaries work under Wine. Is there a fundamental reason that it can't work under WineLib, or is it a simple lack of code? If the latter, what is missing?
Ferenc Wagner wferi@afavant.elte.hu writes:
Unfortunately this is exactly what the ok() and trace() macros do in the tests. In the light of this I'm surprised that the cross compiled binaries work under Wine. Is there a fundamental reason that it can't work under WineLib, or is it a simple lack of code? If the latter, what is missing?
Cross-compiled binaries use msvcrt so they don't have that problem. What's missing is to allow reading/writing to a Windows console through a Unix fd; it's not exactly trivial to do.
Alexandre Julliard wrote:
Ferenc Wagner wferi@afavant.elte.hu writes:
Unfortunately this is exactly what the ok() and trace() macros do in the tests. In the light of this I'm surprised that the cross compiled binaries work under Wine. Is there a fundamental reason that it can't work under WineLib, or is it a simple lack of code? If the latter, what is missing?
Cross-compiled binaries use msvcrt so they don't have that problem. What's missing is to allow reading/writing to a Windows console through a Unix fd; it's not exactly trivial to do.
Won't linking the Winelib-test against msvcrt solve this problem? I have my winelib App's printf redirected and it works ok. I even run it under Visual-MinGW a native app. (it is a part of the make)
And Now I understand why Linux-gmake did not work under Visual-MinGW. This is a pity. It could be nice if Windows and Linux could interchange through stdin/stdout. (actually maybe it didn't work for another reason)
Free Life Boaz
On Thu, 25 Mar 2004, Alexandre Julliard wrote:
The Windows std handles get redirected but not the Unix ones, so if the Winelib app is using Unix stdio functions the redirection won't have any effect.
Too bad -- having the Windows std handles tied to the Unix ones would be rather useful for console apps.