Einzelnen Beitrag anzeigen
Alt 31.08.2014, 22:29   #4
leecher
Moderator
#unhide (This post can be viewed by guests also)

Hallo !

Ich hab mir das Problem jetzt doch mal näher angesehen und einen Patch dafür gemacht, nachdem M$ leider noch immer säumig ist.
Nachdem er nicht nur deutschsprachige OA-Benutzer interessieren könnte, habe ich meine Erklärungen dafür auf Englisch geschrieben...

Analysis and fix for the fullscreen switching bug in Windows 7
================================================== ============

You may already know that ALT+Enter is a commonly used hotkey to switch
application between window mode and full-screen mode. For the cmd prompt,
the hotkey should work as expected on prior windows OS up to windows XP
and for example enters real Text mode for DOS applications.
But for Windows Vista and Windows 7, cmd can't be switched to
full-screen mode, this is by design.
For further information see http://support.microsoft.com/kb/926657
There is a very interesting article explaining the rasons behind this,
which I recommend you to read:
http://colinxu.wordpress.com/2011/02...ssue-analysis/

Now it's also known and explained in the KB-Article, that you can get
back fullscreen with either a WDM-driver for the Windows XP display driver
model or to switch back to the default VGA video driver, which still
supports the old driver model.
This works, but there are some issues that users experienced, most notably
a bug in the Full screen switching code that causes a NTVDM lockup which I
will cover in this article.

How to enable Fullscreen for your DOS apps
==========================================
But first, how to conveniently use DOS Fullscreen applications without the
need to be stuck with the VGA driver all the time?
The preferred method is to install the XPDM display driver for your graphics
board, but if this doesn't work, I also have a very convenient solution.
So each approach is described here:

Installing the XPDM driver for your video card
-------------------------------------------
First, check if there is a Windows XP videp driver available for your graphics
board. You need to have the driver installation (.inf) files available, so
it won't help to just have an .exe Installer, because most likely this
installer checks for the OS version and refuses to run on Windows 7.
So in case you just get an .exe, you first need to extract the .inf
and .sys files from it, i.e. via 7-zip. Here is a thread describing how to
extract Intel video drivers for instance:
https://communities.intel.com/thread/12591
After you have the .inf files, you need to check if they contain a section
for Windows 7 or if the refuse to run there.
Intel Video drivers i.e. have this section:

Code:
[IntelGfx.NTx86.6.0]
; no install on Vista/Win7

[IntelGfx.NTx86.6.2]
; no install on Win8

