Current version

v1.10.4 (stable)

Navigation

Main page
Archived news
Downloads
Documentation
   Capture
   Compiling
   Processing
   Crashes
Features
Filters
Plugin SDK
Knowledge base
Donate
Contact info
Forum
 
Other projects
   Altirra

Search

Archives

01 Dec - 31 Dec 2013
01 Oct - 31 Oct 2013
01 Aug - 31 Aug 2013
01 May - 31 May 2013
01 Mar - 31 Mar 2013
01 Feb - 29 Feb 2013
01 Dec - 31 Dec 2012
01 Nov - 30 Nov 2012
01 Oct - 31 Oct 2012
01 Sep - 30 Sep 2012
01 Aug - 31 Aug 2012
01 June - 30 June 2012
01 May - 31 May 2012
01 Apr - 30 Apr 2012
01 Dec - 31 Dec 2011
01 Nov - 30 Nov 2011
01 Oct - 31 Oct 2011
01 Sep - 30 Sep 2011
01 Aug - 31 Aug 2011
01 Jul - 31 Jul 2011
01 June - 30 June 2011
01 May - 31 May 2011
01 Apr - 30 Apr 2011
01 Mar - 31 Mar 2011
01 Feb - 29 Feb 2011
01 Jan - 31 Jan 2011
01 Dec - 31 Dec 2010
01 Nov - 30 Nov 2010
01 Oct - 31 Oct 2010
01 Sep - 30 Sep 2010
01 Aug - 31 Aug 2010
01 Jul - 31 Jul 2010
01 June - 30 June 2010
01 May - 31 May 2010
01 Apr - 30 Apr 2010
01 Mar - 31 Mar 2010
01 Feb - 29 Feb 2010
01 Jan - 31 Jan 2010
01 Dec - 31 Dec 2009
01 Nov - 30 Nov 2009
01 Oct - 31 Oct 2009
01 Sep - 30 Sep 2009
01 Aug - 31 Aug 2009
01 Jul - 31 Jul 2009
01 June - 30 June 2009
01 May - 31 May 2009
01 Apr - 30 Apr 2009
01 Mar - 31 Mar 2009
01 Feb - 29 Feb 2009
01 Jan - 31 Jan 2009
01 Dec - 31 Dec 2008
01 Nov - 30 Nov 2008
01 Oct - 31 Oct 2008
01 Sep - 30 Sep 2008
01 Aug - 31 Aug 2008
01 Jul - 31 Jul 2008
01 June - 30 June 2008
01 May - 31 May 2008
01 Apr - 30 Apr 2008
01 Mar - 31 Mar 2008
01 Feb - 29 Feb 2008
01 Jan - 31 Jan 2008
01 Dec - 31 Dec 2007
01 Nov - 30 Nov 2007
01 Oct - 31 Oct 2007
01 Sep - 30 Sep 2007
01 Aug - 31 Aug 2007
01 Jul - 31 Jul 2007
01 June - 30 June 2007
01 May - 31 May 2007
01 Apr - 30 Apr 2007
01 Mar - 31 Mar 2007
01 Feb - 29 Feb 2007
01 Jan - 31 Jan 2007
01 Dec - 31 Dec 2006
01 Nov - 30 Nov 2006
01 Oct - 31 Oct 2006
01 Sep - 30 Sep 2006
01 Aug - 31 Aug 2006
01 Jul - 31 Jul 2006
01 June - 30 June 2006
01 May - 31 May 2006
01 Apr - 30 Apr 2006
01 Mar - 31 Mar 2006
01 Feb - 29 Feb 2006
01 Jan - 31 Jan 2006
01 Dec - 31 Dec 2005
01 Nov - 30 Nov 2005
01 Oct - 31 Oct 2005
01 Sep - 30 Sep 2005
01 Aug - 31 Aug 2005
01 Jul - 31 Jul 2005
01 June - 30 June 2005
01 May - 31 May 2005
01 Apr - 30 Apr 2005
01 Mar - 31 Mar 2005
01 Feb - 29 Feb 2005
01 Jan - 31 Jan 2005
01 Dec - 31 Dec 2004
01 Nov - 30 Nov 2004
01 Oct - 31 Oct 2004
01 Sep - 30 Sep 2004
01 Aug - 31 Aug 2004

