precio - que es delphi 2010
¿Puedo modificar una constante en la clase RTL System.Classes.TStream y reconstruirla en tiempo de ejecución en Delphi XE6? (2)
Puede superar esta limitación usando un desvío, pruebe esta muestra que usa la Delphi Detours Library
Primero defina la firma del método para enganchar
var
Trampoline_TStreamCopyFrom : function (Self : TStream;const Source: TStream; Count: Int64): Int64 = nil;
luego implementar el desvío
function Detour_TStreamCopyFrom(Self : TStream;const Source: TStream; Count: Int64): Int64;
const
MaxBufSize = 1024*1024; //use 1 mb now :)
var
BufSize, N: Integer;
Buffer: TBytes;
begin
if Count <= 0 then
begin
Source.Position := 0;
Count := Source.Size;
end;
Result := Count;
if Count > MaxBufSize then BufSize := MaxBufSize else BufSize := Count;
SetLength(Buffer, BufSize);
try
while Count <> 0 do
begin
if Count > BufSize then N := BufSize else N := Count;
Source.ReadBuffer(Buffer, N);
Self.WriteBuffer(Buffer, N);
Dec(Count, N);
end;
finally
SetLength(Buffer, 0);
end;
end;
Finalmente, reemplace la función original por el trampolín (puede usar este código en la parte de inicialización de alguna unidad)
Trampoline_TStreamCopyFrom := InterceptCreate(@TStream.CopyFrom, @Detour_TStreamCopyFrom);
Y para liberar el gancho puedes usar
if Assigned(Trampoline_TStreamCopyFrom) then
InterceptRemove(@Trampoline_TStreamCopyFrom);
Estoy tratando de evitar una conocida limitación de rendimiento feo en System.Classes.pas, que tiene un límite de búfer constante de la década de 1980 ($ F000) que se ve así:
function TStream.CopyFrom(const Source: TStream; Count: Int64): Int64;
const
MaxBufSize = $F000;
....
Esto está causando importantes penalizaciones de rendimiento en nuestra aplicación Delphi. En Delphi XE2 a XE5, pudimos modificar esto y utilizar uno de los siguientes enfoques:
Podría modificar las fuentes Delphi y, al invocar dcc32.exe desde un archivo por lotes, reconstruir el archivo System.Classes.dcu en la carpeta de la biblioteca Delphi. Me doy cuenta de que esto es feo y no me gustó hacer esto, pero tampoco me gusta este feo problema de rendimiento en la RTL, y nuestros usuarios no pueden vivir con los dolores de cabeza que causa.
Podría intentar poner un archivo system.classes.pas modificado en algún lugar de la ruta de búsqueda de mi proyecto.
Ninguno de los enfoques anteriores me funciona en Delphi XE6, ahora, gracias probablemente a algunos cambios internos en el compilador. El error que obtengo en una aplicación de línea de comandos mínima que incluye System.Contnrs en su cláusula uses, es esto:
[dcc32 Fatal Error] System.Classes.pas(19600): F2051 Unit System.Contnrs was compiled with a different version of System.Classes.TComponent
El programa de ejemplo para reproducir este problema (suponiendo que haya modificado System.Classes.pas y haya cambiado la constante MaxBufSize), se muestra aquí:
program consoletestproject;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.Contnrs,
System.SysUtils;
var
List:System.Contnrs.TObjectList;
begin
WriteLn(''Hello world'');
end.
De nuevo, este problema se reproduce fácilmente en Delphi XE6, pero no es un problema en XE5 o anterior.
¿Cuál es la práctica recomendada cuando DEBE trabajar en una limitación fundamental de RTL o VCL utilizando una copia modificada de System.Classes.pas o System.SysUtils.pas o alguna otra unidad de muy bajo nivel? (Sí, sé que NO debes hacer esto si no tienes que hacerlo, no te molestes con una conferencia).
¿Existe un conjunto mágico de parámetros de línea de comandos que pueda usar a través de "dcc32.exe" en la línea de comandos, para producir una DCU modificada que se vincule correctamente con el ejemplo de aplicación anterior?
Como una pregunta secundaria, ¿hay archivos .dcu para los que no existe una fuente que se rompa cuando se intenta hacer esto, en cuyo caso la respuesta a todo lo anterior es, "no se puede arreglar esto, y si hay un error" en el RTL, no tienes suerte "?
Una solución posible es incluir "$ (BDS) / source / rtl / common" en la ruta de búsqueda del proyecto (o ruta de la biblioteca), obligando a cada DCU interrumpida (que necesita recompilar) a reconstruir CADA vez, pero esto parece feo e incorrecto.
Actualización 1: la sugerencia a continuación no funciona para la unidad de Classes
en XE6. La técnica básica es el sonido y resuelve problemas similares. Pero para XE6, al menos la unidad de Classes
, no es inmediatamente obvio cómo volver a compilarla.
Esto parece ser un error introducido en XE6 porque esta técnica está diseñada para funcionar y está oficialmente respaldada por Embarcadero: http://blog.marcocantu.com/blog/2014_august_buffer_overflow_bitmap.html
Actualización 2:
En XE7, este problema ya no existe. Parece que lo que estaba roto en XE6 ha sido arreglado.
Necesita las opciones del compilador para que coincidan con las utilizadas cuando Embarcadero compiló la unidad. Esa es la razón por la cual su sección de implementación solo cambia, falla cuando parece que debería tener éxito.
Comience un proyecto predeterminado y use CTRL + O + O para generar estas opciones. yo obtengo
{$A8,B-,C+,D+,E-,F-,G+,H+,I+,J-,K-,L+,M-,N-,O+,P+,Q-,R-,S-,T-,U-,V+,W-,X+,Y+,Z1}
cuando hago esto en XE6.
Pon eso en la parte superior de tu copia de la unidad y deberías estar listo para continuar. Probablemente pueda salirse con la suya con un subconjunto reducido de estos, dependiendo de las opciones de su proyecto de host. En mi código, encuentro eso:
{$R-,T-,H+,X+}
basta.