18

My aim is to execute an external executable in my program. First, I used system() function, but I don't want the console to be seen to the user. So, I searched a bit, and found CreateProcess() function. However, when I try to pass a parameter to it, I don't know why, it fails. I took this code from MSDN, and changed a bit:

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

void _tmain( int argc, TCHAR *argv[] )
{
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    ZeroMemory( &pi, sizeof(pi) );
    /*
    if( argc != 2 )
    {
        printf("Usage: %s [cmdline]\n", argv[0]);
        return;
    }
    */
    // Start the child process. 
    if( !CreateProcess( NULL,   // No module name (use command line)
        L"c:\\users\\e\\desktop\\mspaint.exe",        // Command line
        NULL,           // Process handle not inheritable
        NULL,           // Thread handle not inheritable
        FALSE,          // Set handle inheritance to FALSE
        0,              // No creation flags
        NULL,           // Use parent's environment block
        NULL,           // Use parent's starting directory 
        &si,            // Pointer to STARTUPINFO structure
        &pi )           // Pointer to PROCESS_INFORMATION structure
    ) 
    {
        printf( "CreateProcess failed (%d).\n", GetLastError() );
        return;
    }

    // Wait until child process exits.
    WaitForSingleObject( pi.hProcess, INFINITE );

    // Close process and thread handles. 
    CloseHandle( pi.hProcess );
    CloseHandle( pi.hThread );
}

However, this code crated access violation somehow. Can I execute mspaint without showing user the console?

Thank you very much.

Deanna
  • 23,876
  • 7
  • 71
  • 156
John Doe
  • 633
  • 3
  • 14
  • 24
  • 3
    For one thing, `CreateProcess` requires that its second parameter (if provided) be a non-const string. I'm not sure that this is a problem in practice, but I wanted to mention it for completeness. – reuben Jul 05 '12 at 06:56
  • ...and otherwise, where the is AV happening? Do you have a call stack? – reuben Jul 05 '12 at 06:57
  • @reuben Uhm... I'm not quite sure, but I guess this is the output of call stack:`kernel32.dll!76da70ac() [Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll] > msvcr100d.dll!_nh_malloc_dbg(unsigned int nSize, int nhFlag, int nBlockUse, const char * szFileName, int nLine) Line 302 + 0x1d bytes C++` – John Doe Jul 05 '12 at 07:03

3 Answers3

22

The second argument is a LPTSTR, namely a pointer to a non-const char array. The docs specifically say:

this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string)

The reason passing a string literal is a problem:

The system adds a terminating null character to the command-line string to separate the file name from the arguments. This divides the original string into two strings for internal processing.

Which means in your case, it tries to modify read-only memory, hence the crash.

lmiguelmh
  • 3,074
  • 1
  • 37
  • 53
Eran
  • 21,632
  • 6
  • 56
  • 89
  • I can't assign a LPTSTR either. What must my second argument be, if I may ask, for executing mspaint which is located at "c:\users\e\desktop\"? Thank you very much. – John Doe Jul 05 '12 at 07:05
  • 2
    @JohnDoe: `wchar_t path[] = L"C:\\users\\e\\desktop\\"` – hmjd Jul 05 '12 at 07:12
  • `wchar_t path[] = L"C:\\blahblah"` is not the same as `LPWSTR path = L"C:\\blahblah"` but is the same as `wchar_t* path = L"C:\\blahblah"`. You should either use what @hmjd has proposed or you should define `LPWSTR path` and then allocate memory for this var and copy the path to it. – Denis V Jan 11 '16 at 17:55
  • 2
    @DenisV - `wchar_t path[] = L"C:\\users\\e\\desktop\\"` is certainly not the same as `wchar_t* path = L"C:\\blahblah"` (but the latter is in fact the same as `LPWSTR path = L"C:\\blahblah"`, which is bad). – Eran Jan 13 '16 at 12:50
  • @eran yes, you are right, something distracted me when I wrote that, and I misplaced the examples. – Denis V Jan 13 '16 at 14:24
  • ["Why does the CreateProcess function modify its input command line?"](https://blogs.msdn.microsoft.com/oldnewthing/20090601-00/?p=18083) – GSerg Dec 23 '18 at 21:31
  • 1
    @GSerg, that may have been where I learned about this stuff, was an avid reader of that blog at the time. The fact that people still make this mistake (which means the OS does not use an extra buffer and the compiler silently casts a string literal to a `char*`) is a bit disturbing, even though it gets me an occasional upvote ;) – Eran Dec 24 '18 at 10:29
9

Try this, it should work.

TCHAR lpszClientPath[500]= TEXT("c:\\users\\e\\desktop\\mspaint.exe");
if(!CreateProcess(NULL, lpszClientPath, NULL, NULL, FALSE,  NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE|CREATE_UNICODE_ENVIRONMENT,NULL, NULL, &si, &pi))
            {
    printf( "CreateProcess failed (%d).\n", GetLastError() );
        return;
            }
...
...
A_nto2
  • 1,106
  • 7
  • 16
0

Change you code to this:

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

void _tmain( int argc, TCHAR *argv[] )
{
    TCHAR ProcessName[256];
    STARTUPINFO si;
    PROCESS_INFORMATION pi;

    wcscpy(ProcessName,L"c:\\users\\e\\desktop\\mspaint.exe");
    ZeroMemory( &si, sizeof(si) );
    si.cb = sizeof(si);
    ZeroMemory( &pi, sizeof(pi) );
    /*
    if( argc != 2 )
    {
        printf("Usage: %s [cmdline]\n", argv[0]);
        return;
    }
    */
    // Start the child process. 
    if( !CreateProcess( NULL,   // No module name (use command line)
        ProcessName,        // Command line
        NULL,           // Process handle not inheritable
        NULL,           // Thread handle not inheritable
        FALSE,          // Set handle inheritance to FALSE
        0,              // No creation flags
        NULL,           // Use parent's environment block
        NULL,           // Use parent's starting directory 
        &si,            // Pointer to STARTUPINFO structure
        &pi )           // Pointer to PROCESS_INFORMATION structure
    ) 
    {
        printf( "CreateProcess failed (%d).\n", GetLastError() );
        return;
    }

    // Wait until child process exits.
    WaitForSingleObject( pi.hProcess, INFINITE );

    // Close process and thread handles. 
    CloseHandle( pi.hProcess );
    CloseHandle( pi.hThread );
}
Michael Haephrati
  • 3,660
  • 1
  • 33
  • 56