C/Visual C - Ayuda con capturar ventana con C++/CLI

 
Vista:
sin imagen de perfil
Val: 36
Ha mantenido su posición en C/Visual C (en relación al último mes)
Gráfica de C/Visual C

Ayuda con capturar ventana con C++/CLI

Publicado por Allan (18 intervenciones) el 25/02/2020 22:13:50
Hola comunidad, tengo un problema el cual llevo bastante tiempo sin saber como hacerlo, o sin poder lograrlo, viendo de todo en internet, buscando información y leyendo un poco, pero resulta que no consigo hacer una captura de pantalla o lo que sea que hace esto.

Yo tengo un proceso que ejecuto desde mi programa, el proceso es un programa de un tercero, entonces yo quiero capturar la imagen de ese proceso como lo hace OBS Studio con todo y audio, he visto muchas cosas sobre lo que trae Windows.h pero no he logrado conseguirlo incluso he visto sobre Windows.MediaCapture pero parece que solo captura la ventana propia de la aplicación que lo ejecuta.

He visto como lo hace también jsmpeg-vnc, pero yo sigo sin lograrlo porque quiero hacer como un servicio de streaming, pero si no logro capturar la imagen ni audio no podré lograrlo

Esperando su ayuda gracias, aquí les dejo algo de lo que he avanzado en C++/CLI, porque me ayuda a controlar mejor procesos.

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#ifndef MANEJOPROCESOS_H
#define MANEJOPROCESOS_H
 
#include "Estructuras.h"
#include "ManejoDirectorios.h"
 
using namespace System;
using namespace System::Diagnostics;
using namespace System::ComponentModel;
using namespace System::Drawing;
 
[DllImport("user32.dll")]
static bool GetClientRect(IntPtr^ hWnd, Rectangle^ lpRect);
 
ref class ManejoProcesos
{
private:
	List<Servidores^>^ listaServidores;
	Servidores^ structServidor;
	array<Process^>^ listaProcesosBuscados;
	Process^ process;
	Process^ proServidor;
	ProcessStartInfo^ psi;
	String^ msgError;
	String^ servidor;
	// Ejemplo parametros servidor "-b 2000 -s 640x480 -f 30 -p 9006 \"Proyecto_Arduinio_I Game Preview Standalone(64 - bit / PCD3D_SM5)\""
	String^ parametrosServidor;
	int servidores = 0;
	// Esto sirve para que mientras se ejecuta el proceso no vaya a buscar un proceso que todavía no existe
	int dormir = 7000;
public:
	ManejoProcesos()
	{
		listaServidores = gcnew List<Servidores^>;
		servidor = ManejoDirectorios::rutaPrograma + "/jsmpeg-vnc-v0.2/jsmpeg-vnc.exe ";
		parametrosServidor = "-b 2000 -s 640x480 -f 30 -p 9006 ";
	}
 
	inline String^ obtenerError() { return msgError; }
 
	bool lanzarEjecutableConServidor(String^ nombreRuta, int indiceLista)
	{
		try
		{
			process = gcnew Process();
			psi = gcnew ProcessStartInfo(nombreRuta);
			process->StartInfo = psi;
			process->Start();
			// Se detiene un rato el proceso en lo que el proceso de render inicia
			System::Threading::Thread::Sleep(dormir);
			//*************** Lanzar servidor
			this->iniciarServidor(indiceLista, process, psi);
			//*******************************
			msgError = "";
			return true;
		}
		catch (Exception ^ ex)
		{
			msgError = ex->Message;
			return false;
		}
	}
 
	// Inicia un servidor y lo almacena para luego ser terminado cuando se desea
	bool iniciarServidor(int indiceLista, Process^ procesoRender, ProcessStartInfo^ infoRender)
	{
		try
		{
			proServidor = gcnew Process();
			String^ rutaServidor = servidor;
			psi = gcnew ProcessStartInfo(rutaServidor);
			psi->Arguments = parametrosServidor + "\"" + procesoRender->ProcessName + "\"";
			structServidor = gcnew Servidores();
			proServidor->StartInfo = psi;
			proServidor->Start();
 
			structServidor->estadoProceso = EN_STREAMING;
			structServidor->procesoServidor = proServidor;
			structServidor->procesoRender = procesoRender;
			structServidor->indiceLista = indiceLista;
			structServidor->indice = servidores;
			structServidor->infoRender = infoRender;
			structServidor->infoServidor = psi;
 
			listaServidores->Add(structServidor);
 
			msgError = "";
			servidores++;
 
			return true;
		}
		catch (Exception ^ ex)
		{
			msgError = ex->Message;
			return false;
		}
	}
 
	bool detenerServidor(int indiceLista)
	{
		for each (Servidores ^ server in listaServidores)
		{
			if (server->indiceLista == indiceLista)
			{
				try
				{
					server->estadoProceso = APAGADO;
					server->procesoServidor->Kill();
					server->procesoRender->Kill();
					listaServidores->Remove(server);
					msgError = "";
					return true;
				}
				catch (Exception ^ ex)
				{
					msgError = ex->Message;
					return false;
				}
			}
		}
 
		msgError = "Servidor no encontrado...";
		return false;
	}
};
 
