delphi - MidasLib.dcu hace que la aplicación sea más lenta
tclientdataset (3)
Estoy declarando MidasLib para evitar el infierno causado por Midas.dll en algunos clientes.
El siguiente código se ejecuta en aproximadamente 2350 ms. ¡Si elimino la declaración de MidaLib en usos, comienza a ejecutarse en solo 45 ms!
El archivo data.xml se guardó con el método TClientDataSet.SaveToFile, tiene 5000 registros y su tamaño es de aproximadamente 600 Kb.
¿Alguien sabe cómo explicar este extraño comportamiento?
Puedo confirmar el problema en Delphi XE2 upd 3 y en Delphi XE3 upd 2.
Gracias.
program Loader;
{$APPTYPE CONSOLE}
{$R *.res}
uses
MidasLib,
System.SysUtils,
Winapi.Windows,
Data.DB,
Datasnap.DBClient;
var
cds : TClientDataSet;
start, stop : Cardinal;
begin
cds := TClientDataSet.Create(nil);
try
start := GetTickCount;
cds.LoadFromFile(''c:/temp/data.xml'');
stop := GetTickCount;
Writeln(Format(''Time elapsed: %dms'', [stop-start]));
finally
cds.Free;
end;
end.
Es un error / regresión conocido, consulte los informes de control de calidad
No estoy seguro de por qué piensas que necesitas usar MidasLib para "evitar el infierno de DLL".
Cuando el RTL llama a TCustomClientDataSet.CreateDSBase
, esto llama a CheckDbClient
en DSIntf.Pas. Es esta rutina la que determina qué instancia de Midas.Dll se carga al examinar el registro.
Por lo tanto, podría asegurarse de que se utilice una instancia particular de Midas.Dll asegurándose de que el registro refleje su ubicación antes de CheckDbClient
. La configuración de registro es InProcServer32
en HK_Classes_Root/CLSId/{9E8D2FA1-591C-11D0-BF52-0020AF32BD64}
. Se puede actualizar llamando a RegisterComServer
especificando la ruta y el nombre de archivo de Midas, sujeto a los permisos necesarios de acceso al registro, por supuesto.
Solo usamos una copia local de la DLL de Midas independientemente de lo que esté instalado en el sistema, y solo volvemos a la global, si no se encuentra una local.
Usamos XE2 upd4 hf1 y luego cambiamos a Midas DLL de XE4 (el proyecto principal aún está hecho con xe2)
// based on stock MidasLib unit
unit MidasDLL;
interface
implementation
uses Winapi.Windows, Winapi.ActiveX, Datasnap.DSIntf, SysUtils, Registry;
// function DllGetDataSnapClassObject(const CLSID, IID: TGUID; var Obj): HResult; stdcall; external ''Midas.DLL'';
//var DllGetDataSnapClassObject: function(const CLSID, IID: TGUID; var Obj): HResult; stdcall; //external ''Midas.DLL'';
var DllGetDataSnapClassObject: pointer; //external ''Midas.DLL'';
const dllFN = ''Midas.DLL''; dllSubN = ''DllGetDataSnapClassObject'';
var DllHandle: HMODULE = 0;
function RegisteredMidasPath: TFileName;
const rpath = ''/SOFTWARE/Classes/CLSID/{9E8D2FA1-591C-11D0-BF52-0020AF32BD64}/InProcServer32'';
var rry: TRegistry;
begin
Result := '''';
rry := TRegistry.Create( KEY_READ );
try
rry.RootKey := HKEY_LOCAL_MACHINE;
if rry.OpenKeyReadOnly( rpath ) then begin
Result := rry.ReadString('''');
if not FileExists( Result ) then
Result := '''';
end;
finally
rry.Destroy;
end;
end;
procedure TryFindMidas;
var fPath, msg: string;
function TryOne(const fName: TFileName): boolean;
const ver_16_0 = 1048576; // $00060001
var ver: Cardinal; ver2w: LongRec absolute ver;
begin
Result := false;
ver := GetFileVersion( fName );
if LongInt(ver)+1 = 0 then exit; // -1 --> not found
if ver < ver_16_0 then begin
msg := msg + #13#10 +
''Obsolete version found: ''+IntToStr(ver2w.Hi) + ''.'' + IntToStr(ver2w.Lo) + '' in library file '' + fName;
exit;
end;
DllHandle := SafeLoadLibrary(fName);
if DllHandle = 0 then begin
msg := msg + #13#10 +
''Failure loading library '' + fName + ''. Maybe this was Win64 DLL or some other reason.'';
exit;
end;
DllGetDataSnapClassObject := GetProcAddress( DllHandle, dllSubN);
if nil = DllGetDataSnapClassObject then begin // не найдена
msg := msg + #13#10 +
''Incompatible library loaded '' + fName + ''. Missed function '' + dllSubN;
FreeLibrary( DllHandle );
DllHandle := 0;
end;
Result := true;
end;
function TryTwo(const fName: TFileName): boolean; // seek in the given folder and its immediate parent
begin
Result := TryOne(fName + dllFN);
if not Result then
Result := TryOne(fName + ''../' + dllFN); //
end;
begin
fPath := ExtractFilePath( ParamStr(0) );
if TryTwo( fPath ) then exit;
fPath := IncludeTrailingBackslash( GetCurrentDir() );
if TryTwo( fPath ) then exit;
fPath := RegisteredMidasPath;
if fPath > '''' then
if TryOne( fPath ) then exit;
msg := ''This program needs the library '' + dllFN + '' version 16.0 or above.''#13#10 +
''It was not found, thus the program can not work.''#13#10 + #13#10 + msg;
Winapi.Windows.MessageBox(0, PChar(msg), ''Launch failure!'',
MB_ICONSTOP or MB_TASKMODAL or MB_DEFAULT_DESKTOP_ONLY or MB_TOPMOST );
Halt(1);
end;
initialization
// RegisterMidasLib(@DllGetDataSnapClassObject); -- static linking does not work for utilities in sub-folders
TryFindMidas; // immediately terminates the application if not found
RegisterMidasLib(DllGetDataSnapClassObject);
finalization
if DllHandle <> 0 then
if FreeLibrary( DllHandle ) then
DllHandle := 0;
end.