Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Principal > OOP
Registrarse FAQ Miembros Calendario Guía de estilo Buscar Temas de Hoy Marcar Foros Como Leídos


Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 02-01-2009
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: May 2003
Posts: 5.511
Poder: 23
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Lightbulb Reto Delphi

¡Hola!

Iniciamos el año 2009. Mis mejores deseos para todos los compañeros.

Hace varias semanas publiqué este reto o acertijo, como quiera llamársele, en la cabecera de mi bitácora Web, pero como casi nadie me lee, he preferido colocarlo en el sitio Delphi de lengua española más visitado.

El tema es interesante porque la solución al acertijo resultará útil en ciertos casos especiales de programación (como en este que implementé cuando todavía no conocía dicha solución).

Como muchos saben, TObject, la clase ancestro común, cuenta con un método clase llamado NewInstance, encargado de ejecutar la asignación de memoria pertinente a la hora de crear una instancia. Este método es además virtual, por lo que podemos redefinirlo, es decir, redeclararlo como "override" en una nueva clase, para alterar la manera en que se realiza esa asignación de memoria, impedir ésta o realizar alguna tarea adicional.

En algunos casos sería interesante que, teniendo ya nuestra nueva clase de objeto y habiendo redefinido en ella el método NewInstance, pudiésemos hacer algo como:

Código Delphi [-]
O := TMiClase.Create (Arg);

Y que el método NewInstance fuese capaz de conocer y tratar el valor del parámetro Arg, por alguna operación intrínseca de la nueva clase que tenga que llevarse a cabo forzosamente en el interior del nuevo NewInstance. Digamos que el parámetro Arg proporciona un dato que le indica a NewInstance cómo o dónde debe realizar la asignación de memoria.

El problema que a muchos saltará a la vista es que NewInstance es un método clase y por tanto no puede tener acceso a ningún campo o propiedad del objeto donde el parámetro Arg pudiese ser guardado por el constructor. Pero el problema es aún mayor (y de ahí la motivación de este reto de programación): el método NewInstance es ejecutado ANTES que el constructor usado para la instanciación. ¿Cómo entonces podría el nuevo NewInstance saber qué fue pasado como parámetro al constructor?

En su momento me pareció un caso inútil, algo que no tenía vuelta de hoja, según yo era imposible. Pero hace unos tres meses me propuse estudiar más a profundidad el asunto y experimentando un poco lo conseguí. ¡Sí es posible que NewInstance conozca y use el parámetro dado al constructor! Y lo más chistoso es que no requiere gran cosa de código.

Considerando puntualmente esta premisa, lanzo formalmente el reto (bajo la acepción de la RAE "objetivo o empeño difícil de llevar a cabo, y que constituye por ello un estímulo y un desafío para quien lo afronta", aunque tal vez de difícil no tenga mucho):

Si escribimos una clase derivada de TComponent con el método NewInstance redefinido, ¿cómo puede éste conocer el valor del parámetro AOwner dado al constructor Create?

(Propuse a TComponent como la clase padre por ser ella y su constructor Create relativamente populares).

Es muy posible que alguien más lo haya solucionado ya (hay cientos de miles de desarrolladores Delphi en el mundo), así que ruego total honestidad y que no se divulgue la solución mientras nadie la haya desarrollado por sí mismo y exprese aquí cómo lo hizo. Si después de un tiempo razonable de días o semanas se pierde interés en este hilo, con mucho gusto damos a conocer la solución.

Vamos, que la idea es hacer esto divertido para todos y fomentar un poco el hábito de la investigación al tiempo que procuramos un interés mayor por la POO y el conocimiento general sobre Delphi. Encontrar la solución tendrá cómo único mérito el gozar de tiempo e interés en el tema, no hablará de si somos buenos o malos programadores.

Un nuevo abrazo.

Al González.
__________________
Twitter
Código
Blog
WhatsApp para consultas rápidas y asesorías profesionales: +52 1 2711260117

Última edición por Al González fecha: 02-01-2009 a las 03:28:34.
Responder Con Cita
  #2  