#endif // MANEJOPROCESOS_H
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder

Ayuda con capturar ventana con C++/CLI

Publicado por Nacho (76 intervenciones) el 26/02/2020 13:58:22
A veces da la impresión de que os gusta liaros.

MediaCaptura da para hacer muchas cosas, streaming incluido. Windows da para muchas cosas, ejecutar el código que quieras en el proceso que quieras incluido. No hay más que poner un hook o crear un thread remoto en ese proceso, por ejemplo. No necesitarás más ayuda.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar
sin imagen de perfil
Val: 36
Ha mantenido su posición en C/Visual C (en relación al último mes)
Gráfica de C/Visual C

Ayuda con capturar ventana con C++/CLI

Publicado por Allan (18 intervenciones) el 26/02/2020 15:31:43
Hola, gracias por responder

Es que yo he visto un poco la documentación de MediaCapture y en cuanto no mas vi que lo que estaban explicando como capturar la ventana de la aplicación lo cerré porque dije, solo captura la ventana de la aplicación, osea sentí que no me servía.

Ahora te pregunto, ¿puedo tomar la imagen que me Media Capture y luego tratarla, también el sonido?

Solo para adelantarme nada mas y gracias por tu respuesta
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Ayuda con capturar ventana con C++/CLI

Publicado por Nacho (76 intervenciones) el 26/02/2020 18:17:13
Mira más abajo en la documentación y verás que captura también vídeo y sonido. Y más abajo también dice que puede producir un stream con los datos de captura que puedes mandar con un NetworkStream, justo lo que quieres, o grabarlo en disco.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar
sin imagen de perfil
Val: 36
Ha mantenido su posición en C/Visual C (en relación al último mes)
Gráfica de C/Visual C

Ayuda con capturar ventana con C++/CLI

Publicado por Allan (18 intervenciones) el 02/03/2020 01:16:32
Hola, soy yo de nuevo, fíjate que he estado mucho tiempo viendo la misma cuestión y Windows.Media.Capture no sirve para eso, entonces me puse a buscar en la API y encontré una que se llama Windows.Graphics.Capture, ahora la cuestión es que los ejemplos que muestran implícitamente le pasan la imagen a la UI y yo no quiero eso, y no he encontrado algo que me entregue una imagen y yo la pueda tomar y mandarla a un servidor que ya tengo listo, solo para enviar audio e imágenes pero la verdad no se si me pudieras ayudar dándome algún ejemplo ó alguna URL dónde yo pueda guiarme

Este es el ejemplo que te digo que le mandan a la UI implícitamente la imagen capturada (Con esto de implícitamente me refiero a que la API es quien hace eso de mostrar la imagen, y despues no muestran como se captura también el audio de la ventana)
https://docs.microsoft.com/es-es/windows/uwp/audio-video-camera/screen-capture

Si puedes ayudarme gracias, si no, no importa
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Ayuda con capturar ventana con C++/CLI

Publicado por Nacho (76 intervenciones) el 02/03/2020 15:42:49
A ver qué quieres hacer.

Dices "no he encontrado algo que me entregue una imagen y yo la pueda tomar y mandarla a un servidor que ya tengo listo". Si por imagen te refieres a un fotograma, mediacapture puede darte un vídeo fotograma a fotograma. Cada vez que se forme un fotograma completo llama a una función, con una información de fotograma en una variable, que puedes mandar vía tcp/ip con un simple networkstream.

