Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Impresión (https://www.clubdelphi.com/foros/forumdisplay.php?f=4)
-   -   [SOLUCIONADO] Problema desbordamiento QReports al generar PDF (win10) (https://www.clubdelphi.com/foros/showthread.php?t=93114)

ginobili20 22-05-2018 18:49:07

[SOLUCIONADO] Problema desbordamiento QReports al generar PDF (win10)
 
Hola gente, despues de que se actualizo el windows 10 en varios clientes( se actulizaron tambien opciones de office), dejo de funcionar el TQRPDFDocumentFilter(es de quickreport) para guardar en formato PDF un reporte.
Me paso en 3 clientes luego de la actualizacion.
el sistema esta en delphi 7, si alguno tiene algun dato o le paso se agradece.
Saludos

Casimiro Notevi 22-05-2018 19:45:42

Se ve que esa actualización está haciendo estragos en multitud de programas. Incluso muchísimos casos en los que estropea el sistema y no pueden ni reinstalarlo.

Yo no uso w10, pero definitivamente, avisaría a todo el mundo para que no lo actualice hasta que lo solucionen.

makividal 22-05-2018 20:30:55

Buenas tardes
Delphi 7 + quickreport +Windows 10: al pasar a pdf el listado da error y se sale del programa, con Windows 7 o Windows server2008
a 2016 va muy bien.
Cansado de buscar y leer soluciones a los muchísimos errores de las actualizaciones del Windows 10.

JuanPa 23-05-2018 17:26:54

Cita:

Empezado por ginobili20 (Mensaje 526455)
Hola gente, despues de que se actualizo el windows 10 en varios clientes( se actulizaron tambien opciones de office), dejo de funcionar el TQRPDFDocumentFilter(es de quickreport) para guardar en formato PDF un reporte.
Me paso en 3 clientes luego de la actualizacion.
el sistema esta en delphi 7, si alguno tiene algun dato o le paso se agradece.
Saludos

Buenos dias,

Igualmente tengo el mismo problema al exportar un reporte a pdf con QuickReport en Windows 10. Lo que puedo agregar es que la exportación funciona bien cuando el reporte tiene una sola página pero se cae cuando el reporte tiene mas de una página. Se cae exactamente en esta instrucción: TCustomQuickrep.ExportToFilter(TQRExportFilter)

ginobili20 23-05-2018 17:31:04

Gracias por contestar gente... la verdad no se como resolverlo porque hasta el momento no hay solucion.

adebonis 24-05-2018 08:54:04

Hola a todos.

Delphi2007 + quickreport +Windows 10: Pasa exactamente igual al generar reportes en pdf. Los clientes ya han empezado a quejarse.

Me parece que Quickreport utiliza la carpeta de archivos temporales de Widows. ¿Podria ser que hubieran cambiado los permisos de esta carpeta?

Si alguien tiene una solución, por favor, compartirla.

Saludos.
Adolfo de Bonis

gguerrini 28-05-2018 18:17:52

Delphi 7 + QReport + Windows 10
 
Tenemos el mismo problema, alguien encontró alguna solución. Lo trato por código mandar a la impresora de "Microsoft to PDF" pero hace agua.
Cualquier ayuda se agradece.

josepvila 28-05-2018 19:00:04

Hola,
Esta actualización ...:mad:, teníamos el mismo error en el exporttofilter con delphi 7 y la unica solución que he encontrado después de debugar es poner un try / except en el createreport(false) y parece que funciona.
Espero que le sirva a alguien.

Programa :c:\program files (x86)\borland\Delphi7\Quickrep5\quickRpt.pas
Código Delphi [-]
procedure TCustomQuickRep.ExportToFilter(AFilter : TQRExportFilter);
  ...
      AProgress.Caption := 'Exportando a pdf';
      QRPrinter.Client := AProgress;
    end;
    // egaraset vr 28/05/2018 modificació provisional per error actualització win 10
    try
       CreateReport(false);
    except
    end;
  finally
    QRPrinter.Free;
    if ShowProgress then
            AProgress.Free;
  end;
...

Saludos

bucanero 28-05-2018 19:13:20

hola a todos,

con esta actualización tan agresiva de windows yo también estoy teniendo problemas, aunque son solo con algunos equipos, (que no he podido determinar porque unos si y otros no, siendo prácticamente idénticos).

El problema es de acceso a nivel de windows a carpetas compartidas en red. Incluso a veces accede una vez y al momento ya no se puede volver a acceder.

Con esta solución que proponen en el foro de MICROSOFT, en algunos equipos si he conseguido solventar los problemas, pero para otros no ha podido ser
https://social.technet.microsoft.com...itprogeneralES

Tras múltiples intentos de solución, el problema que hemos detectado es que al intentar acceder a la ruta de red mediante el nombre del PC y a veces no es en el primer intento, se produce un error de permisos, denegando el acceso a la carpeta. La solución encontrada hasta ahora, pasa por acceder directamente mediante la IP local del equipo en vez de con el nombre de equipo, pero para eso ha sido necesario asignar a los equipos IP fijas. Después de aplicar esta solución parece que ya no han vuelto a tener problemas.

Espero que les pueda ayudar con esta solución.
Un saludo

gguerrini 28-05-2018 21:43:40

Que complicado !!!!!
 
Hola a Todos, Gracias Bucanero por tu respuesta, estas seguro que es tan complicada la solución ??? No has encontrado algo mas sencillo, lo digo por la cantidad de las maquinas en red, usar el ping y ponerles fijo es demasiado. Es una locura, pero convendrá actualizar el QReport ??? o cambiar de Re porteador, en las nuevas versiones de delphi esta por defecto el FastReport. Que les parece ???? Muchas Gracias por su respuesta.

JuanPa 28-05-2018 22:58:45

QuickReport y Windows 10
 
Ciertamente capturando la excepcion en el procedimiento ExportToFilter la aplicacion no se cierra pero finalmente el pdf que se crea no se crea bien ya que al intentar abrirlo muestra el mensaje "There was an error opening this document. The file is damaged and could not be repaired".

Casimiro Notevi 28-05-2018 23:21:44

Cita:

Empezado por JuanPa (Mensaje 526624)
Ciertamente capturando la excepcion en el procedimiento ExportToFilter la aplicacion no se cierra pero finalmente el pdf que se crea no se crea bien ya que al intentar abrirlo muestra el mensaje "There was an error opening this document. The file is damaged and could not be repaired".

Lo único que se logra es que no avise de ningún error, pero no funciona con eso.

manelb 29-05-2018 07:47:08

Nosotros estamos en la misma situación.


Lo he probado con una versión trial de Delphi Berlin y QuickReport(6.0) y parece que la exportación a pdf funciona bien.
Pero nuestros programas creo que utilizan la versión 3.5 o 4 de QuickReport(no lo tengo ahora a mano) y falla también.

Saludos

adebonis 29-05-2018 10:03:51

Hola.

Estoy usando delphi 2007 y QuickReport 4.05.

La versión 6 de QuickReport solo está disponible a partir de Delphi XE2. ¿Alguien sabe si QuickReport 5 también falla en la exportación a pdf?

A ver si deberemos cambiar a Rave Reports...

Un saludo.
Adolfo de Bonis

Casimiro Notevi 29-05-2018 10:19:37

Cita:

Empezado por adebonis (Mensaje 526642)
A ver si deberemos cambiar a Rave Reports...

En teoría es problema de la actualización de w10, ya que son infinidad de problemas los que está generando a todo el mundo y con montones de programas distintos.

HccSoft 29-05-2018 15:36:43

A mi me ocurre igual. Delphi 7 con QR y de golpe el software se cierra al intentar generar cualquier PDF.

gguerrini 30-05-2018 14:20:49

Estamos haciendo de tod un poco para encontrarle la vuelta, otra que me di cuenta es que con la nueva actualizacion no me deja cambiar la impresora por defecto por codigo tradicional como siempre. Ya hice un programa que lo hace sobre windows 7 y funciona perfecto. Alguien tiene algun codigo que no sea cambiando el indice de la impresora ????
Dentro del mismo tema estube controlando los PDF que genera con error, comparando el mismo archivo hecho en windows 7, es como que los inicializa igual y al final no lo puede terminar de cerrar. Le pegue del archivo que genere en windows 7 y magicamente el PDF se puede leer correctamente. Que loco ???
Y otra es que los archivos no se pueden guardar en cualquier parte del disco, es como que ha modificado los permisos y la seguridad. Que locura. HELP !!!!!

JuanPa 31-05-2018 17:52:54

Finalmente parece que encontramos la solucion al problema de exportar el reporte a pdf en windows 10. Vale indicar que el problema se produce por el tipo de letra que en el caso de mi reporte utilizaba "Arial" y lo he cambiado por otro tipo de letra y ha funcionado correctamente. Tambien hay que corregir la siguiente linea en el archivo QRPDFFilt.pas del QuickReport.

En esta sentencia ntabs:=cvtInt(Buff, 4); es donde se cae por lo cual hay que cambiarlo por lo siguiente:
Código Delphi [-]
if (FontName='Arial') then
  ntabs:=0
else
  ntabs:=cvtInt(Buff, 4);
Espero que puedan resolverlo con lo indicado.
Saludos.

gguerrini 01-06-2018 14:44:34

Hola Buenos Dias, nos dejaste con la intriga por que fuente la cambiaste, porque antes no funcionaba otra font y decian que habia que ponerle ARIAL ???? Muchas Gracias. Saludos.

JuanPa 01-06-2018 16:34:20

Yo lo cambie de "Arial" a "Courier New" que es el tipo de letra que en mi caso permite mantener centralizados los controles ya que imagino que con otro tipo de letra puede descuadrarse el reporte y tocara modificar el tamaño, la posiciónde los controles, etc.

gguerrini 01-06-2018 17:50:48

Realmente me resulta raro, hace un tiempo, para que mis Qreport pudieran funcionar en windows 10, tube que cambiar los Fonts de "Courrier New" a "Arial", porque se rompia. Lo cambiamos el año pasado y con Arial funcionaba perfecto. Despues de la actualizacion agua...... Sera que ahora hay que volver a cambiar de fuente ?????

josepvila 04-06-2018 13:23:20

Cita:

Empezado por JuanPa (Mensaje 526746)
Finalmente parece que encontramos la solucion al problema de exportar el reporte a pdf en windows 10. Vale indicar que el problema se produce por el tipo de letra que en el caso de mi reporte utilizaba "Arial" y lo he cambiado por otro tipo de letra y ha funcionado correctamente. Tambien hay que corregir la siguiente linea en el archivo QRPDFFilt.pas del QuickReport.

En esta sentencia ntabs:=cvtInt(Buff, 4); es donde se cae por lo cual hay que cambiarlo por lo siguiente:
Código Delphi [-]
if (FontName='Arial') then
  ntabs:=0
else
  ntabs:=cvtInt(Buff, 4);
Espero que puedan resolverlo con lo indicado.
Saludos.

Funciona perfecto, muchas gracias!!

adebonis 04-06-2018 20:48:44

Hola.

Yo he cambiado todos los tipos de letra de los reportes de "Arial" a "Tahoma" y funciona perfectamente!!

La verdad es que no me lo explico. ¿Alguuien tiene alguna explicación?

Saludos.
Adolfo de Bonis.

Casimiro Notevi 04-06-2018 23:00:35

:confused::confused::confused:

bazsar 07-06-2018 11:37:46

Cita:

Empezado por JuanPa (Mensaje 526746)
Finalmente parece que encontramos la solucion al problema de exportar el reporte a pdf en windows 10. Vale indicar que el problema se produce por el tipo de letra que en el caso de mi reporte utilizaba "Arial" y lo he cambiado por otro tipo de letra y ha funcionado correctamente. Tambien hay que corregir la siguiente linea en el archivo QRPDFFilt.pas del QuickReport.

En esta sentencia ntabs:=cvtInt(Buff, 4); es donde se cae por lo cual hay que cambiarlo por lo siguiente:
Código Delphi [-]
if (FontName='Arial') then
  ntabs:=0
else
  ntabs:=cvtInt(Buff, 4);
Espero que puedan resolverlo con lo indicado.
Saludos.

This is not the correct solution. The problem is that the cvtInt and the cvtDWord functions don't get font data buffer as reference. Use this instead:
Código Delphi [-]
function cvtDWord(const Buf: array of byte; P: Integer): DWORD;

...

function cvtInt(const Buf: array of byte; P: Integer): Integer;

juanelo 07-06-2018 21:26:40

Cita:

Empezado por bazsar (Mensaje 526900)
This is not the correct solution. The problem is that the cvtInt and the cvtDWord functions don't get font data buffer as reference. Use this instead:
Código Delphi [-]function cvtDWord(const Buf: array of byte; P: Integer): DWORD; ... function cvtInt(const Buf: array of byte; P: Integer): Integer;

Esto funciona a la perfeccion y no hay que cambiar ningun font.
Muchas gracias !!

gguerrini 07-06-2018 22:24:32

Felicitaciones !!!!
 
Muchas Gracias!!!! Funciona Perfecto !!!!!!!!!!

Casimiro Notevi 07-06-2018 23:57:29

Cita:

Empezado por bazsar (Mensaje 526900)
This is not the correct solution. The problem is that the cvtInt and the cvtDWord functions don't get font data buffer as reference. Use this instead:
Código Delphi [-]function cvtDWord(const Buf: array of byte; P: Integer): DWORD; ... function cvtInt(const Buf: array of byte; P: Integer): Integer;

^\||/^\||/^\||/

ginobili20 12-06-2018 18:26:41

me pasaron la solucion
 
En QRPDFFilt.pas reemplazar las llamadas a las funciones cvtInt y cvtDword

x := cvtInt(Buff, y);

se convierte en estas dos lineas:

P := y;
x := (256*byte(Buff[P]))+(byte(Buff[P+1]));

Y

x := cvtDword(Buff, y); becomes

P := y;
x :=(256*256*256*byte(Buff[P]))+(256*256*byte(Buff[P+1]))+(256*byte(Buff[P+2]))+byte(Buff[P+3]);

Funciona perfecto...

Casimiro Notevi 12-06-2018 18:42:06

No olvides poner las etiquetas para el código:



ginobili20 12-06-2018 18:54:30

In QRPDFFilt.pas replace calls to functions cvtInt and cvtDword with inline code

Código Delphi [-]
x := cvtInt(Buff, y);

becomes 2 lines

Código Delphi [-]
P := y;
x := (256*byte(Buff[P]))+(byte(Buff[P+1]));

and

Código Delphi [-]

x := cvtDword(Buff, y);

se convierte en

Código Delphi [-]
P := y;
x :=(256*256*256*byte(Buff[P]))+(256*256*byte(Buff[P+1]))+(256*byte(Buff[P+2]))+byte(Buff[P+3]);

REPUSOFT 30-09-2018 13:14:35

Solución al problema de desdoblamiento de QReports al generar PDF's
 
Hola
Ante todo gracias por dejarme formar parte de vuestro foro ya que, gracias a vosotros he podido encontrar
la guía que me ha llevado a la solución correcta y poder compartirla con vosotros.
Aunque la solución que dais puede que funcione, no es la correcta ya que lo único que
hace es disimular el problema pero éste permanece latente y te puede explotar por otro lado.
El problema es que, desde la última actualización de W10(1803) las fuentes parece ser que son más ricas en cuanto a información(probablemente para trabajar mejor con pantallas de alta resolución) y la información recogida por la función GetFontData para, por ejemplo, la fuente Arial se ha triplicado.
Por ejemplo en la penúltima versión de W10, antes de la actualización "maldita"(1803), GetFontData devolvía unos 350.000 bytes de información y ahora devuelve aproximadamente 1.500.000. El buffer donde se recoge la información de GetFontData es inicializado como una PByteArray con SetLength() y, desgraciadamente esta función parece sufrir un desbordamiento cuando intenta reservar tanta memoria.

Yo he hecho todo el proceso con QuickReport 5.02 y C++Builder 6 pero seguro que se puede aplicar a mas versiones de Delphi

Esto se puede encontrar dentro del módulo QRPDFFilt
procedure MakeTTFont
dentro de la sección 'var'

Canviar
Código Delphi [-]
Buff: array of Byte;
por:
Código Delphi [-]
Buff: PByteArray;

Esto nos permitirá tratar la infomación como un puntero a una matriz de Bytes y, en vez de
usar el gestionador de memoria de Delphi para generar matrices (arrays) de longitud variable (y que
es lo que falla realmente cuando se le pide una cantidad tan astronómica de Bytes mediante SetLength()), utilizar otro más potente del
propio Windows: CoTaskMemAlloc. Éste seguro que no se quedará corto a la hora de guardar memoria ya que es el que
utiliza Windows para su tecnología COM

Para poder usar CoTaskMemAlloc necesitamos poner en la clausula uses de QRPDFFilt 'ActiveX' (naturalmente sin las comillas).
Yo lo he puesto después de Db, pero podría ser en cualquier parte de dicha cláusula

uses
Código Delphi [-]
  Windows, Classes, Controls, StdCtrls, SysUtils, Graphics, Buttons, Forms, ExtCtrls, Dialogs, Printers, Db,
  ActiveX,
  {$IFDEF QRBDE} DBTables, {$ENDIF}
  ComCtrls, qrexport, QRPrntr, QuickRpt, QR5Const, QRCtrls, grimgctrl, pdfconst, LZW;

Y ahora viene lo bueno:
Hacia la línea de código 1628 del módulo QRPDFFilt, donde se hace la reserva de memoria para recuperar la informació de 'GetFontData'
SUBSTITUIR:
Código Delphi [-]
SetLength(Buff,FSize);
POR ESTAS DOS LÍNEAS
Código Delphi [-]
Buff:=CoTaskMemAlloc(FSize);{ahora que nos pidan la cantidad de memoria que quieran que nuesto stack no se desbordará:-)}
if Buff=nil then raise EOutOfMemory.Create('Memoria insuficiente"){esta línea no es necesaria pero me gusta estar seguro}

Como ahora la memoria reservada no se libera sola, hemos de llamar a CoTraskMemFree. Para ello,
en la clausula 'finally'(linea 1627 aproximadamente) que aparece más abajo (justo debajo de SetEncoding) añadir la siguiente línea:
Código Delphi [-]
 SetEncoding;
finally
 if Buff<>nil then CoTaskMemFree(Buff);{añadir esta línea}
 TmpImage.Free;
end;

Como ahora pasamos un PByteArray a las funciones cvtInt y cvtDWord hemos de canviar sus argumentos quedando las
declaraciones de la siguiente manera (el cuerpo de las funciones queda exactamente igual)

Código Delphi [-]
function cvtDWord(Buf: PByteArray; P: Integer) : DWORD;
begin
  Result:=(256*256*256*Buf[P])+(256*256*Buf[P+1])+(256*Buf[P+2])+Buf[P+3];
end;

function cvtInt(Buf: PByteArray; P: Integer) : Integer;
begin
  Result:=(256*Buf[P])+(Buf[P+1]);
end;


Y ya está!!! ahora sí que podeis generar los pdf's sin miedo a desbordamientos de memoria. Además como utilizamos el mismo gestionador
de memoria de COM, el cual está gestionado por Windows no creo que esto vuelva a dar problemas aunque haya más actualizaciones
y la información de las fuentes se vuelva a triplicar.

Por cierto, en el módulo 'pdfobjs.pas' aparece otra llamada a 'GetFontData' en el procedimiento AnalyseTTFOnt, bajando hacia la línia 728 podemos encontrar de nuevo la sentencia SetLength(buff,fsize), justo antes de la llamada a GetFontData os recomiendo que hagais el mismo proceso en este módulo y la cambiéis por CoTaskMalloc. Aseguraros que liberáis la memoria alojada por CoTaskMalloc con CoTaskMemFree en un bloque finally que tendreis que añadir
expresamente al final de 'AnalyseTtFont' . Yo lo he puesto despues de la sentencia
Código Delphi [-]
   encoding := encoding + '>>';{hacia la línia de código 854 de pdfobjs.pas)}
finally
  if Buff<>nil then CoTaskMemFree(Buff);
end;

REPUSOFT 30-09-2018 14:02:44

Hola Ginobili20 y gracias por tu respuesta, la cual me ha ayudado mucho para encontrar la verdadera causa del problema.
Aunque el código que das aparentemente funciona no es la solución correcta porque el desbordamiento del buffer
se produce ya cuando vuelves de SetLength(). Tu código funciona porque pones el cuerpo de las funciones 'inline'
y por tanto no hace falta utilizar el stack para pasar el buffer desbordado a las funciones pero el
desbordamiento ya está latente.
Saludos y gracias de nuevo a tí y a todos los miembros del foro

REPUSOFT 30-09-2018 17:47:54

Rectificación del título
 
El título del mensaje debería decir "Solución al problema de de desbordamiento de QReports al general PDF´s" Perdonad!

juanelo 01-10-2018 18:38:01

Cita:

Empezado por REPUSOFT (Mensaje 528709)
El título del mensaje debería decir "Solución al problema de de desbordamiento de QReports al general PDF´s" Perdonad!

Sería de gran ayuda si puedes compartir las unidades pas que has modificado.
Gracias

bazsar 02-10-2018 17:14:31

Cita:

Empezado por REPUSOFT (Mensaje 528706)
Hola
Ante todo gracias por dejarme formar parte de vuestro foro ya que, gracias a vosotros he podido encontrar
la guía que me ha llevado a la solución correcta y poder compartirla con vosotros.
Aunque la solución que dais puede que funcione, no es la correcta ya que lo único que
hace es disimular el problema pero éste permanece latente y te puede explotar por otro lado.
El problema es que, desde la última actualización de W10(1803) las fuentes parece ser que son más ricas en cuanto a información(probablemente para trabajar mejor con pantallas de alta resolución) y la información recogida por la función GetFontData para, por ejemplo, la fuente Arial se ha triplicado.
Por ejemplo en la penúltima versión de W10, antes de la actualización "maldita"(1803), GetFontData devolvía unos 350.000 bytes de información y ahora devuelve aproximadamente 1.500.000. El buffer donde se recoge la información de GetFontData es inicializado como una PByteArray con SetLength() y, desgraciadamente esta función parece sufrir un desbordamiento cuando intenta reservar tanta memoria.

Yo he hecho todo el proceso con QuickReport 5.02 y C++Builder 6 pero seguro que se puede aplicar a mas versiones de Delphi

Esto se puede encontrar dentro del módulo QRPDFFilt
procedure MakeTTFont
dentro de la sección 'var'

Canviar
Código Delphi [-]
Buff: array of Byte;
por:
Código Delphi [-]
Buff: PByteArray;

Esto nos permitirá tratar la infomación como un puntero a una matriz de Bytes y, en vez de
usar el gestionador de memoria de Delphi para generar matrices (arrays) de longitud variable (y que
es lo que falla realmente cuando se le pide una cantidad tan astronómica de Bytes mediante SetLength()), utilizar otro más potente del
propio Windows: CoTaskMemAlloc. Éste seguro que no se quedará corto a la hora de guardar memoria ya que es el que
utiliza Windows para su tecnología COM

Para poder usar CoTaskMemAlloc necesitamos poner en la clausula uses de QRPDFFilt 'ActiveX' (naturalmente sin las comillas).
Yo lo he puesto después de Db, pero podría ser en cualquier parte de dicha cláusula

uses
Código Delphi [-]
  Windows, Classes, Controls, StdCtrls, SysUtils, Graphics, Buttons, Forms, ExtCtrls, Dialogs, Printers, Db,
  ActiveX,
  {$IFDEF QRBDE} DBTables, {$ENDIF}
  ComCtrls, qrexport, QRPrntr, QuickRpt, QR5Const, QRCtrls, grimgctrl, pdfconst, LZW;

Y ahora viene lo bueno:
Hacia la línea de código 1628 del módulo QRPDFFilt, donde se hace la reserva de memoria para recuperar la informació de 'GetFontData'
SUBSTITUIR:
Código Delphi [-]
SetLength(Buff,FSize);
POR ESTAS DOS LÍNEAS
Código Delphi [-]
Buff:=CoTaskMemAlloc(FSize);{ahora que nos pidan la cantidad de memoria que quieran que nuesto stack no se desbordará:-)}
if Buff=nil then raise EOutOfMemory.Create('Memoria insuficiente"){esta línea no es necesaria pero me gusta estar seguro}

Como ahora la memoria reservada no se libera sola, hemos de llamar a CoTraskMemFree. Para ello,
en la clausula 'finally'(linea 1627 aproximadamente) que aparece más abajo (justo debajo de SetEncoding) añadir la siguiente línea:
Código Delphi [-]
 SetEncoding;
finally
 if Buff<>nil then CoTaskMemFree(Buff);{añadir esta línea}
 TmpImage.Free;
end;

Como ahora pasamos un PByteArray a las funciones cvtInt y cvtDWord hemos de canviar sus argumentos quedando las
declaraciones de la siguiente manera (el cuerpo de las funciones queda exactamente igual)

Código Delphi [-]
function cvtDWord(Buf: PByteArray; P: Integer) : DWORD;
begin
  Result:=(256*256*256*Buf[P])+(256*256*Buf[P+1])+(256*Buf[P+2])+Buf[P+3];
end;

function cvtInt(Buf: PByteArray; P: Integer) : Integer;
begin
  Result:=(256*Buf[P])+(Buf[P+1]);
end;


Y ya está!!! ahora sí que podeis generar los pdf's sin miedo a desbordamientos de memoria. Además como utilizamos el mismo gestionador
de memoria de COM, el cual está gestionado por Windows no creo que esto vuelva a dar problemas aunque haya más actualizaciones
y la información de las fuentes se vuelva a triplicar.

Por cierto, en el módulo 'pdfobjs.pas' aparece otra llamada a 'GetFontData' en el procedimiento AnalyseTTFOnt, bajando hacia la línia 728 podemos encontrar de nuevo la sentencia SetLength(buff,fsize), justo antes de la llamada a GetFontData os recomiendo que hagais el mismo proceso en este módulo y la cambiéis por CoTaskMalloc. Aseguraros que liberáis la memoria alojada por CoTaskMalloc con CoTaskMemFree en un bloque finally que tendreis que añadir
expresamente al final de 'AnalyseTtFont' . Yo lo he puesto despues de la sentencia
Código Delphi [-]
   encoding := encoding + '>>';{hacia la línia de código 854 de pdfobjs.pas)}
