?
Solved

Change DOS Font size programatically

Posted on 2003-03-03
16
Medium Priority
?
720 Views
Last Modified: 2013-12-03
I am using Windows NT currently, though we may upgrade to XP in a year or so.
In the properties of a running DOS prompt, there is a Font tab, which allows you to change the size and type of font, and immediately apply this to the current window. The changes are applied during runtime.

Now the DOS application we have made can change its columns from 80 to 132 depending on what information we need to display, however, when we change to width 132, the window takes up considerably more area than we want it to (80->132 is more than half again the original window width). We'd prefer instead to decrease the font size, and keep the window size about the same.

So, the question is, how can we programatically change the font size/font of a DOS application during runtime?
0
Comment
Question by:Crius
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
16 Comments
 
LVL 86

Expert Comment

by:jkr
ID: 8058396
You can read and alter all the console settings under HKEY_CURRENT_USER\Console\ - note that there might be subkeys specifying settings that belong to certain console mode executables.
0
 
LVL 3

Author Comment

by:Crius
ID: 8058449
Will this work while the console app is running? I don't want to have to restart the console app to get these changes since this width change is dynamic within the console app itself.

Typically, changing registry settings requires at least a program restart, if not, a windows restart. Would I need anything else to effect the change without restarting the console app?
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 8063347
It seems possible... after all, one can press

 Alt+Shift+Space
 P
 Alt+S
 8
 Enter
 Enter

and set the font size to Lucida 8 pt immediately.

But I can't locate any API access to those interal settings (You already know about HKCU/Console/<console name> in the registery.

As one thing to try:  I monitored the registry while doing that sequence above and I noticed one odd thing... it seems the console handler does a GetConsoleOuputCP() followed by a SetConsoleOutputCp().  It also sets HKCU/Console/CurrentPage to a dword value of 0x01 (even though it is already set at that) These actions may trigger the system to re-examine registery settings.
=-=-=-=-=-=-=-=-
If nothing else works, you could try GetConsoleHWND and post a series of keystrokes as described above.
=-=-=-=-=-=-=-=-
And finally, I hope that you know that what you are doing is completely foolish.  If you want font control, you should use this wonderful thing called the Windows GUI.

-- Dan
0
Microsoft Certification Exam 74-409

Veeam® is happy to provide the Microsoft community with a study guide prepared by MVP and MCT, Orin Thomas. This guide will take you through each of the exam objectives, helping you to prepare for and pass the examination.

 
LVL 3

Author Comment

by:Crius
ID: 8065105
I too was unable to find any API anywhere. I will try this method today to see if it works.

And yes, I know this *seems* completely foolish, but the program exists, and has existed for about 18 years, and originally on the Vax (CHUI). It is far easier to do this foolish thing than to try to convert the entire CHUI interface to a GUI interface. :)
0
 
LVL 3

Author Comment

by:Crius
ID: 8067421
Fooling with the registry (within the app), then setting the OutputCP to itself, and setting the CurrentPage to 1 did not alter the font in any way. I've confirmed that the settings are correct, and do take place when the application is restarted.

Any other possible methods?

     unsigned char WorkCharStr[100];
     unsigned long WorkLong = 100;
     HKEY hKey;
     
     RegOpenKeyEx(HKEY_CURRENT_USER,
         TEXT("Console\\D:_dvl_TESTAPP_Debug_TESTAPP.exe"),
         0,
         KEY_QUERY_VALUE,
         &hKey);
     
     RegQueryValueEx(hKey,
         TEXT("FaceName"),
         NULL,
         NULL,
         WorkCharStr,
         &WorkLong);
     if(strcmp((char *)WorkCharStr, "Lucida Console"))
         strcpy((char *)WorkCharStr, "Lucida Console");
     else
         strcpy((char *)WorkCharStr, "Andale Mono");
     
     RegCloseKey(hKey);

     RegOpenKeyEx(HKEY_CURRENT_USER,
         TEXT("Console\\D:_dvl_TESTAPP_Debug_TESTAPP.exe"),
         0,
         KEY_SET_VALUE,
         &hKey);

     RegSetValueEx(hKey,
         TEXT("FaceName"),
         NULL,
         REG_SZ,
         WorkCharStr,
         strlen((char *)WorkCharStr)+1);
     
     RegCloseKey(hKey);

     SetConsoleOutputCP(GetConsoleOutputCP());
     
     RegOpenKeyEx(HKEY_CURRENT_USER,
         TEXT("Console"),
         0,
         KEY_SET_VALUE,
         &hKey);
     strcpy((char *)WorkCharStr, "1");
     RegSetValueEx(hKey,
         TEXT("CurrentPage"),
         NULL,
         REG_DWORD,
         WorkCharStr,
         strlen((char *)WorkCharStr)+1);
     
     RegCloseKey(hKey);
