Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > API de Windows
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 05-02-2010
Avatar de DriverOp
DriverOp DriverOp is offline
Miembro
 
Registrado: ago 2007
Posts: 93
Poder: 17
DriverOp Va por buen camino
Pasar cadenas, string, entre aplicaciones.

Hola a todos.

Necesito que dos aplicaciones hechas en Delphi se pasen entre sí una cadena de caracteres (string).

He hecho algo parecido a esto con integers usando SendMessage y PostMessage. Entiendo que no se pueden pasar strings directamente, hay que usar PChar y he conseguido hacerlo así:

Aplicación que envia el string:
Código Delphi [-]
var
  Cadena: string;
  wParam, Tam: integer;
begin
    Codigo:='Algún texto';
    if ForeginHandle > 0 then
      begin
        wParam := GlobalAddAtom(PChar(Cadena));
        Tam:=Length(Cadena);
        PostMessage(ForeginHandle,CM_MYSTR,wParam,Tam);
      end;
ForeginHandle es el handle de la aplicación que recibirá la cadena, eso lo obtengo con otro mensaje que no es parte del problema actual.

GlobalAddAtom es una función de la API de Windows que crea un atom que es un puntero a la cadena que estoy intentando pasar, wParam es ese puntero. Tal como dice la documentación lo que esta función recibe es un string terminado en nulo, o sea un PChar, por eso casteo el string 'Cadena'.

CM_MYSTR es un mensaje de Windows personalizado. Y Tam contiene el tamaño actual de la cadena que estoy enviando.

Aplicación que recibe el string:
Código Delphi [-]

procedure RecibirCadena(var message: TMessage); message CM_MYSTR;

procedure TAlgunFormulario.RecibirCadena(var message: TMessage);
var
  S: PChar;
begin
  GlobalGetAtomName(Message.WParam,S,Message.LParam+1);
  GlobalDeleteAtom(Message.WParam);
  EdtCodigo.Text:=string(S);
El procedimiento responde con la llegada del mensaje personalizado CM_MYSTR.

GlobalGetAtomName es una función de la API de Windows que toma la cadena apuntada por el puntero que se le pasa como primer parámetro, la pone en el segundo según el tamaño indicado en el tercer parámetro. El puntero es igual al que generé desde la aplicación que envía la cadena.

GlobalDeleteAtom destruye el puntero y los recursos asociados.

S es de tipo PChar pues GlobalGetAtomName requiere de un buffer para almacenar la cadena.

Al tamaño de ese buffer le sumo uno más que el tamaño enviado desde la otra aplicación (variable Tam) porque así me funciona bien aunque no sé por qué ya que si la cadena original medía 20 caracteres (Length(Cadena) = 20) ¿por qué tendía que establecer un buffer de 21 caracteres?.

Hay otro problema con el código receptor. Si lo compilo tal cual está Delphi se queja con un warning diciéndome que 'S' podría estar indefinido. Momentaneamente lo he solucionado encerrando este procedimiento entre {$WARNINGS OFF} y {$WARNINGS ON} ya que si intento asignar cualquier cosa a 'S' antes de usarla en GlobalGetAtomName recibo un access violation que supongo se debe a que 'S' ya está apuntando a otra cosa.

Si bien el código tal como lo veo yo es simple y funciona bien, me da la impresión de que no es la mejor manera de hacer esto. ¿Alguien ve algo malo o se le ocurre una forma mejor de hacer esto?.

Gracias por atenderme.

Un saludo.
Responder Con Cita
  #2  
Antiguo 05-02-2010
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Leyendo lo que escribes me parece que vas por buen camino; pero falta un detalle que es importante porque por el momento tu aplicación funciona de milagro.

La mayoría de funciones de la API de Windows a las que se les pasa un buffer como parámetro, presuponen que dicho buffer ya existe. Recuerda que un PChar no es sino un apuntador y tú debes asignarle memoria explícitamente, por ejemplo, con GetMem:

Código Delphi [-]
GetMem(S, Message.LParam+1);

Al no hacerlo, el compilador te manda la advertencia y GlobalGetAtomName pone la información a donde quiera que apunte S, que, al no estar inicializada, como puede apuntar a un lugar donde no hace daño, también puede apuntar a un lugar que cause un Access Violation.

Posteriormente, antes de salir del procedimiento RecibirCadena, deberás liberar la memoria asignada con FreeMem.

Ahora bien, la documentación de GlobalAddAtom indica que la cadena deberá tener un máximo de 255 caracteres. Una forma de evitar la asignación manual de memoria es usando un arreglo de caracteres:

Código Delphi [-]
var
  S: array[0..255] of Char;

Una variable de este tipo es compatible con PChar por lo que puedes pasarla directamente a GlobalGetAtomName y ya tiene asignados 256 bytes de memoria.

Finalmente, veamos porque de sumarle 1.

Todo PChar, además de los caracteres en sí que contenga, debe terminar en un caracter 0 (#0) que es lo que sirve para saber dónde en la memoria termina la cadena.

Cuando pasas PChar(Cadena) a GlobalAddAtom, el compilador automáticamente convierte el string en pchar agregando el #0 necesario. Pero en GlobalGetAtomName, el trabajo ya no lo hace delphi sino Windows y él va a agregar ese cero. Si tu cadena mide 20 caracteres y sólo reservas espacio para 20, Windows colocara el cero como caracter 21, excediendo el tamaño reservado y por tanto en una parte de memoria que no te pertenece.

// Saludos
Responder Con Cita
  #3  
Antiguo 05-02-2010
Avatar de DriverOp
DriverOp DriverOp is offline
Miembro
 
Registrado: ago 2007
Posts: 93
Poder: 17
DriverOp Va por buen camino
Roman:
Tu respuesta para que sea más clara solo hace falta agregarle agua

Habría asumido erróneamente que era Windows quien inicializaba el PChar por eso lo dejaba así al aire (malditos haraganes de Redmond ).

Eso resuelve el misterio del warning.

Y lo del +1 quedó comprendido.

Gracias por la respuesta.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
pasar un tipo de datos (array of record) entre aplicaciones mauqu Varios 4 26-10-2007 20:04:31
Compatibilidad entre aplicaciones ASP.NET entre Delphi 8 .Net y Visual Studio.Net kenyamg .NET 0 21-02-2007 07:30:33
Arreglo De Cadenas : String victor2023 OOP 6 19-05-2006 22:41:44
Pasar parametros entre aplicaciones Iceman OOP 2 14-06-2005 16:29:25
Pasar mensajes entre aplicaciones snuffer Varios 4 21-11-2003 01:44:21


La franja horaria es GMT +2. Ahora son las 02:05:10.


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
Copyright 1996-2007 Club Delphi