Foros - Stratos

Programadores => General Programadores => Mensaje iniciado por: Ipis en 22 de Octubre de 2003, 06:40:46 PM

Título: Getparent?
Publicado por: Ipis en 22 de Octubre de 2003, 06:40:46 PM
 
Tengo una aplicación MDI y al pulsar un botón de la barra de herramienta del marco principal ejecuto "ShellExecute" para iniciar un nuevo programa llamado(Matlab,por si os suena de algo)

No me da error y funciona perfectamente,pero no consigo integarlo en el área cliente:al maximizarlo o minimizarlo no se queda dentro de mi marco principal

He probado con GetParent(),GetParentFrame() e incluso estoy probando con SetWindowPlacement()(que,por cierto,me da problemas al inicializar el miembro ptMaxPosition) pero no debo hacerlo bien porque el programa se sigue ejecutando independientemente...... a lo mejor es que ShellExecute no es la función apropiada para ello  :blink:

Por favor,si a alguien se le ocurre una idea..... (uoh) a mí ya se me están acabando

Gracias  
Título: Getparent?
Publicado por: Zaelsius en 22 de Octubre de 2003, 07:50:55 PM
 En vez de GetParent() deberías usar la contraria.. ¿no?


The SetParent function changes the parent window of the specified child window.

Syntax

HWND SetParent(      
   HWND hWndChild,
   HWND hWndNewParent
);



hWndNewParent es el handle de tu aplicación. Para obtener hWndChild utiliza la función FindWindow():

HWND FindWindow(      
   LPCTSTR lpClassName,
   LPCTSTR lpWindowName
);


Como lpWindowName podría variar(tal vez no, pero no siempre podría llamarse la ventana "Matlab", a lo mejor otra versión se llama "Matlab 5" o algo así), es mejor que averigües el valor de lpClassName con la herramienta Spy++(incluida con Visual Studio).

PD: Conozco er Matlab ;)
Título: Getparent?
Publicado por: Ipis en 22 de Octubre de 2003, 08:07:35 PM
 Pos mira tú por donde...yo usaba GetParent para obtener
el handle de mi marco principal y pasárselo a ShellExecute,pero
voy a probar lo que dices  :rolleyes:

Por cierto,es el primer foro en el que alguien conoce "er Matlab"(claro que es el primer foro "decente" que me encuentro  :D )

Gracias..... :P

Título: Getparent?
Publicado por: Ipis en 22 de Octubre de 2003, 08:32:56 PM
 Jo,que no sale!!!! (nooo)  (nooo)

Ya no pueo más,no veo dónde falla(aunque a lo mejor sería más rápido buscar lo que está bien...si es que hay algo) Para colmo el Spy++ no me funciona(se me abre la pantalla y enseguida se cierra)

