[Bug 5541] WriteConsole can't write to stdout; affects e.g. wsh's cscript' s usage message

wine-bugs at winehq.org wine-bugs at winehq.org
Thu Jan 24 14:31:48 CST 2008


http://bugs.winehq.org/show_bug.cgi?id=5541


Anastasius Focht <focht at gmx.net> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |focht at gmx.net




--- Comment #13 from Anastasius Focht <focht at gmx.net>  2008-01-24 14:31:46 ---
Hello,

I took a quick glance at this ...

cscript.exe is subsystem "windows console" (flags value 3).

Relevant trace:

--- snip trace ---
..
0009:Call KERNEL32.GetStdHandle(fffffff5) ret=0100261a
0009:Ret  KERNEL32.GetStdHandle() retval=00000008 ret=0100261a 
..
0009:Call KERNEL32.GetFileType(00000008) ret=01002112
0009:Ret  KERNEL32.GetFileType() retval=00000001 ret=01002112 
..
--- snip trace ---

When writing to output, cscript basically does this (pseudo code):

--- snip pseudo code ---
if( GetFileType( GetStdHandle(STD_OUTPUT_HANDLE)) == FILE_TYPE_CHAR)
{
    WriteConsole( ...)
}
else
{
    WriteFile( ...)
}
--- snip pseudo code ---

Because wine doesn't return FILE_TYPE_CHAR for std handles (returns
FILE_TYPE_DISK), WriteConsole is not used.
Let's have a look at wine code.

--- snip dlls/kernel32/environ.c ---
HANDLE WINAPI GetStdHandle( DWORD std_handle )
{
    switch (std_handle)
    {
        case STD_INPUT_HANDLE:  return
NtCurrentTeb()->Peb->ProcessParameters->hStdInput;
        case STD_OUTPUT_HANDLE: return
NtCurrentTeb()->Peb->ProcessParameters->hStdOutput;
...
}
--- snip dlls/kernel32/environ.c ---

STD_OUTPUT_HANDLE is just straight from
"NtCurrentTeb()->Peb->ProcessParameters->hStdOutput" (setup at process init)

--- snip dlls/kernel32/file.c ---
DWORD WINAPI GetFileType( HANDLE hFile )
{
    FILE_FS_DEVICE_INFORMATION info;
    IO_STATUS_BLOCK io;
    NTSTATUS status;

    if (is_console_handle( hFile )) return FILE_TYPE_CHAR;
...
--- snip dlls/kernel32/file.c ---

and

--- snip dlls/kernel32/kernel32_private.h ---
static inline BOOL is_console_handle(HANDLE h)
{
    return h != INVALID_HANDLE_VALUE && ((UINT_PTR)h & 3) == 3;
}
--- snip dlls/kernel32/kernel32_private.h ---

Ok, wine win32 style console handles have bit 0,1 set.
When converting from/to real wine server handles these bits are
set/unset/tested.

Let's have a look what happens at process init:

--- snip dlls/kernel32/kernel_main.c --- 
static BOOL process_attach( HMODULE module )
{ 
..
    RTL_USER_PROCESS_PARAMETERS *params =
NtCurrentTeb()->Peb->ProcessParameters;
..
    /* convert value from server:
     * + 0 => INVALID_HANDLE_VALUE
     * + console handle needs to be mapped
     */
    if (!params->hStdInput)
        params->hStdInput = INVALID_HANDLE_VALUE;
    else if (VerifyConsoleIoHandle(console_handle_map(params->hStdInput)))
        params->hStdInput = console_handle_map(params->hStdInput);

    if (!params->hStdOutput)
        params->hStdOutput = INVALID_HANDLE_VALUE;
    else if (VerifyConsoleIoHandle(console_handle_map(params->hStdOutput)))
        params->hStdOutput = console_handle_map(params->hStdOutput);

    if (!params->hStdError)
        params->hStdError = INVALID_HANDLE_VALUE;
    else if (VerifyConsoleIoHandle(console_handle_map(params->hStdError)))
        params->hStdError = console_handle_map(params->hStdError);

    /* copy process information from ntdll */
    ENV_CopyStartupInformation(); 
..
    if (params->ConsoleHandle == (HANDLE)1)  /* FIXME */
    {
        HMODULE mod = GetModuleHandleA(0);
        if (RtlImageNtHeader(mod)->OptionalHeader.Subsystem ==
IMAGE_SUBSYSTEM_WINDOWS_CUI)
            AllocConsole();
    }
    /* else TODO for DETACHED_PROCESS:
     * 1/ inherit console + handles
     * 2/ create std handles, if handles are not inherited
     * TBD when not using wineserver handles for console handles
     */
..
--- snip dlls/kernel32/kernel_main.c --- 

And a bit of server trace for proof:

--- snip server trace ---
..
000d: get_startup_info( )
000d: get_startup_info() = 0 { exe_file=(nil), hstdin=0x4, hstdout=0x8,
hstderr=0xc,
info={AllocationSize=1000,Size=66a,Flags=0,DebugFlags=0,ConsoleHandle=(nil),ConsoleFlags=0
..
000d: get_console_mode( handle=0x4 )
000d: get_console_mode() = OBJECT_TYPE_MISMATCH { mode=0 }
000d: get_console_mode( handle=0x8 )
000d: get_console_mode() = OBJECT_TYPE_MISMATCH { mode=0 }
000d: get_console_mode( handle=0xc )
000d: get_console_mode() = ACCESS_DENIED { mode=0 } 
..
--- snip server trace ---

hstdin=0x4, hstdout=0x8, hstderr=0xc

When the process environment/startup info is initialized, the wine server
handles are not associated with any console i/o ops yet (see server
get_console_mode and alloc_console).
Hence "VerifyConsoleIoHandle(console_handle_map(params->hStdOutput))" returns
FALSE and std handles are not converted into their "win32" console handle
counterparts (bits 0,1 set).

Explicit console allocation only occurs if the (child) process was created with
CREATE_NEW_CONSOLE (see that params->ConsoleHandle == (HANDLE)1 FIXME).

The case of a IMAGE_SUBSYSTEM_WINDOWS_CUI process, manually started from shell
requiring win32 style console i/o handles needs to be handled.

Regards


-- 
Configure bugmail: http://bugs.winehq.org/userprefs.cgi?tab=email
Do not reply to this email, post in Bugzilla using the
above URL to reply.
------- You are receiving this mail because: -------
You are watching all bug changes.



More information about the wine-bugs mailing list