Console Window - subclassing (capturing WM_PAINT) : How ?

13 views
Skip to first unread message

R.Wieser

unread,
Sep 17, 2022, 7:49:20 AM9/17/22
to
Hello all,

I'm trying to draw some simple graphics (dots, lines) into a windowed
console.

Although grabbing its DC and use that to draw on works, any updating of the
screen by the running program (partially) causes havoc - from the drawing
being partially erased to it fully disappearing.

So, I'm looking for a way to subclass a console window so I can intercept
its WM_PAINT message, and redraw my stuff after an update of the window
occurs.

The problem is that although I have a hWnd to the console, a
'SetWindowSubclass' fails (incorrect parameter), and a GetWindowLong
GWL_WINPROC returns Zero (whut ?).

This morning I've been searching the intarnetz for information on how to
intercept WM_* messages of a console window, but I've not been able to find
anything in that direction. :-\

Anyone knows how to do it and wants to share ?

Target OS: XPsp3

Regards,
Rudy Wieser


Paul N

unread,
Sep 17, 2022, 12:47:22 PM9/17/22
to
I thought the basic idea of a console was that you weren't going to do that sort of thing?

I don't know how to do what you want to do, and I'm not even sure if it's possible. A possible way round things though - why don't you have a normal window, with a big multi-line edit box covering some or all of it, and "print" text by adding it to the text in the box?

JJ

unread,
Sep 18, 2022, 2:40:11 AM9/18/22
to
Have you tried using `SetWindowLong()` or `SetClassLong()` instead?

R.Wieser

unread,
Sep 18, 2022, 3:00:41 AM9/18/22
to
Paul,

> I thought the basic idea of a console was that you weren't going to do
> that sort of thing?

Well ... I've been using graphics in a console windows for years thru QBASIC
(and INT 0x10). Yep, I'm working with/looking at DOS programs there. :-)

The problem is that one of my 'puters has a /very/ basic video card, which
just causes the puter to lockup (needing a hard reset) whenever I now try.
:-(

So, I'm looking for something to keep everything in textmode, but add the
graphics as an "overlay".

> I don't know how to do what you want to do, and I'm not even sure if
> it's possible.

I'm not sure either. But I'm trying different things to see if something
works better than directly drawing to the windows DC (which does work, just
badly).

> A possible way round things though - why don't you have a normal window,
> with a big multi-line edit box covering some or all of it, and "print"
> text by adding it to the text in the box?

That would work if I could redirect all the text output to code I control.
Alas, old DOS programs sometimes (often?) write directly to the text memory
(0xB800 IIRC), which is rather hard to intercept. The above-mentioned
QBASIC program is one of them.

Thanks for the suggestion though.

Regards,
Rudy Wieser


R.Wieser

unread,
Sep 18, 2022, 9:48:02 AM9/18/22
to
JJ,

> Have you tried using `SetWindowLong()` or `SetClassLong()` instead?

Neither. The first because reading the GWLWNDPROC returned zero, and the
second because only want to affect a specific console window, not all of
them.

But you're right, I could at least try to see what happens.

Regards,
Rudy Wieser


R.Wieser

unread,
Sep 18, 2022, 10:14:49 AM9/18/22
to
JJ,

[quote=me]
But you're right, I could at least try to see what happens.
[/quote]

Alas, changing either/both doesn't give any kind of different result. No
intercepted messages, nothing throwing a hissy fit either. Its as if I've
done nothing at all.

Worse: changing both GWL_WNDPROC and CWL_WNDPROC and checking them later
shows the same values as before I made the change. IOW, its as if setting
them is ignored.

Regards,
Rudy Wieser


JJ

unread,
Sep 19, 2022, 4:16:56 AM9/19/22
to
On Sun, 18 Sep 2022 16:14:41 +0200, R.Wieser wrote:
>
> Alas, changing either/both doesn't give any kind of different result. No
> intercepted messages, nothing throwing a hissy fit either. Its as if I've
> done nothing at all.
>
> Worse: changing both GWL_WNDPROC and CWL_WNDPROC and checking them later
> shows the same values as before I made the change. IOW, its as if setting
> them is ignored.

I think the system has an unconditional hardcoded protection for console
window message handler, since GetWindowLong returns zero with an access
denied error code when the console application is run using the SYSTEM
account. Weirdly, if the console application is not run using the SYSTEM
account, GetWindowLong returns a kernel-space pointer (e.g. 0xFFFF0501) with
a success error code.

This conclusion is based on the fact that, an application run using the
SYSTEM account can terminate CSRSS.EXE and BSOD-ed the system. So, if it
can't subclass the console window, it should mean that, the system has
prevented it unconditionally - regardless of user credentials and
privileges. Because IMO, it's unbelievable to think that a console window
message handler is more crucial than CSRSS.EXE.

R.Wieser

unread,
Sep 19, 2022, 5:52:45 AM9/19/22
to
JJ,

> GetWindowLong returns a kernel-space pointer (e.g. 0xFFFF0501)

Hmmm.. In my case (XPsp3) GetWindowLong returned Zero, and getClassLong
returned a kernel-space pointer. I must say that I didn't try to check for
an error though (didn't realize that the standard GWL_* GCL_* indices could
throw them).

> This conclusion is based on the fact that, an application run using
> the SYSTEM account can terminate CSRSS.EXE and BSOD-ed the system.
> So, if it can't subclass the console window, it should mean that,
> the system has prevented it unconditionally - regardless of user
> credentials and privileges.

My focus is userland, so I again didn't even think of trying it under
different accounts. But thank you for the testing (and posting it :-) ).

