#ifndef usememcheck
  #print "memcheck.hmm: [1;36;44myou can use #define usememcheck[1;37;40m\n"
#endif

#ifdef usememcheck
  #ifndef logmemoryfunctions
    #print "memcheck.hmm: [1;36;44myou can use #define logmemoryfunctions[1;37;40m\n"
  #endif

  extern WINAPI "kernel32.dll"
  {
    GetModuleHandleA();
    GetProcAddress();
    IsBadReadPtr();
  }

  #include "myprintf.h--"

  struct
  {
    dword stdcall (*globalalloc)();
    dword stdcall (*globalrealloc)();
    dword stdcall (*globalfree)();

    dword stdcall (*localalloc)();
    dword stdcall (*localrealloc)();
    dword stdcall (*localfree)();
  }oldglobalfunctions;

  struct THandleCollection
  {
    int Count;
    int Delta;
    int Items;
    int Limit;

    THandleCollection( int ALimit, ADelta );
    ~THandleCollection();
    int  At( int Index );
    void AtDelete( int Index );
    void AtInsert( int Index, Item );
    void Insert( int Item );
    int  Search( int Key, Index );
    void SetLimit( int ALimit );
  };

  :int THandleCollection::At( int Index )
  {
    return DSDWORD[ Index*sizeof(int)+Items ];
  }

  :void THandleCollection::AtDelete( int Index )
  {
    ECX = Count-Index-1;
    EDI = Index*sizeof(int)+Items; ESI = EDI+4; $cld; $rep;$movsd;
    Count --;
  }

  :void THandleCollection::AtInsert( int Index, Item )
  {
    $pushfd
    IF( Count == Limit )
    {
      SetLimit( Count+Delta );
    }
    ECX = Count-Index;
    EDI = Count*sizeof(int)+Items;
    ESI = EDI-4; $std $rep $movsd
    DSDWORD[ EDI ] = Item;
    Count ++;
    $popfd
  }

  :THandleCollection::THandleCollection( int ALimit, ADelta )
  {
    Items = 0;
    Count = 0;
    Limit = 0;
    Delta = ADelta;
    SetLimit( ALimit );
  }

  :THandleCollection::~THandleCollection( void )
  {
    Count=0;
    SetLimit(0);
  }

  :void THandleCollection::SetLimit( int ALimit )
  {
    int AItems;

    IF( ALimit < Count )ALimit = Count;
    IF( ALimit != Limit )
    {
      IF( !ALimit ) AItems = 0;
      ELSE
      {
        AItems = oldglobalfunctions.globalalloc( GMEM_FIXED, ALimit*sizeof(int) );
        IF( Count )&&( Items )
        {
          CopyMemory( AItems, Items, Limit*sizeof(int) );
        }
      }
      IF( Limit )oldglobalfunctions.globalfree( Items );
      Items = AItems;
      Limit = ALimit;
    }
  }

  :void THandleCollection::Insert( int Item )
  {
    int i;
    IF( !Search(Item,#i) ) AtInsert( i, Item );
  }

  :int THandleCollection::Search( int Key, Index )
  {
    int L, H, I, C;
    int S;

    S = 0;
    L = 0;
    H = Count-1;
    WHILE( L <= H )
    {
      I = L+H >> 1;
      ECX = I*sizeof(int)+Items;
      C = DSDWORD[ECX] - Key;
      IF( C < 0 ){ L = I+1; }
      ELSE
      {
        H = I-1;
        IF( !C ){
          S = 1;
          L = I;
        }
      }
    }
    DSDWORD[ Index ]=L;
    return S;
  }
  //////////////////////////////////////////////////////////
  memcheckat(dword ebp)
  {
    $pushad
    EBX=ebp;
    for(EDI=0;EDI<16;EDI++)
    {
      if(IsBadReadPtr(EBX,8))break;
      ESI=DSDWORD[EBX+4];
      if(IsBadReadPtr(ESI-6,6))break;
      IF(DSBYTE[ESI-5]==0xE8)ESI-=5;
      ELSE
      IF(DSWORD[ESI-6]==0x15FF)ESI-=6;
      $push EDI
      myprintf("%08X ",ESI);
      $pop EDI
      EBX=DSDWORD[EBX];
    }
    myprintf("\n");
    $popad
  }

  :THandleCollection globalhandles;
  :THandleCollection localhandles;

  dword GlobalAlloc(dword flags,size)
  {
  if(!size)$nop
    if(oldglobalfunctions.globalalloc(flags,size))
    {
      $pushad
      globalhandles.Insert(EAX);
      $popad
    }
    #ifdef logmemoryfunctions
      $pushad myprintf("globalalloc(%d)... allocated %d blocks\n",size,globalhandles.Count);$popad
    #endif
  }

  dword GlobalReAlloc(dword mem,size,flags)
  int i;
  {
    #ifdef logmemoryfunctions
      $pushad myprintf("globalrealloc\n");$popad
    #endif
    $pushad
    if(!globalhandles.Search(mem,#i))
    {
      myprintf("globalrealloc(what?) at ");
      memcheckat(EBP);
    }
    $popad
    if(oldglobalfunctions.globalrealloc(mem,size,flags))
    {
      $pushad
      $push EAX
      globalhandles.AtDelete(i);
      $pop EAX
      globalhandles.Insert(EAX);
      $popad
    }
  }

  dword GlobalFree(dword mem)
  int i,retcode;
  {
    $pushad
    if(!globalhandles.Search(mem,#i))
    {
      myprintf("globalfree(what?) at ");
      memcheckat(EBP);
      i=-1;
    }
    if(!retcode=oldglobalfunctions.globalfree(dword mem))
    &&(i!=-1)
    {
      globalhandles.AtDelete(i);
    }
    $popad
    #ifdef logmemoryfunctions
      $pushad myprintf("globalfree... now is %d blocks\n",globalhandles.Count);$popad
    #endif
  }

  dword LocalAlloc(dword flags,size)
  {
    if(oldglobalfunctions.localalloc(flags,size))
    {
      $pushad
      localhandles.Insert(EAX);
      $popad
    }
  }

  dword LocalReAlloc(dword mem,size,flags)
  int i;
  {
    $pushad
    if(!localhandles.Search(mem,#i))
    {
      myprintf("localrealloc(what?) at ");//,SSDWORD[EBP+4]);
      memcheckat(EBP);
    }
    $popad
    if(oldglobalfunctions.localrealloc(mem,size,flags))
    {
      $pushad
      $push EAX
      localhandles.AtDelete(i);
      $pop EAX
      localhandles.Insert(EAX);
      $popad
    }
  }

  dword LocalFree(dword mem)
  int i,retcode;
  {
    $pushad
    if(!localhandles.Search(mem,#i))
    {
      myprintf("localfree(what?) at ");
      memcheckat(EBP);
      i=-1;
    }
    if(!retcode=oldglobalfunctions.localfree(dword mem))
    &&(i!=-1)
    {
      localhandles.AtDelete(i);
    }
    $popad
    #ifdef logmemoryfunctions
      $pushad myprintf("localfree... now is %d blocks\n",localhandles.Count);$popad
    #endif
  }


  :gmeminit()
  dword hkernel;
  {
    hkernel=GetModuleHandleA("kernel32.dll");

    oldglobalfunctions.globalalloc=GetProcAddress(hkernel,"GlobalAlloc");
    oldglobalfunctions.globalrealloc=GetProcAddress(hkernel,"GlobalReAlloc");
    oldglobalfunctions.globalfree=GetProcAddress(hkernel,"GlobalFree");

    oldglobalfunctions.localalloc=GetProcAddress(hkernel,"LocalAlloc");
    oldglobalfunctions.localrealloc=GetProcAddress(hkernel,"LocalReAlloc");
    oldglobalfunctions.localfree=GetProcAddress(hkernel,"LocalFree");

    globalhandles.THandleCollection(32,32);
    localhandles.THandleCollection(32,32);
  }

  :gmemdone()
  {
    if(globalhandles.Count)
    {
      myprintf("%d non unallocated global blocks\n",globalhandles.Count);
    }
    if(localhandles.Count)
    {
      myprintf("%d non unallocated local blocks\n",localhandles.Count);
    }
    delete localhandles;
    delete globalhandles;
  }
#else
  #define gmeminit()
  #define gmemdone()
#endif