Antiguo 02-01-2009
Avatar de RolphyReyes
RolphyReyes RolphyReyes is offline
Miembro
 
Registrado: Aug 2004
Ubicación: Santo Domingo
Posts: 287
Poder: 15
RolphyReyes Va por buen camino
Smile

Una idea.

Creo que deberías de pedir a algún moderador que lo ponga adherido (creo que ese es el termino) para cuando uno entre a esta sección se vea inmediatamente. Por lo menos por un tiempo prudente.
__________________
Gracias,
Rolphy Reyes
Responder Con Cita
  #3  
Antiguo 03-01-2009
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: May 2003
Posts: 5.511
Poder: 23
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Cita:
Empezado por RolphyReyes Ver Mensaje
Una idea.

Creo que deberías de pedir a algún moderador que lo ponga adherido (creo que ese es el termino) para cuando uno entre a esta sección se vea inmediatamente. Por lo menos por un tiempo prudente.
Estupenda idea Rolphy, parece que ya lo hizo alguno de los moderadores (http://www.clubdelphi.com/foros/forumdisplay.php?f=5).

Gracias a ambos.
__________________
Twitter
Código
Blog
WhatsApp para consultas rápidas y asesorías profesionales: +52 1 2711260117
Responder Con Cita
  #4  
Antiguo 10-01-2009
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: May 2003
Posts: 5.511
Poder: 23
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
¡Hola a todos!

Ha transcurrido una semana sin que alguien dijera "¡acepto el reto!". Sé que es poco tiempo pero aún así creo que valdría la pena ponerlo hoy en condiciones más despejadas, mediante un ejemplo burdo.

Código Delphi [-]
implementation

{$R *.dfm}

Type
  { Se da por entendido que en un caso real tendríamos esta
    declaración en la sección Interface (la he puesto aquí para
    simplificar el ejemplo) }
  TMiComponente = Class (TComponent)
    Public
      Constructor Create (AOwner :TComponent); Override;
      Class Function NewInstance :TObject; Override;
  End;

  Constructor TMiComponente.Create (AOwner :TComponent);
  Begin
    { El reto es mover este par de líneas al método NewInstance,
      ¡y que funcionen! }
//    If AOwner <> Nil Then
//      ShowMessage (AOwner.Name);

    Inherited Create (AOwner);
  End;

  { Porque ¿cómo puede NewInstance tener acceso al parámetro
    AOwner dado al constructor Create? }
  Class Function TMiComponente.NewInstance :TObject;
  Var
    AOwner :TComponent;  // Es necesaria una variable auxiliar
  Begin
    // La respuesta está en el código que debe ir aquí 

    { No vale "AOwner := Form1;".  El objetivo es acceder al
      mismo parámetro que se le dé al constructor, cualquiera que
      sea su valor. }

    // Par de líneas que teníamos en el constructor
    If AOwner <> Nil Then
      ShowMessage (AOwner.Name);

    Result := Inherited NewInstance;
  End;

procedure TForm1.Button1Click(Sender: TObject);
Var
  C :TMiComponente;
begin
  // Creación de la instancia
  C := TMiComponente.Create (Self);

  Try
    // Uso hipotético del objeto
  Finally
    // Destrucción de la instancia
    C.Free;
  End;
end;

¿Alguien interesado en hacer magia con Delphi? ¿Qué código es ese que falta ahí para que todo funcione?

Anexo una copia del programa.

Saludos.

Al González.
Archivos Adjuntos
Tipo de Archivo: zip NewInstance.zip (5,4 KB, 29 visitas)
__________________
Twitter
Código
Blog
WhatsApp para consultas rápidas y asesorías profesionales: +52 1 2711260117
Responder Con Cita
  #5  
Antiguo 10-01-2009
Avatar de felipe88
[felipe88] felipe88 is offline
Miembro Premium
 
Registrado: May 2007
Ubicación: Mi Valle del Cauca... Colombia!!!
Posts: 1.123
Poder: 13
felipe88 Va por buen camino
Al, la verdad me parece interesante lo que planteas, lo habia leido desde el principio cuando lo publicaste; yo por ejemplo no puedo decir mucho al respeto, a veces pienso que me estoy encrudeciendo en POO o que por el contrario no se nada ...

Saludos.

Última edición por felipe88 fecha: 11-01-2009 a las 19:28:24.
Responder Con Cita
  #6  
Antiguo 10-01-2009
Avatar de felipe88
[felipe88] felipe88 is offline
Miembro Premium
 
Registrado: May 2007
Ubicación: Mi Valle del Cauca... Colombia!!!
Posts: 1.123
Poder: 13
felipe88 Va por buen camino
Bueno, nada mal una lectura para familiarizarse con el tema

http://delphi.about.com/od/adptips2005/qt/aowner.htm
Responder Con Cita
  #7  
Antiguo 10-01-2009
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: Jul 2004
Ubicación: Salta, Argentina
Posts: 5.598
Poder: 20
Delphius Va camino a la fama
Hola Al,
He leído muchas veces en esta semana el hilo y todavía sigo pensando en el tema.

Por como lo estoy viendo, intuyo que el casi el único modo de acceder es a través de otros métodos de clase puesto que no se puede acceder a las propiedades de forma directa.

Como bien se sabe, Owner es una propiedad de TComponent, quien es quien guarda el valor. Si fuera método de clase se podría tal vez (estoy divagando) realizar algo como:

Código Delphi [-]
AClass := TMiComponente.GetClassParent;
AOwner := TComponent(AClass).Owner;

Esto da un EAccessViolation, fundamentalmente por lo que he descripto: Owner es una propiedad.

Yo quisiera preguntarte si no es molestia, si debemos emplear esa única variable, o si se nos permite otras. Por ahora no se me ocurre nada...

La verdad es que es un reto un tanto fuera de mis posibilidades pero que es muy interesante.

Como otra opción he pensado es intentar obtener el valor desde métodos RTTI, pero sólo es posible para métodos publicados,y nuevamente otro dilema: Owner es público.

Aqui en este punto, otra pregunta ¿Podemos hacer esos truquitos como del tipo TClase = Unidad.TClase y/o alterar la visibilidad de los atributos?

A lo que voy es si me tengo que ceñir a no alterar nada de como "viene de fábrica", no creo que me sea posible llegar a la solución.

No se... por ahora estoy pensando...

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #8  
Antiguo 10-01-2009
Avatar de roman
roman roman is offline
Moderador
 
Registrado: May 2003
Ubicación: Ciudad de México
Posts: 20.186
Poder: 10
roman Tiene un aura espectacularroman Tiene un aura espectacular
Mi primer intento fue algo como

Código Delphi [-]
function TMiComponente.NewInstance: TObject;
begin
  Result := inherited NewInstance;

  if Result is TComponent then
    Bingo(TComponent(Result).Owner);
end;

pero, aunque Result sí sea a esas alturas un TComponent, la propiedad Owner no ha sido asignada. De hecho, tal asignación se hace en el consructor de TComponent, mismo que sucede mucho después de la llamada a NewInstance.

Por ello no creo que la solución pase por examinar alguna propiedad de este tipo.

Lo único que se me ocurre pero no sabría cómo resolverlo ni si sea factible, es que cuando NewInstance entra en acción, el stack debe contener la referencia al parámetro AOwner (la llamada a Create empuja dicha referencia al stack). Si de alguna forma puede obtenerse este dato del stack, simplemente habría que hacer el moldeo con TComponent. Pero, como digo, no tengo idea de si esta vía es posible.

// Saludos
Responder Con Cita
  #9  
Antiguo 10-01-2009
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: Jul 2004
Ubicación: Salta, Argentina
Posts: 5.598
Poder: 20
Delphius Va camino a la fama
Entonces, roman, ¿tu crees que con RTTI no fuera posible?
Si es así, yo me quedo sin ideas...

Yo no intenté. Como dije, si me tengo que ceñir a "seguir las reglas" pues no tengo muchas opciones.

¿Tu dices si será posible acceder en forma más o menos directa a la tabla de memoria, en el momento en que se está llenando ese valor?

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]

