Link to home
Start Free TrialLog in
Avatar of arunykand
arunykandFlag for United States of America

asked on

C++ console app - window on top

I have a C++ console app in VS2005 and from within the app, I make a call to run a standalone executable, and I really want this app to run in the background or minimized and not take focus away from my console app.  I have tried a bunch of different methods (See code below) to accomplish what I needed, but it seems to be a no-go.  The standalone executable seems to take focus away from my console app, or not starting minimized.  

Any help would be greatly appreciated.

Method 1:

system("C:\\StartEasySuite.bat");
Batch file contains: start /min c:\test\EasySuite.exe

Method 2:
WinExec("C:\\test\\EasySuite.exe",SW_FORCEMINIMIZE);

Method 3:

STARTUPINFO         siStartupInfo;
PROCESS_INFORMATION piProcessInfo;

memset(&siStartupInfo, 0, sizeof(siStartupInfo));
memset(&piProcessInfo, 0, sizeof(piProcessInfo));
siStartupInfo.cb = sizeof(siStartupInfo);
		
BOOL bSuccess;


bSuccess = CreateProcess(TEXT("C:\\Test\\EasySuite.exe"),    
                     0,						 
                     0,
                     0,
                     FALSE,
                     NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW ,
                     0,
                     0,                              
                     &siStartupInfo,
                     &piProcessInfo) ; 

Open in new window

Avatar of jkr
jkr
Flag of Germany image

You're on the right track - make that
siStartupInfo.cb           =   sizeof(STARTUPINFO);
	siStartupInfo.dwFlags      =   STARTF_USESHOWWINDOW;
	siStartupInfo.wShowWindow  =   SW_HIDE;

Open in new window


Or use this shrink-wrapped function that does that for you and waits until the called app finishes:
DWORD ExecuteAndWaitForCompletion   (   LPSTR   pszCmd, BOOL bShow)
{
	STARTUPINFO         si;
	PROCESS_INFORMATION pi;

	BOOL                bRes;

	DWORD               dwCode  =   0;

	MSG				   msg;

	ZeroMemory  (   &si,    sizeof  (   STARTUPINFO));

	si.cb           =   sizeof  (   STARTUPINFO);
	si.dwFlags      =   STARTF_USESHOWWINDOW;
	si.wShowWindow  =   bShow ? SW_SHOWNORMAL : SW_HIDE;

	bRes    =   CreateProcess   (   NULL,
								   pszCmd,
								   NULL,
								   NULL,
								   TRUE,
								   NORMAL_PRIORITY_CLASS,
								   NULL,
								   NULL,
								   &si,
								   &pi
							   );

	while   (   WAIT_OBJECT_0   !=  MsgWaitForMultipleObjects   (   1,
																   &pi.hProcess,
																   FALSE,
																   INFINITE,
																   QS_ALLINPUT
															   )
		   )
		   {
			   while   (   PeekMessage (   &msg,   NULL,   0,  0,  PM_REMOVE))
					   {
						   DispatchMessage     (   &msg);
					   }
		   }

	GetExitCodeProcess  (   pi.hProcess,    &dwCode);

	CloseHandle (   pi.hProcess);
	CloseHandle (   pi.hThread);

	return  (   dwCode);
}

Open in new window

As a side note, 'SW_HIDE' is the key here. Oh, BTW, other alternatives would be
WinExec("C:\\test\\EasySuite.exe",SW_HIDE);

ShellExecute(NULL,"open","C:\\test\\EasySuite.exe",NULL,NULL,SW_HIDE);

Open in new window

Avatar of arunykand

ASKER

JKR....I'm still playing around with your suggestions..I cannot get any of them to work as expected, my window loses focus and the other software is shown, even when SW_HIDE is implemented.

FYI...my app is a full-screen console app (not GUI) that was created in c++ using 'CreateWindow', I didn't write this code, but in-herited.

g_hWnd = CreateWindow(WINDOW_CLASS_NAME, 0,
                         WS_VISIBLE |WS_POPUP | CS_DBLCLKS ,
                         CW_USEDEFAULT, CW_USEDEFAULT,
                         DEFAULT_VIDEO_WIDTH, DEFAULT_VIDEO_HEIGHT,
                         0, 0, g_hInstance, 0);

Open in new window

That is more than weird. Can you double-check that with e.g. 'notepad.exe'?
Hmm, I tried notepad, and works as intended.....

This software i'm trying to invoke from my app is called "EasySuite" from Targus.  It comes pre-loaded on their USB File Share cable http://http://www.staples.com/Targus-Data-SYNC-Cable/product_857875?cmArea=SC3:CG58:DP1426:CL164417  and it is supposed to 'Autorun' when inserted, but since auto-run was disabled on the PC due to security reasons, I thought I would invoke it, and have it minimized.  

Any ideas?
Well, if an application choses not to obey the 'int nCmdShow' parameter passed in to 'WinMain()', there's hardly anything you can do other to complain that the program does not behave the way the Windows style guides require it. Another option would be (albeit the last resort) to start it on an invisible desktop...
Ooops, another idea - try to set 'dwX' and/or 'dwY' in STARTUPINFO to positions outside your visible screen area and use 'STARTF_USEPOSITION' in 'dwFlags' - that could also work.
Hmm...Ok i'm not sure how to proceed...My issue is, when this pc boots, it does an auto-login and starts up my software (full-screen, command window program), I've replaced the explorer shell with my software, so even if the user tries to exit, there will be no desktop, they just have to do a log-off or shutdown via ctrl-alt-del.  So to get back to my point, when my software is running in full screen mode, one of the options is to have this "EasySuite" software invoked, and run in the background, but as you can see, I haven't had much luck today!

I just saw your comments about screen position, but I think the issue will be, I will still lose focus away from my app, but now I just won't be able to see the "EasySuite" software, still back to the same issue as before....
>>I haven't had much luck today!

Don't say that, the 'invisible desktop' way will certainly work, but I'd certainly try the other way outlined in my last comment first ;o)
Is it somehow possible to run the EasySuite software as a service....I'm out of ideas, just throwing it out there...
ASKER CERTIFIED SOLUTION
Avatar of jkr
jkr
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
So going back to the position comment you made, 0 0 is top left right?  What do I need to put in to take it out of my screen?  

Jkr, I appreciate the help
Yes, that's right - yet I assume the 'focus' issue would remain. I'd try something ridiculpusly high for testing purposes, e.g. ix you have 1600x1200, try to set

siStartupInfo.dwX = 3200;
siStartupInfo.dwY = 0;
I will give that a shot first thing in the morning.  Fyi....I went out and bought a different brand of usb databtransfer cable with built in software and unfortunately the software is the same used by targus
>> FYI...my app is a full-screen console app (not GUI) that was created in c++ using 'CreateWindow', I didn't write this code, but in-herited.
I'm a bit confused. CreateWindow is called for GUI apps, not for console apps.
Do you mean your app looks like a terminal? (just like putty or the like)

Besides this, what about this idea:

1) launch child process
2) wait the creation of the main window
3) once created, hide the main window
4) maybe get focus back calling SetForegroundWindow

have a look at example - I used notepad just to test.
be careful: after execution you'll have a wandering hidden notepad window... :-)

#include <windows.h>
#include <tchar.h>
#include <string.h>
#include <stdio.h>

BOOL CALLBACK MyEnumProc(HWND hWnd, LPARAM param)
{
	TCHAR buf[256];

	//is this the window we're looking for?
	if (GetClassName(hWnd, buf, 256) &&
		_tcsicmp(buf, TEXT("Notepad")) == 0)
	{
		//yes: store handle and stop searching
		*((HWND*)param) = hWnd;
		return FALSE;
	}
	else
		return TRUE; //go on searching
}

HWND WaitNotepadWindow()
{
	HWND ret = NULL;

	for (int i = 0; i < 100; i++)
	{
		//enum windows
		EnumWindows(MyEnumProc, (LPARAM)&ret);

		//found our main window?
		if (ret != NULL)
			break;

		//have a small rest, the retry
		Sleep(50);
	}

	return ret;
}

int main(int argc, char** argv)
{
	STARTUPINFO si;
	PROCESS_INFORMATION pi;

	ZeroMemory(&si, sizeof(si));
	ZeroMemory(&pi, sizeof(pi));

	si.cb = sizeof(si);
		
	BOOL bSuccess;

	if ((bSuccess = CreateProcess(TEXT("C:\\WINDOWS\\System32\\Notepad.exe"),
		0, 0, 0, FALSE, NORMAL_PRIORITY_CLASS, 0, 0, &si, &pi)) == TRUE)
	{
		//detach from process
		CloseHandle(pi.hProcess);
		CloseHandle(pi.hThread);
		
		HWND hWindow;

		//wait for main window to come up
		if ((hWindow = WaitNotepadWindow()) != NULL)
			ShowWindow(hWindow, SW_HIDE); //then hide it
		
		//if we were a GUI app, we could make this
		//call to get back focus
		//SetForegroundWindow(g_hWnd);
	}
}

Open in new window

JKR...got it working, you're the man!
Thanks ;o)

BTW, don't forget to 'CloseWindowStation()' and 'CloseDesktop()' when you're done.