finally
  if Buff<>nil then CoTaskMemFree(Buff);
end;

This is too complicated, see my previous comment, there you can find a simply solution for the problem. The issue is, that the the functions don't get the parametes by reference, but by copy over the heap. When the buffer is bigger than the heap can handle, then the application crashes. If you use the 'const' keyword passing the parameter, then it will be given by reference. Not to mention it faster then copy the buffer.

TURCOCAN 24-01-2019 00:22:09

Cita:

Empezado por REPUSOFT (Mensaje 528706)
Hola
Ante todo gracias por dejarme formar parte de vuestro foro ya que, gracias a vosotros he podido encontrar
la guía que me ha llevado a la solución correcta y poder compartirla con vosotros.
Aunque la solución que dais puede que funcione, no es la correcta ya que lo único que
hace es disimular el problema pero éste permanece latente y te puede explotar por otro lado.
El problema es que, desde la última actualización de W10(1803) las fuentes parece ser que son más ricas en cuanto a información(probablemente para trabajar mejor con pantallas de alta resolución) y la información recogida por la función GetFontData para, por ejemplo, la fuente Arial se ha triplicado.
Por ejemplo en la penúltima versión de W10, antes de la actualización "maldita"(1803), GetFontData devolvía unos 350.000 bytes de información y ahora devuelve aproximadamente 1.500.000. El buffer donde se recoge la información de GetFontData es inicializado como una PByteArray con SetLength() y, desgraciadamente esta función parece sufrir un desbordamiento cuando intenta reservar tanta memoria.