Última edición por Delphius fecha: 10-01-2009 a las 05:51:43.
Responder Con Cita
  #10  
Antiguo 10-01-2009
Avatar de roman
roman roman is offline
Moderador
 
Registrado: May 2003
Ubicación: Ciudad de México
Posts: 20.186
Poder: 10
roman Tiene un aura espectacularroman Tiene un aura espectacular
Pues no lo sé, Delphius, pero no me parece factible. A fin de cuentas, si no mal entiendo, NewInstance básicamente lo único que hace es asignar memoria al nuevo objeto, pero éste, como tal, todavía está vacío.

Tampoco sé lo de la tabla de memoria. Según recuerdo sólo hay un stack por aplicación, así que, posiblemente puedan hacerse los suficientes pop, leer la referencia y hacer los correspondientes push. Pero conforme lo escribo, más me parece que la solución de Al ha de ser mucho más sencilla y de otra índole completamente.

// Saludos
Responder Con Cita
  #11  
Antiguo 10-01-2009
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: Jul 2004
Ubicación: Salta, Argentina
Posts: 5.598
Poder: 20
Delphius Va camino a la fama
Al igual que tu yo también me inclino a que seguramente la solución de Al es sencilla. Así pareciera ser por lo que comenta.

Pues hasta donde yo llego NewInstance reserva la memoria e inicializa la instancia, valiendose de InitInstance.