[IntelGfx.NTx86.5.1]
%iSNBGM1%  = iSNBM0, PCI\VEN_8086&DEV_0106
%iSNBGD1%  = iSNBD0, PCI\VEN_8086&DEV_0102
%iSNBGM2%  = iSNBM0, PCI\VEN_8086&DEV_0116
%iSNBGD2%  = iSNBD0, PCI\VEN_8086&DEV_0112
%iSNBGM2P%  = iSNBM0, PCI\VEN_8086&DEV_0126
%iSNBGD2P% = iSNBD0, PCI\VEN_8086&DEV_0122
%iSNBGD3%  = iSNBD0, PCI\VEN_8086&DEV_010A
%iIVBGD0%       = iIVBD0, PCI\VEN_8086&DEV_0162
%iIVBGM0%       = iIVBM0, PCI\VEN_8086&DEV_0166
%iIVBGD0SRV%    = iIVBD0, PCI\VEN_8086&DEV_016A
%iIVBGD0GT1%    = iIVBD0, PCI\VEN_8086&DEV_0152
%iIVBGM0GT1%    = iIVBM0, PCI\VEN_8086&DEV_0156
%iIVBGD0SRVGT1% = iIVBD0, PCI\VEN_8086&DEV_015A
As you can see, there is a section for Win7 (IntelGfx.NTx86.6.0), but
it doesn't contain any entries. So simply copy all the PCI strings
from Windows XP section (IntelGfx.NTx86.5.1) to this section
(just place the entries right under [IntelGfx.NTx86.6.0] line.

After fixing the .inf file, go to the Devie manager, uninstall the
WDDM driver and update the driver to the XPDM driver by pointing
the installation source to the diectory you have your .inf file in.
If everything works, it will detect and install the XP driver and if
you have luck, you are then running the XP driver which supports
fullscreen.
If you fail or are unabe to do this, please consider the following
option instead:

Using Fullsreen by dynamically switching between VGA and WDDM
---------------------------------------------------------------
Note: This is just meant for users that don't have a Windows XP Display
driver available for their Video card, using the XP Video driver is still the
preferred method as it saves you don't need to switch between the
video modes as described here. However the XPDM display driver may
have performance issues, so you can decide which works better for
you.
In Windows 7, you can dynamically enable and disable the video driver
without reboot, which is great because this way, you can also script this
and therefore make a batchfile, which disables your current WDM video
driver so that you have the standard VGA XPDM video driver, then
switch to fullscreen, use your DOS app and after you are done
restore the WDM video driver with devcon.
I made a patch that automates this for you which can be found here

Otherwise here is how to do it:
* Download devcon [http://support.microsoft.com/kb/311272] and place
it in your application directory, i.e. C:\OA4
* Put my Fullscreen switch utility (fullscr) attached below into your application directory.
* Now create a batchfile to start your application, i.e. STARTOA4.bat with
the following content:

------------------------------------------------------------------------------
Code:
@echo off
c:
cd \oa4
setlocal enableDelayedExpansion
for /f "tokens=1 skip=1 delims=:" %%I in ('devcon listclass display') do set J=%%I && devcon disable "!J:~0,44!"

fullscr
oa4.exe

fullscr 2
for /f "tokens=1 skip=1 delims=:" %%I in ('devcon listclass display') do set J=%%I && devcon enable "!J:~0,44!"
endlocal
------------------------------------------------------------------------------
You obviously have to adapt OA4.EXE to the application file for your application
to start (i.e. you may have a batch file to start, then use "call mybat.bat"
so that the startoa.bat isn't quit) and the "cd" at the beginning to go to your
application's directory. This is
necessary, as all Batch files that are run as admin via a link start in
%SystemRoot%, so you have to go to your dir first.

* Now as devcon is messing around with the system hardware, it needs
Administration rights to do its task.
So you now should create a shortcut to STARTOA4.BAT, i.e. on your desktop
and in its properties under "Advanced..." select [x] Run as administrator.

Done, now everytime you click your shortcut, video mode is switched to standard
VGA, then your DOS APP is run in fullscreen and
after exit, VGA card driver is restored back by enabling it. The fullscr 2 command does a switch back to windowed mode [fullscr.exe was updated on 2016/10/13 to support this], as some WDDM video drivers crash when switching back from textmode directly when reenabling.
I hope it works for you.
Don't forget to change the video resolution when in Standard VGA mode to
your normal resolution, as it's usually impractical to be stuck at 640x480
and even the Standard VGA driver normally supports higher resolutions,
but default is 640x480 when you disable your WDDM Display driver for
the first time.
As you now have the possibility to run your application in full screen text
mode, now let's go for the bugs that you are facing.

The Fullscreen NTVDM Bug
========================

Just try the following to reproduce it:
Just run your favourite DOS program in full screen mode, either by using
the trick mentioned above or by generally running in Standard VGA mode
and editing the settings of your favourite DOS program to switch it to Full screen
(Properties of .EXE -> Screen -> change from Windowed to Full screen) so that
it starts in full screen mode. Also ensure that you enabled the possibility to
capture ALT+Tab for switch (default). When the DOS App starts in Full-screen,
try to switch away with ALT+TAB and boom, your machine keeps hangig for almost
a Minute, afterwars you are back in the GUI mode and have a message box telling
you "NTVDM has encountered a system error. The parameter is incorrect".
This is especially naughty combined with the bug that the guy in the blog
mentioned above found. Once you switched to VGA and back to the driver,
Fullscreen is not blocked and therefore you also get into this lockup trouble,
once you notice that the mode switch went wrong and you want to go back
(i.e. by pressing ALT+RETURN again).
So that's pretty annoying, of course, so time to debug this issue.

It's not easy to find, as you can't have your debugger open while in full
screen, so I attached the WinDbg kernel debugger to the COM port and tried
to debug a usermode application with it.
Let's see where it hangs in ntvdm:

Code:
1: kd> !process 0 0 ntvdm.exe
PROCESS 84171460  SessionId: 1  Cid: 0f04    Peb: 7ffd6000  ParentCid: 0968
    DirBase: 3ed32500  ObjectTable: 8633df00  HandleCount:  60.
    Image: ntvdm.exe

1: kd> .process /r /p 84171460  
Implicit process is now 84171460
.cache forcedecodeuser done
Loading User Symbols
..........................
1: kd> !process 84171460  
PROCESS 84171460  SessionId: 1  Cid: 0f04    Peb: 7ffd6000  ParentCid: 0968
    DirBase: 3ed32500  ObjectTable: 8633df00  HandleCount:  60.
    Image: ntvdm.exe
    VadRoot 85d8ee60 Vads 66 Clone 0 Private 285. Modified 53. Locked 0.
    DeviceMap 8a275650
    Token                             9f245ac8
    ElapsedTime                       00:00:07.140
    UserTime                          00:00:00.000
    KernelTime                        00:00:00.000
    QuotaPoolUsage[PagedPool]         0
    QuotaPoolUsage[NonPagedPool]      0
    Working Set Sizes (now,min,max)  (1010, 50, 345) (4040KB, 200KB, 1380KB)
    PeakWorkingSetSize                1010
    VirtualSize                       56 Mb
    PeakVirtualSize                   56 Mb
    PageFaultCount                    1153
    MemoryPriority                    BACKGROUND
    BasePriority                      8
    CommitCharge                      644

        THREAD 84dd25e0  Cid 0f04.07ac  Teb: 7ffdf000 Win32Thread: fe50add8 WAIT: (UserRequest) UserMode Non-Alertable
            841180e8  NotificationEvent
        Not impersonating
        DeviceMap                 8a275650
        Owning Process            0       Image:         <Unknown>
        Attached Process          84171460       Image:         ntvdm.exe
        Wait Start TickCount      3571787        Ticks: 257 (0:00:00:04.015)
        Context Switch Count      225             
        UserTime                  00:00:00.187
        KernelTime                00:00:00.437
        Win32 Start Address ntvdm!EntryPoint (0x0e2e5095)
        Stack Init 8a5c5fd0 Current 8a5c5bc8 Base 8a5c6000 Limit 8a5c3000 Call 0
        Priority 10 BasePriority 8 PriorityDecrement 2 IoPriority 2 PagePriority 5
        ChildEBP RetAddr  
        8a5c5be0 82687b15 nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4])
        8a5c5c18 82686403 nt!KiSwapThread+0x266
        8a5c5c40 826802cf nt!KiCommitThreadWait+0x1df
        8a5c5cb8 8284a515 nt!KeWaitForSingleObject+0x393
        8a5c5d20 8265c42a nt!NtWaitForSingleObject+0xc6
        8a5c5d20 76e564f4 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 8a5c5d34)
        0122f9d8 76e55e6c ntdll!KiFastSystemCallRet (FPO: [0,0,0])
        0122f9dc 7502179c ntdll!NtWaitForSingleObject+0xc (FPO: [3,0,0])
        0122fa48 752ef003 KERNELBASE!WaitForSingleObjectEx+0x98 (FPO: [SEH])
        0122fa60 752eefb2 kernel32!WaitForSingleObjectExImplementation+0x75 (FPO: [3,0,4])
        0122fa74 0e323125 kernel32!WaitForSingleObject+0x12 (FPO: [2,0,0])
        0122fa8c 0e32321c ntvdm!CheckScreenSwitchRequest+0x2f (FPO: [1,0,0])
        0122faa8 0e2e53e4 ntvdm!cpu_simulate+0xd4 (FPO: [0,1,4])
        0122fab4 0e2e535f ntvdm!host_main+0x5f (FPO: [2,0,4])
        0122faf0 0e2e559c ntvdm!main+0x3a (FPO: [SEH])
        0122fbd0 752f1174 ntvdm!host_main+0x217 (FPO: [SEH])
        0122fbdc 76e6b3f5 kernel32!BaseThreadInitThunk+0xe (FPO: [1,0,0])
        0122fc1c 76e6b3c8 ntdll!__RtlUserThreadStart+0x70 (FPO: [SEH])
        0122fc34 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [2,2,0])

        THREAD 840f78f0  Cid 0f04.0268  Teb: 7ffde000 Win32Thread: fe4e1008 WAIT: (UserRequest) UserMode Alertable
            841180e8  NotificationEvent
        Not impersonating
        DeviceMap                 8a275650
        Owning Process            0       Image:         <Unknown>
        Attached Process          84171460       Image:         ntvdm.exe
        Wait Start TickCount      3571786        Ticks: 258 (0:00:00:04.031)
        Context Switch Count      16             
        UserTime                  00:00:00.000
        KernelTime                00:00:00.000
        Win32 Start Address ntvdm!ConsoleEventThread (0x0e317abb)
        Stack Init 8a5e1fd0 Current 8a5e1bc8 Base 8a5e2000 Limit 8a5df000 Call 0
        Priority 13 BasePriority 10 PriorityDecrement 2 IoPriority 2 PagePriority 5
        ChildEBP RetAddr  
        8a5e1be0 82687b15 nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4])
        8a5e1c18 82686403 nt!KiSwapThread+0x266
        8a5e1c40 826802cf nt!KiCommitThreadWait+0x1df
        8a5e1cb8 8284a515 nt!KeWaitForSingleObject+0x393
        8a5e1d20 8265c42a nt!NtWaitForSingleObject+0xc6
        8a5e1d20 76e564f4 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 8a5e1d34)
        0238fca0 76e55e6c ntdll!KiFastSystemCallRet (FPO: [0,0,0])
        0238fca4 0e3164eb ntdll!NtWaitForSingleObject+0xc (FPO: [3,0,0])
        0238fcb4 0e317a38 ntvdm!nt_process_suspend_event+0x1b (FPO: [0,0,0])
        0238fd44 0e317b01 ntvdm!nt_event_loop+0x1a1 (FPO: [0,31,4])
        0238fd78 752f1174 ntvdm!ConsoleEventThread+0x46 (FPO: [SEH])
        0238fd84 76e6b3f5 kernel32!BaseThreadInitThunk+0xe (FPO: [1,0,0])
        0238fdc4 76e6b3c8 ntdll!__RtlUserThreadStart+0x70 (FPO: [SEH])
        0238fddc 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [2,2,0])

        THREAD 83fb9d48  Cid 0f04.0ff4  Teb: 7ffdd000 Win32Thread: 00000000 WAIT: (WrLpcReply) UserMode Non-Alertable
            83fb9f7c  Semaphore Limit 0x1
        Waiting for reply to ALPC Message 9ef6f548 : queued at port 840941d8 : owned by process 84101200
        Not impersonating
        DeviceMap                 8a275650
        Owning Process            0       Image:         <Unknown>
        Attached Process          84171460       Image:         ntvdm.exe
        Wait Start TickCount      3571791        Ticks: 253 (0:00:00:03.953)
        Context Switch Count      52             
        UserTime                  00:00:00.015
        KernelTime                00:00:00.000
        Win32 Start Address ntvdm!HeartBeatThread (0x0e309a56)
        Stack Init 8a633fd0 Current 8a633ad0 Base 8a634000 Limit 8a631000 Call 0
        Priority 15 BasePriority 15 PriorityDecrement 0 IoPriority 2 PagePriority 5
        ChildEBP RetAddr  
        8a633ae8 82687b15 nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4])
        8a633b20 82686403 nt!KiSwapThread+0x266
        8a633b48 826802cf nt!KiCommitThreadWait+0x1df
        8a633bc0 826cfb66 nt!KeWaitForSingleObject+0x393
        8a633be8 8288ebee nt!AlpcpSignalAndWait+0x7b
        8a633c0c 82884c6f nt!AlpcpReceiveSynchronousReply+0x27
        8a633c9c 828782ca nt!AlpcpProcessSynchronousRequest+0x276
        8a633cf8 8288fb17 nt!LpcpRequestWaitReplyPort+0x6a
        8a633d20 8265c42a nt!NtRequestWaitReplyPort+0x4c
        8a633d20 76e564f4 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 8a633d34)
        024dfa5c 76e558ac ntdll!KiFastSystemCallRet (FPO: [0,0,0])
        024dfa60 752f1331 ntdll!NtRequestWaitReplyPort+0xc (FPO: [3,0,0])
        024dfa80 752ecbcb kernel32!ConsoleClientCallServer+0x88 (FPO: [4,0,4])
        024dfb40 752ecb55 kernel32!GetConsoleScreenBufferInfoEx+0x3d (FPO: [2,41,4])
        024dfbb0 0e311cb5 kernel32!GetConsoleScreenBufferInfo+0x1b (FPO: [2,24,0])
        024dfbf0 0e31210d ntvdm!resizeWindow+0x28 (FPO: [2,9,4])
        024dfc04 0e3123ce ntvdm!textResize+0x5b (FPO: [0,0,0])
        024dfc10 0e312611 ntvdm!nt_init_screen+0x1ce (FPO: [0,0,0])
        024dfc24 0e2fc60f ntvdm!nt_set_paint_routine+0x1b2 (FPO: [2,0,4])
        024dfc3c 0e319249 ntvdm!choose_vga_display_mode+0x16d (FPO: [0,0,4])
        024dfc64 0e3195f4 ntvdm!syncVGAEmulationToHardware+0x399 (FPO: [0,5,4])
        024dfc68 0e319795 ntvdm!fullScreenToWindowed+0xf (FPO: [0,0,0])
        024dfca4 0e3095ca ntvdm!DoHandShake+0x13a (FPO: [SEH])
        024dfcc0 0e309916 ntvdm!DelayHeartBeat+0x53 (FPO: [1,2,4])
        024dfcdc 0e309ad0 ntvdm!Win32_host_timer+0x19 (FPO: [0,2,0])
        024dfd10 752f1174 ntvdm!HeartBeatThread+0x7a (FPO: [SEH])
        024dfd1c 76e6b3f5 kernel32!BaseThreadInitThunk+0xe (FPO: [1,0,0])
        024dfd5c 76e6b3c8 ntdll!__RtlUserThreadStart+0x70 (FPO: [SEH])
        024dfd74 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [2,2,0])
