CreateProcess() falla con una infracción de acceso [duplicate]

5 minutos de lectura

avatar de usuario
Juan Pérez

Mi objetivo es ejecutar un ejecutable externo en mi programa. Primero, usé system() función, pero no quiero que el usuario vea la consola. Así que busqué un poco y encontré CreateProcess() función. Sin embargo, cuando trato de pasarle un parámetro, no sé por qué, falla. Tomé este código de MSDN y cambié un poco:

#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 );
}

Sin embargo, este código creó una violación de acceso de alguna manera. ¿Puedo ejecutar mspaint sin mostrarle al usuario la consola?

Muchas gracias.

  • Por una cosa, CreateProcess requiere que su segundo parámetro (si se proporciona) sea una cadena no constante. No estoy seguro de que esto sea un problema en la práctica, pero quería mencionarlo para completarlo.

    – Rubén

    5 de julio de 2012 a las 6:56

  • … y de lo contrario, ¿dónde está sucediendo AV? ¿Tienes una pila de llamadas?

    – Rubén

    5 de julio de 2012 a las 6:57

  • @reuben Uhm… No estoy muy seguro, pero supongo que este es el resultado de la pila de llamadas: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

    5 de julio de 2012 a las 7:03

avatar de usuario
eran

El segundo argumento es un LPTSTR, es decir, un puntero a una matriz de caracteres no const. los documentos específicamente decir:

este parámetro no puede ser un puntero a la memoria de solo lectura (como una variable const o una cadena literal)

La razón por la que pasar un literal de cadena es un problema:

El sistema agrega un carácter nulo de terminación a la cadena de la línea de comandos para separar el nombre del archivo de los argumentos. Esto divide la cadena original en dos cadenas para el procesamiento interno.

Lo que significa que, en su caso, intenta modificar la memoria de solo lectura, de ahí el bloqueo.

  • Tampoco puedo asignar un LPTSTR. ¿Cuál debe ser mi segundo argumento, si puedo preguntar, para ejecutar mspaint que se encuentra en “c:\users\e\desktop\”? Muchas gracias.

    – John Doe

    5 de julio de 2012 a las 7:05

  • @JohnDoe: wchar_t path[] = L"C:\\users\\e\\desktop\\"

    – hmjd

    5 de julio de 2012 a las 7:12

  • wchar_t path[] = L"C:\\blahblah" no es lo mismo que LPWSTR path = L"C:\\blahblah" pero es lo mismo que wchar_t* path = L"C:\\blahblah". Debe usar lo que ha propuesto @hmjd o debe definir LPWSTR path y luego asigne memoria para esta var y copie la ruta a ella.

    – Denis V.

    11/01/2016 a las 17:55

  • @DenisV- wchar_t path[] = L"C:\\users\\e\\desktop\\" ciertamente no es lo mismo que wchar_t* path = L"C:\\blahblah" (pero este último es de hecho lo mismo que LPWSTR path = L"C:\\blahblah"cual es malo).

    – eran

    13/01/2016 a las 12:50

  • @GSerg, ahí pudo haber sido donde aprendí sobre estas cosas, era un ávido lector de ese blog en ese momento. El hecho de que la gente aún cometa este error (lo que significa que el sistema operativo no usa un búfer adicional y el compilador lanza silenciosamente una cadena literal a un char*) es un poco inquietante, a pesar de que ocasionalmente me vota a favor 😉

    – eran

    24 de diciembre de 2018 a las 10:29

avatar de usuario
A_nto2

Prueba esto, debería funcionar.

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;
            }
...
...

Cambia tu código a esto:

#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 );
}

¿Ha sido útil esta solución?