PDA

Ver la Versión Completa : Direccion de memoria de una funcion cuyo nombre esta en una variable


Rudorf
29-07-2003, 14:43:29
Buenas, necesito ayuda para pasar la direccion de una funcion a una variable puntero. El problema es que el nombre de la funcion está dentro de una variable y no se como pasarlo.

Nombrefuncion:='MiFuncion';
VPuntero:=addr(Nombrefuncion); // Algo similar a esto busco

Si a Addr le paso MiFuncion en vez de Nombrefuncion, funciona perfectamente, el problema es que no tengo más remedio que hacerlo como lo describo.

Si alguien lo sabe o sabe que no se puede, respondame al mail.
GRACIAS

__marcsc
29-07-2003, 14:56:24
Hola,

piensa que esto es una cosa poco natural, y sería conveniente que tuvieras un buen motivo para hacerlo...

Lo que puedes hacer, en teoría, es conocer la dirección de un método publicado de un objeto, gracias a la función de clase MethodAddress de la clase TObject.


class function MethodAddress(const Name: ShortString): Pointer;


Si eso no te sirve dudo mucho que puedas hacerlo, recuerda que Delphi es un lenguaje compilado y por tanto para hacer eso que tu quieres el compilador debería generar esa información (que yo sepa no lo hace).

Lo que hace esa función de la clase TObject puede hacerse gracias a la RTTI (Runtime Type Information) que se mantiene de cada objeto. Concretamente esa función es utilizada por el sistema de streaming de Delphi, es decir, se utiliza cuando se lee de un fichero dfm, ya que de allí se lee un nombre de procedimiento (publicado) que debe poder traducirse en una dirección de memoria.

Espero una contestación :)

Saludos.

Rudorf
30-07-2003, 08:39:52
Pues muy bien, me ha funcionado y me ha sacado de un buen apuro.

Matizo que la funcion o procedimiento debe estar declarada public o published para que funcione correctamente el MethodAddress.

Un saludo y GRACIAS

__marcsc
30-07-2003, 08:43:22
Pues gracias por el matiz, no sabía que funcionaba con métodos public (en el help dice que solamente funciona con published, y la verdad nunca he utilizado el método :D)

Un saludo y me alegro que te haya servido.

delphi.com.ar
30-07-2003, 16:08:46
Posteado originalmente por marcsc
Lo que hace esa función de la clase TObject puede hacerse gracias a la RTTI (Runtime Type Information) que se mantiene de cada objeto.
Dudo mucho esto, pues este método de clase pertenece a TObject que es una clase que no guarda "Run Time Type Information", y si lo implementamos en una clase heredada de TObject, funciona de todos modos. (Empezó el debate? :D )

Saludos!

__marcsc
30-07-2003, 16:31:57
Esto es la guerra!! :D:D:D:D

cierto lo que dices, no se guarda RTTI de TObject porqué no tiene miembros published :rolleyes:

Lo que me despistó, y lo que en parte no comprendo es que el propio help comenta que solo es válido para miembros published. Por tanto si es published es que se genera RTTI (dado que en teoría esta es la diferencia entre public y published). Además, si las funciones sirven para hacer el streaming de un dfm, que sentido tiene que estén disponibles a partir de TObject? No sería más lógico que estuviera disponible a partir de TComponent? Ya que, en un dfm solo se almacenan propiedades publicadas, que son las que aparecen en el Object Inspector, no? Quizás puede ser que interese que yo tenga propiedades publicadas aunque no sea un componente. Pero aún así, Delphi no podría guardarlos automáticamente en el dfm a menos que no derivara de TComponent, no?

Saludos!

delphi.com.ar
30-07-2003, 17:26:57
Posteado originalmente por marcsc
cierto lo que dices, no se guarda RTTI de TObject porqué no tiene miembros published :rolleyes:
Te paso un fragmento de un artículo que escribí hace ya tiempo: ...Las clases que al compilar generan la RTTI, son aquellas que han sido declaradas bajo la directiva {$M} y todas las clases heredadas de estas, por ejemplo TPersistent con esta directiva, esto implica que todas las clases heredadas de TPersistent generarán RTTI y podremos acceder a la lista de propiedades publicadas en tiempo de diseño y ejecución...
Entre tantas cosas MethodAddress la debe utilizar el TReader cuando lee el DFM del form, recordemos que el código que se encuentra en el DFM no se compila, lo que a mi parecer es una pequeña desventaja del lenguaje.

Saludos!!

PD:
¡¡¡¡Será guerra!!!!

__marcsc
31-07-2003, 01:24:41
Hola,

esto es un pequeño resumen del help de delphi, en referencia a la RTTI:


Los miembros publicados tienen la misma visibilidad que los públicos. La diferencia es que se genera RTTI para los miembros publicados

...


Una clase no puede tener métodos publicados a menos que sea compilada con la directiva {$M+} o que descienda de una clase compilada con la directiva {$M+}. La mayoría de las clases descienden de TPersistent que está compilada con esta directiva por lo que no es necesario añadirla.


