Ir al contenido



Foto

TStream.SaveToFile() Access Violation


Mejor respuesta egostar , 13 septiembre 2017 - 12:08

¿ Puedes instalar MadExcept para que haga un Log con el error ?. Nos va a decir en que línea exacta del código interno de la VCL falla el programa, además de mucha más información interesante.

 
Hola amigo Marc,
 
Ya he encontrado el error, resulta que por alguna extraña razón *-)  *-)  *-)  tenia la siguiente línea
 


delphi
  1. begin
  2. //.....
  3. if not DirectoryExists( Ruta ) then
  4. if not CreateDir( Ruta ) then
  5.  
  6. Cadena := DecodeString(Content);
  7. //.....
  8. end;

El punto es que el decodeString() es parte del if y nunca lo hacía. WTF.........

Ya necesito vacaciones......  ^o|  :|  

Saludos

Ir al mensaje completo


  • Por favor identifícate para responder
20 respuestas en este tema

#1 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.648 mensajes
  • LocationMéxico

Escrito 08 septiembre 2017 - 03:15

Hola amigos
 
Resulta que estoy creando un servicio Web y necesito almacenar un archivo que me enviarán en Base64, éste procedimiento funciona perfectamente en una aplicación de escritorio, pero al intentar ejecutarlo en la implementación del método del servicio web me genera el siguiente error.
  
 

       <faultstring>Access violation at address 0042060F in module 'Preval.exe'. Read of address 00000004</faultstring>

 
 
El código utilizado es el siguiente:
 
  


delphi
  1. procedure Base64ToFile(FileStr, FName: String);
  2. var
  3.   Stream: TMemoryStream;
  4.   Cadena : TStringStream;
  5. begin
  6.   Stream:= TMemoryStream.Create;
  7.   Cadena := TStringStream.Create(FileStr);
  8. //  Cadena.Seek(0,0);
  9. //  Stream.CopyFrom( Cadena, Cadena.Size );
  10. //  Stream.LoadFromStream(Cadena);
  11.   MimeDecodeStream(Cadena,Stream); //En esta línea se genera el error....
  12.   Stream.Seek(0,0);
  13.   Stream.SaveToFile(Rutasafe + '\Almacen\' + FName);
  14.   Stream.Free;
  15.   Cadena.Free;
  16. end;

 
Las líneas comentadas son las que he intentado utilizar y en todas me genera el mismo access violation.
 
Ojalá y alguien pudiera ayudarme.
 
Saludos


  • 0

#2 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 794 mensajes
  • LocationArgentina

Escrito 08 septiembre 2017 - 05:43

Una busqueda rapida en google me dice que MimeDecodeStream es de la biblitoeca JEDI. Yo optaria por la alternativa de usar las funciones de la RTL del propio Delphi, que yo sepa hay dos unidades nativas que proveen esta funcionalidad: Soap.EncdDecd y System.NetEncoding

 

Aca hay ejemplos: 

 

https://flixengineer...om/archives/270

https://stackoverflo...encddec-library

 

Documentacion: System.NetEncoding.TBase64Encoding. Soap.EncdDecd queda obsoleta y se recomienda el uso de System.NetEncoding

 

Otra opcion podria ser usar Indy


  • 0

#3 seoane

seoane

    Advanced Member

  • Administrador
  • 1.221 mensajes
  • LocationEspaña

Escrito 09 septiembre 2017 - 03:22

O puedes usar esta libreria https://github.com/dxeoane/secrypt(si se me permite el autopromo ;) )

 

La otra opcion que tienes es no usar un TMemoryStream y usar directamente un TFileStream. No creo que notes mucha diferencia de rendimiento y ahorraras muchos problemas con la memoria si el fichero es muy grande.

 

Saludos


  • 0

#4 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.648 mensajes
  • LocationMéxico

Escrito 09 septiembre 2017 - 07:38

Una busqueda rapida en google me dice que MimeDecodeStream [/size]
es de la biblitoeca JEDI. Yo optaria por la alternativa de usar las funciones de la RTL del propio Delphi, que yo sepa hay dos unidades nativas que proveen esta funcionalidad: Soap.EncdDecd y System.NetEncoding
 
Aca hay ejemplos: 
 
https://flixengineer...om/archives/270
https://stackoverflo...encddec-library
 
Documentacion: System.NetEncoding.TBase64Encoding. Soap.EncdDecd queda obsoleta y se recomienda el uso de System.NetEncoding
 
Otra opcion podria ser usar Indy

 
Muchas gracias Agustín, voy a hacer pruebas con el soap que me parece será una de las mejores alternativas ya que precisamente estoy usando SOAP server. :)

 

