Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

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

Grupo de Teaming del ClubDelphi

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 24-11-2004
Avatar de sitrico
[sitrico] sitrico is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Caracas, Venezuela
Posts: 295
Poder: 21
sitrico Va por buen camino
Optener un Stream como "Result" en una funcion

Buenas:

Estoy mejorando una aplicación y se me ocurrio usar Streams en lugar de archivos temporales pero no he podido "pasar" el resultado de una funcion como un stream.

El caso es el siguiente:

Tengo una aplicacion que usa campos memo para almacenar archivos html (comprimidos) (En el registro 1 guardo los encabezados, y en los siguientes los diferentes contenidos, lo trabajé así para ahorrar espacio ya que como los html son generados desde winword los encabezados de los archivos eran identicos y muy, MUY grandes) entonces para poder usar el archivo html completo uso:

Código Delphi [-]
FiltrarTextos(db,Encabezados,Codigo,IdLibro);  
// Toma el Registro 1 + el que me interesa
Html         :=  TMemoryStream.Create;
InputStream  := TMemoryStream.Create;
OutputStream := TMemoryStream.Create;
Temp         := TMemoryStream.Create;
db.First;
While Not(db.Eof) do
   Begin
   InputStream.Clear;
   OutputStream.Clear;
   Temp.Clear;
   TBlobField(db.FieldByName('Data')).SaveToStream(Temp);
   InputStream.LoadFromStream(temp);
   If InputStream.Size <> 0 Then
      Begin
      ZDecompressStream(InputStream,OutputStream); // estan comprimidos
      Html.CopyFrom(OutputStream,0);
      End;
   db.Next;
   End;
html.SaveToFile(Destino);
Temp.Free;
OutputStream.Free;
InputStream.Free;
html.Free;

Como pueden ver eso me deja con un archivo temporal (destino)
Que cargo en un componente WebBrowser: TEmbeddedWB que permite usar:

WebBrowser.LoadFromFile(Destino);

Pero revizandolo un poco más tambien permite cargarlo desde:

WebBrowser.LoadFromStream(Destino);

Lo que quisiera hacer es convertir el procedimiento anterior en una funcion donde al final poga algo como:

Código Delphi [-]
Function CargarStreamHTML:TMemoryStream;

Begin
// Mismo codigo de antes para leer y descomprimir
// pero en lugar de:
// html.SaveToFile(Destino);
// Usar
Result := html;
End;

He hecho algunas pruebas y he tenido problemas con los create's y Free's ya que al final no sé si debo liberar el objeto asignado al result o si tengo que crear un objeto para asignarle el resultado.

En fin lo que necesito es un ejemplo de una funcion en la que el resultado pueda ir directo a un método "LoadFromStream".

Gracias

