Click here to Skip to main content
Click here to Skip to main content

Using dialogs in console apps

By , 23 May 2000
 

Introduction

Traditionally, the world has been divided into two kinds of apps, and ne'er the twain shall meet: Console applications and GUI applications. (Actually, if you write a console app that talks to a scanner, and a GUI app that talks to a scanner, they both meet the TWAIN...)

Strictly speaking, this separation has not been true. A console app can presumably create a message loop and pop up windows; a GUI app can create and attach a console. But these are considered major pieces of effort.

A popular reason GUI apps seem to want to create consoles is to have a logging window to which debug output can be written. I solved this problem years ago with a technology that has evolved into a fairly sophisticated set of MFC classes, my Logging ListBox class.

However, last week a client contacted me. He needed the ability to handle a MessageBox from a console app, and I had everything working with one little, but showstopper, glitch: I couldn't find any API that gave me a handle to the window in which the console app was running.

So I did the obvious thing: I posted the question on the microsoft.public.vc.mfc newsgroup where I hang out. Sure enough, David Lowndes replied within minutes with the solution, which I have incorporated into the answer below. Thanks, and a Tip Of The Flounder Fin to David.

David's suggestion was to use SetConsoleTitle to set a window title for the window, then use FindWindow to find it. In order to guarantee the name is unique, he also suggested using a GUID (my favorite technique) for the window name, since that guarantees that no other window will have that name!

HWND FindConsoleHandle()
{
   static LPCTSTR temptitle = _T("{98C1C303-2A9E-11d4-9FF5-006067718D04}");
   TCHAR title[512];
   if(GetConsoleTitle(title, sizeof(title)/sizeof(TCHAR)) == 0)
      return NULL;
   SetConsoleTitle(temptitle);
   HWND wnd = FindWindow(NULL, temptitle);
   SetConsoleTitle(title);
   return wnd;
}

To invoke the MessageBox, just use the HWND returned from this function as the HWND for the parent window.

For example, I am now able to execute the following in a plain-vanilla console app:

int response = MessageBox( FindConsoleHandle(), 
                           _T("File read error, continue?"), 
                           _T("File Error"), 
                           MB_ICONERROR | MB_YESNO);

Be sure to replace the GUID above with a GUID of your own that you get from GUIDGEN; otherwise you lose the desired uniqueness.

This should work equally well for operations like standard dialogs such as File Open, File Save, and even custom dialogs of your own. Note that it won't work for modeless dialogs, because they don't have their own message pump.


The views expressed in these essays are those of the author, and in no way represent, nor are they endorsed by, Microsoft.

Send mail to newcomer@flounder.com with questions or comments about this web site.
Copyright © 1999 CompanyLongName All Rights Reserved.
www.flounder.com/mvp_tips.htm

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Joseph M. Newcomer
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralThere is always an easier waymemberbdawson@newcorp.com22 Feb '06 - 8:26 
Here is the easiest code you will ever need.
 
Add the following function definition to your code:
 
extern "C" WINBASEAPI HWND WINAPI GetConsoleWindow();
Make sure the kernel32.lib is included in your project.
 
Now just do this:
 
HWND hwConsole = GetConsoleWindow();
 
Badabing badabang
General? What about the other way aroundmemberSynetech4 Dec '03 - 18:18 
Hi,
 
I've got the opposite problem, I've got an MFC Dialog app and I need a way of printing stuff when the app is executed from the console. Specifically, if it is executed with no parameters, the dialog pops up, but if there are parameters, then it just processes them without bringing up the dialog. For example, opening a command prompt and typing "blah.exe /?" should print the parameters like a console app would do.
 
How can I do that? Confused | :confused:
 
thanks.

--
FireBox @ Synetech

GeneralLet me know too, please!sussAnonymous3 Apr '04 - 2:44 
Man, if someone finds a way to output to the console if the user passes in a help switch (to an MFC Dialog app), let me know as well!
Cheers,
Tony.