The last thread is interesting to us, it hangs at GetConsoleScreenBufferInfo
when waiting for a LPC message. We have to consider the new console
architecture of Windows 7 which is very well explained here:
http://blogs.technet.com/b/askperf/a...sole-host.aspx

There now is a seperated Usermode process called ConHost.exe that hosts
a console. It is talked to by a LPC call. So NTVDM is asking ConHost about
GetConsoleScreenBufferInfo, but ConHost.exe is not replying causing the hang.
That means we have to debug ConHost and check where it locks up:

Code:
1: kd> !process 0 0 conhost.exe
PROCESS 84101200  SessionId: 1  Cid: 0548    Peb: 7ffd8000  ParentCid: 018c
    DirBase: 3ed323a0  ObjectTable: 9e88c418  HandleCount:  46.
    Image: conhost.exe

1: kd> .process /r /p 84101200  
Implicit process is now 84101200
.cache forcedecodeuser done
Loading User Symbols
.................
1: kd> !process 84101200
PROCESS 84101200  SessionId: 1  Cid: 0548    Peb: 7ffd8000  ParentCid: 018c
    DirBase: 3ed323a0  ObjectTable: 9e88c418  HandleCount:  46.
    Image: conhost.exe
    VadRoot 8590b548 Vads 44 Clone 0 Private 166. Modified 0. Locked 0.
    DeviceMap 8a275650
    Token                             863c3a98
    ElapsedTime                       00:00:07.046
    UserTime                          00:00:00.000
    KernelTime                        00:00:00.015
    QuotaPoolUsage[PagedPool]         0
    QuotaPoolUsage[NonPagedPool]      0
    Working Set Sizes (now,min,max)  (904, 50, 345) (3616KB, 200KB, 1380KB)
    PeakWorkingSetSize                904
    VirtualSize                       39 Mb
    PeakVirtualSize                   39 Mb
    PageFaultCount                    926
    MemoryPriority                    BACKGROUND
    BasePriority                      8
    CommitCharge                      204

        THREAD 840ef030  Cid 0548.0230  Teb: 7ffde000 Win32Thread: fe9d9dd8 WAIT: (UserRequest) UserMode Non-Alertable
            83ef73b8  SynchronizationEvent
        Not impersonating
        DeviceMap                 8a275650
        Owning Process            0       Image:         <Unknown>
        Attached Process          84101200       Image:         conhost.exe
        Wait Start TickCount      3571791        Ticks: 253 (0:00:00:03.953)
        Context Switch Count      98             
        UserTime                  00:00:00.000
        KernelTime                00:00:00.031
        Win32 Start Address conhost!ConsoleLpcThread (0x00dc159c)
        Stack Init 8a5d9fd0 Current 8a5d9bc8 Base 8a5da000 Limit 8a5d7000 Call 0
        Priority 11 BasePriority 8 PriorityDecrement 2 IoPriority 2 PagePriority 5
        ChildEBP RetAddr  
        8a5d9be0 82687b15 nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4])
        8a5d9c18 82686403 nt!KiSwapThread+0x266
        8a5d9c40 826802cf nt!KiCommitThreadWait+0x1df
        8a5d9cb8 8284a515 nt!KeWaitForSingleObject+0x393
        8a5d9d20 8265c42a nt!NtWaitForSingleObject+0xc6
        8a5d9d20 76e564f4 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 8a5d9d34)
        004af6ac 76e55e6c ntdll!KiFastSystemCallRet (FPO: [0,0,0])
        004af6b0 76e3fc72 ntdll!NtWaitForSingleObject+0xc (FPO: [3,0,0])
        004af714 76e3fb56 ntdll!RtlpWaitOnCriticalSection+0x13e (FPO: [2,17,4])
        004af73c 00dc1584 ntdll!RtlEnterCriticalSection+0x150 (FPO: [1,3,4])
        004af744 00dc17df conhost!LockConsole+0xb (FPO: [0,0,0])
        004af74c 00dc4577 conhost!RevalidateConsole+0xa (FPO: [1,0,0])
        004af774 00dc1661 conhost!SrvGetConsoleScreenBufferInfo+0x15 (FPO: [2,6,4])
        004af840 752f1174 conhost!ConsoleLpcThread+0x13e (FPO: [1,45,0])
        004af84c 76e6b3f5 kernel32!BaseThreadInitThunk+0xe (FPO: [1,0,0])
        004af88c 76e6b3c8 ntdll!__RtlUserThreadStart+0x70 (FPO: [SEH])
        004af8a4 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [2,2,0])

        THREAD 84064a28  Cid 0548.06b8  Teb: 7ffdf000 Win32Thread: fe9f6b80 WAIT: (UserRequest) UserMode Non-Alertable
            84103500  SynchronizationEvent
            83e5a858  NotificationEvent
        Not impersonating
        DeviceMap                 8a275650
        Owning Process            0       Image:         <Unknown>
        Attached Process          84101200       Image:         conhost.exe
        Wait Start TickCount      3571791        Ticks: 253 (0:00:00:03.953)
        Context Switch Count      90             
        UserTime                  00:00:00.000
        KernelTime                00:00:00.140
        Win32 Start Address conhost!ConsoleInputThread (0x00dc300a)
        Stack Init 8a5f5fd0 Current 8a5f5748 Base 8a5f6000 Limit 8a5f3000 Call 544
        Priority 8 BasePriority 8 PriorityDecrement 0 IoPriority 2 PagePriority 5
        ChildEBP RetAddr  
        8a5f5760 82687b15 nt!KiSwapContext+0x26 (FPO: [Uses EBP] [0,0,4])
        8a5f5798 82686403 nt!KiSwapThread+0x266
        8a5f57c0 826826ef nt!KiCommitThreadWait+0x1df
        8a5f593c 8284b625 nt!KeWaitForMultipleObjects+0x535
        8a5f5bc8 8284b392 nt!ObpWaitForMultipleObjects+0x262
        8a5f5d18 8265c42a nt!NtWaitForMultipleObjects+0xcd
        8a5f5d18 76e564f4 nt!KiFastCallEntry+0x12a (FPO: [0,3] TrapFrame @ 8a5f5d34)
        0097f508 76e55e4c ntdll!KiFastSystemCallRet (FPO: [0,0,0])
        0097f50c 00de2f04 ntdll!NtWaitForMultipleObjects+0xc (FPO: [5,0,0])
        0097f650 00dcee01 conhost!DisplayModeTransition+0x6fe (FPO: [2,71,4])
        0097f6e8 767986ef conhost!ConsoleWindowProc+0x419 (FPO: [4,31,4])
        0097f714 76798876 USER32!InternalCallWinProc+0x23
        0097f78c 767970f4 USER32!UserCallWinProcCheckWow+0x14b (FPO: [SEH])
        0097f7e8 7679738f USER32!DispatchClientMessage+0xda (FPO: [SEH])
        0097f810 76e5642e USER32!__fnDWORD+0x24 (FPO: [1,3,0])
        0097f83c 76798f8f ntdll!KiUserCallbackDispatcher+0x2e (FPO: [0,0,0])
        0097f840 76798fc2 USER32!NtUserGetMessage+0xc (FPO: [4,0,0])
        0097f85c 00dc30bb USER32!GetMessageW+0x33 (FPO: [4,0,4])
        0097f8a0 752f1174 conhost!ConsoleInputThread+0xed (FPO: [1,8,4])
        0097f8ac 76e6b3f5 kernel32!BaseThreadInitThunk+0xe (FPO: [1,0,0])
        0097f8ec 76e6b3c8 ntdll!__RtlUserThreadStart+0x70 (FPO: [SEH])
        0097f904 00000000 ntdll!_RtlUserThreadStart+0x1b (FPO: [2,2,0])