Me parece que por allí está el meollo del asunto. Yo de asm ni idea, pero por el código que puedo ver... tal parece que InitInstance es quien se encarga de acceder a la tabla:

Código Delphi [-]
class function TObject.InitInstance(Instance: Pointer): TObject;
{$IFDEF PUREPASCAL}
var
  IntfTable: PInterfaceTable;
  ClassPtr: TClass;
  I: Integer;
begin
  FillChar(Instance^, InstanceSize, 0);
  PInteger(Instance)^ := Integer(Self);
  ClassPtr := Self;
  while ClassPtr <> nil do
  begin
    IntfTable := ClassPtr.GetInterfaceTable;
    if IntfTable <> nil then
      for I := 0 to IntfTable.EntryCount-1 do
  with IntfTable.Entries[i] do
  begin
    if VTable <> nil then
      PInteger(@PChar(Instance)[IOffset])^ := Integer(VTable);
  end;
    ClassPtr := ClassPtr.ClassParent;
  end;
  Result := Instance;
end;
{$ELSE}
asm
        PUSH    EBX
        PUSH    ESI
        PUSH    EDI
        MOV     EBX,EAX
        MOV     EDI,EDX
        STOSD
        MOV     ECX,[EBX].vmtInstanceSize
        XOR     EAX,EAX
        PUSH    ECX
        SHR     ECX,2
        DEC     ECX
        REP     STOSD
        POP     ECX
        AND     ECX,3
        REP     STOSB
        MOV     EAX,EDX
        MOV     EDX,ESP
@@0:    MOV     ECX,[EBX].vmtIntfTable
        TEST    ECX,ECX
        JE      @@1
        PUSH    ECX
@@1:    MOV     EBX,[EBX].vmtParent
        TEST    EBX,EBX
        JE      @@2
        MOV     EBX,[EBX]
        JMP     @@0
@@2:    CMP     ESP,EDX
        JE      @@5
@@3:    POP     EBX
        MOV     ECX,[EBX].TInterfaceTable.EntryCount
        ADD     EBX,4
@@4:    MOV     ESI,[EBX].TInterfaceEntry.VTable
        TEST    ESI,ESI
        JE      @@4a
        MOV     EDI,[EBX].TInterfaceEntry.IOffset
        MOV     [EAX+EDI],ESI
@@4a:   ADD     EBX,TYPE TInterfaceEntry
        DEC     ECX
        JNE     @@4
        CMP     ESP,EDX
        JNE     @@3
@@5:    POP     EDI
        POP     ESI
        POP     EBX
end;
{$ENDIF}