0
 
LVL 3

Author Comment

by:Crius
ID: 8067520
Oh, before I forget, I don't see how PostMessaging the keys will work either since as soon as you hit Alt+Shift+Space, that triggers a menu, and from a previous question we both tried to answer, you know how difficult life gets when that happens. The menu triggers a modal-like loop and no more code can run to push keys or buttons. Worse, it's on another window, so we'd have to get that window handle too, which opens the property window, which we'd have to get, and interact with... Basically, the focus changes are horrible, and even if we could do all this, if the user had another properties window open somewhere, we might operate on it instead, and Boom! Face explosion.
0
 
LVL 3

Author Comment

by:Crius
ID: 8068198
The ideal solution would be to simulate the "Apply properties to current window only" button. But simulating either button is fine.
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 8068388
A quick check with Spy++ showed that the Owner window for the "Command Prompt Properties" window is the console window, so knowing the HWND of the console, it should be easy to identify which of these windows to direct the keystrokes (and to be honest, don't you think it would be rather unusual to have several console property sheets open simultaneously?).  

>>and from a previous question we both tried to answer
I don't recall the question

Also PostMessage is asynchronous.  You can pile up a bunch of them and the target window will fetch them in the order in which they were posted.

-- Dan
0
 
LVL 3

Expert Comment

by:Da_Weasel
ID: 8078779
There is a very limited set of Console APIs available.

SetConsoleTextAttribute is the only thing I know of, and this only work for data output by the WriteConsole API, and a couple others.

Your best bet is to use the registry settings to modify the look.
0
 
LVL 3

Author Comment

by:Crius
ID: 8081005
I already checked that API, but all out text output is with printf and similar functions. :( This is why I put 300 points into this rather tough question.

I'll wait a bit for another option, because unless I can cause the console to reload at runtime, it's not going to work.

I also fear posting keystrokes since dialogs do popup (it's a really bad hack at best), and I don't believe it'll work. Has anyone tried doing it?
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 8083962
This looks promising:  The VB documentation for the OLEObject object that I found under the RichTextBox control dox:

   http://msdn.microsoft.com/library/en-us/rtfbox98/html/vbobjOLEObjectObjectOLEObjectsCollection.asp

It appears to have properties such as Height and Width and methods such as DoVerb.

-- Dan
0
 
LVL 3

Author Comment

by:Crius
ID: 8084081
I'm sorry, you've gotten me a bit confused.. DOS doesn't support OLE objects... Which are, things like pictures, activeX controls, et al.

Could you please help me out with your train of thought?
0
 
LVL 49

Expert Comment

by:DanRollins
ID: 8084423
Well that explains twhat happened to tha other post.  Sorry... wrong window.
-- Dan
0
 
LVL 3

Author Comment

by:Crius
ID: 8084495
No problem. :)

I guess I should explain why I feel PostMessage won't work...
When you open up a menu, the menu starts a new non-message processing loop as it waits for you to either select a menu item, or close the menu. If you don't believe me, try to move the cursor to the menu down 1 by simulating keypresses. It won't work.

You and I (Dan) tried to answer someone else's question as to how they could change the default menu item, so it would select something other than the top menu item. We couldn't do it. I'm pretty sure that question is still open somewhere, but since search is disabled, I can't find it.

Since we Posted a message, and that message opened the menu, we can assume that the second message we posted would be handled by that same thread. So, it would never get to the second message because the thread would be stuck in this menu processing loop. We'd be stuck basically, until the user either closed the menu, or picked an item, at which point, the next message would likely be processed.
0
 
LVL 49

Accepted Solution

by:
DanRollins earned 1200 total points
ID: 8084884


#include <windows.h>

//----------------------- this fn from MSDN ID: Q124103
HWND GetConsoleHwnd(void)
{
     #define MY_BUFSIZE 1024 // Buffer size for console window titles.
     HWND hwndFound;         // This is what is returned to the caller.
     char pszNewWindowTitle[MY_BUFSIZE]; // Contains fabricated WindowTitle.
     char pszOldWindowTitle[MY_BUFSIZE]; // Contains original WindowTitle.

     // Fetch current window title.
     GetConsoleTitle(pszOldWindowTitle, MY_BUFSIZE);

     // Format a "unique" NewWindowTitle.
     wsprintf(pszNewWindowTitle,"%d/%d", GetTickCount(),GetCurrentProcessId() );
     SetConsoleTitle(pszNewWindowTitle); // Change current window title.
     Sleep(40); // Ensure window title has been updated.
     hwndFound=FindWindow(NULL, pszNewWindowTitle); // Look for NewWindowTitle.
     SetConsoleTitle(pszOldWindowTitle); // Restore original window title.
     return(hwndFound);
}


void main()
{
     HWND  hwndCon= GetConsoleHwnd();
     HMENU hmnuCon= GetSystemMenu( hwndCon, FALSE /*fRevert*/ );

     char szBuf[100];
     MENUITEMINFO rMII;
     rMII.cbSize= sizeof( rMII );
     rMII.fMask= MIIM_STRING;
     rMII.dwTypeData= szBuf;

     BOOL fRet= GetMenuItemInfo(hmnuCon, 9, TRUE, &rMII ); // item 9 in the menu
 
     if ( strcmp( szBuf, "&Properties") != 0 ) {
          ::MessageBox( hwndCon, "woopsiedaisy","OOPS!", MB_OK );
     } else {
          ::MessageBox( hwndCon, "found Properties item in the Menu" ,"KEWL!", MB_OK );
     }

     rMII.fMask= MIIM_ID;
     fRet= GetMenuItemInfo(hmnuCon, 9, TRUE, &rMII );

     SendMessage( hwndCon, WM_SYSCOMMAND, rMII.wID, 0 );
     Sleep(1000); // give it some time
     ... here you could find the prop dlg windo and post some keystroks
        .... (hint" ALT+S, '8', Enter, wait, Enter)
     
     ::MessageBox( hwndCon, "...waiting...","KEWL!", MB_OK );
}

-- Dan
0
 
LVL 3

Author Comment

by:Crius
ID: 8130195
After mentioning the only way we could come up with would cause the dialog to pop up, and be manipulated, it was decided it'd be better to just not have the ability. The smallish project was cancelled, and I don't know if this code will work or not, but, I guess my problems are gone one way or the other.

It looks like, by triggering the menu item directly, we avoid the modal loop caused when you bring up a menu, so, chances are this code will work - although since the properties dialog window would be visible, and could be affected by the user while the code is using the dialog, it is a pretty bad hack. Still, it may be there is no one outside of Microsoft who knows how to do it in a better way.
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

zlib is a free compression library (a DLL) on which the popular gzip utility is built.  In this article, we'll see how to use the zlib functions to compress and decompress data in memory; that is, without needing to use a temporary file.  We'll be c…
After several hours of googling I could not gather any information on this topic. There are several ways of controlling the USB port connected to any storage device. The best example of that is by changing the registry value of "HKEY_LOCAL_MACHINE\S…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
If you’ve ever visited a web page and noticed a cool font that you really liked the look of, but couldn’t figure out which font it was so that you could use it for your own work, then this video is for you! In this Micro Tutorial, you'll learn yo…

777 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question