Si lo que quieres es una secuencia de vídeo, tambíen te lo da mediacapture, e igualmente puedes mandarlo vía tcp/ip.

Y con el sonido exactamente igual.

Otra cosa es que el servidor que tengas hecho no sea el adecuado.

Ahí tienes un ejemplo de código cliente servidor que manda vídeo con mediacapture. Es para Windows phone pero en Windows de escritorio será igual.
https://www.codeproject.com/Articles/995238/Live-Video-Streaming-from-Windows-Phone
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar
sin imagen de perfil
Val: 36
Ha mantenido su posición en C/Visual C (en relación al último mes)
Gráfica de C/Visual C

Ayuda con capturar ventana con C++/CLI

Publicado por Allan (18 intervenciones) el 03/03/2020 02:50:27
Es que la idea principal que tengo, es que yo quiero hacer un servicio de streaming por mencionarte algo, así como Google Stadia, a diferencia que el mio va a controlar más procesos y con procesos me refiero a que a no solo videojuegos, entonces en página web le dirá al servidor que programa que requiere una gran potencia de procesamiento desea ejecutar, entonces yo le envío la imagen de lo que está ejecutando el servidor y también le envío sonido y el usuario podrá también enviar pulsaciones de teclas, archivos y audios dependiendo la necesidad, solo que estoy atascado en esto, que no se como capturar imagen de un proceso ejecutandose en un servidor windows, ni capturar el audio que produce ese proceso.

Esto es lo que tengo por el momento.

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
using System;
using System.Threading.Tasks;
using CaptureSampleCore;
using Composition.WindowsRuntimeHelpers;
using Windows.Graphics.Capture;
 
class ACapturador
{
    private string msgError = "";
    private SProcesos proc;
    private IntPtr hwnd;
    private BasicSampleApplication sample;
 
    public ACapturador()
    {
    }
 
    public string MsgError { get { return msgError; } }
 
    public bool InicializarCapturador()
    {
        if (!Windows.Graphics.Capture.GraphicsCaptureSession.IsSupported())
        {
            this.msgError = "Error Windows.Graphics.Capture no soportado.";
            return false;
        }
        else
        {
            this.msgError = "";
            return true;
        }
    }
 
 
    public SProcesos SProceso
    {
        get { return this.proc; }
        set { this.proc = value; }
    }
 
    public async Task StartPickerCaptureAsync(SProcesos sProc)
    {
        hwnd = sProc.proRender.MainWindowHandle;
 
        var picker = new GraphicsCapturePicker();
        picker.SetWindow(hwnd);
        GraphicsCaptureItem item = await picker.PickSingleItemAsync();
 
        if (item != null)
        {
            sample.StartCaptureFromItem(item);
        }
    }
 
    private void StartHwndCapture(IntPtr hwnd)
    {
        GraphicsCaptureItem item = CaptureHelper.CreateItemForWindow(hwnd);
        if (item != null)
        {
            sample.StartCaptureFromItem(item);
        }
    }
 
}

El ejemplo de código lo obtuve de este repositorio
https://github.com/Microsoft/Windows.UI.Composition-Win32-Samples/tree/master/dotnet/WPF/ScreenCapture

Aquí estoy trabajando con C# y UWP (Universal Windows Platform) se que esto ya no tiene nada que ver con C++/CLI pero yo empece así con C++/CLI y poco a poco fui descubriendo cosas pero aquí estoy que no logró hacer eso, y aquí con UWP está peor porque no puedo ejecutar procesos con el objeto Process porque UWP no tiene permisos para eso, en ese caso se usa TaskRunAsync y algo no recuerdo pero resulta que esa función solo ejecuta el proceso y ya no tengo control sobre el. Entonces he regresado a C++ y C

Este es el archivo .h
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#ifndef PROCESOS_H
#define PROCESOS_H
 
#include <Windows.h>
#include <iostream>
#include "AList.h"
#include "AString.h"
 
class Procesos
{
private:
	// Estructura que guarda un proceso hijo
	struct Proceso
	{
		// Handle Process
		HANDLE hProcess = 0;
		// Handle Thread
		HANDLE hThread = 0;
		// Startup Information
		STARTUPINFO si;
		// Process Information
		PROCESS_INFORMATION pi;
		// Process ID
		DWORD dwProcessId;
		// Process ID Hilo
		DWORD dwThreadId;
		// Boolean Process
		BOOL bProcess;
	};
 