Puede que esto tengo que ver... al menos en algo. Mi poco razonamiento de este código me lleva a pensar que hace un ciclo explorando desde su propia clase hacia las clases superiores y rellenando todo. Si es así, en algún punto debe pasar por TComponent y "llenar" el valor de FOwner.

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #12  
Antiguo 10-01-2009
Avatar de roman
roman roman is offline
Moderador
 
Registrado: May 2003
Ubicación: Ciudad de México
Posts: 20.186
Poder: 10
roman Tiene un aura espectacularroman Tiene un aura espectacular
Cita:
Empezado por Delphius Ver Mensaje
Si es así, en algún punto debe pasar por TComponent y "llenar" el valor de FOwner.
Esto es lo que no me cuadra. Si en:

Código Delphi [-]
constructor TMiComponente.Create(AOwner: TComponent);
begin // <- break point (1)
  inherited; // <- break point (3)
end;

class function TMiComponente.NewInstance: TObject;
begin  // <- break point (2)
  Result := inherited NewInstance;
end;

pones los puntos de ruptura indicados, éstos ocurren en el orden anotado. Dicho de otra forma, la llamada a NewInstance se inserta entre el begin del Create y la primera instrucción que tenga.

O sea, que cuando NewInstance se está ejecutando, aún no se ejecuta el constructor heredado (el de TComponent en este caso), de manera que la asignación

Código Delphi [-]
FOwner := AOwner;

aún no se lleva a cabo.

// Saludos
Responder Con Cita
  #13  
Antiguo 10-01-2009
Avatar de dec
dec dec is offline
Moderador
 
Registrado: Dec 2004
Ubicación: Alcobendas, Madrid, España
Posts: 12.646
Poder: 27
dec Tiene un aura espectaculardec Tiene un aura espectacular
Hola,

Pasaba por aquí... ¿alguien ha visto a Al?
__________________
David Esperalta
www.davidesperalta.com
Responder Con Cita
  #14  
Antiguo 10-01-2009
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: Jul 2004
Ubicación: Salta, Argentina
Posts: 5.598
Poder: 20
Delphius Va camino a la fama
Tienes razón roman.
Lo único que termina haciendo ese Init es meter puros ceros en la tabla, de menor a mayor en el árbol de la jerarquía.
Más no llena ninguna propiedad, ni nada por el estilo.

Al no es de hacer bromas, asi que no creo que esto sea una. Yo estuve buscando referencias sobre el tema y no encontré algo que me oriente al respecto. (O tal vez he buscado mal).

Este reto es superior a mi.
Prefiero esperar a que Al nos brinde la solución.

Si es como asegura, que se trata de algo de pocas líneas y muy sencillo para lo que espero e imagino, me muero.
Este post pasa a ser guardado, impreso, y fichado en un folio.

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #15  
Antiguo 10-01-2009
Avatar de roman
roman roman is offline
Moderador
 
Registrado: May 2003
Ubicación: Ciudad de México
Posts: 20.186
Poder: 10
roman Tiene un aura espectacularroman Tiene un aura espectacular
Creo que ésta es la respuesta

Está encriptada para no quitarle el chiste al reto. Ya le pasaré a Al la contraseña al rato.

// Saludos
Archivos Adjuntos
Tipo de Archivo: zip respuesta.zip (164 Bytes, 34 visitas)
Responder Con Cita
  #16  
Antiguo 11-01-2009
Avatar de Al González
[Al González] Al González is offline
In .pas since 1991
 
Registrado: May 2003
Posts: 5.511
Poder: 23
Al González Es un diamante en brutoAl González Es un diamante en brutoAl González Es un diamante en bruto
Cita:
Empezado por dec Ver Mensaje
Hola,

Pasaba por aquí... ¿alguien ha visto a Al?
¡Presente, David!

Cita:
Empezado por roman Ver Mensaje
Creo que ésta es la respuesta

Está encriptada para no quitarle el chiste al reto. Ya le pasaré a Al la contraseña al rato.
Gracias Román, recibí puntual el dato.

Me complace informarles que Román ha escrito los mismos (y escasos) caracteres visibles que yo introduje en la parte señalada del interior de NewInstance, ¡código que consigue que la operación funcione!

