CmdBkg - use bitmap as background to console window

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Message
Author
aGerman
Expert
Posts: 4008
Joined: 22 Jan 2010 18:01
Location: Germany

Re: CmdBkg - use bitmap as background to console window

#61 Post by aGerman » 11 Nov 2020 12:01

Well, standard C is a simple language with little extend. Understanding pointers might be tricky, memory management is challenging and requires your full attention ... But here we're rather using the Windows API. It's C-style but can be overwhelming. However, programming languages are just istruments. Having a good understanding of how to discribe a problem and it's solution in terms of algorithms (even in natural language or in pseudocode) is already more than half the way. So, I guess if you're already experienced in programming the hurdle could be rather the syntax. COBOL and Basic have closing statements while you're facing curly braces in C-like languages. But that's somehow comparable with parenthesized blocks in Batch. People like you who speak assembly language deserve my full respect. That's something that my grey matter isn't able to grasp :lol:

Steffen

misol101
Posts: 466
Joined: 02 May 2016 18:20

Re: CmdBkg - use bitmap as background to console window

#62 Post by misol101 » 11 Nov 2020 15:30

aGerman wrote:
09 Nov 2020 19:26
Found it :D
We have to call PostQuitMessage for WM_DESTROY.

My original assumption that WMI could be the culprit made me think about alternatives. And indeed I found a much easier way. Instead of passing the console HWND as additional argument it gets now assigned to the user data of the background window. Less dependencies, smaller code, easier processing, quick executable. It really makes a difference 8)
Well done Steffen! 8)

I replaced the archive linked in the first post, version number remains 1.2.

aGerman
Expert
Posts: 4008
Joined: 22 Jan 2010 18:01
Location: Germany

Re: CmdBkg - use bitmap as background to console window

#63 Post by aGerman » 19 Nov 2020 16:11

I swear I leave it alone for a while ...
Time is over :P :lol:

Hopefully the remaining TODOs are all addressed now and you still recognize your own code, Mikael :)
Because we can't attach files to PMs I have to post the code in this thread anyway. So I'll also explain what I did here (a little more verbous than actually sensible in a forum for Batch scripting).
1. Allow centered placement of image, no stretching?
That's the default in the new code. Option /s can be passed for stretching the image to fit.
Because some area of the background might not be covered by the image (and because we also support transparent image backgrounds) I added option /c where a custom background color can be defined as 6-digit HEX value in format RRGGBB. If /c is ommitted it will default to the background color of the console window (e.g. the color that was previously set using the COLOR command).

2. Background window visible a short time after restoring minimized console window. Minimize background if console window is minimized?
I tried to implement it but this didn't work properly because it's been interferred by SetWindowPos. However, after using SetWinEventHook this issue has been mitigated. I refrained from explicit minimizing and restoring without seeing any difference. The background window appeared a little earlier after restoring but that's rather because the console is delayed by fading in. Making the backgroud fading too would add more complexity than being benefitial IMO. Eventually I found it reasonable to setup a timer which elapses approximately at the same time the console finalizes with fading in. I think this looks sound now.

3. Inelegant polling. Use SetWinEventHook instead?
It took me some time to figure out why I couldn't bind the hook to the console process. It turned out that GetWindowThreadProcessId is a liar. Conhost.exe owns console windows instead of the shell process. Finally I decided to filter the events later on in the callback function. Instead of updating the background once in 20ms, we react now to the desired events. The background follows more smoothly if the console is dragged. And it allows to post a WM_CLOSE instead of just dropping out of the message loop while the background window is still alive. (I'm pretty sure this is still leaking in the latest release.) However, we don't get this for free. The drawback is that the events are fired for every update of the window that the OS is able to make out. This might happen thousands of times per second. In the beginning I faced almost 50% CPU utilization while moving of the window. (Coming from ~5% using the 20ms polling loop for this case.) I had to update the hook callback to process only two kinds of events. And I had to carefully refactor the message loop to ensure we only execute indispensable code. E.g. the update of the image is performed only once in a two-times redraw sequence. And I removed the WS_POPUP branch because I didn't get for what purpose this was in. FWIW I also tried to outsource the event handling into an asynchronous thread. This caused all kind of havoc though. Seems that the events have to be posted to the message queue to get them aligned.
Now it's at ~20% CPU utilization as long as the window is getting moved or resized. Of course, still 0% if you leave the window unchanged. So, this should be acceptable.