Este es mi código,por si sirve de algo:[CODE]

 m_hwnd = ::FindWindow("matlab",NULL);  
  ::SetParent(m_hwnd,NULL);
  (ShellExecute(m_hwnd,NULL,"matlab.exe",NULL,"C:\MatlaBR11\bin\",SW_SHOW));

Ni con estas consigo que er dichoso programa se quede dentro de mi aplicación  (grrr)
Título: Getparent?
Publicado por: Zaelsius en 22 de Octubre de 2003, 08:45:45 PM
 Tienes varios fallos gordos... debería ser algo como ésto:



HWND hwnd = ::FindWindow(NULL,"Matlab");
::SetParent(hwnd,m_hwnd);
(ShellExecute(m_hwnd,NULL,"matlab.exe",NULL,"C:\MatlaBR11\bin\",SW_SHOW));



Eso suponiendo que el dato miembro m_hwnd ya lo has inicializado a su valor correcto anteriormente(si es una clase de MFC no tienes que tocarlo!)

Y por supuesto comprobar tb el valor devuelto por FindWindow, no sea que matlab no se esté ejecutando o no encuentre la ventana por ese nombre.
Título: Getparent?
Publicado por: Ipis en 23 de Octubre de 2003, 07:56:41 PM
 Siento la ausencia,pero tenía problemas técnicos para conectarme....

Verás,las dobles barras "\" las tuve que poner para que VC++ me reconociera el carácter \,porque si no me sale el siguiente warning:

[ C:\Erika\Tutorial_C++\PDI\MainFrm.cpp(124) : warning C4129: 'M' : unrecognized character escape sequence]

El resto del código....jo,así no me extraña que no me salga;si es que no doy una.El caso es que tampoco da resultado,pero creo que es porque no sé muy bien cómo conseguir el ID de la ventana marco principal

Perdona mi ignorancia,pero qué significa eso que si es de MFC no tengo que tocarlo??De dónde saco su valor?

Otra cosilla....existe otra forma de verificar el valor de FindWindow sin usar Spy++??Es que no me funciona bien

Asias...... :D  
Título: Getparent?
Publicado por: Zaelsius en 23 de Octubre de 2003, 08:47:20 PM
 Supongo que sabrás que en MFC, todo está organizado en clases. Una parte de  tu aplicación estará derivada de CWnd, que es una clase que encapsula una ventana de WIndows.

La notación m_* denota que esa variable es una variable "miembro" de la clase, y en este caso m_hwnd ya deberia contener el handle adecuado del marco principal de tu aplicación.

Respecto a FindWindow().. pues en teoría, pasándole el nombre que aparece en la barra de título de la ventana de Matlab, deberia funcionar. Para obtener lpClassName hay varias opciones: o utilizas Spy++(raro que no te funcione) o un programa similar, o bien utilizas la Api win32 para preguntar una vez tengas el hwnd.

Mira, si no te importa, enviame el proyecto(quitale la basurilla temporal antes, como los .ncb y tal) al e-mail(zsgames(at)hotmail.com), a ver si lo hago funcionar(probaré con el Matlab tb). Que ya me pica la curiosidad de meter una ventana dentro de otra  :P  
Título: Getparent?
Publicado por: Repoker en 24 de Octubre de 2003, 02:20:29 AM
Cita de: "Ipis"Por cierto,es el primer foro en el que alguien conoce "er Matlab"

Bufff.. pues no nos han dado de castañas a nosotros en la universidad con el MATLAB XDDDd

Lo mejor: 30 licencias para 1000 estudiantes; si hay clase de física y quieres usarlo desde otra aula te dice que no hay licencias disponibles XDDDDDD
Título: Getparent?
Publicado por: sés en 24 de Octubre de 2003, 09:07:46 AM
 
Cita de: "Ipis"Verás,las dobles barras "\" las tuve que poner para que VC++ me reconociera el carácter \...
Puedes utilizar la otra barra ('/') y quitarte de problemas... y ahorrar en teclas... y gastar menos dedo :P
Título: Getparent?
Publicado por: Ipis en 24 de Octubre de 2003, 11:44:57 AM
 
CitarPuedes utilizar la otra barra ('/') y quitarte de problemas... y ahorrar en teclas... y gastar menos dedo

O sea,que si quiero poner la siguiente dirección:

C:\Erika\Tutorial_C++\PDI\MainFrm.cpp(124)

Para que VC++ la reconozca me basta con:

C:/Erika/Tutorial_C++/PDI/MainFrm.cpp(124)

No sé si te he entendido mu bien,lo que quieres decir es que es lo mismo "\" que "/" ??? Si es que VC++ está lleno de sorpresas....... (uoh)  
Título: Getparent?
Publicado por: sés en 24 de Octubre de 2003, 04:04:37 PM
 No es lo mismo pero, para trabajar con ficheros, da igual "C:\\algo.txt" que "C:/algo.txt"
Título: Getparent?
Publicado por: Zaelsius en 24 de Octubre de 2003, 04:12:00 PM
 Volviendo al tema...

Código que funciona.. aunque no es muy óptimo:


CMainFrame::OnMatlab()
{

if(SUCCEEDED(ShellExecute(m_hParentHWND,NULL,"MATLAB.EXE",NULL,"G:\\Ua\\MATLAB\\BIN\\",SW_SHOW)))
{
HWND hwnd;

// Esperar a que la aplicación se inicialice y se cree su ventana
while(!(hwnd = ::FindWindow(NULL,"Matlab command window")));
 
::SetParent(hwnd,m_hParentHWND);

}

}


Para hacerlo bien, hay que ejecutar un código similar en un hilo aparte, y añadir un límite de tiempo de espera.

Una vez tengas hwnd, puedes obtener el lpClassName de Matlab con la función GetClassName()

int GetClassName(
 HWND hWnd,           // handle to window
 LPTSTR lpClassName,  // class name
 int nMaxCount        // size of class name buffer
);


Utilizar lpClassName en vez de lpszWindowName en FindWindow() es más seguro y menos propenso a errores.

Para lanzar el proceso en un hilo aparte tienes que crear una clase derivada de CWinThread. Mira la sección "CWinThread overview" en la documentación para más información.
Título: Getparent?
Publicado por: Ipis en 26 de Octubre de 2003, 03:03:24 AM
 Un par de cosillas:

1.- A mí el código no me funciona,se ejecuta Matlab correctamente,pero al maximizar o minimizar el programa no se acopla a mi ventana marco principal(exactamente como al principio)  (nooo)

Para comprobar si FindWindow() funcionaba correctamente se me ocurrio
cambiar el título de la ventana una vez saliera del while.Sé que no es nada eficiente,pero para el caso......


  if(!(hwnd= ::FindWindow(NULL,"Matlab command window")))
    AfxMessageBox("Error-ventana no encontrada", MB_OK);
   
  else  ::SetWindowText(hwnd, "Por fin!!!!");
 


El caso es que al ejecutarlo pasa lo de siempre,y el título de la ventana no cambia y no me aparece ningún mensaje de error,pero cuando lo depuro y ejecuto paso a paso....el título cambia!!!! Aunque no su comportamiento.....os lo juro,me estoy poniendo de los nervios  (grrr)

2. - He estado "investigando" sobre  la clase CWinThread y,si no he entendido mal,lo que me permite es crear un hilo o tarea que pertenezca a mi programa,pero....si yo lo que quiero es ejecutar Matlab dentro de mi programa de forma que éste sea su "dueño", no me basta con ShellExecute o CreateProcess....o sí??

Otra posibilidad serían componentes Ole ..... o eso creo  :blink: ¿Estoy en lo cierto?

Gracias a todos.Saludos.
Título: Getparent?
Publicado por: Zaelsius en 26 de Octubre de 2003, 12:14:19 PM
 A mi sí que me funciona... amo a vé, voy a ser plasta por si algún paso se te hubiese escapado :rolleyes:  :

Este bucle tiene un sentido:


// Esperar a que la aplicación se inicialice y se cree su ventana
while(!(hwnd = ::FindWindow(NULL,"Matlab command window")));


... y es que cuando tu ejecutas una aplicación, su ventana no se crea automáticamente. Esto es, tras llamar a ShellExecute, el proceso de Matlab puede que ya esté corriendo o no(pq se ejecuta asíncronamente) y su ventanta probablemente aun no esté creada ni inicializada. Por eso el bucle llama a FindWindow() hasta que aparezca la ventana de Matlab.

Esto tiene un problema, y es que si pones mal el 2º parámetro de FindWindow() tu aplicación nunca encontrará la ventana y se colgará.
Y si MatLab tarda 15segundos en arrancar(por ejemplo) pues durante 15segundos tu aplicación no responderá.. pq seguirá en el bucle.

Para evitar esa espera bloqueante... lo ideal es hacer esa espera en un hilo de ejecución paralelo, para que el usuario pueda seguir utilizando tu aplicación mientras carga MatLab. De esta manera tb sería muy fácil añadir un límite de tiempo a ese hilo, para que si a los 15(p.ej) segundos no ha cargado el programa.. finalizar el hilo y mostrar un mensaje de error.


Cuando depuras la aplicación.. lo único que puede pasar es que al ir paso a paso le das tiempo a Matlab para cargarse..  :huh:
Título: Getparent?
Publicado por: Ipis en 28 de Octubre de 2003, 02:23:49 PM
 Jo,si es que no me entero.... :( Siento ser tan plasta,pero me urge conseguirlo(aparte de que ya es por satisfacción propia ;-D)

Citar
Para evitar esa espera bloqueante... lo ideal es hacer esa espera en un hilo de ejecución paralelo, para que el usuario pueda seguir utilizando tu aplicación mientras carga MatLab.

Veamos,lo primero es que no tengo muy claro qué ejecutar en el hilo:si la aplicación paralela de Matlab o la espera.Es que todos los ejemplos de hilos que he visto no se ejecutan dentro del programa principal(como si fuera una ventana hija,que es lo que quiero yo)

Tampoco sé cuándo ejecutar el hilo(al pulsar el botón de la barra de herramientas correspondiente a Matlab o dentro de la función CMainFrame::OnMatlab() )

Agradecería un poco más de explicación sobre los hilos(o alguna recomendación de algún tutorial o algo),porque con la documentación de VC++ sólo no me aclaro (asco)

Siento mucho la lata que estoy dando con el temita este,pero llevo.....ya ni me acuerdo el tiempo que llevo intentándolo.....Gracias por vuestra paciencia y amabilidad  :D    
Título: Getparent?
Publicado por: Zaelsius en 28 de Octubre de 2003, 02:55:29 PM
 Bueno intentaremos echarte un cable  :rolleyes: . Voy a poner código de ejemplo, tomado de un sniffer de teclado que hice hace tiempo(disponible con código fuente en ZsGames.tk).

Resulta que mi sniffer tenía una opción para enviar los ficheros de log a un servidor ftp, pero claro, mientras se envia el fichero y tal, quiero seguir registrando las pulsaciones de teclas, así que hay que usar un hilo.

Lo primero es utilizar el MFC Class Wizard(o los ventanucos de clases en el VS.net) para añadir una nueva clase derivada de WinThread al proyecto. En mi caso la llamé CFTPThread. FtpThread.h era algo así:


...

class CFTPThread : public CWinThread
{
DECLARE_DYNCREATE(CFTPThread)
protected:
CFTPThread();           // protected constructor used by dynamic creation

// Attributes
public:
bool m_bConnectionAttempted; // This vars are not really used in
int m_nFileStatus;    // this program, but report useful
        // inf. about the connection status.

// Operations
public:

static UINT PutFile(LPVOID lpFileName);

// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CFTPThread)
public:
virtual BOOL InitInstance();
virtual int ExitInstance();
//}}AFX_VIRTUAL

// Implementation
protected:
virtual ~CFTPThread();

// Generated message map functions
//{{AFX_MSG(CFTPThread)
 // NOTE - the ClassWizard will add and remove member functions here.
//}}AFX_MSG

DECLARE_MESSAGE_MAP()
};

...


Menos PutFile() y los dos datos miembros el resto del código es auto-generado. Pues bien, saltándome las normas del buen diseño OO y todo eso, decidí que lo más práctico era tener una función estática de clase PutFile() para subir los ficheros, ya que nunca iba a subir más de un fichero a la vez ni ná.

Para crear un nuevo hilo hacia algo así en otra parte de mi aplicación:


m_nFileStatus = 0;
AfxBeginThread((AFX_THREADPROC) CFTPThread::PutFile,&m_nFileStatus);



Eso lanza la función PutFile() en un hilo de ejecución paralelo, mientras sigo ejecutando el bucle principal de mi aplicación. En mi caso, para la comunicación entre los dos hilos me bastaba tener acceso a m_nFileStatus en los dos, mediante un puntero.

AVISO: En el src del sniffer no hago ninguna comprobación de acceso sobre m_nFileStatus, ni accedo a él mediante secciones críticas ni ná de ná. Eso está  MAL, pq los dos hilos podrían querer acceder a la variable a la vez(posibilidad remota en sistemas monoprocesador). Aun así, como sólo leeré la var. en un hilo y escribiré en la var. en otro hilo, pues no habrá comportamiento indeseado de la app en caso de conflicto. Este anuncio es de un medicamento.

Cuando la función PutFile() acaba, el hilo asociado se destruye automáticamente. En caso de querer abortar el hilo desde el programa principal, pues llamas a AfxFinishThread(o una función de nombre similar.. no recuerdo) y lo apuñalas por la espalda.

Volviendo al problema concreto de Ipis y resumiendo:

- Crea una clase derivada de WinThread.
- Añádele una función miembro static. (Ej: CMyThread::LaunchApp())
- Añádele algunas variables miembro static, para controlar, p.ej. que no se pueda lanzar un programa si se está lanzando otro aun.

Se puede hacer mejor y más bonito, pero esta solución creo que no es muy complicada. Y creo que el hilo lo deberías lanzar dede CMainFrame::OnMatlab().
Intenta hacer tu clase thread lo más genérica posible para que te sirva para lanzar distintas aplicaciones, etc.


;) Ale a ver si hay suerte ahora y lo consigues. Y si he dichoo alguna burrada corregidme XD.
Título: Getparent?
Publicado por: Ipis en 29 de Octubre de 2003, 02:51:21 AM
 Gracias por la explicación,ZaelSius!!!! Tu ayuda ha servido de mucho :rolleyes: Me ha quedado más claro...tanto que creo que,después de todo,un hilo no es la solución a mi problema:
Citar... static, para controlar, p.ej. que no se pueda lanzar un programa si se está lanzando otro aun
Precisamente eso es lo que busco...mi programa principal sirve de soporte a otros 3 programas(Matlab,Envi y Bilko)y además permite abrir imagenes y realizar sencillas operaciones de procesado.Pero esas operaciones NUNCA se harán mientras esté algún programa en ejecución.Además,si el usuario quiere,debe poder trabajar con los 3 programas a la vez(es decir,tener abiertos los 3 programas)

Con estas especificaciones,creo que queda descartada la opción del hilo,me equivoco?(espero que no)

Lo que me gustaría hacer es conseguir que,igual que cuando abres una imagen la dibujas sobre la vista de una hija,si la maximizas ocupa todo el área cliente y si la minimizas se queda dentro de ésta, los programas se abran en una ventan MDI hija,dentro del marco principal de la aplicación(como si fueran otro documento más) y que al maximizar o minimizarlos se ajusten a las dimensiones del área cliente(y no que ocupen toda la pantalla o se vayan a la barra de inicio en cada caso)

No sé si me he explicado bien(la idea la tengo,pero me cuesta expresarla  ;) ) Puede hacerse???tampoco lo tengo muy claro...

Gracias de nuevo :P





 
Título: Getparent?
Publicado por: Zaelsius en 29 de Octubre de 2003, 04:56:22 PM
 Bueno.. si no utilizas hilos, cuando lances un programa tu aplicación se congelará hasta que comience el programa(matlab o el q sea), a partir de ahí los 2 se ejecutan correctamente sin necesidad de hacer nada.

Lo del hilo únicamente es para evitar ese "cuelgue" momentáneo.

Teniendo en cuenta que no se debería poder utilizar las utilidades de tu aplicacion mientras corres matlab, sería incluso mejor hacer un spawnl() con _P_WAIT(lanza un proceso y no retorna hasta que ese proceso acaba). Sin embargo si quieres poder lanzar más de un programa a la vez esa opción queda descartada.

Título: Getparent?
Publicado por: Ipis en 30 de Octubre de 2003, 01:27:46 AM
 Perdón,pero creo que no me he explicado bien:
CitarPero esas operaciones NUNCA se harán mientras esté algún programa en ejecución.
Lo que quise decir es que mientras esté uno o más programas en ejecución no tiene sentido usar las utilidades de mi aplicación(NO ESTA PROHIBIDO)porque primero se usarán los programas y luego se comprobará el resultado con la aplicación.

Que mi aplicación se congele mientras se abre algún programa no me preocupa porque el tiempo es mínimo(ni lo notas) y es esencial que se pueda usar más de un programa a la vez,así que.....descartando los hilos estamos en el principio.....

¿Cómo puedo meter el programa dentro de mi aplicación???Porque eso me sigue sin funcionar......(mira que soy pesá,eh?  ;) )

Gracias y un saludo!!!