	AList<Proceso> listaProcs;
	AString msgError;
public:
	// Constructor
	Procesos();
 
	// Añade un nuevo proceso a la lista y lo ejecuta
	bool nuevoProceso(LPCWSTR rutaEjecutable);
 
	void cerrarProceso(int pos);
 
	HANDLE obtenerHandleProceso(int pos);
	DWORD obtenerIdProceso(int pos);
};
 
 
 
#endif // PROCESOS_H

Este es el archivo .cpp
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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include "Procesos.h"
 
Procesos::Procesos()
{
	listaProcs.borrar_todosElementos();
}
 
bool Procesos::nuevoProceso(LPCWSTR rutaEjecutable)
{
	Proceso proc;
	// Lleno los espacios de zeros para ocupar ese espacio de memoria despues
	// Paso 1
	ZeroMemory(&proc.si, sizeof(proc.si));
	ZeroMemory(&proc.pi, sizeof(proc.pi));
	// Paso 2
	proc.bProcess = CreateProcess(
		rutaEjecutable,	// Nombre de la aplicacion
		NULL,							// Linea de comandos
		NULL,							// Atributos del proceso
		NULL,							// Hilo de atributos
		FALSE,							// Inherit handle
		0,								// Creacion de bandera
		NULL,							// Enviroment variable
		NULL,							// Directorio actual
		&proc.si,						// Start info
		&proc.pi						// Process Information
	);
 
 
	// Paso 3
	if (proc.bProcess == FALSE)
	{
		msgError.setAString("Error al crear proceso: CREATE_PROCESS");
		return false;
	}
	else
	{
		// Paso 4
		//WaitForSingleObject(proc.pi.hProcess, 0);
		listaProcs.insertar(proc);
		return true;
	}
}
 
void Procesos::cerrarProceso(int pos)
{
	// Paso 5
	// Cerrar los handles que iniciaron el proceso
	Proceso proc = listaProcs.obtener_at(pos);
	CloseHandle(proc.hProcess);
	CloseHandle(proc.hThread);
	TerminateProcess(proc.hProcess, 0);
}
 
 
HANDLE Procesos::obtenerHandleProceso(int pos)
{
	Proceso proc = listaProcs.obtener_at(pos);
	return proc.pi.hProcess;
}
 
DWORD Procesos::obtenerIdProceso(int pos)
{
	Proceso proc = listaProcs.obtener_at(pos);
	return GetProcessId(proc.pi.hProcess);
}

Y Aquí intento capturar una imagen aunque sea del proceso que ejecuto

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include "ACapturador.h"
#include <atlimage.h>
#include <gdiplusimaging.h>
#include <Windows.h>
 
//**********************************************************************************************
 
// Estas funciones no son posibles compilarlas en un archivo .h
 
//**********************************************************************************************
 
typedef struct {
	char* prefix;
	HWND window;
} window_with_prefix_data_t;
 
BOOL CALLBACK window_with_prefix_callback(HWND window, LPARAM lParam) {
	window_with_prefix_data_t* find = (window_with_prefix_data_t*)lParam;
 
	char title[80];
	GetWindowTextA(window, title, sizeof(title));
 
	if (!find->window && strncmp(find->prefix, title, strlen(find->prefix)) == 0) {
		find->window = window;
	}
	return TRUE;
}
 
HWND window_with_prefix(char* title_prefix) {
	window_with_prefix_data_t find = { title_prefix, NULL };
	EnumWindows(window_with_prefix_callback, (LPARAM)&find);
 
	return find.window;
}
 
// Structure used to communicate data from and to enumeration procedure
struct EnumData {
	DWORD dwProcessId;
	HWND hWnd;
};
 