GeneralRe: Let me know too, please!memberbaker_tony3 Apr '04 - 2:46 
Bah, I didn't log in when I posted that message!
email is "baker_tony AT hotmail.com"
GeneralRe: ? What about the other way aroundmemberJoseph M. Newcomer3 Apr '04 - 7:13 
As far as I know, this is not possible. GUI apps are GUI apps and console apps are console apps. There is a bit in the .exe header that determines what subsystem runs them
GeneralRe: ? What about the other way aroundmemberWasteland76 May '04 - 21:24 
Yes, if you've noticed when you run a GUI app from the console it *immediately* detaches from the console, as opposed to console applications that wait until they are finished before returning control to the console. Your best bet would be to have your application be a console application that immediately hides it's console window (don't forget to unhide it when you exit!) and then starts into your main loop. Most programs just pop up a dummy graphical box with the command line parameters (try runnig MSVC's "devenv.exe /?" to see what I mean) and then exit.
GeneralRe: ? What about the other way aroundmembercowsonfire22 Feb '06 - 1:42 
http://cowsonfire.com/runtest.cpp
GeneralBeeter way to get HWND of parentmemberMLoibl16 Feb '01 - 8:00 
the following code -sniplet does NOT change any title and is not independent of any UUIDs!
 
HWND hwndNext,
hWindow;
DWORD dwID,
dwIDWe;
 

/* find window */
dwIDWe = GetCurrentProcessId();
hwndNext = GetWindow(GetDesktopWindow(), GW_CHILD);
while (hwndNext != NULL)
{
GetWindowThreadProcessId(hwndNext, &dwID);

if( dwID == dwIDWe )
{
hWindow = hwndNext;
break;
}
 
hwndNext = GetWindow(hwndNext, GW_HWNDNEXT);
}
 
/* find parent */
if( hWindow )
{
hwndNext = hWindow;
while( hWindow )
hWindow = GetWindow(hWindow, GW_OWNER);

if( !hWindow )
hWindow = hwndNext;
}
 

in hWindow the handle is stored !!
Generala missing thingmemberMLoibl16 Feb '01 - 22:58 
Initialize hWindow first:
HWND hwndNext,
hWindow = NULL;

GeneralRe: Beeter way to get HWND of parentmemberLim Bio Liong8 Jan '02 - 20:07 
Hello MLoibl,
 
I think your alternative code is good and will work for GUI apps and console apps that are launched from Explorer or the Desktop. However, if you open up a command prompt and start your console app from there, the algorithm will not help to find the Command Prompt's console window.
 
This is because the Command Prompt Console Window is not a window of our   console app. In Windows NT, the Command Prompt Console Window is a window generated from the Console Sub-System Process.
 
Our own console app does not own this window and so (in your algorithm above), the final value in "hWindow" will be NULL.
 
Regards,
Bio.

GeneralRe: Beeter way to get HWND of parentmemberWasteland76 May '04 - 21:20 
The best/most reliable solution is to:
   a) set the console window title to some unique *per process* not per application, otherwise starting two at the same time will cause them to both find the same window!   A string like "<insert UID>:<GetCurrentProcessId()>" will guarantee no two instances grab the same window accidentally.
   b) retry on failture!   The FindWindow call sometimes fails to find the window on the first or second try as apparently the act of changing the console window gets put in a queue somewhere and might not be finished by the time you call FindWindow!
 
I have a load testing console program that needed it's HWND, and ran into both of these issues when spawning hundreds of console applications at the same time, and even then it was only 1 in thousands that managed to hit just the right race conditions, so chances are you won't need to do either of these for your average app. =)
GeneralYou don't need all this codesusslandshark7 Jun '00 - 3:55 
Why not just call:
MessageBox(NULL, "foo", "bar", MB_OK);
works for me..
GeneralRe: You don't need all this codesussGene18 Jul '00 - 7:34 
If you do that (NULL parent), then the user can select either the console window, or the dialog. With the proper parent, then the console window will be disabled when the messagebox is active
GeneralEast is east...sussRavi Bhavnani6 Jun '00 - 9:18 
> they both meet the TWAIN...
 
Very punny!
 
/ravi
 
"There is always one more bug..."
http://www.ravib.com
ravib@ravib.com
GeneralRe: dialogs in console appssussGisle Vanem24 May '00 - 22:05 
I'm not sure I would be happy with having messageboxes
popping up in a full-screen console application. One
should atleast check if the console is in full screen
before doing it. And what about using those apps in scripts?
Error/warnings should IMHO go to a log-file instead

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130516.1 | Last Updated 24 May 2000
Article Copyright 2000 by Joseph M. Newcomer
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid