running an application within a vc++ progam

I am trying to create a Visual C++ 2010 program that will call another application and close right away after it calls the app. I need to pass in parameter that indicates which environment to use, i.e. dev, QA or prod. I then need to use the parameter in reading a text file to find the location and name of the application to run. I also need to use the parameter when running the exe. i.e. K:\progpath\prog.exe dev. I need some assistance in figuring out how to get the exe to run without having a command window pop up. I also mention that the program and application will be running off of a network drive and if the parameter information is not fond in the text file I need to display a messagebox stating that the application can not start for that environment. So I am using:

INT API WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
Is this academic? Or is there any other real reason that you have to create an entire executable just for a launcher? I only ask because this is traditionally a job for a script. Even Batch can handle a trivial task like this. Functionally speaking of course.
A batch script will not work in this specific case as OP insists on not displaying any command prompt window whatsoever.
I read that as more of a "would be nice" then a strict requirement, but I concede the point. VBScript is another option, that will not display a Window and can be set to die right after the child process is launched.

EDIT: I'm not trying to dismiss your approach outright OP, it's actually really simple. I simply want to make sure that you are taking the most appropriate approach to solving this issue. Scripting files are the more traditional approach to solving the situation that you are describing mostly because it is faster to update them if\when the need arises and less intimidating in the case that the task gets shifted onto another, "lower tier", engineer.
Last edited on
I guess it doesn't have to be in visual studio c++. I am trying to recreate an exe that is used to launch an application. right now the user uses a shortcut that calls the exe, which opens the application. from what I can tell is was written in an older visual c++ and will not work in window 7. I need to work the same as it does now and right now the black cmd box does not appear. I was able to get it to run in a windows 7 box using the system("k:\path\prog.exe") command, but the cmd box appears. I have tried CreateProcess and ShellExecute, but neither have worked.

for ShellExecute I have tried:

String Path = "K:\\path\\prog.exe dev";

ShellExecute (NULL, ("open"), LPCSTR(path.c_str()), NULL, NULL, SW_SHOWNORMAL);

a black box appear and then disappears. the application doesn't start.


For createProcess:

LPWSTR path = "K:\\path\\prog.exe dev";


If( !CreateProcess(NULL,
path,
NULL,
NULL,
FALSE,
0,
NULL,
NULL,
&si,
&pi)
)
{
error message
}

I always get an error message






thanks
The correct approach will be:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
if (ShellExecuteA (NULL, "open", "K:\\path\\prog.exe", "dev", NULL, SW_SHOWNORMAL)) > 32 {
// success
}



// or another variant
PROCESS_INFORMATION procInfo = {0};
STARTUPINFO startupInfo = {0};
if (CreateProcessA("K:\\path\\prog.exe", "dev", NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &startupInfo, &procInfo)) {
// success
}

CloseHandle (procInfo.hThread);
CloseHandle (procInfo.hProcess);

I think a slight tweak is needed to the CreateProcess example?

The problem with the call as-is is that the command line is passed to new app pretty literally. As called, "dev" is going to end up as argv[0] (assuming the standard main(int argc, char* arv[]) signature) when argv[0] is the application path (or at least name) by convention.

You also need to be aware that the second argument to CreateProcess is a non-const string and that the MSDN entry for this function states that:

The Unicode version of this function, CreateProcessW, can modify the contents of this string.

So a string literal should not be passed for this argument (better to be safe with the ANSI version than sorry...)

Andy

In more detail:

Hacking a hello app I had lying about to dump the args passed to it

1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>

int main(int argc, char* argv[])
{
    printf("Hello world!\n");
    printf("argc = %d\n", argc);
    for(int m = 0; m < argc; ++m)
    {
        printf("argv[%d] = %s\n", m, argv[m]);
    }

    return 0;
}


and launching it with this app

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <windows.h>
#include <iostream>
using namespace std;

int main(int argc, char **argv)
{
    const char appPath[] = "C:\\test\\hello.exe";
    char cmdLine[16] = "one two three"; // non const
    PROCESS_INFORMATION procInfo = {0};
    STARTUPINFOA startupInfo = {0};
    if (CreateProcessA(appPath, cmdLine, NULL, NULL,
        TRUE, 0, NULL, NULL, &startupInfo, &procInfo)) {
        // wait for app to exit (to tidy console output up)
        WaitForSingleObject(procInfo.hProcess, INFINITE);
        // close handles
        CloseHandle(procInfo.hThread);
        CloseHandle(procInfo.hProcess);
    } else {
        cout << "CreateProcessA failed with error " << GetLastError() << "\n";
    }
    return 0;
}


I get

Hello world!
argc = 3
argv[0] = one
argv[1] = two
argv[2] = three


Altering the launching app to the following code gets the right arguments to the target app.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <windows.h>
#include <iostream>
using namespace std;

int main(int argc, char **argv)
{
    const char appPath[] = "C:\\test\\hello.exe";
    const char args[] = "one two three";
    PROCESS_INFORMATION procInfo = {0};
    STARTUPINFOA startupInfo = {0};
    char cmdLine[MAX_PATH * 2] = {0};
    // good practice to quote paths
    sprintf(cmdLine, "\"%s\" %s", appPath, args);
    if (CreateProcessA(appPath, cmdLine, NULL, NULL,
        TRUE, 0, NULL, NULL, &startupInfo, &procInfo)) {
        // wait for app to exit (to tidy console output up)
        WaitForSingleObject(procInfo.hProcess, INFINITE);
        // close handles
        CloseHandle(procInfo.hThread);
        CloseHandle(procInfo.hProcess);
    } else {
        cout << "CreateProcessA failed with error " << GetLastError() << "\n";
    }
    return 0;
}


Hello world!
argc = 4
argv[0] = C:\test\hello.exe
argv[1] = one
argv[2] = two
argv[3] = three


Last edited on
As the OP wants a GUI application to not show any command window and using WinMain instead of main he can use global variables __argc and __argv available in VC++ runtime by default. These are not standard, but we are already talking about a windows-only application here.

I already assumed he know how to extract command line arguments, the example was a very simplistic example.
I was able to get the launch the application using code similar to what modoran listed above when I
use the following:

(CreateProcess(L"K:\\path\\prog.exe", L"dev", NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &startupInfo, &procInfo))

however when I try to lauch it when passing in "K:\\path\\prog.exe" and "dev" using variables. where
I have str1 = "K:\\path\\prog.exe" and str2 = dev.

LPWSTR CH1 = (LPWSTR)str1.c_str();
LPWSTR CH2 = (LPWSTR)str2.c_str();

and then using

(CreateProcess(CH1, CH3, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &startupInfo, &procInfo))

Nothing happens. the program does not launch the application , but I don't see any errors. I'm not sure what I am doing wrong.
If you're having to cast a string you ARE doing something VERY wrong.

- casting does not change an ANSI string to a Unicode one (using these terms in the Windows sense...); if you need to make this conversion, use the WinAPI MultiByteToWideChar() function.

- you should particularly avoid casting away const-ness when you're calling someone else's function!

As it seems you're building Unicode, going by the L prefixes to your string literals, then you should be using std::wstring rather than std::string (without a cast.)
http://www.cplusplus.com/reference/string/wstring/

Or fix you code to call the ANSI entrypoint -- CreateProcessA

Andy

PS And as I said previously, the second param of CreateProcess is a non-const string.

PPS If you're working with the WinAPI a lot, then this series of posts by Dissch is prob worth reading:

WinAPI: Being Unicode Friendly
http://www.cplusplus.com/forum/articles/16820/


Topic archived. No new replies allowed.