// Application-defined callback for EnumWindows
BOOL CALLBACK EnumProc(HWND hWnd, LPARAM lParam) {
	// Retrieve storage location for communication data
	EnumData& ed = *(EnumData*)lParam;
	DWORD dwProcessId = 0x0;
	// Query process ID for hWnd
	GetWindowThreadProcessId(hWnd, &dwProcessId);
	// Apply filter - if you want to implement additional restrictions,
	// this is the place to do so.
	if (ed.dwProcessId == dwProcessId) {
		// Found a window matching the process ID
		ed.hWnd = hWnd;
		// Report success
		SetLastError(ERROR_SUCCESS);
		// Stop enumeration
		return FALSE;
	}
	// Continue enumeration
	return TRUE;
}
 
// Main entry
HWND FindWindowFromProcessId(DWORD dwProcessId) {
	EnumData ed = { dwProcessId };
	if (!EnumWindows(EnumProc, (LPARAM)&ed) &&
		(GetLastError() == ERROR_SUCCESS)) {
		return ed.hWnd;
	}
	return NULL;
}
 
// Helper method for convenience
HWND FindWindowFromProcess(HANDLE hProcess) {
	return FindWindowFromProcessId(GetProcessId(hProcess));
}
 
//**********************************************************************************************
 
// Estas funciones no son posibles compilarlas en un archivo .h
 
//**********************************************************************************************
 
ACapturador::ACapturador()
{
}
 
ACapturador::~ACapturador()
{
	delete img;
}
 
CImage ACapturador::capturarImagen(HANDLE hProcess)
{
	RECT rect;
	HWND ventana = NULL;
	// Obtengo el proceso
	/*do
	{
		ventana = FindWindowEx(NULL,ventana, NULL, NULL);
		GetWindowThreadProcessId(ventana, &idProc);
		if (idProc == procId)
		{
			break;
		}
	} while (ventana != NULL);*/
 
 
	// Dibujo el cuadro
	//char* window_title = (char*)"PruebasIA";
	//ventana = window_with_prefix(window_title);
	//ventana = FindWindowEx(0,0, TEXT("PruebasIA"),0);
 
	ventana = FindWindowFromProcess(hProcess);
 
	//GetWindowThreadProcessId(ventana, &procId);
	GetClientRect(ventana, &rect);
 
	HDC ventanaDC = GetDC(ventana);
	HDC memoriaDC = CreateCompatibleDC(ventanaDC);
	HBITMAP bmp = CreateCompatibleBitmap(ventanaDC, rect.right - rect.left, rect.bottom - rect.top);
	img.Attach(bmp);
	CLSID pngClsid;
	img.Save(L"archivo.jpeg", Gdiplus::ImageFormatJPEG); //Esta linea solo es para hacer una comprobacion que si obtengo una captura del proceso
	return img;
}
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Ayuda con capturar ventana con C++/CLI

Publicado por Nacho (76 intervenciones) el 03/03/2020 17:55:33
Ya no digo vamos a ver porque no sé si acabaremos viendo algo.

Yo no he pasado de c#, con mucho Dllimport, claro. Todas esas cosas más modernas para hacer programas o manejar bases de datos sí es verdad que hacen todo más fácilmente, pero sólo hacen lo que permiten hacer, que suele ser poco.

¿Y no acabarías antes con el escritorio remoto o el UltraVNC? El UltraVNC es de código abierto y puedes añadir cosas.

Por lo que has pegado ahora, parece que te vale con hacer una captura de pantalla. Para eso el c# se vale muy bien. Capturar la pantalla completa es tan sencillo como
1
2
3
4
5
6
7
8
9
10
11
Bitmap CapPantalla(String filename, ImageFormat format)
{
    Rectangle bounds = Screen.GetBounds(Point.Empty);
    Bitmap bitmap = new Bitmap(bounds.Width, bounds.Height);
    using (Graphics g = Graphics.FromImage(bitmap))
    {
        g.CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
    }
     if (filename != null) bitmap.Save(filename, format);
    return bitmap;
}

Eso devuelve un Bitmap, que es tan sencillo mandarlo por un socket como
1
2
3
4
5
6
7
8
9
10
void MandarBitmap(Socket soc, Bitmap bitmap)
{
    NetworkStream stream = new NetworkStream(soc);
    MemoryStream ms = new MemoryStream();
    bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
    byte[] imageBuffer = ms.GetBuffer();
    stream.Write(imageBuffer, 0, imageBuffer.Length);
    stream.Flush();
    stream.Close();
}