Stuff

Powered by Pivot  
XML: RSS feed 
XML: Atom feed 

§ Why Ctrl+Break doesn't work with QBasic in DOSBox

One of the problems with switching to a 64-bit version of Windows is that you can't run 16-bit DOS programs, due to the removal of NTVDM. While this is usually attributed to Microsoft cleaning legacy house, it's also due to a hardware limitation: the original x86-64 specification prohibited VM86 mode under long mode. Therefore, I've been making greater use of DOSBox in the few cases where I need to run such programs, since it integrates a little better than virtualization.

Unfortunately, one of the old programs I occasionally run is QBasic, and there's a long standing problem where Ctrl+Break doesn't work in QBasic under DOSBox.

I finally got annoyed enough about this to try to diagnose it myself. I'd had luck doing this previously, when I tracked down the bug where the keyboard would suddenly stop working if you pressed Ctrl+Esc. (I'm actually not a fan of the "fix it yourself it's open source" mentality, and I don't have any good memories of 16-bit real mode x86, but scuttle four Colonization games in a row and I will launch the debugger.) Now, I already had a suspicion as to what was causing this: there's an anomaly in the PC keyboard where certain scan codes change depending on modifier keys. One of them is Pause, which magically turns to Break when Ctrl is also pressed. This anomaly is often reflected in higher level APIs, and in Win32, this manifests as your window handler getting a WM_KEYDOWN message with VK_CANCEL instead of VK_PAUSE. Therefore, somewhere along the line, it's likely that this difference wasn't being emulated.

Sure enough, when I dug into the keyboard emulation code, it was always sending the scan codes for the pause key. That was easily fixed, but I noticed that Ctrl+Break was never arriving from the UI, either. Okay, we probably just need to check for the analogous SDL constant for VK_CANCEL, which appears to be SDLK_BREAK. Easily done. Except... that doesn't seem to be arriving either. In fact, no keyboard events are arriving at all when I press Ctrl+Break. Luckily, I built the SDL library in Debug configuration from source, so I can debug into it. Let's see, no WM_KEYDOWN handler, which means it's probably using DirectInput, so let's set a breakpoint on the DirectInput code... uh oh.

DirectX, like most Windows APIs, has a lot of unwritten lore that still isn't really documented after a decade, basic stuff that you need to know but end up learning the hard way. An example is dynamic vertex/index buffers in Direct3D9, which seem easy, until you find out that occasionally on mode switches Lock() hands back an invalid pointer while still returning D3D_OK. Apparently, one of the undocumented gotchas for DirectInput is that you might not get Ctrl+Break events, ever. I'd never encountered this because I use window messages for keyboard input in my own programs. There wasn't a straightforward fix for this, and I didn't really have the intention to rewrite the input path in both DOSBox and SDL, so I decided to just bypass it and try to get the Pause key to send Ctrl+Break into the emulation.

The next step, then, was to figure out how to push Ctrl+Break through. As I said earlier, it was easy enough to send down the right set of scancodes, but that wasn't working. That meant the next likely missing part was the BIOS handling, which involves setting a break flag, pushing a break code into the keyboard buffer, and calling a break interrupt vector. None of that was working either, so I had to figure out how QBasic handles Ctrl+Break. Surprisingly, WinDbg has a limited ability to debug 16-bit code -- disassembly's a bit wonky, but breakpoints do work -- so I was able to debug the IRQ1 handler under NTVDM on a machine running 32-bit XP. It turns out that while QBasic hooks the BIOS Ctrl+Break callback to block it in edit mode, it run mode it takes over the IRQ1 interrupt vector and monitors the raw scan codes for Ctrl+Break. Not only that, but it won't accept it as such unless it also sees the Ctrl key down, which is why I couldn't get it to work with Pause as the host key. I hacked the emulator's keyboard hardware code to also send Ctrl down/up codes, and sure enough, QBasic finally broke out of run mode. Victory!

Of course, soon after that, I found a post saying that you can just bind Ctrl+ScrollLock instead, since QBasic also accepts that. Figures. On my current laptop, that ends up being the unintuitive and very discoverable Ctrl+Fn+F5.

Anyway, in conclusion, the reason why Ctrl+Break hasn't been fixed yet in DOSBox is because there's half a dozen things in the way.

Comments

Comments posted:


Maybe an example of a bug that was intentionally not fixed. Makes you understand a little better why Microsoft sometimes closes connect bugs with "won't fix" or "by design".

tobi - 28 05 11 - 22:06


My guess is that the Ctrl-Break issue just never got reported by anyone with enough clout to get Microsoft to fix it.

After all, Microsoft Connect isn't their primary bug reporting mechanism. From what Raymond Chen writes, corporate developers with gold-plated support contracts seem to have top priority for getting bugs accepted. For DirectX, the equivalent of the big corporate developer would be the large game ISV. And games have a famously short support lifetime.

(I was surprised a while back to find that ex-abandonware is now being sold directly on Steam by the original developers -- bundled with a pre-configured DOSBox. I don't know if they're actually making real money or just doing it as a hobby, but if this ever takes off ...)

Tom - 29 05 11 - 03:31


Won't fix yes, By Design no.

The main issue I have is that lots of bugs don't get documented very well or anywhere at all, and everyone had to rediscover them. Another one I just ran into is comctl32 v5 no longer supporting live drag on column scrolling under Windows 7. For Visual Studio you can sometimes look them up on Connect, but Windows doesn't have a running live connection (for obvious reasons, unfortunately).

Phaeron - 29 05 11 - 07:41


http://vogons.zetafleet.com/viewtopic.ph..

ksoam - 29 05 11 - 20:41


I wrote an 68k emulator that originally ran under DOS and later ported it to Windows. As the client-OS expected PC scan codes I used DirectInput in event mode to get the same behavior as the previous IRQ1 implementation. Which worked fine, except for one key: "\" on English ("

Marcel - 29 05 11 - 21:07


Repost without the "smaller than" character that seemed to confuse the comment software...

I wrote an 68k emulator that originally ran under DOS and later ported it to Windows. As the client-OS expected PC scan codes I used DirectInput in event mode to get the same behavior as the previous IRQ1 implementation. Which worked fine, except for one key: "backslash" on English ("smaller than"/"angled bracket" on German) keyboards. I think the handler was called, but there never was a scan code in the queue, so I had to implement a workaround using IDirectInputDevice_GetDeviceState (which correctly showed the key status, thank god) for this single key. On my XPSP3 system it seems to be finally get signaled as "OEM-Key 102", but this thing was broken for years without a fix.

Marcel - 29 05 11 - 21:15


When a "smaller than" character confuses your comment software, you can usually get it to display < by typing &lt;

Steve - 14 06 11 - 03:35


How do you work around the vertex/index buffers problem? Is there any way or basically just avoid those APIs?

Christian - 15 06 11 - 08:31


> How do you work around the vertex/index buffers problem? Is there any way or basically just avoid those APIs?

There is no good way that I know of other than to wrap all writes to the dynamic VB or IB in a structured exception handling (SEH) block, catch the AV, and abort the draw in that case. For a memcpy() it's cleanest to create a protected copy function; for something more complicated, you need the code writing into the VB/IB to be simple. Otherwise, you either run into the C++EH/SEH conflict in VC++ and need to split the function, or your complex code malfunctions and you end up having to compile it with /EHa (boo). I think this long standing kernel bug may have been fixed starting in Vista (WDDM), but it's definitely still present in XP.

While we're talking about ways you get hosed by mode switches, another fun one is GetRenderTargetData() returning S_OK but giving you garbage. That's no big deal in a game, but it's annoying in a program that's doing off-screen rendering.

Phaeron - 15 06 11 - 15:28

Comment form


Please keep comments on-topic for this entry. If you have unrelated comments about VirtualDub, the forum is a better place to post them.
Name:  
Remember personal info?

Email (Optional):
Your email address is only revealed to the blog owner and is not shown to the public.
URL (Optional):
Comment: /

An authentication dialog may appear when you click Post Comment. Simply type in "post" as the user and "now" as the password. I have had to do this to stop automated comment spam.



Small print: All html tags except <b> and <i> will be removed from your comment. You can make links by just typing the url or mail-address.