Yo he hecho todo el proceso con QuickReport 5.02 y C++Builder 6 pero seguro que se puede aplicar a mas versiones de Delphi

Esto se puede encontrar dentro del módulo QRPDFFilt
procedure MakeTTFont
dentro de la sección 'var'

Canviar
Código Delphi [-]Buff: array of Byte;

por:
Código Delphi [-]Buff: PByteArray;


Esto nos permitirá tratar la infomación como un puntero a una matriz de Bytes y, en vez de
usar el gestionador de memoria de Delphi para generar matrices (arrays) de longitud variable (y que
es lo que falla realmente cuando se le pide una cantidad tan astronómica de Bytes mediante SetLength()), utilizar otro más potente del
propio Windows: CoTaskMemAlloc. Éste seguro que no se quedará corto a la hora de guardar memoria ya que es el que
utiliza Windows para su tecnología COM

Para poder usar CoTaskMemAlloc necesitamos poner en la clausula uses de QRPDFFilt 'ActiveX' (naturalmente sin las comillas).
Yo lo he puesto después de Db, pero podría ser en cualquier parte de dicha cláusula

uses
Código Delphi [-] Windows, Classes, Controls, StdCtrls, SysUtils, Graphics, Buttons, Forms, ExtCtrls, Dialogs, Printers, Db, ActiveX, {$IFDEF QRBDE} DBTables, {$ENDIF} ComCtrls, qrexport, QRPrntr, QuickRpt, QR5Const, QRCtrls, grimgctrl, pdfconst, LZW;


