• Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 324
  • Last Modified:

Making an .exe modal when launched from another .exe in C++

I have a couple C++ apps.   One is coded with C++, using VC6.  The other app is also coded with C++, using VS2005.

Let's call them App_A and App_B, respectively.

Both of these apps contain a user interface.

I want to launch App_B from App_A.  And I want App_B to behave modally, in that, I want App_A's interface to be "disabled" while App_B is open.  Only When App_B is closed should App_A once again become enabled.

So far I can launch App_B successfully from App_A, using CreateProcess(....).  I also can get App_B to behave "modally" by calling WaitForSingleObject(pi.hProcess, INFINITE) immediately after launching it with CreateProcess(....).  However, I've found that if I click on the menu bar in App_A when App_B is open, then App_A displays the classic windows "(Not Responding)" message in its title bar, giving the appearance of a crash in progress (menu bar becomes white and menu text is obscured).

Any thoughts on how to tighten this up?  I feel like I'm 95% there.

Thanks very much.

0
cjm20
Asked:
cjm20
3 Solutions
 
AndyAinscowCommented:
Hide App_A (ShowWindow(HWND_ofMainWndHere, SW_HIDE)) whilst App_B is running then reshow afterwards - SW_SHOW in place of SW_HIDE.
0
 
cjm20Author Commented:
I would very much like to keep App_A in the background.  Sorry for not specifiying that in the initial question. The reason being is that there are graphics in App_A that are useful to see while using App_B.
0
 
cjm20Author Commented:
Perhaps instead of ShowWindow(...), I could use EnableWindow(HANDLE_App_A, FALSE)?
0
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
AndyAinscowCommented:
I think it isn't going to be easy.
I might be wrong but I suspect you will have to disable all functionality of App_A rather than using the blocking Wait... call.  Which of course means you need to know when App_B finishes so you can re-enable everything afterwards.  (Start App_B via a thread so you can block that with a wait then use events to falg App_A that App_B is finished).
0
 
jkrCommented:
'WaitForSingleObject()' is a good approach, but in order to keep the UI functional, you'll need more, e.g.
while   (   WAIT_OBJECT_0   !=  MsgWaitForMultipleObjects   (   1,
                                                                   &pi.hProcess,
                                                                   FALSE,
                                                                   INFINITE,
                                                                   QS_ALLINPUT
                                                               )
           )
           {
               while   (   PeekMessage (   &msg,   NULL,   0,  0,  PM_REMOVE))
                       {

                           // in 'FilterMessage()' you'll check for messages that activate your app and discard them
                           if (FilterMessage(&msg)) DispatchMessage     (   &msg);
                       }
           }

Open in new window

0
 
AndyAinscowCommented:
You could just try the EnableWindow call but you still might run into redrawing problems if you occlude part of App_A then show it again.
0
 
ZoppoCommented:
Hi cjm20,

this happens because the WaitForSingleObject blocks the calling thread so the application cannot proceed any windows messages until the App_B terminates.

One way to implement what you want could be something like this:
- Create the process from App_A and store the new process's handle (pi.hProcess) somewhere where the main window class from App_A can access it
- After creating the process create a timer in App_A which is i.e. called every 10 ms
- Then disable the main window from App_A with EnableWindow( FALSE )
- In the timer message handler (or callback function) check whether App_B is still running (see below)
- If you detected App_B isn't running anymore in App_A remove the timer and enable the main window again with
EnableWindow( TRUE )

Open in new window


To detect if the process App_B is running in the timer you can use i.e.
...
if ( WaitForSingleObject( hProcess, 0 ) != TIMEOUT )
{
 // the process has terminated
}
...

Open in new window

Hope that helps,

ZOPPO
0
 
cjm20Author Commented:
Thanks to everyone for assisting.  I tried the above approaches, but finally decided to convert App_B from an .exe to a .dll.  This allows me to call the dll from App_A, and within the dll, call the dialog I need to display AS MODAL.  Thus, App_B now has all the normal modal functionality i'm looking for (App_A is disabled while using App_B, App_A is still visible while using App_B, etc).

To call App_B as a dll, I used the following approach (in case anyone is interested, this is the logic to call the dll from the calling application, aka App_A in my case -- i've omitted the error checking to make this concise):

m_hLibMyDll = LoadLibrary("MyDll.dll");

if (m_hLibMyDll != NULL)
{
m_lpfnMyDllFunction = (LPFNDLLFUNC)GetProcAddress(m_hLibMyDll , "MyDllExportedFunction");

int nOK = m_lpfnMyDllFunction ();

//process the dll return value, as necessary

}

As far as converting App_B to a dll, I simply created a new project in Visual Studio.   The new project is an "MFC Dll".  Then I added my preexisting files from my App_B project (which is an .exe) in the dll project.  Finally, as I've always had issues trying to copy / import dialogs and resources from one project to another, I recreated manually in the dll project the one and only dialog that exists in my App_B .exe project.  Once I had created (using the Class Wizard) a dialog class for it, I then copied the dialog code from App_B's MyDialog class into the dll's newly created MyDialog class.
0
 
cjm20Author Commented:
Just to clarify, when I said in the above comment "This allows me to call the dll from App_A, and within the dll, call the dialog I need to display AS MODAL", I meant this allows me to simply used the dlg.DoModal() functionality as provided by the CDialog class.  Thus, the dialog that was formerly inside App_B (but is now in a dll) can behave modally when called from App_A.
0

Featured Post

Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

Tackle projects and never again get stuck behind a technical roadblock.
Join Now