{$A+,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} {**************************************************************************************************} { } { MidasSpeedFix unit - Unoffical speed fix for Midas (Delphi/C++Builder 6 to 2009) } { Version 1.0 (2009-01-21) } { } { The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); } { you may not use this file except in compliance with the License. You may obtain a copy of the } { License at http://www.mozilla.org/MPL/ } { } { Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF } { ANY KIND, either express or implied. See the License for the specific language governing rights } { and limitations under the License. } { } { The Original Code is MidasSpeedFix.pas. } { } { The Initial Developer of the Original Code is Andreas Hausladen (Andreas.Hausladen@gmx.de). } { Portions created by Andreas Hausladen are Copyright (C) 2009 Andreas Hausladen. } { All Rights Reserved. } { } {**************************************************************************************************} { History: 2009-01-21: Initial implementation How to use: Add the MidasSpeedFix.pas unit to your Delphi or C++ Project (ProjectManager: Add Unit) } unit MidasSpeedFix; interface {$IFDEF CONDITIONALEXPRESSIONS} {$IF CompilerVersion >= 15.0} {$WARN UNSAFE_TYPE OFF} {$WARN UNSAFE_CODE OFF} {$WARN UNSAFE_CAST OFF} {$IFEND} {$ENDIF} implementation uses Windows, SysUtils, DSIntf; {------------------------------------------------------------------------------} function MidasMalloc(Size: LongWord): Pointer; stdcall; begin GetMem(Result, Size); end; procedure MidasFree(P: Pointer); stdcall; begin FreeMem(P); end; function MidasCalloc(Count, ElementSize: LongWord): Pointer; stdcall; begin Result := AllocMem(Count * ElementSize); end; function MidasRealloc(P: Pointer; OldSize, NewSize: LongWord): Pointer; stdcall; begin ReallocMem(P, NewSize); Result := P; if (Result <> nil) and (OldSize < NewSize) then FillChar(Pointer(PAnsiChar(Result) + OldSize)^, NewSize - OldSize, 0); end; {------------------------------------------------------------------------------} {$UNDEF REQUIRE_NEW_MEMORY_MANAGER} {$IFDEF CONDITIONALEXPRESSIONS} {$IF CompilerVersion < 18.0} // Delphi 2006 was the first shipped with FastMM {$DEFINE REQUIRE_NEW_MEMORY_MANAGER} {$IFEND} {$ELSE} {$DEFINE REQUIRE_NEW_MEMORY_MANAGER} {$ENDIF CONDITIONALEXPRESSIONS} type TJumpOfs = Integer; PPointer = ^Pointer; type PXRedirCode = ^TXRedirCode; TXRedirCode = packed record Jump: Byte; Offset: TJumpOfs; end; { Hooking } procedure HookProc(Proc, Dest: Pointer; var BackupCode: TXRedirCode); var n: DWORD; Code: TXRedirCode; begin Assert(Proc <> nil); if ReadProcessMemory(GetCurrentProcess, Proc, @BackupCode, SizeOf(BackupCode), n) then begin Code.Jump := $E9; Code.Offset := PAnsiChar(Dest) - PAnsiChar(Proc) - SizeOf(Code); WriteProcessMemory(GetCurrentProcess, Proc, @Code, SizeOf(Code), n); end; end; procedure UnhookProc(Proc: Pointer; var BackupCode: TXRedirCode); var n: Cardinal; begin if (BackupCode.Jump <> 0) and (Proc <> nil) then begin WriteProcessMemory(GetCurrentProcess, Proc, @BackupCode, SizeOf(BackupCode), n); BackupCode.Jump := 0; end; end; function FindMethodPtr(Start: THandle; const Bytes: array of Smallint): Pointer; var P, Address, BytePtr: PAnsiChar; MemInfo: TMemoryBasicInformation; I: Cardinal; FirstByte: Byte; StartOffset, Index: Integer; BytesLen: Integer; Found: Boolean; AllocBase: Pointer; begin Result := nil; BytesLen := Length(Bytes); if (Start <> 0) and (BytesLen >= 8) then begin StartOffset := 0; while (StartOffset < BytesLen) and (Bytes[StartOffset] = -1) do Inc(StartOffset); if StartOffset = BytesLen then Exit; FirstByte := Byte(Bytes[StartOffset]); try Address := PAnsiChar(Start); if not VirtualQuery(Address, MemInfo, SizeOf(MemInfo)) = SizeOf(MemInfo) then Exit; AllocBase := MemInfo.AllocationBase; while (VirtualQuery(Address, MemInfo, SizeOf(MemInfo)) = SizeOf(MemInfo)) and (MemInfo.AllocationBase = AllocBase) do begin if MemInfo.Protect and $000000F0 <> 0 then // PAGE_EXECUTE | ... begin P := Address; for I := 0 to MemInfo.RegionSize - 1 do begin if Byte(P[0]) = FirstByte then begin BytePtr := P + 1; Found := True; for Index := StartOffset + 1 to BytesLen - 1 do begin if (Bytes[Index] <> -1) and (Byte(Bytes[Index]) <> Byte(BytePtr^)) then begin Found := False; Break; end; Inc(BytePtr); end; if Found then begin Result := P; Exit; end; end; Inc(P); end; end; Inc(Address, MemInfo.RegionSize); end; except on E: EAccessViolation do ; on E: EPrivilege do ; end; end; end; {------------------------------------------------------------------------------} const MidasMallocBytes: array[0..15] of SmallInt = ( $55, // push ebp $8B, $EC, // mov ebp,esp $FF, $75, $08, // push dword ptr [ebp+$08] $E8, -1, -1, -1, -1, // call _malloc $59, // pop ecx $5D, // pop ebp $C2, $04, $00 // ret $0004 ); MidasFreeBytes: array[0..20] of SmallInt = ( $55, // push ebp $8B, $EC, // mov ebp,esp $8B, $45, $08, // mov eax,[ebp+$08] $85, $C0, // test eax,eax $74, $07, // jz +$07 $50, // push eax $E8, -1, -1, -1, -1, // call _free $59, // pop ecx $5D, // pop ebp $C2, $04, $00 // ret $0004 ); MidasMallocBytesGlobal: array[0..56] of SmallInt = ( $55, // push ebp $8B, $EC, // mov ebp,esp $53, // push ebx $56, // push esi $57, // push edi $33, $DB, // xor ebx, ebx $66, $BE, $02, $00, // mov si, $0002 $FF, $75, $08, // push dword ptr [ebp+$08] $0F, $BF, $C6, // movsx eax,si $50, // push eax $E8, -1, -1, -1, -1, // call GlobalAlloc $8B, $F8, // mov edi,eax $85, $C0, // test eax,eax $74, $12, // jz +$12 $57, // push edi $E8, -1, -1, -1, -1, // call GlobalLock $8B, $D8, // mov ebx,eax $85, $C0, // test eax,eax $75, $06, // jnz +$06 $57, // push edi $E8, -1, -1, -1, -1, // call GlobalFree $8B, $C3, // mov eax,ebx $5F, // pop edi $5E, // pop esi $5B, // pop ebx $5D, // pop ebp $C2, $04, $00 // ret $0004 ); MidasFreeBytesGlobal: array[0..39] of SmallInt = ( $55, // push ebp $8B, $EC, // mov ebp,esp $53, // push ebx $8B, $45, $08, // mov eax,[ebp+$08] $85, $C0, // test eax,eax $74, $18, // jz +$18 $50, // push eax $E8, -1, -1, -1, -1, // call GlobalHandle $8B, $D8, // mov ebx,eax $85, $DB, // test ebx,ebx $74, $0C, // jz +$0c $53, // puch ebx $E8, -1, -1, -1, -1, // call GlobalUnlock $53, // push ebx $E8, -1, -1, -1, -1, // call GlobalFree $5B, // pop ebx $5D, // pop ebp $C2, $04, $00 // ret $0004 ); MidasCallocBytes: array[0..43] of SmallInt = ( $55, // push ebp $8B, $EC, // mov ebp,esp $53, // push ebx $56, // push esi $8B, $75, $08, // mov esi,[ebp+$08] $0F, $AF, $75, $0C, // imul esi,[ebp+$0c] $56, // push esi $E8, -1, -1, -1, -1, // call $004d2097 MidasMalloc $8B, $D8, // mov ebx,eax $85, $DB, // test ebx,ebx $74, $0C, // jz +$0c $56, // push esi $6A, $00, // push $00 $53, // push ebx $E8, -1, -1, -1, -1, // call _memset $83, $C4, $0C, // add esp,$0c $8B, $C3, // mov eax,ebx $5E, // pop esi $5B, // pop ebx $5D, // pop ebp $C2, $08, $00 // ret $0008 ); MidasReallocBytes: array[0..54] of SmallInt = ( $55, // push ebp $8B, $EC, // mov ebp,esp $53, // push ebx $56, // push esi $8B, $75, $08, // mov esi,[ebp+$08] $FF, $75, $10, // push dword ptr [ebp+$10] $6A, $01, // push $01 $E8, -1, -1, -1, -1, // call $004d20a7 MidasCalloc $8B, $D8, // mov ebx,eax $85, $DB, // test ebx,ebx $74, $17, // jz +$17 $85, $F6, // test esi,esi $74, $13, // jz +$13 $FF, $75, $0C, // push dword ptr [ebp+$0c] $56, // push esi $53, // push ebx $E8, -1, -1, -1, -1, // call _memmove $83, $C4, $0C, // add esp,$0c $56, // push esi $E8, -1, -1, -1, -1, // call $004d20d3 MidasFree $8B, $C3, // mov eax,ebx $5E, // pop esi $5B, // pop ebx $5D, // pop ebp $C2, $0C, $00 // ret $000c ); var Org_MidasMalloc: Pointer; Org_MidasFree: Pointer; Org_MidasCalloc: Pointer; Org_MidasRealloc: Pointer; MidasMallocHook: TXRedirCode; MidasFreeHook: TXRedirCode; MidasCallocHook: TXRedirCode; MidasReallocHook: TXRedirCode; {$IFDEF REQUIRE_NEW_MEMORY_MANAGER} function RequireNewerMemoryManager: Boolean; var MemMan: TMemoryManager; begin GetMemoryManager(MemMan); if @MemMan.GetMem = @SysGetMem then begin MessageBox(0, 'You must install an alternative memory manager like FastMM4. FastMM4 must run in RELEASE mode to see an improved performance.', 'Delphi - Midas Speed Fix', MB_OK or MB_ICONERROR); Result := False; end else Result := True; end; {$ENDIF REQUIRE_NEW_MEMORY_MANAGER} procedure Init; var DSBase: IDSBase; IsCRTLMemMan: Boolean; begin {$IFDEF REQUIRE_NEW_MEMORY_MANAGER} if not RequireNewerMemoryManager then Exit; {$ENDIF REQUIRE_NEW_MEMORY_MANAGER} IsCRTLMemMan := True; // C RTL memory manager Org_MidasMalloc := FindMethodPtr(HInstance, MidasMallocBytes); if Org_MidasMalloc = nil then begin Org_MidasMalloc := FindMethodPtr(HInstance, MidasMallocBytesGlobal); if Org_MidasMalloc <> nil then IsCRTLMemMan := False; end; if Org_MidasMalloc = nil then begin CreateDbClientObject(CLSID_DSBase, IDSBase, DSBase); // load midas.dll DSBase := nil; // release alloctated midas memory Org_MidasMalloc := FindMethodPtr(GetModuleHandle('midas.dll'), MidasMallocBytes); if Org_MidasMalloc = nil then begin Org_MidasMalloc := FindMethodPtr(HInstance, MidasMallocBytesGlobal); if Org_MidasMalloc <> nil then IsCRTLMemMan := False; end; end; if Org_MidasMalloc = nil then begin OutputDebugString('Midas speed fix could not be installed.'); Exit; end; Assert(Org_MidasMalloc <> nil); if IsCRTLMemMan then Org_MidasFree := FindMethodPtr(HINST(Org_MidasMalloc), MidasFreeBytes) else Org_MidasFree := FindMethodPtr(HINST(Org_MidasMalloc), MidasFreeBytesGlobal); Org_MidasCalloc := FindMethodPtr(HINST(Org_MidasMalloc), MidasCallocBytes); Org_MidasRealloc := FindMethodPtr(HINST(Org_MidasMalloc), MidasReallocBytes); Assert(Org_MidasFree <> nil); Assert(Org_MidasCalloc <> nil); Assert(Org_MidasRealloc <> nil); HookProc(Org_MidasMalloc, @MidasMalloc, MidasMallocHook); HookProc(Org_MidasFree, @MidasFree, MidasFreeHook); HookProc(Org_MidasCalloc, @MidasCalloc, MidasCallocHook); HookProc(Org_MidasRealloc, @MidasRealloc, MidasReallocHook); end; procedure Fini; begin UnhookProc(Org_MidasMalloc, MidasMallocHook); UnhookProc(Org_MidasFree, MidasFreeHook); UnhookProc(Org_MidasCalloc, MidasCallocHook); UnhookProc(Org_MidasRealloc, MidasReallocHook); end; initialization Init; finalization Fini; end.