Seems like both threads have a deadlock condition, so time to take a closer
look on it. First interesting up in the stack is LockConsole:

Code:
1: kd> u conhost!LockConsole
conhost!LockConsole:
00dc1579 68c081df00      push    offset conhost!gConsoleInformation (00df81c0)
00dc157e ff155c13dc00    call    dword ptr [conhost!_imp__RtlEnterCriticalSection (00dc135c)]
00dc1584 c3              ret
So there is a global Critical section object for the lock.
RevalidateConsole just calls LockConsole and always returns 0:

Code:
1: kd> u conhost!RevalidateConsole
conhost!RevalidateConsole:
00dc17d5 8bff            mov     edi,edi
00dc17d7 55              push    ebp
00dc17d8 8bec            mov     ebp,esp
00dc17da e89afdffff      call    conhost!LockConsole (00dc1579)
00dc17df 8b4508          mov     eax,dword ptr [ebp+8]
00dc17e2 c700c081df00    mov     dword ptr [eax],offset conhost!gConsoleInformation (00df81c0)
00dc17e8 33c0            xor     eax,eax
00dc17ea 5d              pop     ebp
00dc17eb c20400          ret     4
Now let's have a look at ConsoleWindowProc, which is calling DisplayModeTransition:

Code:
...
conhost!ConsoleWindowProc+0x28:
00dc2f2b c745ac01000000  mov     dword ptr [ebp-54h],1
00dc2f32 e842e6ffff      call    conhost!LockConsole (00dc1579)
00dc2f37 8b0d6082df00    mov     ecx,dword ptr [conhost!gConsoleInformation+0xa0 (00df8260)]
00dc2f3d 8b355882df00    mov     esi,dword ptr [conhost!gConsoleInformation+0x98 (00df8258)]
...
00dc2fca 7409            je      conhost!ConsoleWindowProc+0x306 (00dc2fd5)
00dc2fcc e834e5ffff      call    conhost!UnlockConsole (00dc1505)
00dc2fd1 8365ac00        and     dword ptr [ebp-54h],0
00dc2fd5 ff75b4          push    dword ptr [ebp-4Ch]
So the global lock is being held by ConsoleWindowProc when calling
DisplayModeTransition. Now let's check DisplayModeTransition: where it
hangs:

Code:
conhost!DisplayModeTransition+0xb5:
00de28bb 7512            jne     conhost!DisplayModeTransition+0xc9 (00de28cf)
00de28bd 8b357013dc00    mov     esi,dword ptr [conhost!_imp__DbgPrintEx (00dc1370)]
00de28c3 68c030de00      push    offset conhost!`string' (00de30c0)
00de28c8 51              push    ecx
00de28c9 6a70            push    70h
00de28cb ffd6            call    esi
00de28cd ebcd            jmp     conhost!DisplayModeTransition+0x96 (00de289c)
00de28cf f705cc82df0000020000 test dword ptr [conhost!gConsoleInformation+0x10c (00df82cc)],200h
00de28d9 8b357013dc00    mov     esi,dword ptr [conhost!_imp__DbgPrintEx (00dc1370)]
00de28df 8b3d2413dc00    mov     edi,dword ptr [conhost!_imp__NtSetEvent (00dc1324)]
00de28e5 0f84e7000000    je      conhost!DisplayModeTransition+0x1cc (00de29d2)
00de28eb 838d10ffffffff  or      dword ptr [ebp-0F0h],0FFFFFFFFh
00de28f2 53              push    ebx
00de28f3 ff35fc82df00    push    dword ptr [conhost!gConsoleInformation+0x13c (00df82fc)]
00de28f9 c7850cffffff00ba3cdc mov dword ptr [ebp-0F4h],0DC3CBA00h
00de2903 ffd7            call    edi
00de2905 3bc3            cmp     eax,ebx
00de2907 89851cffffff    mov     dword ptr [ebp-0E4h],eax
00de290d 0f8c86000000    jl      conhost!DisplayModeTransition+0x193 (00de2999)
00de2913 a1cc81df00      mov     eax,dword ptr [conhost!gConsoleInformation+0xc (00df81cc)]
00de2918 a38084df00      mov     dword ptr [conhost!gConsoleInformation+0x2c0 (00df8480)],eax
00de291d e81edcffff      call    conhost!UnlockConsoleForCurrentThread (00de0540)
00de2922 898504ffffff    mov     dword ptr [ebp-0FCh],eax
00de2928 8d850cffffff    lea     eax,[ebp-0F4h]
00de292e 50              push    eax
00de292f 53              push    ebx
00de2930 6a01            push    1
00de2932 8d85ecfeffff    lea     eax,[ebp-114h]
00de2938 50              push    eax
00de2939 ffb508ffffff    push    dword ptr [ebp-0F8h]
00de293f ff15f412dc00    call    dword ptr [conhost!_imp__NtWaitForMultipleObjects (00dc12f4)]
00de2945 89851cffffff    mov     dword ptr [ebp-0E4h],eax
00de294b 8d8500ffffff    lea     eax,[ebp-100h]
00de2951 50              push    eax
00de2952 e87eeefdff      call    conhost!RevalidateConsole (00dc17d5)
00de2957 3bc3            cmp     eax,ebx
00de2959 898514ffffff    mov     dword ptr [ebp-0ECh],eax
00de295f 7d27            jge     conhost!DisplayModeTransition+0x182 (00de2988)
00de2961 399d00ffffff    cmp     dword ptr [ebp-100h],ebx
00de2967 7414            je      conhost!DisplayModeTransition+0x177 (00de297d)
00de2969 8b8504ffffff    mov     eax,dword ptr [ebp-0FCh]
00de296f 53              push    ebx
00de2970 ff350483df00    push    dword ptr [conhost!gConsoleInformation+0x144 (00df8304)]
00de2976 a38484df00      mov     dword ptr [conhost!gConsoleInformation+0x2c4 (00df8484)],eax
00de297b ffd7            call    edi
00de297d 8b8514ffffff    mov     eax,dword ptr [ebp-0ECh]
00de2983 e91a060000      jmp     conhost!DisplayModeTransition+0x79c (00de2fa2)
00de2988 ffb504ffffff    push    dword ptr [ebp-0FCh]
00de298e e88bdbffff      call    conhost!LockConsoleForCurrentThread (00de051e)
00de2993 891d8084df00    mov     dword ptr [conhost!gConsoleInformation+0x2c0 (00df8480)],ebx
00de2999 399d1cffffff    cmp     dword ptr [ebp-0E4h],ebx
00de299f 7431            je      conhost!DisplayModeTransition+0x1cc (00de29d2)
00de29a1 8125cc82df00ffbfffff and dword ptr [conhost!gConsoleInformation+0x10c (00df82cc)],0FFFFBFFFh
00de29ab 53              push    ebx
00de29ac ff350483df00    push    dword ptr [conhost!gConsoleInformation+0x144 (00df8304)]
00de29b2 ffd7            call    edi
...
As the function is quite long and a bit complicated, let me wrap this up for you as
stripped pseudocode to better understand what is going on here:

Code:
#define CONSOLE_VDM_REGISTERED 0x200

  g_uOwningThread = gConsoleInformation.OwningThread;
  nRecursions = UnlockConsoleForCurrentThread();
  dwWaitRet = NtWaitForMultipleObjects(HandleCount, &Handles, WaitAny, 0, &Timeout);
  dwRevalConsRet = RevalidateConsole(&pstgConsoleInformation);
  if ( dwRevalConsRet >= 0 )
  {
    LockConsoleForCurrentThread(nRecursions);
    g_uOwningThread = 0;
    if (dwWaitRet) { 
      // ERROR: VDM not responding to initial request
      ...
    }
    if ( arg_1 == FALSE )
    {
      // Display Mode transition to windowed
      ...
      // Flag 0x200 seems to indicate, that we are currently operating in 
      // real textmode Fullscreen
      if ( gConsoleInformation_Flags & CONSOLE_VDM_REGISTERED ) 
      {
        NtSetEvent(hObject, 0);
        fsctrlstr.StateHeader = g_BaseAddress;
        fsctrlstr.StateLength = g_Length;
        if (NtWaitForMultipleObjects(HandleCount, &Handles, WaitAny, 0, &Timeout) < 0 ||
            GdiFullscreenControl(FullscreenControlSaveHardwareState, &State, StateSize, &State, &StateSize) < 0)
        {
          // ERROR: VDM not responding: Save Video States Failed
        }
        else
        {
          ConsoleControl(ConsoleSetVDMCursorBounds, NULL, 0);
          ConnectToEmulator(FALSE);
        }
        if ( gConsoleInformation_Flags & CONSOLE_VDM_REGISTERED )
        {
          Timeout = (LARGE_INTEGER)-600000000i64;
          dwWaitRet = NtSetEvent(hObject, 0);
          if ( dwWaitRet >= 0 )
            dwWaitRet = NtWaitForMultipleObjects(HandleCount, &Handles, WaitAny, 0, &Timeout);
          ...
        }
      }
    }
  }
  if ( pstgConsoleInformation )
  {
    g_nRecursions = nRecursions;
    NtSetEvent(g_hDoneEvent, 0);
  }
  return dwRevalConsRet;
First thing to notice: As seen above, RevalidateConsole always returns
0, that means that the first IF path is always taken and the rest after that
path will never be reached. That dead code is a good place that can be used for
a patch lateron.
What is interesting are the functions UnlockConsoleForCurrentThread and
LockConsoleForCurrentThread:

Code:
1: kd> u conhost!UnlockConsoleForCurrentThread
conhost!UnlockConsoleForCurrentThread:
00de0540 8bff            mov     edi,edi
00de0542 56              push    esi
00de0543 8b35c881df00    mov     esi,dword ptr [conhost!gConsoleInformation+0x8 (00df81c8)]
00de0549 85f6            test    esi,esi
00de054b 760c            jbe     conhost!UnlockConsoleForCurrentThread+0x19 (00de0559)
00de054d 57              push    edi
00de054e 8bfe            mov     edi,esi
00de0550 e8b00ffeff      call    conhost!UnlockConsole (00dc1505)
00de0555 4f              dec     edi
00de0556 75f8            jne     conhost!UnlockConsoleForCurrentThread+0x10 (00de0550)
00de0558 5f              pop     edi
00de0559 8bc6            mov     eax,esi
00de055b 5e              pop     esi
00de055c c3              ret
Code:
typedef struct _RTL_CRITICAL_SECTION {
  PRTL_CRITICAL_SECTION_DEBUG DebugInfo;
  LONG LockCount;
  LONG RecursionCount;
  HANDLE OwningThread; // from the thread's ClientId->UniqueThread
  HANDLE LockSemaphore;
  ULONG_PTR SpinCount; // force size on 64-bit systems when packed
} RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION;
So gConsoleInformation.RecursionCount gets returned and if there are
Recursions, the console is Unlocked the number of recursions given.
Now the counterpart LockConsoleForCurrentThread:

Code:
1: kd> u conhost!LockConsoleForCurrentThread
conhost!LockConsoleForCurrentThread:
00de051e 8bff            mov     edi,edi
00de0520 55              push    ebp
00de0521 8bec            mov     ebp,esp
00de0523 56              push    esi
00de0524 8b7508          mov     esi,dword ptr [ebp+8]
00de0527 eb05            jmp     conhost!LockConsoleForCurrentThread+0x10 (00de052e)
00de0529 e84b10feff      call    conhost!LockConsole (00dc1579)
00de052e 3935c881df00    cmp     dword ptr [conhost!gConsoleInformation+0x8 (00df81c8)],esi
00de0534 75f3            jne     conhost!LockConsoleForCurrentThread+0xb (00de0529)
00de0536 5e              pop     esi
00de0537 5d              pop     ebp
00de0538 c20400          ret     4
So it calls LockConsole for the given number of recursions, unless it's
already locked. In the above code, it's adding back the number of
recursive Locks that were taken and released prior to
NtWaitForMultipleObjects() call.
Fine so far, but there also is a call to RevalidateConsole() which does
a LockConsole internally as seen above. This doesn't hurt, as LockConsole
only adds locks, if there are too few, but as RevalidateConsole()
already adds the missing lock, it doesn't do anything. As there is
already a lock from the ConsoleWindowProc in place, the call to
Revalidateconsole() is unnecessary, as LockConsoleForCurrentThread() will
also be able to add the missing lock itself.
Its return values are of no use either, as the code branch is never taken.
So this call is another thing that can be eliminated. -> Even more space

Now where does the deadlock finally happen?
It's the NtWaitForMultipleObjects call after ConnectToEmulator(), so my
assumption about what is happening here is the following:
Normally there is always one event queued to the VDM, then the event
hObject is signalled to actually run the task in the VDM and then it's
waiting for the VDM to complete the task by waiting on the wait-handles
via NtWaitForMultipleObjects. Now one of these tasks calls
GetConsoleScreenBufferInfo (As seen in the stack above), which in turn
is waiting for the lock. As the lock is actually being held by the
ConsoleWindowProc --> DEADLOCK!!

Now it seems that this may be expected so there are the
UnlockConsoleForCurrentThread and LockConsoleForCurrentThread functions
that temporarily remove the lock to prevent such situations while
waiting for the console to execute the requested task and afterwards
immediately place a lock on it again. But this is only done on the first
Wait-call and the deadlock-Condition actually occurs on the third
NtWaitForMultipleObjects call. These code blocks are only used for NTVDM
processing anway (as they are guarded by CONSOLE_VDM_REGISTERED flags),
so I guess this was just a programming error.
So this leads us to a strategy for fixing:

How to patch this deadlock
==========================
The simplest solution would be to just eliminate all the locking calls
and just leave the UnlockConsoleForCurrentThread call so that there are
no locks to wait for. This indeed works, but doesn't look like a proper
solution. When having a look at the way the NtWaitForMultipleObjects
function is called in all 3 places, it can be seen that it's always the
same call and it's always using the same variables. This gives us the
opportunity to reuse the existing calls to it and just add a wrapper
with UnlockConsoleForCurrentThread before and LockConsoleForCurrentThread
afterwards so that it's "guarded" by the Mutex releasing functions.
In pseudocode, we would replace all NtWaitForMultipleObjects calls with:

Code:
nRecursions = UnlockConsoleForCurrentThread();
dwWaitRet = NtWaitForMultipleObjects(HandleCount, &Handles, WaitAny, 0, &Timeout);
LockConsoleForCurrentThread(nRecursions);
To see how this can be accomplished, have a look at how this Sequence
is implemented in the ASM-code:

Code:
007A2905  |. 3BC3           CMP EAX,EBX
007A2907  |. 8985 1CFFFFFF  MOV DWORD PTR SS:[EBP-E4],EAX
007A290D  |. 0F8C 86000000  JL conhost.007A2999
007A2913  |. A1 CC817B00    MOV EAX,DWORD PTR DS:[7B81CC]
007A2918  |. A3 80847B00    MOV DWORD PTR DS:[7B8480],EAX
007A291D  |. E8 1EDCFFFF    CALL conhost.007A0540                    ;  UnlockConsoleForCurrentThread
007A2922  |. 8985 04FFFFFF  MOV DWORD PTR SS:[EBP-FC],EAX
007A2928  |. 8D85 0CFFFFFF  LEA EAX,DWORD PTR SS:[EBP-F4]
007A292E  |. 50             PUSH EAX
007A292F  |. 53             PUSH EBX
007A2930  |. 6A 01          PUSH 1
007A2932  |. 8D85 ECFEFFFF  LEA EAX,DWORD PTR SS:[EBP-114]
007A2938  |. 50             PUSH EAX
007A2939  |. FFB5 08FFFFFF  PUSH DWORD PTR SS:[EBP-F8]
007A293F  |. FF15 F4127800  CALL DWORD PTR DS:[<&ntdll.NtWaitForMult>;  ntdll.ZwWaitForMultipleObjects
007A2945  |. 8985 1CFFFFFF  MOV DWORD PTR SS:[EBP-E4],EAX
007A294B  |. 8D85 00FFFFFF  LEA EAX,DWORD PTR SS:[EBP-100]
007A2951  |. 50             PUSH EAX                                 ; /Arg1
007A2952  |. E8 7EEEFDFF    CALL conhost.007817D5                    ; \RevalidateConsole
007A2957  |. 3BC3           CMP EAX,EBX
007A2959  |. 8985 14FFFFFF  MOV DWORD PTR SS:[EBP-EC],EAX
007A295F  |. 7D 27          JGE SHORT conhost.007A2988
007A2961  |. 399D 00FFFFFF  CMP DWORD PTR SS:[EBP-100],EBX
007A2967  |. 74 14          JE SHORT conhost.007A297D
007A2969  |. 8B85 04FFFFFF  MOV EAX,DWORD PTR SS:[EBP-FC]
007A296F  |. 53             PUSH EBX
007A2970  |. FF35 04837B00  PUSH DWORD PTR DS:[7B8304]
007A2976  |. A3 84847B00    MOV DWORD PTR DS:[7B8484],EAX
007A297B  |. FFD7           CALL EDI
007A297D  |> 8B85 14FFFFFF  MOV EAX,DWORD PTR SS:[EBP-EC]
007A2983  |. E9 1A060000    JMP conhost.007A2FA2
007A2988  |> FFB5 04FFFFFF  PUSH DWORD PTR SS:[EBP-FC]               ; /Arg1
007A298E  |. E8 8BDBFFFF    CALL conhost.007A051E                    ; \LockConsoleForCurrentThread
007A2993  |. 891D 80847B00  MOV DWORD PTR DS:[7B8480],EBX
007A2999  |> 399D 1CFFFFFF  CMP DWORD PTR SS:[EBP-E4],EBX
Now let's also have a look at the other places in the code, that call
the NtWaitForMultipleObjects function (only those who are used that have
gConsoleInformation_Flags set to CONSOLE_VDM_REGISTERED (0x200), as
only they are relevant for Fullscreen handling):


Code:
007A2DD8  |. 0F8C 95000000  JL conhost.007A2E73
007A2DDE  |. 8D85 0CFFFFFF  LEA EAX,DWORD PTR SS:[EBP-F4]
007A2DE4  |. 50             PUSH EAX
007A2DE5  |. 53             PUSH EBX
007A2DE6  |. 6A 01          PUSH 1
007A2DE8  |. 8D85 ECFEFFFF  LEA EAX,DWORD PTR SS:[EBP-114]
007A2DEE  |. 50             PUSH EAX
007A2DEF  |. FFB5 08FFFFFF  PUSH DWORD PTR SS:[EBP-F8]
007A2DF5  |. FF15 F4127800  CALL DWORD PTR DS:[<&ntdll.NtWaitForMult>;  ntdll.ZwWaitForMultipleObjects
007A2DFB  |. 8985 1CFFFFFF  MOV DWORD PTR SS:[EBP-E4],EAX
007A2E01  |. 3D 02010000    CMP EAX,102

007A2EE5  |. 7C 23          JL SHORT conhost.007A2F0A
007A2EE7  |. 8D85 0CFFFFFF  LEA EAX,DWORD PTR SS:[EBP-F4]
007A2EED  |. 50             PUSH EAX
007A2EEE  |. 53             PUSH EBX
007A2EEF  |. 6A 01          PUSH 1
007A2EF1  |. 8D85 ECFEFFFF  LEA EAX,DWORD PTR SS:[EBP-114]
007A2EF7  |. 50             PUSH EAX
007A2EF8  |. FFB5 08FFFFFF  PUSH DWORD PTR SS:[EBP-F8]
007A2EFE  |. FF15 F4127800  CALL DWORD PTR DS:[<&ntdll.NtWaitForMult>;  ntdll.ZwWaitForMultipleObjects
007A2F04  |. 8985 1CFFFFFF  MOV DWORD PTR SS:[EBP-E4],EAX
007A2F0A  |> 399D 1CFFFFFF  CMP DWORD PTR SS:[EBP-E4],EBX
It can be seen that the code for calling it is always the same.
So the first function that does the locked calls can be rewritten to
immediately lock again after the wait and reused in all functions.
Be aware that the code is a minefield full of relocations because of the
many globals that get used and these places cannot be overwritten with
our code without removing them from the relocation table. On the other hand,
code that is necessary and contains relocations shouldn't be removed as this
would also require touching the relocations. Therefore a solution is needed
that just fits in place.
So here is my solution to this (see comments for details)

Code:
0046290D     EB 48                    JMP SHORT conhost.00462957	; Jump to regained space that does the actual
0046290F     90                       NOP				; JL that should be at that place and then
00462910     90                       NOP				; issue the CALL to the original code before
00462911     90                       NOP				; continuing
00462912     90                       NOP
00462913  |. A1 CC814700              MOV EAX,DWORD PTR DS:[4781CC]	; ATTN: Relocation fixups!
00462918  |. A3 80844700              MOV DWORD PTR DS:[478480],EAX	; ATTN: Relocation fixups!
0046291D  |. E8 1EDCFFFF              CALL conhost.00460540		; UnlockConsoleForCurrentThread
00462922  |. 8985 04FFFFFF            MOV DWORD PTR SS:[EBP-FC],EAX
00462928  |. 8D85 0CFFFFFF            LEA EAX,DWORD PTR SS:[EBP-F4]
0046292E  |. 50                       PUSH EAX
0046292F  |. 53                       PUSH EBX
00462930  |. 6A 01                    PUSH 1
00462932  |. 8D85 ECFEFFFF            LEA EAX,DWORD PTR SS:[EBP-114]
00462938  |. 50                       PUSH EAX
00462939  |. FFB5 08FFFFFF            PUSH DWORD PTR SS:[EBP-F8]
0046293F  |. FF15 F4124400            CALL DWORD PTR DS:[<&ntdll.NtWaitForMult>;  ntdll.ZwWaitForMultipleObjects
00462945  |. 8985 1CFFFFFF            MOV DWORD PTR SS:[EBP-E4],EAX
0046294B     FFB5 04FFFFFF            PUSH DWORD PTR SS:[EBP-FC]	; Lock was placed here instead of RevalidateConsole
00462951     E8 C8DBFFFF              CALL conhost.0046051E		; LockConsoleForCurrentThread
00462956     C3                       RETN				; RETURN from CALL
00462957     7C 40                    JL SHORT conhost.00462999		; Here is the JL that originally was above
00462959     E8 B5FFFFFF              CALL conhost.00462913		; Now call the original code
0046295E     EB 33                    JMP SHORT conhost.00462993	; And continue at the code after the original Lock
00462960     90                       NOP				; Align
00462961  |. 399D 00FFFFFF            CMP DWORD PTR SS:[EBP-100],EBX	; -- Start of dead code
00462967  |. 74 14                    JE SHORT conhost.0046297D
00462969  |. 8B85 04FFFFFF            MOV EAX,DWORD PTR SS:[EBP-FC]
0046296F  |. 53                       PUSH EBX
00462970  |. FF35 04834700            PUSH DWORD PTR DS:[478304]
00462976  |. A3 84844700              MOV DWORD PTR DS:[478484],EAX
0046297B  |. FFD7                     CALL EDI
0046297D  |> 8B85 14FFFFFF            MOV EAX,DWORD PTR SS:[EBP-EC]
00462983  |. E9 1A060000              JMP conhost.00462FA2
00462988  |> FFB5 04FFFFFF            PUSH DWORD PTR SS:[EBP-FC]        ; /Arg1
0046298E  |. E8 8BDBFFFF              CALL conhost.0046051E             ; \LockConsoleForCurrentThread
00462993  |. 891D 80844700            MOV DWORD PTR DS:[478480],EBX	; -- End of dead code, execution continues here
00462999  |> 399D 1CFFFFFF            CMP DWORD PTR SS:[EBP-E4],EBX
Now the CALLs to Wait function get substituted like this:

Code:
00462DD8  |. 0F8C 95000000            JL conhost.00462E73
00462DDE     E8 30FBFFFF              CALL conhost.00462913		; Call our new wait function from above
00462DE3     EB 1C                    JMP SHORT conhost.00462E01	; And continue at original location after wait
00462DE5  |. 53                       PUSH EBX				; Start of dead code
00462DE6  |. 6A 01                    PUSH 1
00462DE8  |. 8D85 ECFEFFFF            LEA EAX,DWORD PTR SS:[EBP-114]
00462DEE  |. 50                       PUSH EAX
00462DEF  |. FFB5 08FFFFFF            PUSH DWORD PTR SS:[EBP-F8]
00462DF5  |. FF15 F4124400            CALL DWORD PTR DS:[<&ntdll.NtWaitForMult>;  ntdll.ZwWaitForMultipleObjects
00462DFB  |. 8985 1CFFFFFF            MOV DWORD PTR SS:[EBP-E4],EAX	; End of dead code
00462E01  |. 3D 02010000              CMP EAX,102			; First instruction after Wait
Same here:

Code:
00462EE5  |. 7C 23                    JL SHORT conhost.00462F0A
00462EE7     E8 27FAFFFF              CALL conhost.00462913
00462EEC     EB 1C                    JMP SHORT conhost.00462F0A
00462EEE  |. 53                       PUSH EBX
00462EEF  |. 6A 01                    PUSH 1
00462EF1  |. 8D85 ECFEFFFF            LEA EAX,DWORD PTR SS:[EBP-114]
00462EF7  |. 50                       PUSH EAX
00462EF8  |. FFB5 08FFFFFF            PUSH DWORD PTR SS:[EBP-F8]
00462EFE  |. FF15 F4124400            CALL DWORD PTR DS:[<&ntdll.NtWaitForMult>;  ntdll.ZwWaitForMultipleObjects
00462F04  |. 8985 1CFFFFFF            MOV DWORD PTR SS:[EBP-E4],EAX
00462F0A  |> 399D 1CFFFFFF            CMP DWORD PTR SS:[EBP-E4],EBX
So finally this is now fixed, as M$ doesn't seem to care.
Btw.: CONHOST issues some debug messages, if you attached a kernel debugger,
you can use the command

Code:
 ed Kd_USERGDI_MASK ff
to enable tracing these messages.

Why is this not happening when starting the console in windowed mode?
================================================== ===================
As we have seen in the stack trace at the time of deadlock above, there are
some functions on the stack that finally cause a call to
GetConsoleScreenBufferInfo API which causes the deadlock. So let's trace
down the function calls on the stack and compare the execution flow to
see where it differs between start in full screen and start in windowed
mode (and then sithcing to fulscreen).
The function in nt_init_screen+0x1ce seems to be good candidate, so let's
trace it. Let's have a look at the function s a whole first:

Code:
0: kd> u ntvdm!nt_init_screen+0x11c
ntvdm!nt_init_screen+0x11c:
0e5e231c 8bff            mov     edi,edi
0e5e231e 53              push    ebx
0e5e231f 33db            xor     ebx,ebx
0e5e2321 391d4483620e    cmp     dword ptr [ntvdm!soft_reset (0e628344)],ebx
0e5e2327 0f842b010000    je      ntvdm!nt_init_screen+0x258 (0e5e2458)
0e5e232d 56              push    esi
0e5e232e be49040000      mov     esi,449h
0e5e2333 56              push    esi
0e5e2334 e8451f0100      call    ntvdm!sas_hw_at (0e5f427e)
0e5e2339 3c10            cmp     al,10h
0e5e233b 7643            jbe     ntvdm!nt_init_screen+0x180 (0e5e2380)
0e5e233d 56              push    esi
0e5e233e e8dc210100      call    ntvdm!sas_hw_at_no_check (0e5f451f)
0e5e2343 3c04            cmp     al,4
0e5e2345 7228            jb      ntvdm!nt_init_screen+0x16f (0e5e236f)
0e5e2347 56              push    esi
0e5e2348 e8d2210100      call    ntvdm!sas_hw_at_no_check (0e5f451f)
0e5e234d 3c07            cmp     al,7
0e5e234f 741e            je      ntvdm!nt_init_screen+0x16f (0e5e236f)
0e5e2351 33c0            xor     eax,eax
0e5e2353 391dacc3630e    cmp     dword ptr [ntvdm!EGA_GRAPH+0xc (0e63c3ac)],ebx
0e5e2359 0f95c0          setne   al
0e5e235c 40              inc     eax
0e5e235d 0faf05ecc4630e  imul    eax,dword ptr [ntvdm!PCDisplay+0xc (0e63c4ec)]
0e5e2364 0faf05e8c4630e  imul    eax,dword ptr [ntvdm!PCDisplay+0x8 (0e63c4e8)]
0e5e236b 8bf0            mov     esi,eax
0e5e236d eb0d            jmp     ntvdm!nt_init_screen+0x17c (0e5e237c)
0e5e236f 8b3534c5630e    mov     esi,dword ptr [ntvdm!PCDisplay+0x54 (0e63c534)]
0e5e2375 0faf35e8c4630e  imul    esi,dword ptr [ntvdm!PCDisplay+0x8 (0e63c4e8)]
0e5e237c 3bf3            cmp     esi,ebx
0e5e237e 7505            jne     ntvdm!nt_init_screen+0x185 (0e5e2385)
0e5e2380 be80020000      mov     esi,280h
0e5e2385 391d54d9650e    cmp     dword ptr [ntvdm!sc+0x34 (0e65d954)],ebx
0e5e238b 754d            jne     ntvdm!nt_init_screen+0x1da (0e5e23da)
0e5e238d 391d7c2b630e    cmp     dword ptr [ntvdm!BeepLastDuration+0x38 (0e632b7c)],ebx
0e5e2393 7521            jne     ntvdm!nt_init_screen+0x1b6 (0e5e23b6)
0e5e2395 a1f0c4630e      mov     eax,dword ptr [ntvdm!PCDisplay+0x10 (0e63c4f0)]
0e5e239a 3b05782b630e    cmp     eax,dword ptr [ntvdm!BeepLastDuration+0x34 (0e632b78)]
0e5e23a0 7514            jne     ntvdm!nt_init_screen+0x1b6 (0e5e23b6)
0e5e23a2 393d602b630e    cmp     dword ptr [ntvdm!BeepLastDuration+0x1c (0e632b60)],edi
0e5e23a8 750c            jne     ntvdm!nt_init_screen+0x1b6 (0e5e23b6)
0e5e23aa 3935702b630e    cmp     dword ptr [ntvdm!BeepLastDuration+0x2c (0e632b70)],esi
0e5e23b0 0f8497000000    je      ntvdm!nt_init_screen+0x24d (0e5e244d)
0e5e23b6 a13cc5630e      mov     eax,dword ptr [ntvdm!PCDisplay+0x5c (0e63c53c)]
0e5e23bb 0fafc7          imul    eax,edi
0e5e23be 8935b0d9650e    mov     dword ptr [ntvdm!sc+0x90 (0e65d9b0)],esi
0e5e23c4 a3acd9650e      mov     dword ptr [ntvdm!sc+0x8c (0e65d9ac)],eax
0e5e23c9 e8e4fcffff      call    ntvdm!textResize (0e5e20b2)
0e5e23ce a1f0c4630e      mov     eax,dword ptr [ntvdm!PCDisplay+0x10 (0e63c4f0)]
0e5e23d3 a3782b630e      mov     dword ptr [ntvdm!BeepLastDuration+0x34 (0e632b78)],eax
0e5e23d8 eb61            jmp     ntvdm!nt_init_screen+0x23b (0e5e243b)
0e5e23da 33db            xor     ebx,ebx
0e5e23dc 43              inc     ebx
0e5e23dd 391d7c2b630e    cmp     dword ptr [ntvdm!BeepLastDuration+0x38 (0e632b7c)],ebx
0e5e23e3 752a            jne     ntvdm!nt_init_screen+0x20f (0e5e240f)
0e5e23e5 393d602b630e    cmp     dword ptr [ntvdm!BeepLastDuration+0x1c (0e632b60)],edi
0e5e23eb 7522            jne     ntvdm!nt_init_screen+0x20f (0e5e240f)
0e5e23ed 3935702b630e    cmp     dword ptr [ntvdm!BeepLastDuration+0x2c (0e632b70)],esi
0e5e23f3 751a            jne     ntvdm!nt_init_screen+0x20f (0e5e240f)
0e5e23f5 a1682b630e      mov     eax,dword ptr [ntvdm!BeepLastDuration+0x24 (0e632b68)]
0e5e23fa 3b054cd9650e    cmp     eax,dword ptr [ntvdm!sc+0x2c (0e65d94c)]
0e5e2400 750d            jne     ntvdm!nt_init_screen+0x20f (0e5e240f)
0e5e2402 a1582b630e      mov     eax,dword ptr [ntvdm!BeepLastDuration+0x14 (0e632b58)]
0e5e2407 3b0504d9650e    cmp     eax,dword ptr [ntvdm!host_screen_scale (0e65d904)]
0e5e240d 743e            je      ntvdm!nt_init_screen+0x24d (0e5e244d)
0e5e240f a13cc5630e      mov     eax,dword ptr [ntvdm!PCDisplay+0x5c (0e63c53c)]
0e5e2414 0fafc7          imul    eax,edi
0e5e2417 8935b0d9650e    mov     dword ptr [ntvdm!sc+0x90 (0e65d9b0)],esi
0e5e241d a3acd9650e      mov     dword ptr [ntvdm!sc+0x8c (0e65d9ac)],eax
0e5e2422 e8eefcffff      call    ntvdm!graphicsResize (0e5e2115)
0e5e2427 a14cd9650e      mov     eax,dword ptr [ntvdm!sc+0x2c (0e65d94c)]
0e5e242c a3682b630e      mov     dword ptr [ntvdm!BeepLastDuration+0x24 (0e632b68)],eax
0e5e2431 a104d9650e      mov     eax,dword ptr [ntvdm!host_screen_scale (0e65d904)]
0e5e2436 a3582b630e      mov     dword ptr [ntvdm!BeepLastDuration+0x14 (0e632b58)],eax
0e5e243b 891d7c2b630e    mov     dword ptr [ntvdm!BeepLastDuration+0x38 (0e632b7c)],ebx
0e5e2441 8935702b630e    mov     dword ptr [ntvdm!BeepLastDuration+0x2c (0e632b70)],esi
0e5e2447 893d602b630e    mov     dword ptr [ntvdm!BeepLastDuration+0x1c (0e632b60)],edi
0e5e244d a1782b630e      mov     eax,dword ptr [ntvdm!BeepLastDuration+0x34 (0e632b78)]
0e5e2452 a39cd9650e      mov     dword ptr [ntvdm!sc+0x7c (0e65d99c)],eax
0e5e2457 5e              pop     esi
0e5e2458 5b              pop     ebx
0e5e2459 c3              ret
A lot of compares in there! We know from the stack trace above that it hits
0e5e23c9 e8e4fcffff call ntvdm!textResize (0e5e20b2)
when starting in full screen mode. So now trace the function in windowed mode:

Code:
0: kd> ! process 0 0 ntvdm.exe
PROCESS 840d8030  SessionId: 1  Cid: 08b8    Peb: 7ffda000  ParentCid: 0968
    DirBase: 3ed323a0  ObjectTable: 9ea89170  HandleCount:  59.
    Image: ntvdm.exe

0: kd> .process /r /p 840d8030  
Implicit process is now 840d8030
.cache forcedecodeuser done
Loading User Symbols
..........................
0: kd> ba e1 ntvdm!nt_set_paint_routine+0x1ad
0: kd> g
Display Mode transition to windowed
Breakpoint 1 hit
ntvdm!nt_set_paint_routine+0x1ad:
001b:0e6d260c e80bfdffff      call    ntvdm!nt_init_screen+0x11c (0e6d231c)
1: kd> t
ntvdm!nt_init_screen+0x11c:
001b:0e6d231c 8bff            mov     edi,edi
001b:0e6d231f 33db            xor     ebx,ebx
001b:0e6d2321 391d4483710e    cmp     dword ptr [ntvdm!soft_reset (0e718344)],ebx
001b:0e6d2327 0f842b010000    je      ntvdm!nt_init_screen+0x258 (0e6d2458)
001b:0e6d232d 56              push    esi
001b:0e6d232e be49040000      mov     esi,449h
001b:0e6d2333 56              push    esi
001b:0e6d2334 e8451f0100      call    ntvdm!sas_hw_at (0e6e427e)
001b:0e6d2339 3c10            cmp     al,10h
001b:0e6d233b 7643            jbe     ntvdm!nt_init_screen+0x180 (0e6d2380)
001b:0e6d2380 be80020000      mov     esi,280h
001b:0e6d2385 391d54d9740e    cmp     dword ptr [ntvdm!sc+0x34 (0e74d954)],ebx
001b:0e6d238b 754d            jne     ntvdm!nt_init_screen+0x1da (0e6d23da)
001b:0e6d238d 391d7c2b720e    cmp     dword ptr [ntvdm!BeepLastDuration+0x38 (0e722b7c)],ebx
001b:0e6d2393 7521            jne     ntvdm!nt_init_screen+0x1b6 (0e6d23b6)
001b:0e6d2395 a1f0c4720e      mov     eax,dword ptr [ntvdm!PCDisplay+0x10 (0e72c4f0)]
001b:0e6d239a 3b05782b720e    cmp     eax,dword ptr [ntvdm!BeepLastDuration+0x34 (0e722b78)]
001b:0e6d23a0 7514            jne     ntvdm!nt_init_screen+0x1b6 (0e6d23b6)
001b:0e6d23a2 393d602b720e    cmp     dword ptr [ntvdm!BeepLastDuration+0x1c (0e722b60)],edi
001b:0e6d23a8 750c            jne     ntvdm!nt_init_screen+0x1b6 (0e6d23b6)
001b:0e6d23aa 3935702b720e    cmp     dword ptr [ntvdm!BeepLastDuration+0x2c (0e722b70)],esi
001b:0e6d23b0 0f8497000000    je      ntvdm!nt_init_screen+0x24d (0e6d244d)
001b:0e6d244d a1782b720e      mov     eax,dword ptr [ntvdm!BeepLastDuration+0x34 (0e722b78)]
001b:0e6d2452 a39cd9740e      mov     dword ptr [ntvdm!sc+0x7c (0e74d99c)],eax
001b:0e6d2457 5e              pop     esi
001b:0e6d2458 5b              pop     ebx
The function should hit 0e5e23b6, but it never does.
Let's have a look at some pseudocode again:

Code:
if (dw0e722b7c || dw0e72c4f0 != dw0e722b78 || dw0e722b60 != edi || dw0e722b70 != esi)
{
  ...
  textResize();
}
So it seems, that everything is equal already (text size already calcualted?)
when starting in windowed mode, but when starting in full scren mode, there
seems to be a difference:

Code:
0: kd> dd ntvdm!PCDisplay+0x10
0e5dc4f0  00000010 

0: kd> dd ntvdm!BeepLastDuration+0x34
0e5d2b78  00000008
So that's the reason for this. From my point of view, it's still the fault of
conhost not to permit calls from NTVDM while it's processing some requests.

The patcher
===========
I wrote a little patcher that applies the patches and hopefully works for every
released version of conhost.exe on Windows 7.
Just download the patch and run it as administrator and then check if the bug
is fixed. I'd love to hear from you if it worked for you too.

The file can be downloaded as unregistered member from here:
http://www.waldbauer.com/tmp/reference.php?
Angehängte Dateien
Dateityp: zip conhost_pat.zip‎ (4.0 KB, 17x aufgerufen)
Dateityp: exe fullscr.exe‎ (1.0 KB, 11x aufgerufen)

Geändert von leecher (10.11.2016 um 01:16 Uhr) Grund: Added reference to automatic fullscreen switcher
leecher ist offline   Mit Zitat antworten