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.
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 queLPWSTR path = L"C:\\blahblah"
pero es lo mismo quewchar_t* path = L"C:\\blahblah"
. Debe usar lo que ha propuesto @hmjd o debe definirLPWSTR 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 quewchar_t* path = L"C:\\blahblah"
(pero este último es de hecho lo mismo queLPWSTR 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
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 );
}
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