De Indy no se me había ocurrido, dehecho no lo sabía. (y)

 

Aunque me parece extraño que funcione sin problema en aplicaciones normales, bueno no estoy usandolo en una aplicación normal :).
 
Saludos y gracias


  • 0

#5 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.648 mensajes
  • LocationMéxico

Escrito 09 septiembre 2017 - 07:40

O puedes usar esta libreria https://github.com/dxeoane/secrypt(si se me permite el autopromo ;) )


Ya la pruebo, estoy seguro que funciona de maravilla :)
 

La otra opcion que tienes es no usar un TMemoryStream y usar directamente un TFileStream. No creo que notes mucha diferencia de rendimiento y ahorraras muchos problemas con la memoria si el fichero es muy grande.
 
Saludos

 
No había pensado en esa opción, la probaré. :)
 
Saludos y gracias.
  • 0

#6 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.648 mensajes
  • LocationMéxico

Escrito 11 septiembre 2017 - 11:27

Hola amigos

 

Pues ya hice todas las pruebas que me sugirieron, y no es posible hacer que trabajen los TStreams en un servicio web, sigue generando errores de violación de acceso.

 

Utilicé el siguiente código:


delphi
  1. procedure TPreval.Base64ToFile(Content, nomArch: String);
  2. var
  3. StrList: TStrings;
  4. Cadena: string;
  5. begin
  6. Cadena := DecodeString(Content);
  7. StrList := TStringList.Create;
  8. StrList.Text := Cadena;
  9. StrList.SaveToFile(Ruta + nomArch);
  10. StrList.Free;
  11. end;

Sin embargo (no todo es miel sobre ojuelas :s) no está decodificando el string de base64 a texto, genera el archivo vacío, pero en una aplicación normal funciona sin problema, genera el archivo con el dato decodificado correctamente.

 

Lo que estoy enviando es lo siguiente:

 

Contenido = 'NDc2NiA4NDA3IDAwNTAgNzc5NiA='

 

Y el valor decodificado es '4766 8407 0050 7796'

 

Yo sigo buscando la razón de éste comportamiento atípico :D.

 

Saludos 


  • 0

#7 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 794 mensajes
  • LocationArgentina

Escrito 11 septiembre 2017 - 12:32

Quien gestiona la memoria en tu servicio web? El server? El cliente? Creo que dependiendo del framework y los parametros cuando instancias la clase proxy (el querido boolean InstanceOwner) es el que determina si las instancias se liberan automaticamente o no

 

No es posible tener una traza completa de la llamada de todos los metodos (Call Stack)

 

A que queres acceder exactamente cuando rompe en la excepcion?


  • 1

#8 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.648 mensajes
  • LocationMéxico

Escrito 11 septiembre 2017 - 04:45

Quien gestiona la memoria en tu servicio web? El server? El cliente? Creo que dependiendo del framework y los parametros cuando instancias la clase proxy (el querido boolean InstanceOwner) es el que determina si las instancias se liberan automaticamente o no

 

No es posible tener una traza completa de la llamada de todos los metodos (Call Stack)

 

A que queres acceder exactamente cuando rompe en la excepcion?

 

El Servicio Web es un CGI que solo recibe una cadena en base 64 la cual se decodificará y se guardará como contenido de un archivo de texto.

 

Voy a crear el debugger del Servicio web para saber exactamente donde está el error.

 

Saludos (y)


  • 0

#9 Marc

Marc

    Advanced Member

  • Moderadores
  • PipPipPip
  • 1.482 mensajes
  • LocationMallorca

Escrito 12 septiembre 2017 - 12:32

Hola amigo,

 

Prueba simplificandolo un poco más, con este código no necesitas crear ni usar ningún objeto :


php
  1. uses Soap.EncdDecd, IOUtils;
  2.  
  3. procedure TPreval.Base64ToFile(Content, nomArch: String);
  4. begin
  5. TFile.WriteAllText(DecodeString(Content), nomArch);

A mi me funciona bien en servicio Datasnap REST corriendo como módulo ISAPI, no se me ocurre donde puedes tener el problema. Asegúrate que la cuenta del sistema bajo la que corre el servicio/servidor web tiene permisos de escritura en la carpeta donde se guardan los resultados (aunque si ya te genera un archivo vacío, ése no debería ser el problema. Pero tampoco pierdes demasiado tiempo probar un momento con otra carpeta).


  • 1