Con esto lo único que quiero decir es que la RTTI se genera porque hay algun miembro de la clase con visibilidad published. Para que esto sea posible es necesario añadir la directiva {$M+}, pero no por añadir esta directiva se generará RTTI de miembros no published.

Repito esto está sacado del help de Delphi, ignoro completamente si es verdadero o falso, pero al menos tiene sentido para mi :)

La guerra continua :D

Saludos!!

roman
31-07-2003, 04:32:03
Un pequeño apunte. De acuerdo con Rudorf MethodAddress funciona para métodos públicos o publicados. Sin embargo una pequeña prueba me mostró lo contrario:


TFoo = class
published
function Doo: Integer;
end;

...

procedure TForm1.Button1Click(Sender: TObject);
var
Foo: TFoo;

begin
Foo := TFoo.Create;
if Foo.MethodAddress('Doo') <> nil then
Beep;

Foo.Free;
end;


El botón hace beep pero se queda mudo si cambiamos published por public

En el primer caso, por cierto, noten que no hay directiva $M de forma que se compila con el default {$M-} de manera que no se genera RTTI (como se comprueba viendo que Foo.ClassInfo es nil) lo cual demuestra que MethodAddress funciona sin usar RTTI.

// Saludos

Rudorf
31-07-2003, 07:31:40
Roman, pues a mi me está funcionando ahora con published, y lo probé con public y tambien iba.

Tengo lo siguiente:

type Cambios=class (TObject)
published
procedure TAG15_Change();
end;

...

type Tag = class (TObject)
PUBLIC
TagChange: procedure();
end;

...

Constructor de Tag
ProcName:=TAGName + '_Change'; // TAG15_Change
TagChange:=Vcambio.methodAddress(ProcName);

...

Evento click de un botón
// TAGLIST de la clase Tag
TAGLIST.TagChange; // LLama al procedimiento TAG15_Change

No se si me he explicado bien
:p

roman
31-07-2003, 08:10:57
No estoy muy convencido del cambio al foro de debates ya que el último mensaje de Rudorf así como la respuesta que doy me parece que regresan el hilo a sus orígenes.

De cualquier forma aquí va la respuesta


No indicas de qué tipo es la variable VCambio pero, a juzgar por la nomenclatura, supongo que es de tipo Cambios que declara el método TAG15_Change como publicado. El que TagChange sea público no tiene nada que ver ya que el punto aquí es si el método MethodAddress funciona o no si el parámetro es el nombre de un método público o publicado. De hecho, si te fijas podrías asignar el resultado de Vcambio.methodAddress incluso a una variable privada de la clase Tag y, me arriesgo a decir, incluso a una variable cualquiera, esto es, un puntero que no forme parrte de una clase.

Por otra parte, si no te va mal, me agradaría que nos contaras el propósito de lo que estás haciendo. Por un lado me llama la atención; pareciera que intentas asignar eventos "OnChange" a ciertos controles pero no alcanzo a entender el papel de la clase Cambios. Por otro lado, muchas preguntas relacionadas con obtener variables o procedimientos a partir de su nombre provienen de personas acostumbradas a lenguajes interpretados como VB o Clipper por lo cual quizá no sepan que hay otras técnicas posiblemente más eficientes y "elegantes" de hacer lo mismo en un lenguaje compilado como Delphi.

// Saludos

__marcsc
31-07-2003, 09:43:32
Hola Roman,

Posteado originalmente por roman
lo cual demuestra que MethodAddress funciona sin usar RTTI.


esto ya me lo vi venir cuando delphi.com.ar hizo notar que es un método de TObject, clase de la cual no se genera RTTI.

Lo que yo digo, y que fue lo que me hizo despistar, aunque visto ahora es un hecho independiente, es qué sentido puede tener la existencia de este método en la clase TObject si funciona para métodos published.

Al principio pensaba que seria más lógico que estuviera disponible a partir de TComponent, ya que en teoría solamente se pueden guardar propiedades en un dfm a partir de TComponent (dado que sinó ni tan solo aparecen en el IDE). Recordemos que el help de Delphi dice que no debería haber necesidad de llamar este método directamente ya que Delphi lo utiliza internamente para streaming. ¿Entonces porqué en TObject? ¿No sería más lógico en TComponent o haciendo alguna concesión más en TPersistent que ya está compilada con la directiva {$M+}?

La respuesta radica en que aunque el Delphi no lo necesite hasta TComponent sí que puede ser que a nosotros nos interese hacerlo antes (como es el caso de Rudorf). De hecho, viendolo de este modo TObject es el sitio adecuado ya que significa que podemos crear un descendiente directo que publique algun miembro y utilizar este método.

Saludos.

delphi.com.ar
31-07-2003, 16:04:41
Ahhhhh... ¡¡Los hice investigar!! ;)
Sabía que se iba a sumar Román en este tema...


Saludos!

__marcsc
31-07-2003, 16:31:10
Posteado originalmente por delphi.com.ar
Ahhhhh... ¡¡Los hice investigar!! ;)
Sabía que se iba a sumar Román en este tema...


Yo también, y aún sabiendo que está de vacaciones y ahora mismo su principal ocupación es contar chistes de elefantes :D :D :D

Saludos!