> Because IMO, it's unbelievable to think that a console window
> message handler is more crucial than CSRSS.EXE.

Hmmmm... I'm allowed to tinker around with most all GUI windows, but am not
allowed to do the same with a console one. I'm not so sure I understand
that distinction.

But, as doing anything with a console window is either not allowed or is
iffy I'm already looking in another direction (creating a GUI window and
sending the graphical data to it).

By the way, I also tried to use VESA, but that locked up the 'puter as well.
:-\ I knew (was warned about it that) the NVIDIA GT 730 video card is a
simple one, but *that* simple ?...

Regards,
Rudy Wieser


JJ

unread,
Sep 20, 2022, 4:21:51 AM9/20/22
to
On Mon, 19 Sep 2022 11:52:36 +0200, R.Wieser wrote:
>
> My focus is userland, so I again didn't even think of trying it under
> different accounts. But thank you for the testing (and posting it :-) ).

That was a userland test, but using the SYSTEM account rather than an
account member of the Administrator group.

> Hmmmm... I'm allowed to tinker around with most all GUI windows, but am not
> allowed to do the same with a console one. I'm not so sure I understand
> that distinction.

To my understanding, console window is a protected window. Since Vista, it's
even more protected, by separating the handler in a separate CONHOST.EXE
process which is spawned by CSRSS.EXE for each console window. Perhaps the
contents of the console window is rendered in a special way, which I
suspect, is handled directly from kernel-space. Because that would explain
the blazingly fast rendering of a console window content. If we try to
create our own "console" window class using our own renderer, it will never
be as fast as the real console.

> By the way, I also tried to use VESA, but that locked up the 'puter as well.
>:-\ I knew (was warned about it that) the NVIDIA GT 730 video card is a
> simple one, but *that* simple ?...

What do you mean "use VESA"? AFAIK, Windows doesn't expose any of the
display adapter's VESA API.

R.Wieser

unread,
Sep 20, 2022, 4:50:11 AM9/20/22
to
JJ,

> What do you mean "use VESA"? AFAIK, Windows doesn't expose any of
> the display adapter's VESA API.

My problem started with a DOS program (QBASIC) locking up when I tried to
switch sceen modus ("screen 13", 640x640, 256 color graphics).

I stayed in DOS and checked INT 0x10, AH=0x00 to see if it would make a
difference. It didn't. Than I also tried VESA (INT 0x10, AH=0x4E) with a
modus returned by the card itself(?) (INT 0x10 AX=4E00). No workie either.

And before you ask: I'm using the BOP method to transfer data from the DOS
environment to the Windows one : http://sta.c64.org/blog/dosvddaccess.html

Regards,
Rudy Wieser


R.Wieser

unread,
Sep 27, 2022, 5:03:02 AM9/27/22
to

"R.Wieser" <add...@not.available> wrote in message
news:tg4c7r$148$1...@gioia.aioe.org...
> Hello all,
>
> I'm trying to draw some simple graphics (dots, lines) into a windowed
> console.
...
> Anyone knows how to do it and wants to share ?

I found some almost decade-old code that does it here :

http://blog.airesoft.co.uk/2012/10/things-ms-can-do-that-they-dont-tell-you-about-console-graphics/

Although there are a number of restrictions, it shows that you can indeed
use the console window for graphics output. :-)