Enhorabuena Román. Más adelante, una vez develado el misterio, me gustaría que comentáramos los pormenores que explican por qué esa solución funciona tan bien.

¿Alguien más desea aventurarse a encontrar la solución?

Un abrazo.

Al González.
__________________
Twitter
Código
Blog
WhatsApp para consultas rápidas y asesorías profesionales: +52 1 2711260117
Responder Con Cita
  #17  
Antiguo 11-01-2009
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: Jul 2004
Ubicación: Salta, Argentina
Posts: 5.598
Poder: 20
Delphius Va camino a la fama
Pues yo estoy un cero a la izquierda... No veo como se puede hacer.
Me muero de la emoción por saber cual es la solución.

¡quiero dormir tranquilo!

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #18  
Antiguo 11-01-2009
Avatar de roman
roman roman is offline
Moderador
 
Registrado: May 2003
Ubicación: Ciudad de México
Posts: 20.186
Poder: 10
roman Tiene un aura espectacularroman Tiene un aura espectacular
Cita:
Empezado por roman Ver Mensaje
Lo único que se me ocurre [...] es que cuando NewInstance entra en acción, el stack debe contener la referencia al parámetro AOwner (la llamada a Create empuja dicha referencia al stack).
Aquí estaba equivocado, pero esencialmente fue lo que me llevó a la solucion.

Por otra parte, creo que no está de más recordar del mensaje original de Al, que el planteamiento del problema es para cualquier clase, no necesariamente derivada de TComponent.

// Saludos
Responder Con Cita
  #19  
Antiguo 11-01-2009
Avatar de Delphius
[Delphius] Delphius is offline
Miembro Premium
 
Registrado: Jul 2004
Ubicación: Salta, Argentina
Posts: 5.598
Poder: 20
Delphius Va camino a la fama
Cita:
Empezado por roman Ver Mensaje
Aquí estaba equivocado, pero esencialmente fue lo que me llevó a la solucion.

Por otra parte, creo que no está de más recordar del mensaje original de Al, que el planteamiento del problema es para cualquier clase, no necesariamente derivada de TComponent.

// Saludos
Ummm... ¿el stack te inspiró?
No se si volver a entrarle. Tengo el cerebro frito por ahora.
Haces bien en recordarlo, estuve haciendo una traza del que sucede en los create y NewInstance con clases que no derivan de TComponent. Estuve probando con clases propias... para ver si descubría alguna diferencia. Todavía no descubro nada.

No se si vale que siga intentando. No se, quizá luego retorme el tema. Por ahora es para mi más que un reto.

Saludos,
__________________
Delphius
[Guia de estilo][Buscar]
Responder Con Cita
  #20  
Antiguo 11-01-2009
Avatar de roman
roman roman is offline
Moderador
 
Registrado: May 2003
Ubicación: Ciudad de México
Posts: 20.186
Poder: 10
roman Tiene un aura espectacularroman Tiene un aura espectacular
Cita:
Empezado por Delphius Ver Mensaje
Ummm... ¿el stack te inspiró?
Digamos que yo "sabía" que el stack se usaba para pasar los parámetros a las funciones, y en eso estaba (parcialmente) equivocado.

Cita:
Empezado por Al González
Más adelante, una vez develado el misterio, me gustaría que comentáramos los pormenores que explican por qué esa solución funciona tan bien.
Creo que ahora entiendo cabalmente la razón, aunque confieso que al momento de encontrar la solución, estaba yo dando palos de ciego.

// Saludos
Responder Con Cita
Respuesta


Herramientas Buscar en Tema
Buscar en Tema:

Búsqueda Avanzada
Desplegado

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
¿Qué les parece un reto? D-MO PHP 20 24-07-2007 18:45:11
Un reto con Qreport MRSAM Conexión con bases de datos 8 13-07-2007 19:10:58
Esto si es un reto perrogrun OOP 10 09-07-2004 22:49:25
Un reto a todos Rendertaker Internet 3 14-04-2004 22:51:29
Reto de Impresora (VB vs Delphi) torito Varios 12 21-11-2003 19:54:59


La franja horaria es GMT +2. Ahora son las 07:08:33.


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