Si sólo quieres la ventana de un proceso puedes crearlo con la clase Process, y a través del ManWindowHandle copiar su ventana en un graphics y mandarlo exatamente igual. O copiar sólo el rect que quieras, que también te da el rect que ocupa la ventana de un proceso la clase Process. La clase process te da más cosas incluso que el CreateProcess sin más.

Y con el audio, igual. No tienes más que pasar las muestras a un MemoryStream y mandarlo como en la segunda función.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar
sin imagen de perfil
Val: 36
Ha mantenido su posición en C/Visual C (en relación al último mes)
Gráfica de C/Visual C

Ayuda con capturar ventana con C++/CLI

Publicado por Allan (18 intervenciones) el 04/03/2020 03:36:01
Hola, fíjate que pareciera que estamos cerca de lo que quiero lograr, pero no entiendo porque no me da la imagen que quiero y cuando la encuentra me genera un error en tiempo de ejecución que me comienza a abrir la misma ventana muchas veces hasta que detengo el proceso.

Hasta pena me da ya molestarte tanto con más información pero me da errores cuando intento llamar a la ventana, me dice el error Insuficiente memoria y se detiene el programa.

Y yo quiero capturar la ventana y no el escritorio, sobre hacer una captura de pantalla del escritorio si puedo, pero lo que no puedo es con una ventana en especifico. Eso de FromHwnd pareciera que funciona pero algo me falta y no logró identificar que es.

Encontré esto https://docs.microsoft.com/en-us/dotnet/api/system.drawing.graphics.fromhwnd?view=netframework-4.8
Pero parece que modifican visualmente la ventana actual (osea la del programa que lo ejecuta).

Oye y muchas gracias por hacerme ganas durante todo esto.

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public ref class Form1 : Form
    {
 
        bool termino = false;
        Process^ _proc;
        ProcessStartInfo^ psi;
        Thread hilo;
 
        public: Form1()
        {
            InitializeComponent();
 
            ThreadStart^ threadStart = gcnew ThreadStart(capturar);
            hilo = gcnew Thread(threadStart);
        }
 
        private: void btnCapturar_Click(object^ sender, EventArgs^ e)
        {
            termino = false;
            _proc = gcnew Process();
            psi = gcnew ProcessStartInfo("C:/Users/usuario/source/repos/E-Cloud v1.2/E-Cloud v1.2/Aplicaciones/PruebasIA/PruebasIA.exe");
            _proc->StartInfo = psi;
            _proc->Start();
 
            hilo->Start();
        }
 
        private: void capturar()
        {
            while(!termino)
            {
                Rectangle^ bounds = Screen::FromHandle(_proc.MainWindowHandle).Bounds;
                Bitmap^ bitmap = gcnew Bitmap(bounds.Width, bounds.Height);
 
                Graphics^ g = Graphics.FromHwnd(_proc.MainWindowHandle);
 
                    g->DrawImage(bitmap, bounds);
                    //g->CopyFromScreen(Point.Empty, Point.Empty, bounds.Size);
 
                System::Threading::Thread::Sleep(100);
                picImg->Image = bitmap;
            }
        }
 
        private: void btnDetener_Click(object^ sender, EventArgs^ e)
        {
            termino = false;
        }
    }
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Ayuda con capturar ventana con C++/CLI

Publicado por Nacho (76 intervenciones) el 04/03/2020 10:52:46
Puede ser que la distancia que quede sea la de un pequeño detalle.

Como decíamos en este hilo https://www.lawebdelprogramador.com/foros/Visual-Basic.NET/1728926-Como-liberar-memoria-tras-crear-graficos-e-imagenes.html un objeto graphics siempre hay que liberarlo antes de acabar la función en la que lo creas. Si no lo haces pueden producirse errores como los que comentas y más gordos. En mi función uso la cláusula using, que lo que hace es destruir lo que se cree dentro de las llaves en cuanto se cierran.

Tienes que tener en cuenta también que ese método sólo funciona con una ventana que sea visible. Una no visible no puede copiarse de esa manera.

Ahora puede venir otro a discutírmelo y ponerme votos en contra.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
1
Comentar
sin imagen de perfil
Val: 36
Ha mantenido su posición en C/Visual C (en relación al último mes)
Gráfica de C/Visual C

Ayuda con capturar ventana con C++/CLI

