Prev: How To: CStatubar panel Right-align text
Next: Can I make child frame dock to main frame in MDI?
From: Vertilka on 27 Mar 2010 17:28 I need to create a console application that has a main() function and pop a modeless dialog, so the console can still work in parallel to the modeless dialog (do other work, like communicating with the modeless dialog). Whatever i tried, i could only pop a modal dialog. (where the console is in hold till the modal dialog close itself). When switching to modeless dialog using Create() and ShowWindow() the dialog is displayed without its controls and it freeze / block (you can see the hourglass cursor). 1) I tried to pop the modeless dialog from the main() function: void main() { AfxWinInit(GetModuleHandle(NULL), NULL, GetCommandLine(), SW_SHOW); TestGUI * gui; gui = new TestGUI(); gui->Create(TestGUI::IDD); gui->ShowWindow(SW_SHOW); // just to see if the modeless dialog responses Sleep(10000); } 2) I tried to pop the modeless dialog from the InitInstance() of a CWinApp derived class: extern int AFXAPI AfxWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow); class MyApp : public CWinApp { public: virtual BOOL InitInstance() { gui = new TestGUI(); gui->Create(TestGUI::IDD); gui->ShowWindow(SW_SHOW); return TRUE; } private: TestGUI * gui; }; MyApp my_app; void main() { AfxWinMain(GetModuleHandle(NULL), NULL, GetCommandLine(), SW_SHOW); // just to see if the modeless dialog responses Sleep(10000); } In all cases the modeless dialog freeze. I believe this is a one line solution. Please help. TNX, Vertilka
From: Hector Santos on 27 Mar 2010 20:32 Vertilka wrote: > I need to create a console application that has a main() function and > pop a modeless dialog, so the console can still work in parallel to > the modeless dialog (do other work, like communicating with the > modeless dialog). > void main() > { > AfxWinMain(GetModuleHandle(NULL), NULL, GetCommandLine(), > SW_SHOW); > > // just to see if the modeless dialog responses > Sleep(10000); > } > > In all cases the modeless dialog freeze. > > I believe this is a one line solution. Well, not one line :) A GUI requires a message pump. All GUI applications start with 1 thread called the main process thread and the pump is assigned to this thread. A console application also has 1 thread, the main thread so when you do the SLEEP() it is blocked and nothing else happens. So you have two solutions: 1) You can create a 2nd thread with a window and give it is own message pump. The thread will run on its own independent on the main thread. 2) Instead of blocking in the main thread, you yield with a message pump dispatch, like so: while (1) { MSG msg; while (::PeekMessage(&msg,NULL,0,0,PM_REMOVE)){ ::TranslateMessage(&msg); ::DispatchMessage(&msg); } } However, there is one problem with that. You are a console, the keyboard is your input. So unless the Thread with the WINDOW has a BUTTON to send the EXIT message or set a global flag, where in the loop you will detect the message or global flag, and break out of the loop, without that, the only way to break out is to put a keyboard monitor, like so: #include <conio.h> .... _cprint("* Press ESC to exit\n"); while (1) { if (_kbhit() && _getch() == 27) break; Sleep(75); // <<-- BE FRIENDLY WITH WINDOWS! MSG msg; while (::PeekMessage(&msg,NULL,0,0,PM_REMOVE)){ ::TranslateMessage(&msg); ::DispatchMessage(&msg); } } The low Sleep() is good because without it, the loop is very fast and there is a lot of "context switching" (look up what that means). It otherwise it is CPU expensive. You might see a few CPU % without the sleep because the kbhit checking actually promotes an interrupt so there is some CPU context switching with it. But with the Sleep(75), you will see 0% CPU!!!!!!! You can probably go as high with good sensitivity around 200-400 ms. DO NOT USE SLEEP(0). Have fun. -- HLS
From: Hector Santos on 27 Mar 2010 20:54 Just another technical point. There are other ways to break out of this. For most of my console applications, I prepare a Console Control Handler with the WIN32 API function: SetConsoleCtrlHandler((PHANDLER_ROUTINE)&ConsoleHandler,TRUE); where ConsoleHandler is a call back proc that will detect various signals, like control-c, log off, close from the SysMenu pull down window, etc, allowing to create a graceful shutdown in a console application. Here is a ConsoleHandler call back: HANDLE hExitEvent = NULL; // <<---- SEE BELOW BOOL ConsoleHandler(DWORD dwCtrlType) { switch (dwCtrlType) { case CTRL_C_EVENT: PRINTF("CTRL_C_EVENT\n"); return TRUE; case CTRL_CLOSE_EVENT: PRINTF("CTRL_CLOSE_EVENT\n"); SetEvent(hExitEvent); return FALSE; // TRUE for Windows END TASK popup case CTRL_BREAK_EVENT: PRINTF("CTRL_BREAK_EVENT\n"); SetEvent(hExitEvent); return TRUE; case CTRL_LOGOFF_EVENT: PRINTF("CTRL_LOGOFF_EVENT\n"); SetEvent(hExitEvent); return FALSE; case CTRL_SHUTDOWN_EVENT: PRINTF("CTRL_SHUTDOWN_EVENT\n"); SetEvent(hExitEvent); return FALSE; default: PRINTF("default\n"); SetEvent(hExitEvent); return FALSE; } } The hExitEvent is useful to create a good break out *Kernel Object* signal. So in the LOOP I provided, it will change to to this: hExitEvent = CreateEvent(0, TRUE, FALSE, 0); SetConsoleCtrlHandler((PHANDLER_ROUTINE)&ConsoleHandler,TRUE); _cprint("* Press ESC to exit\n"); while (WaitForSingleObject(hExitEvent,100) != WAIT_OBJECT_0) { if (_kbhit() && _getch() == 27) break; MSG msg; while (::PeekMessage(&msg,NULL,0,0,PM_REMOVE)){ ::TranslateMessage(&msg); ::DispatchMessage(&msg); } } Now you don't need the Sleep(75) because call to: WaitForSingleObject(hExitEvent,100) is the most *efficient* form of synchronization and waiting for events to occur in Windows! The 100 says wait for 100ms for the hExitEvent to be signal which is done by the SetEvent() in the control handler. When its not signaled, windows will return with a timeout result (WAIT_TIMEOUT) and the loop continues allowing you to check for the keyboard and do the messages pumping for the GUI. So while Sleep(75) works, using a Kernel Object to wait on something is better under windows. Its like saying "Sleep Until the time expires or until something Happens." -- HLS Hector Santos wrote: > Vertilka wrote: > >> I need to create a console application that has a main() function and >> pop a modeless dialog, so the console can still work in parallel to >> the modeless dialog (do other work, like communicating with the >> modeless dialog). >> void main() >> { >> AfxWinMain(GetModuleHandle(NULL), NULL, GetCommandLine(), >> SW_SHOW); >> >> // just to see if the modeless dialog responses >> Sleep(10000); >> } >> >> In all cases the modeless dialog freeze. >> >> I believe this is a one line solution. > > Well, not one line :) > > A GUI requires a message pump. All GUI applications start with 1 thread > called the main process thread and the pump is assigned to this thread. > > A console application also has 1 thread, the main thread so when you do > the SLEEP() it is blocked and nothing else happens. > > So you have two solutions: > > 1) You can create a 2nd thread with a window and give it is own message > pump. The thread will run on its own independent on the main thread. > > 2) Instead of blocking in the main thread, you yield with a message pump > dispatch, like so: > > while (1) { > MSG msg; > while (::PeekMessage(&msg,NULL,0,0,PM_REMOVE)){ > ::TranslateMessage(&msg); > ::DispatchMessage(&msg); > } > } > > However, there is one problem with that. > > You are a console, the keyboard is your input. So unless the Thread > with the WINDOW has a BUTTON to send the EXIT message or set a global > flag, where in the loop you will detect the message or global flag, and > break out of the loop, without that, the only way to break out is to put > a keyboard monitor, like so: > > #include <conio.h> > > .... > > _cprint("* Press ESC to exit\n"); > while (1) { > if (_kbhit() && _getch() == 27) break; > > Sleep(75); // <<-- BE FRIENDLY WITH WINDOWS! > > MSG msg; > while (::PeekMessage(&msg,NULL,0,0,PM_REMOVE)){ > ::TranslateMessage(&msg); > ::DispatchMessage(&msg); > } > } > > The low Sleep() is good because without it, the loop is very fast and > there is a lot of "context switching" (look up what that means). It > otherwise it is CPU expensive. You might see a few CPU % without the > sleep because the kbhit checking actually promotes an interrupt so there > is some CPU context switching with it. But with the Sleep(75), you will > see 0% CPU!!!!!!! You can probably go as high with good sensitivity > around 200-400 ms. DO NOT USE SLEEP(0). > > Have fun. > -- HLS
From: Joseph M. Newcomer on 27 Mar 2010 22:04 I'm curious why you need a "console application" AND a modeless dialog. You have not really stated the rationale for this. Key here is that you have no message pump. To be honest, this is one of the very few weird and exotic situations where I would consider launching a secondary thread, using AfxBeginThread for a UI thread, and let the UI thread launch the modeless dialog. Any UI components would be in this one-and-only window-owning UI thread. It is not clear what you gain by building a console app. joe On Sat, 27 Mar 2010 14:28:52 -0700 (PDT), Vertilka <vertilka(a)gmail.com> wrote: >I need to create a console application that has a main() function and >pop a modeless dialog, so the console can still work in parallel to >the modeless dialog (do other work, like communicating with the >modeless dialog). > >Whatever i tried, i could only pop a modal dialog. (where the console >is in hold till the modal dialog close itself). > >When switching to modeless dialog using Create() and ShowWindow() the >dialog is displayed without its controls and it freeze / block (you >can see the hourglass cursor). > >1) I tried to pop the modeless dialog from the main() function: > >void main() >{ > AfxWinInit(GetModuleHandle(NULL), NULL, GetCommandLine(), >SW_SHOW); > > TestGUI * gui; > gui = new TestGUI(); > gui->Create(TestGUI::IDD); > gui->ShowWindow(SW_SHOW); > > // just to see if the modeless dialog responses > Sleep(10000); >} > >2) I tried to pop the modeless dialog from the InitInstance() of a >CWinApp derived class: > >extern int AFXAPI AfxWinMain(HINSTANCE hInstance, > HINSTANCE hPrevInstance, > LPTSTR lpCmdLine, int nCmdShow); > >class MyApp : public CWinApp >{ >public: > virtual BOOL InitInstance() > { > gui = new TestGUI(); > gui->Create(TestGUI::IDD); > gui->ShowWindow(SW_SHOW); > > return TRUE; > } > >private: > TestGUI * gui; >}; > >MyApp my_app; > >void main() >{ > AfxWinMain(GetModuleHandle(NULL), NULL, GetCommandLine(), >SW_SHOW); > > // just to see if the modeless dialog responses > Sleep(10000); >} > >In all cases the modeless dialog freeze. > >I believe this is a one line solution. >Please help. > >TNX, >Vertilka Joseph M. Newcomer [MVP] email: newcomer(a)flounder.com Web: http://www.flounder.com MVP Tips: http://www.flounder.com/mvp_tips.htm
From: Vertilka on 28 Mar 2010 04:11 Well, This is a realtime software, it works againt an hardware. There is a special mode where you can debug the hardware. a GUI is a good way to interact with the user, in contrary to using a command line. Developing the GUI is easy with .NET but the marsheling is a quite an overhead, thats why i tried MFC.
|
Next
|
Last
Pages: 1 2 Prev: How To: CStatubar panel Right-align text Next: Can I make child frame dock to main frame in MDI? |