Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   C++ Builder (https://www.clubdelphi.com/foros/forumdisplay.php?f=13)
-   -   Pasar mensajes con punteros a otra aplicación (https://www.clubdelphi.com/foros/showthread.php?t=53234)

escafandra 14-02-2008 18:13:17

Pasar mensajes con punteros a otra aplicación
 
Por lo que se, para que TApplication reciba un mensaje de usuario hay que definir el evento Application->OnMessage = AppMessage; y escribir AppMensage:
Código:

//---------------------------------------------------------------------------
void __fastcall TForm1::FormCreate(TObject *Sender)
{
  // Asignación del procesador de mensajes para la aplicación y sus ventanas
  Application->OnMessage  = AppMessage;
}
.
.
.
.
//---------------------------------------------------------------------------
void __fastcall TForm1::AppMessage(tagMSG &Msg, bool &Handled)
{
  // USERM_SETPARAM Mensaje de Usuario pasar parámetros
  if (Msg.message == USERM_SETPARAM){
    CmdLine = (char*)Msg.wParam;
    Handled = true;
  }
}

Para que esta forma de enviar mensajes funcione, deben enviarse con la funcion PostMessage. No admite SendMessage del API de Windows, según la propia ayuda de Builder y mi propia experiencia.

El problema está que la ayuda de Builder advierte que no se pasen punteros pues se perderán antes de recibir el mensaje.

He comprobado que si ese mensaje con punteros se envía desde la propia aplicación, el puntero no se pierde. Sin embargo, si es otra la aplicación que lo envía, se recibe el puntero, pero su contenido es NULL.

Se me ocurre sobrecargar la funcion TApplication:WndProc(Messages::TMessage &Message), pero me parece engorroso.

¿Alguien tiene una idea de un método más simple?

Saludos

jachguate 14-02-2008 18:51:58

¿son ambas aplicaciones hechas en builder?

Si es así, revisa la idea de Al de los objetos SuperGlobales

Hasta luego.

;)

Mick 14-02-2008 18:59:44

El problema lo estas enfocando de una manera incorrecta, cada aplicacion tienen un espacio de direcciones distinto, y no se ven unas a otras, aunque pases el puntero de una aplicacion a otra (total solo es un numero una direccion de memoria) no podras hacer nada con eso para acceder a los datos de la otra aplicacion ya que te saldra un "access violation".

Tendras que usar ficheros mapeados en memoria o crear memoria compartida, para que las dos aplicaciones puedan acceder a la misma zona de memoria.


Ssludos

escafandra 14-02-2008 19:24:21

jachquate, si, ambas aplicaciones están escritas en Builder.
Mick, No estoy muy seguro de que no pueda pasar punteros por los espacios de memoria diferentes. No obtengo errores "access violation", simplemente el valor se borra, como advierte la ayuda "Si se usa PostMessage".

Por otro lado el propio Windows tiene mensajes para pasar texto WM_GETTEXT y WM_SETTEXT. Y con esto yo si paso texto con las API.
Yo pretendo un mensaje de usuario para poder interceptarlo inequívocamente y de alguina manera emular lo que el propio windows hace...

Me miraré lo de los objetos superglobales....

Gracias

seoane 14-02-2008 20:49:24

Si se pudieran compartir punteros a través de simples mensajes me pregunto para que creo microsoft el mensaje WM_COPYDATA.

En realidad es como te dice Mick, no se pueden compartir punteros entre aplicaciones. Sin embargo con ciertos mensajes puede dar esa impresión, pero es internamente windows el que se encarga de "copiar" los datos de un proceso a otro.

En resumen, yo utilizaría WM_COPYDATA que por algo lo creo microsoft ;)

escafandra 14-02-2008 21:48:21

Muchas gracias [seoane]. Voy a seguir tu consejo.

EDITO:
Parece ser que sólo se puede usar con SendMessage y no con PostMessage.
Para sobrecargar la recepción de un mensaje a una aplicación en Builder, e imagino que también en delphi, solo se puede usar PostMessage. Esto obliga a utilizar otro método de sobrecarga, quizas reescribir (como ya apunté al principio) TApplication:WndProc(Messages::TMessage &Message) o en su caso usar una clase derivada de TApplication.

Se me antoja que debería ser mas sencillo.

Ñuño Martínez 15-02-2008 09:33:18

Una pregunta, ¿por qué no utilizar la comunicación por red, a través del loop-back (localhost ó 127.0.0.1)? Es el método que se suele utilizar en los sistemas POSIX (UNIX, Linux, Solaris, MacOS, ...), incluso para comunicar el programa con el gestor de ventanas, y en mi opinión es bastante mejor, más lento pero mucho más flexible y menos propenso a las corrupciones de memoria.