Publicado por Allan (18 intervenciones) el 14/03/2020 05:30:41
Acabo de encontrar la solución de como capturar la pantalla, eso de Graphics no funciona así, yo supongo que solo funciona la ventana misma que lo ejecuta así que dejare este código aquí, para que le sirva a alguien.

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
26
27
28
29
30
31
32
33
34
CImage ACapturador::capturarImagen(HWND ventana)
{
	RECT rect;
 
	HWND otra = FindWindow(0, TEXT("Nombre de la ventana"));
	ventana = otra;
	if (ventana== NULL)
	{
		// Capturo el error
		this->msgError.setAString("Error al encontrar ventana...");
		return img;
	}
	//Obtengo el cuadro
	GetClientRect(ventana, &rect);
	// Preparo el capturador
	HDC ventanaDC = GetDC(NULL);
	HDC memoriaDC = CreateCompatibleDC(ventanaDC);
	HBITMAP bmp = CreateCompatibleBitmap(ventanaDC, rect.right - rect.left, rect.bottom - rect.top);
	// Selecciono los objetos y los capturo
	SelectObject(memoriaDC, bmp);
	PrintWindow(otra, memoriaDC, PW_CLIENTONLY);
 
	// Ingreso la imagen a un CImage
	img.Attach(bmp);
	CLSID pngClsid;
	img.Save(L"archivo.jpeg", Gdiplus::ImageFormatJPEG);
 
	//Libero memoria
	DeleteDC(memoriaDC);
	DeleteObject(bmp);
	ReleaseDC(NULL, ventanaDC);
	//Retorno la imagen
	return img;
}

Solamente que hay un error que no he podido solucionar, pero eso ya abriré otra pregunta si no logró hacerlo por mi cuenta

Es que con este fragmento de código se puede ir a buscar la ventana, y si la encuentra pero cuando se la paso a la función
pareciera que busca otra cosa, no se

1
2
3
4
5
6
7
8
9
10
11
12
13
// Buscar la ventana
HWND h = ::GetTopWindow(0);
while (h)
{
    DWORD pid;
    DWORD dwTheardId = ::GetWindowThreadProcessId(h, &pid);
 
    if (pid == proc.pi.dwProcessId)
    {
        break;
    }
    h = ::GetNextWindow(h, GW_HWNDNEXT);
}

El proc.pi.dwProcessId es una estructura que yo hice para almacenar algunas variables cuando creo el proceso

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Proceso proc;
	// Lleno los espacios de zeros para ocupar ese espacio de memoria despues
	// Paso 1
	ZeroMemory(&proc.si, sizeof(proc.si));
	ZeroMemory(&proc.pi, sizeof(proc.pi));
	// Paso 2
	proc.bProcess = CreateProcess(
		rutaEjecutable.AString2wchar_t(),	// Nombre de la aplicacion
		NULL,								// Linea de comandos
		NULL,								// Atributos del proceso
		NULL,								// Hilo de atributos
		FALSE,								// Inherit handle
		0,									// Creacion de bandera
		NULL,								// Enviroment variable
		NULL,								// Directorio actual
		&proc.si,							// Start info
		&proc.pi							// Process Information
	);

Gracias por responder siempre a está preguntando, así que dejo el código para cualquiera que lo necesite
C++/CLI, C, Captura de ventana desde cualquier proceso
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Ayuda con capturar ventana con C++/CLI

Publicado por Nacho (76 intervenciones) el 14/03/2020 15:34:16
Ya, claro que se puede usar las funciones del Windows para eso. Códigos como ese los he usado yo mucho antes de usar c#, para el Windows 3.1 además. He copiado ventanas para grabarlos en un archivo, mostrar trozos de ventana ampliados, dibujado en ventanas de otro proceso... Con c# se puede hacer también sin ninguna limitación más que de velocidad. El hecho de que no te funcione a ti no quiere decir que no pueda hacerse.

Es muy fácil equivocarse, como parece que haces buscando ventanas. Me imagino que querrás buscar ventanas en el escritorio, y GetTopWindow y GetNextWindow buscan ventanas, sí, pero dentro de otra ventana padre que no va a ser el escritorio. Como bien dice la MSDN: Examines the Z order of the child windows associated with the specified parent window and retrieves a handle to the child window at the top of the Z order. Lo que debes querer usar es EnumWindows.
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar