2012-07-19 55 views
10

Estoy teniendo un problema grave aquí. Necesito ejecutar una línea de comandos de CMD a través de C++ sin que se muestre la ventana de la consola. Por lo tanto, no puedo usar system(cmd), ya que se mostrará la ventana.C++ Ejecutando comandos CMD

He intentado winExec(cmd, SW_HIDE), pero esto tampoco funciona. CreateProcess es otro que probé. Sin embargo, esto es para ejecutar programas o archivos por lotes.

he terminado de tratar ShellExecute:

ShellExecute(NULL, "open", 
    "cmd.exe", 
    "ipconfig > myfile.txt", 
    "c:\projects\b", 
    SW_SHOWNORMAL 
); 

¿Alguien puede ver nada malo en el código anterior? He usado SW_SHOWNORMAL hasta que sé que esto funciona.

Realmente necesito ayuda con esto. Nada ha salido a la luz, y lo he estado intentando durante bastante tiempo. Cualquier consejo que alguien pueda dar sería genial :)

+0

¿Ha comprobado el código de retorno? – Collin

+1

Sé que has recibido una respuesta, pero normalmente es una buena idea decir cómo no funciona. – Deanna

+0

¿Por qué no llamas a las funciones de WMI_ y escribes los resultados en el archivo? Sin ventana y solo los datos que necesita. –

Respuesta

6

redirigiendo la salida a su propia tubería es una solución más ordenado, ya que evita la creación del archivo de salida, pero esto funciona bien:

ShellExecute(0, "open", "cmd.exe", "/C ipconfig > out.txt", 0, SW_HIDE); 

no ve la ventana de CMD y la salida se redirige como se esperaba .

Su código probablemente está fallando (aparte de la cosa /C) porque especifica la ruta como "c:\projects\b" en lugar de "c:\\projects\\b".

4

Debe usar CreateProcess en cmd.exe con el parámetro /C para tunelizar el comando ipconfig. El> no funciona per se en la línea de comando. Tienes que redirect programmatically the stdout.

+0

Si se trata de una línea de comando 'cmd/c', entonces, por supuesto, la redirección'> 'funcionará. – eryksun

3

Aquí está mi implementación de una función DosExec que permite (silenciosamente) ejecutar cualquier comando DOS y recuperar el resultado generado como una cadena unicode.

// Convert an OEM string (8-bit) to a UTF-16 string (16-bit) 
#define OEMtoUNICODE(str) CHARtoWCHAR(str, CP_OEMCP) 

/* Convert a single/multi-byte string to a UTF-16 string (16-bit). 
We take advantage of the MultiByteToWideChar function that allows to specify the charset of the input string. 
*/ 
LPWSTR CHARtoWCHAR(LPSTR str, UINT codePage) { 
    size_t len = strlen(str) + 1; 
    int size_needed = MultiByteToWideChar(codePage, 0, str, len, NULL, 0); 
    LPWSTR wstr = (LPWSTR) LocalAlloc(LPTR, sizeof(WCHAR) * size_needed); 
    MultiByteToWideChar(codePage, 0, str, len, wstr, size_needed); 
    return wstr; 
} 

/* Execute a DOS command. 

If the function succeeds, the return value is a non-NULL pointer to the output of the invoked command. 
Command will produce a 8-bit characters stream using OEM code-page. 

As charset depends on OS config (ex: CP437 [OEM-US/latin-US], CP850 [OEM 850/latin-1]), 
before being returned, output is converted to a wide-char string with function OEMtoUNICODE. 

Resulting buffer is allocated with LocalAlloc. 
It is the caller's responsibility to free the memory used by the argument list when it is no longer needed. 
To free the memory, use a single call to LocalFree function. 
*/ 
LPWSTR DosExec(LPWSTR command){ 
    // Allocate 1Mo to store the output (final buffer will be sized to actual output) 
    // If output exceeds that size, it will be truncated 
    const SIZE_T RESULT_SIZE = sizeof(char)*1024*1024; 
    char* output = (char*) LocalAlloc(LPTR, RESULT_SIZE); 

    HANDLE readPipe, writePipe; 
    SECURITY_ATTRIBUTES security; 
    STARTUPINFOA  start; 
    PROCESS_INFORMATION processInfo; 

    security.nLength = sizeof(SECURITY_ATTRIBUTES); 
    security.bInheritHandle = true; 
    security.lpSecurityDescriptor = NULL; 

    if (CreatePipe(
        &readPipe, // address of variable for read handle 
        &writePipe, // address of variable for write handle 
        &security, // pointer to security attributes 
        0   // number of bytes reserved for pipe 
        )){ 


     GetStartupInfoA(&start); 
     start.hStdOutput = writePipe; 
     start.hStdError = writePipe; 
     start.hStdInput = readPipe; 
     start.dwFlags  = STARTF_USESTDHANDLES + STARTF_USESHOWWINDOW; 
     start.wShowWindow = SW_HIDE; 

// We have to start the DOS app the same way cmd.exe does (using the current Win32 ANSI code-page). 
// So, we use the "ANSI" version of createProcess, to be able to pass a LPSTR (single/multi-byte character string) 
// instead of a LPWSTR (wide-character string) and we use the UNICODEtoANSI function to convert the given command 
     if (CreateProcessA(NULL,     // pointer to name of executable module 
          UNICODEtoANSI(command), // pointer to command line string 
          &security,    // pointer to process security attributes 
          &security,    // pointer to thread security attributes 
          TRUE,     // handle inheritance flag 
          NORMAL_PRIORITY_CLASS, // creation flags 
          NULL,     // pointer to new environment block 
          NULL,     // pointer to current directory name 
          &start,     // pointer to STARTUPINFO 
          &processInfo    // pointer to PROCESS_INFORMATION 
         )){ 

      // wait for the child process to start 
      for(UINT state = WAIT_TIMEOUT; state == WAIT_TIMEOUT; state = WaitForSingleObject(processInfo.hProcess, 100)); 

      DWORD bytesRead = 0, count = 0; 
      const int BUFF_SIZE = 1024; 
      char* buffer = (char*) malloc(sizeof(char)*BUFF_SIZE+1); 
      strcpy(output, ""); 
      do {     
       DWORD dwAvail = 0; 
       if (!PeekNamedPipe(readPipe, NULL, 0, NULL, &dwAvail, NULL)) { 
        // error, the child process might have ended 
        break; 
       } 
       if (!dwAvail) { 
        // no data available in the pipe 
        break; 
       } 
       ReadFile(readPipe, buffer, BUFF_SIZE, &bytesRead, NULL); 
       buffer[bytesRead] = '\0'; 
       if((count+bytesRead) > RESULT_SIZE) break; 
       strcat(output, buffer); 
       count += bytesRead; 
      } while (bytesRead >= BUFF_SIZE); 
      free(buffer); 
     } 

    } 

    CloseHandle(processInfo.hThread); 
    CloseHandle(processInfo.hProcess); 
    CloseHandle(writePipe); 
    CloseHandle(readPipe); 

    // convert result buffer to a wide-character string 
    LPWSTR result = OEMtoUNICODE(output); 
    LocalFree(output); 
    return result; 
} 
+0

¡Gracias por el código de muestra! –

0

que tienen un programa similar [Windows7 y 10 probado] en github

https://github.com/vlsireddy/remwin/tree/master/remwin

Este es programa que

  1. escuchas en "Conexión de área local" servidor de interfaz llamada en Windows para el puerto UDP (5555) y recibe el paquete udp.
  2. El contenido del paquete udp recibido se ejecuta en cmd.exe [no se cierra cmd.exe después de ejecutar el comando y la cadena de salida [la salida del comando ejecutado] se retroalimenta al programa cliente sobre el mismo puerto udp].
  3. En otras palabras, orden recibida en paquetes UDP -> analizada paquete UDP -> ejecutar en cmd.exe -> salida enviada de nuevo al mismo puerto programa cliente

Esto no muestra "ventana de la consola" No es necesario que alguien ejecute el comando manualmente en cmd.exe remwin.exe se puede ejecutar en segundo plano y es un programa de servidor delgado

+0

Hola, parece demasiado de vigilancia, puse un enlace probado válido y responde la pregunta específica por respuesta específica con el código probado, no entiendo su recomendación de revisión de eliminación. Ejecuta el código [MSVC], verifica su salida, lo prueba y si no le queda, elimínelo. – particlereddy

+0

Lo siento, he eliminado mi comentario. Fui demasiado rápido en el gatillo ... – Jolta

+0

Al leer su respuesta, me parece que ha resuelto el problema. Sin embargo, Stack Overflow desalienta las respuestas que proporcionan soluciones en forma de enlaces externos. – Jolta

Cuestiones relacionadas