All in all I believe the first item adds the only relevant new features for the user. I mean nobody will seriously move, resize, or minimize and restore the window all along :wink:

Syntax:

Code: Select all

Usage: cmdbkg ["file.[bmp|jpg|gif|png]" [/t p] [/c bg] [/b] [/s]]
  /t  Transparency with p = percentage 0..100 (default 33).
  /c  Color of the background with bg = hex value format RRGGBB
      (default is the color of the console buffer's upper left corner
      at the time CmdBkg is called).
  /b  Borders included.
  /s  Stretch to fit.
Specify no arguments to remove previous background.
Specify /? as first argument to see this help message.
Due to the new command line options the syntax isn't downward compatible anymore. Probably it should be released as version 2.0 now.

Steffen
Attachments
cmdbkg_C_source9.zip
(6.95 KiB) Downloaded 11 times

misol101
Posts: 466
Joined: 02 May 2016 18:20

Re: CmdBkg - use bitmap as background to console window

#64 Post by misol101 » 22 Nov 2020 10:43

:lol:

You're on a roll! Well done.

I have very limited time now, will try to make a release next week.

Interesting that using hooks is more cpu-consuming than polling, but the way you describe it makes sense.

aGerman
Expert
Posts: 4008
Joined: 22 Jan 2010 18:01
Location: Germany

Re: CmdBkg - use bitmap as background to console window

#65 Post by aGerman » 22 Nov 2020 14:54

misol101 wrote:
22 Nov 2020 10:43
Interesting that using hooks is more cpu-consuming than polling
Well there's still room for improvements. Inserting the image is just super expensive.

1) The original picture has to be scaled. The larger the picture is, the more bytes have to be processed to calculate the resulting bitmap. The performance could decrease to an extend where the message queue grows because our message loop iterates too slow. To mitigate this we could do two things.
- Check the dimension of the picture after reading the file. If both width and hight are greater then the dimensions of the screen then shrink it once in memory, and use the smaller bitmap for every scaling that needs to be performed afterwards.
- Make the bitmap insertion a thread routine. Skip any draw requests as long as we are still about to draw in the thread. This will keep the message loop iterating, and the window responsive.

2) Drawing the image isn't necessary as long as the window is only moved. There is one exception though. If the window was partially moved across the edges of the screen, the parts of the picture which have been invisible won't get restored. Fortunately we can bind this case to WM_NCPAINT.

Steffen
Attachments
cmdbkg_C_source10.zip
(7.86 KiB) Downloaded 11 times

aGerman
Expert
Posts: 4008
Joined: 22 Jan 2010 18:01
Location: Germany

Re: CmdBkg - use bitmap as background to console window

#66 Post by aGerman » 24 Nov 2020 12:23

OK, one last update because it's not yet realeased. Two improvements:
1) I found a way to get the scaled bitmap back from the DC to reuse it. That way the CPU utilization is still low if the draw request comes from WM_NCPAINT as explained above.
2) I never actually understood why the short delay after WaitForInputIdle was necessary. Now I got it. It's a matter of when we call FreeConsole. That's the trigger for WaitForInputIdle to return. After moving it to the point after the console handle was assigned to the user data of the background window, closing the previous background window works reliable without any further delay.

Steffen
Attachments
cmdbkg_C_source11.zip
(7.9 KiB) Downloaded 8 times

misol101
Posts: 466
Joined: 02 May 2016 18:20

Re: CmdBkg - use bitmap as background to console window

#67 Post by misol101 » 30 Nov 2020 16:13

Archive finally updated (to 2.0). Again, good work :)

I prefer to keep the original behavior of scaling the image. The /s option was removed, instead /c [bg] is now the center option, with optional background color.

aGerman
Expert
Posts: 4008
Joined: 22 Jan 2010 18:01
Location: Germany

Re: CmdBkg - use bitmap as background to console window

#68 Post by aGerman » 30 Nov 2020 16:58

Thank you, Mikael! It was fun to work on it and - as always - I learned something new :)
misol101 wrote:
30 Nov 2020 16:13
The /s option was removed, instead /c [bg] is now the center option, with optional background color.
I love it :!: This is much more intuitive.

Steffen

Post Reply