Alas, as it doesn't draw the graphics over the already existing text (and
only works in a windowed console) its not really usefull toward my own goal.
:-\

Regards,
Rudy Wieser


JJ

unread,
Sep 28, 2022, 7:51:21 AM9/28/22
to
On Tue, 27 Sep 2022 11:02:46 +0200, R.Wieser wrote:
>
> I found some almost decade-old code that does it here :
>
> http://blog.airesoft.co.uk/2012/10/things-ms-can-do-that-they-dont-tell-you-about-console-graphics/
>
> Although there are a number of restrictions, it shows that you can indeed
> use the console window for graphics output. :-)

That's interresting. I forgot that, console was designed to be able to
present graphic content from DOS based programs while still being windowed.

> You can only create graphics buffers on 32-bit versions of Windows [4].

Kind of expected that, since 64-bit Windows no longer support 16-bit
programs. But... FUUU!!

> Alas, as it doesn't draw the graphics over the already existing text (and
> only works in a windowed console) its not really usefull toward my own goal.
>:-\

That may be worked around by hooking the drawing function and if necessary,
use an off-screen console graphic buffer, but I suspect that the code which
use the function is in kernel space.

R.Wieser

unread,
Sep 28, 2022, 8:56:32 AM9/28/22
to
JJ,

>> You can only create graphics buffers on 32-bit versions of Windows [4].
>
> Kind of expected that, since 64-bit Windows no longer support 16-bit
> programs. But... FUUU!!

I'm not so sure it has anything to do with 16-bit programs : In the example
the console buffer itself is 32 bits, as is the program feeding it.

Having said that, I've got no idea what actually prohibits it.

>> Alas, as it doesn't draw the graphics over the already existing text
>> (and only works in a windowed console) its not really usefull toward
>> my own goal. :-\
>
> That may be worked around by hooking the drawing function

:-) That was what I was looking for, but have not been able to find.

I /could/ do it the other way around I suppose : grab a copy of the target
window(s graphics), draw my own stuff over it and present that as the new
data. But again, no synchronisation between the two.

And I got caught out by the example : I implemented that code and got zero
result from it. ...Until I realized that I was running the code in a
fullscreen 80x25 console, and not from a windowed one. After I switched
over the image did indeed appear. :-)


By the way : I got something to work with that BOP method, but ultimatily
decided against it - the intermediate DLL needs to be registered *and
unregistered* in the DOS program. Fail to unregister it and the next usage
doesn't give the desired result. :-|

As switching to a DOS graphics mode isn't possible (on that one machine) and
as such I'm forced to use a windowed console anyway I thought of just using
a standard Windows dialog and communicate with it (from within the DOS
program) thru a 'named pipe' (which I can just "print" to). Seems to work
alright.

Regards,
Rudy Wieser


JJ

unread,
Sep 29, 2022, 12:58:47 PM9/29/22
to
On Wed, 28 Sep 2022 14:56:16 +0200, R.Wieser wrote:
>
> I'm not so sure it has anything to do with 16-bit programs : In the example
> the console buffer itself is 32 bits, as is the program feeding it.
>
> Having said that, I've got no idea what actually prohibits it.

I wasn't referring to the graphic console buffer's bitmap bit depth.

Graphic content in windowed console only exist for supporting real mode or
V86 mode programs which may use graphic video mode. 64-bit Windows no longer
has 16-bit subsystem. There's no longer need to have graphic cosole buffer
in 64-bit Windows, since there's nothing which runs in real or V86 mode.

R.Wieser

unread,
Sep 29, 2022, 2:47:58 PM9/29/22
to
JJ,

>> Having said that, I've got no idea what actually prohibits it.
>
> I wasn't referring to the graphic console buffer's bitmap bit depth.

I didn't think you where. I was just putting forward that both the screen
buffer as well as the code are 32 bit, and should be no problem for a 64-bit
environment.

> There's no longer need to have graphic cosole buffer in 64-bit Windows,
> since there's nothing which runs in real or V86 mode.

As it seems that the calls / code runs fine without either real or V86 mode*
it doesn't quite look as if thats the reason.

* I just checked, running that code doesn't activate/use NTVDM.

It might just be the reason why we are not allowed to tap into the message
loop of a console window : security. Being able to control (override) what
is shown in a console window might be considered a problem.

Than again, who knows. :-)

Regards,
Rudy Wieser


Reply all
Reply to author
Forward
0 new messages