Eryk Sun added the comment:

> An .lnk is launched with ShellExecute which returns control
> immediately upon successful launch

cmd calls ShellExecuteEx, not ShellExecute, and it uses the flags 
SEE_MASK_NO_CONSOLE (0x8000, don't create a new console) and 
SEE_MASK_NOCLOSEPROCESS (0x0040, return a process handle if possible). 

Here's a walk-through with a debugger attached to cmd while executing a LNK 
shortcut to "C:\Program Files\Python27\python.exe": 

    C:\Temp>.\python.lnk -c "import sys,time;time.sleep(60);sys.exit(42)"
    Breakpoint 0 hit
    SHELL32!ShellExecuteExW:
    00007ff9`a5710e20 48895c2408      mov     qword ptr [rsp+8],rbx
                                        ss:000000a3`eb3af3a0=000000a3eb597ca0
    0:000> ; as /x info @rcx
    0:000> ; as /x sz @@(*((unsigned long *)${info}))
    0:000> bd 2,3,4; pt; be 2,3,4

ShellExecuteEx returns the process handle:

    0:000> ?? *((void **)(${info} + ${sz} - 8)); * hProcess
    void * 0x00000000`000002fc
    0:000> !handle 2fc
    Handle 2fc
      Type          Process
    0:000> g

cmd uses the handle to read the ImageSubsystem type from the process 
environment block (PEB), for which 3 is a console process and 2 is a GUI 
process.

    Breakpoint 1 hit
    cmd!GetProcessSubsystemType:
    00007ff7`a133faf4 48895c2410      mov     qword ptr [rsp+10h],rbx
                                        ss:000000a3`eb3af458=000000a3eb585640
    0:000> g
    Breakpoint 2 hit
    KERNELBASE!ReadProcessMemory:
    00007ff9`a49ac230 4883ec48        sub     rsp,48h
    0:000> as /x buf @r8
    0:000> pt
    KERNELBASE!ReadProcessMemory+0x2b:
    00007ff9`a49ac25b c3              ret

    0:000> ?? ((ntdll!_PEB *)${buf})->ImageSubsystem
    unsigned long 3
    0:000> g

Since it's a console process, cmd waits and queries the exit code.

    Breakpoint 3 hit    
    KERNELBASE!WaitForSingleObject:
    00007ff9`a49840c0 4533c0          xor     r8d,r8d
    0:000> r rcx
    rcx=00000000000002fc
    0:000> g

    Breakpoint 4 hit
    KERNELBASE!GetExitCodeProcess:
    00007ff9`a49c46d0 4053            push    rbx
    0:000> as /x rc @rdx
    0:000> pt
    KERNELBASE!GetExitCodeProcess+0x3a:
    00007ff9`a49c470a c3              ret
    0:000> ?? *((unsigned long *)${rc})
    unsigned long 0x2a
    0:000> ? 0x2a
    Evaluate expression: 42 = 00000000`0000002a

It sets the exit code in the 'hidden' environment variable "=ExitCode" as a 
unsigned hexadecimal number.

    C:\Temp>echo %=ExitCode%
    0000002A

You can also query the signed value using the pseudo environment variable 
"errorlevel".

    C:\Temp>echo %errorlevel%
    42

----------

_______________________________________
Python tracker <rep...@bugs.python.org>
<http://bugs.python.org/issue26189>
_______________________________________
_______________________________________________
Python-bugs-list mailing list
Unsubscribe: 
https://mail.python.org/mailman/options/python-bugs-list/archive%40mail-archive.com

Reply via email to