En fin, una simple opinión.

escafandra 18-02-2008 01:12:36

Pues como parece que la solución no pasa por enviar un simple mensaje, tendre que tratar de hacerlo de otra forma. La idea de la memoria compartida suena bien, pero no se como hacerlo. Tampoco se como mapear ficheros en memoria, como apuntaba Mick.

Una solución fácil puede ser escribir un fichero en disco, pero parece chapucero...

Ñuño Martínez 18-02-2008 10:43:20

Pues yo insisto con lo del loop-back :rolleyes:

Mick 18-02-2008 14:01:58

Busca en google "delphi shared memory" y encontraras documentacion de sobra,
por ejemplo:

http://www.eagle9.nl/main/Programmin.../ProgShMem.asp

Saludos

escafandra 18-02-2008 21:22:08

Cita:

Empezado por Mick (Mensaje 266604)
Busca en google "delphi shared memory" y encontraras documentacion de sobra,
por ejemplo:

http://www.eagle9.nl/main/Programmin.../ProgShMem.asp

Saludos

El tema es muy interesante. Cuando tenga un rato experimentaré. Promete ser una buena solución y no muy compleja.

Gracias.

escafandra 19-02-2008 16:30:27

Correcto shared memory funciona.
He implementado una clase para hacerlo y utilizando esa clase, con dos líneas de programación, consigo comunicar los dos programas con éxito.

El tema del loop-back lo investigaré mas despacio. También parece interesante.

Gracias.

EDITO:

Pero... al pasar punteros tengo problemas si copio sus contenidos en memoria local del proceso.
En el servidor, copio el contenido de un array de texto (char*) al shared memory dimensionado para tal. En el cliente copio esa memoria a un array de dimensión conocida. Si hago este último paso, termino teniendo errores en otras zonas de código, posiblemente por corrupción de memoria. Algo hago mal o no es un buen sistema para pasar arrays. Seguiré investigando.

jachguate 19-02-2008 22:58:15

Bueno, los elementos del arreglo deben estar "auto contenidos" en la misma zona de memoria compartida. En c un array de texto (char*) es, en realidad, un array de punteros... por lo que volvemos al inciso 1.

Si te las arreglas para que todos los datos estén en la zona compartida, no te dará problemas.

Hasta luego.

;)

escafandra 20-02-2008 08:15:22

Cita:

Empezado por jachguate (Mensaje 267080)
Bueno, los elementos del arreglo deben estar "auto contenidos" en la misma zona de memoria compartida. En c un array de texto (char*) es, en realidad, un array de punteros... por lo que volvemos al inciso 1.

Si te las arreglas para que todos los datos estén en la zona compartida, no te dará problemas.

Hasta luego.

;)

Si, si tengo problemas. No paso un array de cadenas (char**) sino una simple cadena (char*) y no paso el puntero, sino su valor, es decir copio el contenido del puntero char* a la memoria compartida. Al otro lado la puedo leer, pero si lo hago.... Corrupción de memoria.

Por otro lado, creo que en algunas ocasiones el sistema puede impedirte la creación de memoria compartida. ¿Puedes hacerlo si el programa corre sin identificarse como administrador?.

jachguate 20-02-2008 08:21:46

No tengo C a mano, y dado que no lo uso mas que eventualmente, no creo ser el mas adecuado para hablar de esto. Pero char* no es un puntero a una cadena terminada en nulo?

Si "copias" el contenido del puntero, lo que estas copiando es eso, el puntero.. que del otro lado, apuntará a una dirección que no existe.

Por que no probás, por ejemplo, en lugar de esto, construir un arreglo de caracteres en la memoria compartida.

Se me hace mas fácil de explicar en pascal: el equivalente al tipo string[x] o a un array[0..x] of char.

Hasta luego.

;)

escafandra 20-02-2008 11:03:06

No. char* es un puntero a un caracter (char), o mas bien, un número de 16 bits. Por convenio, las cadenas en C terminan en nulo, Así con un puntero a un char (char*) puedes referirte a una cadena si quieres. Así char* apunta el primer caracter de la cadena. El nulo te indica el final de la cadena, de esta forma no tienes que conocer su longitud. Evidentemente para que char* sea una cadena de caracteres, se debe tener reservada memoria consecutiva + un caracter que será el nulo.

Yo copio esa memoria consecutiva, desde el primen cáracter hasta el nulo, incluido en la memoria compartida, es decir, en esa memoria no hay punteros, solo valores de tipo char (caracteres). Que es lo que tratas de explicar en pascal (string[x] o a un array[0..x] of char).

No se si me explico bien.
Saludos.


La franja horaria es GMT +2. Ahora son las 01:08:11.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi