{ *********************************************************************** }
{                                                                         }
{ Delphi / Kylix Cross-Platform Runtime Library                           }
{                                                                         }
{ Copyright (c) 1995-2001 Borland Software Corporation                    }
{                                                                         }
{ *********************************************************************** }

unit ShareMem;

interface                             

{$IFDEF MEMORY_DIAG}
type
  TBlockEnumProc = function (Block: Pointer): Boolean;
{$ENDIF}

function SysGetMem(Size: Integer): Pointer;
function SysFreeMem(P: Pointer): Integer;
function SysReallocMem(P: Pointer; Size: Integer): Pointer;
function GetHeapStatus: THeapStatus;
function GetAllocMemCount: Integer;
function GetAllocMemSize: Integer;
procedure DumpBlocks;

{$IFDEF MEMORY_DIAG}
function InitBlockMarking: Boolean;
function MarkBlocks: Integer;
function GetMarkedBlocks(MarkID: Integer; Proc: TBlockEnumProc): Boolean;
{$ENDIF}

implementation

{$IFDEF GLOBALALLOC}
uses Windows;
{$ENDIF}

{$IFDEF MEMORY_DIAG}
type
  TInitBlockMarking = function: Boolean;
  TMarkBlocks = function: Integer;
  TGetMarkedBlocks = function (MarkID: Integer; Proc: TBlockEnumProc): Boolean;

var
  MMHandle: Integer = 0;
  SysInitBlockMarking: TInitBlockMarking = nil;
  SysMarkBlocks: TMarkBlocks = nil;
  SysGetMarkedBlocks: TGetMarkedBlocks = nil;
{$ENDIF}

const
  DelphiMM = 'borlndmm.dll';

function SysGetMem(Size: Integer): Pointer; external DelphiMM name '@Borlndmm@SysGetMem$qqri';
function SysFreeMem(P: Pointer): Integer; external DelphiMM name '@Borlndmm@SysFreeMem$qqrpv';
function SysReallocMem(P: Pointer; Size: Integer): Pointer; external DelphiMM name '@Borlndmm@SysReallocMem$qqrpvi';
function GetHeapStatus: THeapStatus; external DelphiMM;
function GetAllocMemCount: Integer; external DelphiMM;
function GetAllocMemSize: Integer; external DelphiMM;
procedure DumpBlocks; external DelphiMM;

function GetModuleHandle(lpModuleName: PChar): Integer; stdcall;
  external 'kernel32.dll' name 'GetModuleHandleA';
function GetProcAddress(hModule: Integer; lpProcName: PChar): Pointer; stdcall;
  external 'kernel32.dll' name 'GetProcAddress';

{$IFDEF MEMORY_DIAG}

procedure InitMMHandle;
begin
  if MMHandle = 0 then MMHandle := GetModuleHandle(DelphiMM);
end;

function InitBlockMarking: Boolean;
begin
  InitMMHandle;
  if @SysInitBlockMarking = nil then
    @SysInitBlockMarking := GetProcAddress(MMHandle, 'InitBlockMarking');
  if @SysInitBlockMarking <> nil then
    Result := SysInitBlockMarking
  else Result := False;
end;

function MarkBlocks: Integer;
begin
  InitMMHandle;
  if @SysMarkBlocks = nil then
    @SysMarkBlocks := GetProcAddress(MMHandle, 'MarkBlocks');
  if @SysMarkBlocks <> nil then
    Result := SysMarkBlocks
  else Result := -1;
end;

function GetMarkedBlocks(MarkID: Integer; Proc: TBlockEnumProc): Boolean;
begin
  InitMMHandle;
  if @SysGetMarkedBlocks = nil then
    @SysGetMarkedBlocks := GetProcAddress(MMHandle, 'GetMarkedBlocks');
  if @SysGetMarkedBlocks <> nil then
    Result := SysGetMarkedBlocks(MarkID, Proc)
  else Result := False;
end;
{$ENDIF}

{$IFDEF GLOBALALLOC}
function xSysGetMem(Size: Integer): Pointer;
begin
  Result := GlobalAllocPtr(HeapAllocFlags, Size);
end;

function xSysFreeMem(P: Pointer): Integer;
begin
  Result := GlobalFreePtr(P);
end;

function xSysReallocMem(P: Pointer; Size: Integer): Pointer;
begin
  Result := GlobalReallocPtr(P, Size, 0);
end;
{$ENDIF}


procedure InitMemoryManager;
var
  SharedMemoryManager: TMemoryManager;
  MM: Integer;
begin
  // force a static reference to borlndmm.dll, so we don't have to LoadLibrary
  SharedMemoryManager.GetMem := SysGetMem;

  MM := GetModuleHandle(DelphiMM);
{$IFDEF GLOBALALLOC}
  SharedMemoryManager.GetMem := xSysGetMem;
  SharedMemoryManager.FreeMem := xSysFreeMem;
  SharedMemoryManager.ReallocMem := xSysReallocMem;
{$ELSE}
  SharedMemoryManager.GetMem := GetProcAddress(MM,'@Borlndmm@SysGetMem$qqri');
  SharedMemoryManager.FreeMem := GetProcAddress(MM,'@Borlndmm@SysFreeMem$qqrpv');
  SharedMemoryManager.ReallocMem := GetProcAddress(MM, '@Borlndmm@SysReallocMem$qqrpvi');
{$ENDIF}
  SetMemoryManager(SharedMemoryManager);
end;

initialization
  if not IsMemoryManagerSet then
    InitMemoryManager;
end.