Uso delphi 7 + el TEmbeddedWB (http://www.euromind.com/iedelphi/embeddedwb.htm)

Toda la aplicación corre localmente y se usa para consultar unos informes históricos
__________________
Sitrico

Última edición por sitrico fecha: 24-11-2004 a las 17:42:16.
Responder Con Cita
  #2  
Antiguo 24-11-2004
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
Puedes regresar directamente como lo haces

Código Delphi [-]
Result := html;

pero no puedes liberarlo dentro de la misma función sino posteriormente. Por tanto, si usas simplemente:


Código Delphi [-]
LoadFromStream(CargarStream);

tendrás una fuga de memoria ya que no tienes ninguna referencia al Stream devuelto para poder liberarlo, así que tendrías que hacer algo como:


Código Delphi [-]
var
  Stream: TStream;

begin
  Stream := CargarStream;
  LoadFromStream(Stream);
  Stream.Free;
end;

de manera que no ahorras nada.

Si de plano te da flojera escribir tanto podrías englobar el stream dentro de una interfaz:

Código Delphi [-]
type
  ILazyStream = interface
    function GetStream: TMemoryStream;
    property Stream:  TMemoryStream read GetStream;
  end;

  TLazyStream = class(TInterfacedObject, ILazyStream)
  private
    FStream: TMemoryStream;

  public
    constructor Create;
    destructor Destroy; override;

    { ILazyStream }
    function GetStream: TMemoryStream;
  end;

...

constructor TLazyStream.Create(AStream: TMemoryStream);
begin
  inherited;
  FStream := TMemoryStream.Create;
end;

destructor TLazyStream.Destroy;
begin
  FStream.Free;
  inherited;
end;

function TLazyStream.GetStream: TMemoryStream;
begin
  Result := FStream;
end;

En tu función CargarStream creas una instancia de TLazyStream y esa es la que devuelves usando LazyStream.Stream:

Código Delphi [-]
function CargarStream: ILazyStream;
begin
  Result := TLazyStream.Create;

  ...
end;

...

LoadFromStream(CargarStream.Stream);

Así, cuando se pierda el contexto de LoadFromStream (es decir termine el procedimiento desde donde lo llamas) CargarStream, siendo una interfaz, automáticamente llamará al destructor de TLazyStream.

// Saludos
Responder Con Cita
  #3  
Antiguo 24-11-2004
Avatar de sitrico
[sitrico] sitrico is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Caracas, Venezuela
Posts: 295
Poder: 21
sitrico Va por buen camino
Bueno Gracias (aunque la parte del interface escapa de mis posibilidades actuales ) creo que has dado en el clavo.

Por suerte, el trabajo de crear los html lo realizo dentro de un objeto:

Código Delphi [-]
Type
TGenHTML = class(TObject)
  Private
  Public
    Procedure   FiltrarTextos(db:TDataSet;Encabezados:Integer;Codigo: String;IdLibro:Integer);
    Function    GetURL(db:TDataSet;Encabezados:Integer;Codigo,Destino:String;IdLibro:Integer): String;
    Function    GetText(db:TDataSet;Codigo:String): String;
    Procedure   ResaltarBusqueda(f,ElTextoBuscado: String);
    Procedure   ComprimirHtml(db:TDataSet;Origen:String);
   End;

Ahora se me ocurre que puedo cambiar el objeto padre de TObject a TMemoryStream (que cuenta con los Métodos LoadFromStream y LoadFromFile (y los save...) entonces lo unico que tendría que hacer es modificar las rutinas para que en lugar de terminar creando un archivo temporal cargen el stream en el propio objeto derivado de TMemoryStream y no tendría que usar una función para obtener el resultado sino que mi objeto TGenHTML seria un "TStreamGenHTML"

Voy a probar a ver que sale. Gracias nuevamente.
__________________
Sitrico
Responder Con Cita
  #4  
Antiguo 24-11-2004
Avatar de sitrico
[sitrico] sitrico is offline
Miembro Premium
 
Registrado: may 2003
Ubicación: Caracas, Venezuela
Posts: 295
Poder: 21
sitrico Va por buen camino
Bueno, quedo muy bien, al convertir el objeto a un tMemoryStream lo único que tuve que hacer fue asignar el resultado a la variable "Self" y listo

Puedo usar:

Código Delphi [-]
Var
html : THTMLdbStream;
Begin
html := THTMLdbStream.Create;
Try
   html.LoadFromDB(Table1,0,'A0100102',1);
   EmbeddedWB1.LoadFromStream(html);
Finally
   html.free;
   End;
end;

Pero y siempre hay un pero. El componente tEmbeddedWB recibe el archivo html y lo muestra como texto (el código html) aparece:

<html xmlns:v="urn:schemas-microsoft-com:vml" xmlns........

En lugar del archivo formateado.

Pienso que el problema puede estar en el largo de la línea (algunas de mucho más de 256 carácteres) o bien en el primer caracter del stream (distinto a "<") como puedo "Ver" y editar el contenido de un MemoryStream?

Ya he probado casí todo y por lo visto el problema es del tEmbeddedWB voy a buscar otras opciones y si acaso luego pondré otro post.
__________________
Sitrico

Última edición por sitrico fecha: 24-11-2004 a las 22:51:46. Razón: Pruebas
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


La franja horaria es GMT +2. Ahora son las 15:38:33.


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