Y ahora viene lo bueno:
Hacia la línea de código 1628 del módulo QRPDFFilt, donde se hace la reserva de memoria para recuperar la informació de 'GetFontData'
SUBSTITUIR:
Código Delphi [-]SetLength(Buff,FSize);

POR ESTAS DOS LÍNEAS
Código Delphi [-]Buff:=CoTaskMemAlloc(FSize);{ahora que nos pidan la cantidad de memoria que quieran que nuesto stack no se desbordará:-)} if Buff=nil then raise EOutOfMemory.Create('Memoria insuficiente"){esta línea no es necesaria pero me gusta estar seguro}


Como ahora la memoria reservada no se libera sola, hemos de llamar a CoTraskMemFree. Para ello,
en la clausula 'finally'(linea 1627 aproximadamente) que aparece más abajo (justo debajo de SetEncoding) añadir la siguiente línea:
Código Delphi [-] SetEncoding; finally if Buff<>nil then CoTaskMemFree(Buff);{añadir esta línea} TmpImage.Free; end;


Como ahora pasamos un PByteArray a las funciones cvtInt y cvtDWord hemos de canviar sus argumentos quedando las
declaraciones de la siguiente manera (el cuerpo de las funciones queda exactamente igual)

Código Delphi [-]function cvtDWord(Buf: PByteArray; P: Integer) : DWORD; begin Result:=(256*256*256*Buf[P])+(256*256*Buf[P+1])+(256*Buf[P+2])+Buf[P+3]; end; function cvtInt(Buf: PByteArray; P: Integer) : Integer; begin Result:=(256*Buf[P])+(Buf[P+1]); end;



Y ya está!!! ahora sí que podeis generar los pdf's sin miedo a desbordamientos de memoria. Además como utilizamos el mismo gestionador
de memoria de COM, el cual está gestionado por Windows no creo que esto vuelva a dar problemas aunque haya más actualizaciones
y la información de las fuentes se vuelva a triplicar.

Por cierto, en el módulo 'pdfobjs.pas' aparece otra llamada a 'GetFontData' en el procedimiento AnalyseTTFOnt, bajando hacia la línia 728 podemos encontrar de nuevo la sentencia SetLength(buff,fsize), justo antes de la llamada a GetFontData os recomiendo que hagais el mismo proceso en este módulo y la cambiéis por CoTaskMalloc. Aseguraros que liberáis la memoria alojada por CoTaskMalloc con CoTaskMemFree en un bloque finally que tendreis que añadir
expresamente al final de 'AnalyseTtFont' . Yo lo he puesto despues de la sentencia
Código Delphi [-] encoding := encoding + '>>';{hacia la línia de código 854 de pdfobjs.pas)} finally if Buff<>nil then CoTaskMemFree(Buff); end;


hola no se español,
Como solución al problema, el número de código 1628 de mi archivo también se ve diferente. No entendí completamente la solución.

1628 on my file:
Código:

WriteStr(Format('/FontBBox [ %-d %-d %-d %-d ]', [PDFFont.BBox[0], PDFFont.BBox[1], PDFFont.BBox[2], PDFFont.BBox[3]]));
¿Me puede enviar este archivo? (qrpdffilt.pas)

Te lo ruego, por favor.

TURCOCAN 27-01-2019 22:33:49

Thank you very much REPUSOFT

olbeup 25-03-2019 16:56:54

Hola REPUSOFT,

Aunque el pos es muy antiguo, mas antiguos es la versión con la que estoy trabajando Delphi 7 y, a la hora de exportar a PDF con el "TQRPDFDocumentFilter" (QuickReport 4), me petaba, ahora con la solución que distes en su día, lo he probado y funciona correctamente y sin ningún problema.

Muchas gracias

Un saludo.


La franja horaria es GMT +2. Ahora son las 12:14:14.

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