#10 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.648 mensajes
  • LocationMéxico

Escrito 12 septiembre 2017 - 12:52

Hola,

 

Prueba simplificandolo un poco más, con este código no necesitas crear ni usar ningún objeto :


php
  1. uses Soap.EncdDecd, IOUtils;
  2.  
  3. procedure TPreval.Base64ToFile(Content, nomArch: String);
  4. begin
  5. TFile.WriteAllText(DecodeString(Content), nomArch);

A mi me funciona bien en servicio Datasnap REST corriendo como módulo ISAPI, no se me ocurre donde puedes tener el problema. Asegúrate que la cuenta del sistema bajo la que corre el servicio/servidor web tiene permisos de escritura en la carpeta donde se guardan los resultados (aunque si ya te genera un archivo vacío, ése no debería ser el problema. Pero tampoco pierdes demasiado tiempo probar un momento con otra carpeta).

 

 

Al rato que llegue a la oficina hago la prueba. :)

 

Y si, mi primer revisión fué a permisos, pero si crea el directorio si no existe y genera  el archivo aunque vacío, 

 

Saludos amigo Marc. (y)


  • 0

#11 Marc

Marc

    Advanced Member

  • Moderadores
  • PipPipPip
  • 1.482 mensajes
  • LocationMallorca

Escrito 12 septiembre 2017 - 02:39

A ver si hay suerte :)

 

Por cierto, si sigue sin funcionar, haz esta simple prueba :


delphi
  1. procedure TPreval.Base64ToFile(Content, nomArch: String);
  2. begin
  3. TFile.WriteAllText('Comprobamos la escritura de archivos', nomArch);
  4. end;

De esta forma podrás saber si el problema está en la decodificación del base64, o en la escritura del resultado. Si te genera bien el archivo, entonces el problema está en la decodificación base64, en caso contrario el problema es la escritura del archivo.

 

Una vez tengamos más delimitado el problema podremos atacarlo mejor.

 

Saludos amigo.


  • 1

#12 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.648 mensajes
  • LocationMéxico

Escrito 12 septiembre 2017 - 09:19

A ver si hay suerte :)

 

Por cierto, si sigue sin funcionar, haz esta simple prueba :


delphi
  1. procedure TPreval.Base64ToFile(Content, nomArch: String);
  2. begin
  3. TFile.WriteAllText('Comprobamos la escritura de archivos', nomArch);
  4. end;

De esta forma podrás saber si el problema está en la decodificación del base64, o en la escritura del resultado. Si te genera bien el archivo, entonces el problema está en la decodificación base64, en caso contrario el problema es la escritura del archivo.

 

Una vez tengamos más delimitado el problema podremos atacarlo mejor.

 

Saludos amigo.

 

Gracias amigo,

 

Pues ya hice la prueba con las dos probabilidades que mencionas (aunque tuve que hacerlo con Delphi XE7 porque la unidad IOUtils no existe en Delphi 2007 :) )

 

Resultado: No se crea el archivo :s

 

Sigo investigando :)

 

Saludos


  • 0

#13 Agustin Ortu

Agustin Ortu

    Advanced Member

  • Moderadores
  • PipPipPip
  • 794 mensajes
  • LocationArgentina

Escrito 12 septiembre 2017 - 09:30

Yo creo que la unica forma de encontrarlo entonces es ir guardando un registro de cada paso. Captura y logea todas las excepciones. Tambien es posible que alguna llamada a la API de Windows para crear archivo eleve un error, de esos que solamente se ven las excepciones si invocas a RaiseLastOSError


  • 1

#14 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.648 mensajes
  • LocationMéxico

Escrito 12 septiembre 2017 - 09:32

Yo creo que la unica forma de encontrarlo entonces es ir guardando un registro de cada paso. Captura y logea todas las excepciones. Tambien es posible que alguna llamada a la API de Windows para crear archivo eleve un error, de esos que solamente se ven las excepciones si invocas a RaiseLastOSError

 

 

Ese es el problema, que le he puesto try's por todos lados y no regresa error :(

 

No quería pero debo hacer una aplicación de depuración del servicio.  :

 

Saludos


  • 0

#15 Gaston

Gaston

    Advanced Member

  • Miembros
  • PipPipPip
  • 71 mensajes

Escrito 12 septiembre 2017 - 09:18


delphi
  1. TFile.WriteAllText(DecodeString(Content), nomArch);

Me parece que estas pasando los parámetros en orden inverso, es decir, primero deberías pasar el nombre del archivo y luego el contenido, al menos según la docwiki de Embarcadero http://docwiki.embar...le.WriteAllText


delphi
  1. class procedure WriteAllText(const Path, Contents: string); overload; static;
  2. class procedure WriteAllText(const Path, Contents: string; const Encoding: TEncoding); overload; static;

Saludos.


  • 1

#16 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.648 mensajes
  • LocationMéxico

Escrito 12 septiembre 2017 - 09:49


delphi
  1. TFile.WriteAllText(DecodeString(Content), nomArch);

Me parece que estas pasando los parámetros en orden inverso, es decir, primero deberías pasar el nombre del archivo y luego el contenido, al menos según la docwiki de Embarcadero http://docwiki.embar...le.WriteAllText


delphi
  1. class procedure WriteAllText(const Path, Contents: string); overload; static;
  2. class procedure WriteAllText(const Path, Contents: string; const Encoding: TEncoding); overload; static;

Saludos.

 

 

 

Cierto, ya lo pruebo mañana en la oficina y les dejo saber los resultados. (y)

 

Muchas gracias amigo Gastón.

 

Saludos


  • 0

#17 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.648 mensajes
  • LocationMéxico

Escrito 13 septiembre 2017 - 09:38

Hola
 
Pues ya he probado todo lo que me han sugerido y nada, sigue sin poder decodificar la base64 :(
 
Amigo Domingo, ¿ésto está bien?

delphi
  1. var
  2.   DatosStr: TStringStream;
  3.   Cifr: TMemoryStream;
  4.   BDec: TBase64Dec;
  5.  
  6. Begin
  7. DatosStr := TStringStream.Create('MTAyNCAyNDU4IDExMTEgNDU2OA==');
  8. Cifr:= TMemoryStream.Create;
  9. BDec:= TBase64Dec.Create(DatosStr);
  10. try
  11. BDec.CopyFrom(Cifr,0);
  12. finally
  13. BDec.Free;
  14. end;
  15. Cifr.SaveToFile('C:\Proyectos\TEST\Prueba.txt');
  16. end;

 
Porque me crea el archivo pero vacío :(
 
Saludos
  • 0

#18 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.648 mensajes
  • LocationMéxico

Escrito 13 septiembre 2017 - 10:29

El problema está en el momento de querer decodificar el Stream de base64.


delphi
  1. DatosStr := TStringStream.Create('MTAyNCAyNDU4IDExMTEgNDU2OA==');
  2. Writeln('Stream: ' + DatosStr.DataString);
  3. Cifr:= TMemoryStream.Create;
  4. try
  5. BDec := TBase64Dec.Create(DatosStr);
  6. Writeln('Tamaño: ' + intTostr(BDec.Size)); //Aquí salta el error....
  7. except
  8. on e: exception do
  9. Writeln('Error: ' + e.Message);
  10. end;
  11. try
  12. BDec.CopyFrom(Cifr,0);
  13. finally
  14. BDec.Free;
  15. end;
  16. Cifr.SaveToFile('C:\Proyectos\TEST\Prueba.txt');

El programa me regresa un error al intentar obtener el tamaño del Stream.

 

La imagen adjunta nos muestra el error. :s

 

Saludos

Archivos adjuntos


  • 0

#19 Marc

Marc

    Advanced Member

  • Moderadores
  • PipPipPip
  • 1.482 mensajes
  • LocationMallorca

Escrito 13 septiembre 2017 - 11:02

¿ Puedes instalar MadExcept para que haga un Log con el error ?. Nos va a decir en que línea exacta del código interno de la VCL falla el programa, además de mucha más información interesante.


  • 0

#20 egostar

egostar

    missing my father, I love my mother.

  • Administrador
  • 13.648 mensajes
  • LocationMéxico

Escrito 13 septiembre 2017 - 12:08   Mejor respuesta

¿ Puedes instalar MadExcept para que haga un Log con el error ?. Nos va a decir en que línea exacta del código interno de la VCL falla el programa, además de mucha más información interesante.

 
Hola amigo Marc,
 
Ya he encontrado el error, resulta que por alguna extraña razón *-)  *-)  *-)  tenia la siguiente línea
 


delphi
  1. begin
  2. //.....
  3. if not DirectoryExists( Ruta ) then
  4. if not CreateDir( Ruta ) then
  5.  
  6. Cadena := DecodeString(Content);
  7. //.....
  8. end;

El punto es que el decodeString() es parte del if y nunca lo hacía. WTF.........

Ya necesito vacaciones......  ^o|  :|  

Saludos


  • 1