2
\$\begingroup\$

With the help of some users here, I finally terminated the conversion of this code from C:

#include <windows.h>
#include <stdio.h>

#define IS_IN_SEARCH(mb, offset) (mb->searchmask[(offset)/8] & (1<<((offset)%8)))
#define REMOVE_FROM_SEARCH(mb, offset)  mb->searchmask[(offset)/8] &= ~(1<<((offset)%8));

typedef struct _MEMBLOCK
{
  HANDLE hProc;
  unsigned char *addr;
  int size;
  unsigned char *buffer;

  unsigned char *searchmask;
  int matches;
  int data_size;

  struct _MEMBLOCK *next;
} MEMBLOCK;

typedef enum
{
  COND_UNCONDITIONAL, 
  COND_EQUALS, 

  COND_INCREASED,
  COND_DECREASED,
} SEARCH_CONDITION;

MEMBLOCK* create_memblock (HANDLE hProc, MEMORY_BASIC_INFORMATION *meminfo, int data_size)
{
  MEMBLOCK *mb = malloc(sizeof(MEMBLOCK));

  if (mb)
  {
    mb->hProc = hProc;
    mb->addr = meminfo->BaseAddress;
    mb->size = meminfo->RegionSize;
    mb->buffer = malloc(meminfo->RegionSize);
    mb->searchmask = malloc(meminfo->RegionSize/8);
    memset (mb->searchmask, 0xff, meminfo->RegionSize/8);
    mb->matches = meminfo->RegionSize;
    mb->next = NULL;
    mb->data_size = data_size;
  }
  return mb;
}

void free_memblock (MEMBLOCK *mb)
{
  if (mb)
  { 
    if (mb->buffer)
    {
      free(mb->buffer);
    }

    if (mb->searchmask)
    {
      free(mb->searchmask);
    }

    free (mb);
  } 
}

void update_memblock (MEMBLOCK *mb, SEARCH_CONDITION condition, unsigned int val)
{
     static unsigned char tempbuf[128*1024];
     unsigned int bytes_left;
     unsigned int total_read;
     unsigned int bytes_to_read;
     unsigned int bytes_read;

  if (mb->matches > 0)
  {

     bytes_left = mb->size;
     total_read = 0;
     mb->matches = 0;

     while (bytes_left)
     {
           bytes_to_read = (bytes_left > sizeof(tempbuf)) ?  sizeof(tempbuf) : bytes_left;
           ReadProcessMemory (mb->hProc, mb->addr + total_read, tempbuf, bytes_to_read, (DWORD*)&bytes_read);
           if (bytes_read != bytes_to_read) break;

           if (condition == COND_UNCONDITIONAL)
           {
               memset (mb->searchmask + (total_read/8), 0xff, bytes_read/8);
               mb->matches += bytes_read;
           }
           else
           {
               unsigned int offset;

               for (offset = 0; offset < bytes_read; offset += mb->data_size)
               {
                   if (IS_IN_SEARCH(mb, (total_read+offset)))
                   {
                      BOOL is_match = FALSE;
                      unsigned int temp_val;
                      unsigned int prev_val = 0;

                      switch (mb->data_size)
                      {
                          case 1:
                               temp_val = tempbuf[offset];
                               prev_val = *((unsigned char*)&mb->buffer[total_read+offset]);
                               break;
                          case 2:
                               temp_val = *((unsigned short*)&tempbuf[offset]);
                               prev_val = *((unsigned short*)&mb->buffer[total_read+offset]);
                               break;
                          case 4: 
                          default:
                               temp_val = *((unsigned int*)&tempbuf[offset]);
                               prev_val = *((unsigned int*)&mb->buffer[total_read+offset]);
                              break;
                      }

                      switch (condition)
                      {
                         case COND_EQUALS:
                              is_match = (temp_val == val);
                              break;
                         case COND_INCREASED:
                              is_match = (temp_val > prev_val);
                              break;
                         case COND_DECREASED:
                              is_match = (temp_val < prev_val);
                              break;
                         default: 
                              break;
                      }

                      if (is_match)
                      {
                        mb->matches++;
                      }
                      else
                      {
                        REMOVE_FROM_SEARCH(mb,(total_read+offset));
                      }

                   }
               }
           }

           memcpy (mb->buffer + total_read, tempbuf, bytes_read);

           bytes_left -= bytes_read;
           total_read += bytes_read;
     }

     mb->size = total_read;
  }   
}

MEMBLOCK* create_scan (unsigned int pid, int data_size)
{
  MEMBLOCK *mb_list = NULL;
  MEMORY_BASIC_INFORMATION meminfo;
  unsigned char *addr = 0;

  HANDLE hProc = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);

  if (hProc)
  {
    while (1)
    {
      if (VirtualQueryEx (hProc, addr, &meminfo, sizeof(meminfo))==0)
      {
        break;
      }   

#define WRITABLE (PAGE_READWRITE | PAGE_WRITECOPY | PAGE_EXECUTE_READWRITE | PAGE_EXECUTE_WRITECOPY)

      if ((meminfo.State & MEM_COMMIT) && (meminfo.Protect & WRITABLE ))
      {   

        MEMBLOCK *mb = create_memblock(hProc, &meminfo, data_size);
        if (mb)
        {
//           update_memblock (mb);
           mb->next = mb_list;
           mb_list = mb;
        }
      } 
        addr = (unsigned char*)meminfo.BaseAddress + meminfo.RegionSize;
    }
  }

  return mb_list;
}

void free_scan (MEMBLOCK *mb_list)
{
     CloseHandle (mb_list->hProc);

     while (mb_list)
     {
           MEMBLOCK *mb = mb_list;
           mb_list = mb_list->next;
           free_memblock (mb);
     }
}

void update_scan (MEMBLOCK *mb_list, SEARCH_CONDITION condition, unsigned int val)
{
     MEMBLOCK *mb = mb_list;
     while (mb)
     {
           update_memblock (mb, condition, val);
           mb = mb->next;
     }
}

void dump_scan_info (MEMBLOCK *mb_list)
{
     MEMBLOCK *mb = mb_list;

     while (mb)
     {
           int i;
           printf ("0x%08x %d\r\n", mb->addr, mb->size);

           for (i = 0; i < mb->size; i++)
           {
               printf("%02x", mb->buffer[i]);
           }
           printf ("\r\n");

           mb = mb->next;
     }
}

void poke (HANDLE hProc, int data_size, unsigned int addr, unsigned int val)
{
     if (WriteProcessMemory (hProc, (void*)addr, &val, data_size, NULL) == 0)
     {
         printf("poke failed\r\n");
     }
}

unsigned int peek (HANDLE hProc, int data_size, unsigned int addr)
{
     unsigned int val = 0;

     if (ReadProcessMemory (hProc, (void*)addr, &val, data_size, NULL) == 0)
     { 
         printf("poke failed\r\n");
     }

     return val;
}

void print_matches (MEMBLOCK *mb_list)
{
     unsigned int offset;
     MEMBLOCK *mb = mb_list;

     while (mb)
     {
           for (offset = 0; offset < mb->size; offset+= mb->data_size)
           {
               if (IS_IN_SEARCH(mb, offset))
               {
                  unsigned int val = peek (mb->hProc, mb->data_size, (unsigned int)mb->addr + offset);
                  printf("0x%08x: 0x%08x (%d) \r\n", mb->addr + offset, val, val);
               }
           }

           mb = mb->next;
     }
}

int get_match_count (MEMBLOCK *mb_list)
{
    MEMBLOCK *mb = mb_list;
    int count = 0;

    while (mb)
    {
          count += mb->matches;
          mb = mb->next;
    }

    return count;
}

unsigned int str2int (char *s)
{
   int base = 10;

   if (s[0] == '0' && s[1] == 'x')
   {
     base = 16;
     s += 2;
   }

   return strtoul (s, NULL, base);
}

MEMBLOCK* ui_new_scan(void)
{
   MEMBLOCK *scan = NULL;
   DWORD pid;
   int data_size;
   unsigned int start_val;
   SEARCH_CONDITION start_cond;
   char s[20];

   while(1)
   {
           printf("\r\nEnter the pid: ");
           fgets (s, sizeof(s), stdin);
           pid = str2int(s);
           printf ("\r\nEnter the data size: ");
           fgets (s, sizeof(s), stdin);
           data_size = str2int(s);
           printf ("\r\nEnter the start value, or 'u' for unknown:  ");
           fgets (s, sizeof(s), stdin);
           if (s[0] == 'u')
           { 
              start_cond = COND_UNCONDITIONAL;
              start_val = 0;
           }
           else
           {
               start_cond = COND_EQUALS;
               start_val = str2int (s);
           }

           scan = create_scan (pid, data_size);
           if (scan) break;
           printf ("\r\nInvalid scan");
   }

   update_scan (scan, start_cond, start_val);
   printf("\r\n%d matches found\r\n", get_match_count(scan));

   return scan;       
}

void ui_poke (HANDLE hProc, int data_size)
{
     unsigned int addr;
     unsigned int val;
     char s[20];

     printf("Enter the address: ");
     fgets (s, sizeof(s), stdin);
     addr = str2int(s);

     printf("\r\nEnter the value: ");
     fgets (s, sizeof(s), stdin);
     val = str2int(s);
     printf ("\r\n");

     poke (hProc, data_size, addr, val);
}

void ui_run_scan(void)
{ 
     unsigned int val;
     char s[20];
     MEMBLOCK *scan;

     scan = ui_new_scan();

     while(1)
     {
        printf("\r\nEnter the next value or");
        printf("\r\n[i] increased");
        printf("\r\n[d] decreased");
        printf("\r\n[m] print matches");
        printf("\r\n[p] poke address");
        printf("\r\n[n] new scan");
        printf("\r\n[q] quit\r\n");

        fgets (s, sizeof(s), stdin);
        printf("\r\n" );

        switch(s[0])
        {
          case 'i':
               update_scan (scan, COND_INCREASED, 0);
               printf(" %d matches found\r\n", get_match_count(scan));
               break;
          case 'd':
               update_scan (scan, COND_DECREASED, 0);
               printf(" %d matches found\r\n", get_match_count(scan));
               break;
          case 'm':
               print_matches(scan);
               break;
          case 'p':
               ui_poke (scan->hProc, scan->data_size);
               break;
          case 'n':
               free_scan(scan);
               scan = ui_new_scan();
               break;
          case 'q':
               free_scan(scan);
               return;
          default:
               val = str2int(s);
               update_scan(scan, COND_EQUALS, val);
               printf(" %d matches found\r\n", get_match_count(scan));
               break;
        }
     }
} 

int main (int argc, char *argv[])
{
     ui_run_scan();
     return 0;
}

to Delphi:

//Declarations
type
 PMEMBLOCK = ^MEMBLOCK;
 MEMBLOCK = packed record
  hProc: THandle;
  addr: array of byte;
  size: integer;
  buffer: array of byte;
  searchmask: array of byte;
  matches: integer;
  data_size: integer;
  next: array of PMEMBLOCK;
end;

type
 SEARCH_CONDITION = (COND_UNCONDITIONAL, COND_EQUALS, COND_INCREASED, COND_DECREASED);

const
 WRITABLE = (PAGE_READWRITE and PAGE_WRITECOPY and PAGE_EXECUTE_READWRITE and PAGE_EXECUTE_WRITECOPY);

function Is_In_Search(mb: PMEMBLOCK; offset: cardinal): Boolean;
begin
  Result := 0 <> (mb.searchmask[offset div 8] and (1 shl (offset mod 8)));
end;

procedure Remove_From_Search(mb: PMEMBLOCK; offset: cardinal);
begin
  mb.searchmask[offset div 8] := mb.searchmask[offset div 8] and not (1 shl (offset mod 8));
end;


function create_memblock(hProc: THandle; meminfo: MEMORY_BASIC_INFORMATION; data_size: integer): PMemblock;
var
 mb: PMemblock;
 x:integer;
begin
x:= round(meminfo.RegionSize/8);
 mb:= malloc(sizeof(MEMBLOCK));
 if mb<>ptr(0) then begin
  mb.hProc := hProc;
  mb.addr := meminfo.BaseAddress;
  mb.size := meminfo.RegionSize;
  mb.buffer := malloc(meminfo.RegionSize);
  mb.searchmask := malloc(x);
  memset(mb.searchmask, $ff, x);
  mb.matches := meminfo.RegionSize;  
  mb.next := NULL;
  mb.data_size := data_size;
 end;
 result := mb;
end;

procedure free_memblock(mb:pmemblock);
begin
 if mb<>ptr(0) then begin
  if mb.buffer<>ptr(0) then free(mb.buffer);
  if mb.searchmask<>ptr(0) then free(mb.searchmask);
  mb:=nil;
 end;
end;

procedure update_memblock(mb:pmemblock; condition:SEARCH_CONDITION; val:cardinal);
var
 tempbuf: array[0..(128*1024)-1] of Byte;
 bytes_left: cardinal;
 total_read: cardinal;
 bytes_to_read: cardinal;
 bytes_read: cardinal;
 offset: cardinal;
 x, z:integer;
 is_match: boolean;
 temp_val, prev_val: cardinal;
begin
 if mb.matches > 0 then begin
  bytes_left := mb.size;
  total_read := 0;
  mb.matches := 0;
  while (bytes_left<>0) do begin
   if bytes_left > sizeof(tempbuf) then bytes_to_read := sizeof(tempbuf) else bytes_to_read := bytes_left;
   //TO USE IN DLL: tempbuf[0] :=  PBYTE(dword(mb.addr)+total_read)^; // bytes_to_read = 1bytes  {PRECISA CRIAR IF PROS OUTROS TIPOS}
   ReadProcessMemory(mb.hProc, pointer(dword(mb.addr)+total_read), @tempbuf, bytes_to_read, dword(bytes_to_read));

   if bytes_read <> bytes_to_read then break;

   if condition = COND_UNCONDITIONAL then begin
    x:= round(total_read/8);   
    z:= round(bytes_read/8);
    memset (pointer(dword(mb.searchmask) + x), $ff, z);
    mb.matches :=+ bytes_read;
   end
   else
   begin
     offset:=0;
     while (offset < bytes_read) do
     begin

       if IS_IN_SEARCH(mb, (total_read+offset)) then begin
        is_match:=false;
        prev_val := 0;
       end;

       case mb.data_size of
       1: begin
            temp_val := tempbuf[offset];
            prev_val := PBYTE(mb.buffer[total_read+offset])^;
            break;
          end;     
       2: begin  
            temp_val := PWORD(tempbuf[offset])^;
            prev_val := PWORD(mb.buffer[total_read+offset])^;
            break;
          end;
       4: begin   
            temp_val := PDWORD(tempbuf[offset])^;
            prev_val := PDWORD(mb.buffer[total_read+offset])^;
            break;
          end;
       end;

       case condition of
          COND_EQUALS: begin
                        is_match := temp_val = val;
                        break;
                       end;
       COND_INCREASED: begin
                        is_match := (temp_val > prev_val);
                        break;
                       end;
       COND_DECREASED: begin
                        is_match := (temp_val < prev_val);
                        break;
                       end;
       end;

       if (is_match) then
        inc(mb.matches)
       else
        REMOVE_FROM_SEARCH(mb,(total_read+offset));

        bytes_left :=- bytes_read;
        total_read :=+ bytes_read;

      Inc(offset, mb.data_size);
     end;
   end;

    memcpy(pointer(dword(mb.buffer) + total_read), @tempbuf, bytes_read);

  end;
  mb.size := total_read;
 end;
end;

function create_scan(pid: cardinal; data_size: integer):PMEMBLOCK;
var
 mb_list: PMEMBLOCK;
 meminfo: MEMORY_BASIC_INFORMATION;
 addr: PBYTE;
 hProc: THandle;
 mb: PMEMBLOCK;
begin
 mb_list:=nil;
 addr:=nil;
 hProc := OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
 if hProc<>0 then begin
  while 1<>0 do begin
    if VirtualQueryEx(hProc, pointer(addr), meminfo, sizeof(meminfo))=0 then break;

     if ((meminfo.State = MEM_COMMIT) and (meminfo.Protect = WRITABLE )) then begin
      mb := create_memblock(hProc, meminfo, data_size);
      if mb<>ptr(0) then begin
            mb.next := @mb_list;
            mb_list := mb;
      end;
     end;
     addr := pbyte(dword(meminfo.BaseAddress) + dword(meminfo.RegionSize));
  end;
 end;
 result := mb_list;
end;


procedure free_scan(mb_list: PMEMBLOCK);
var
 mb: PMEMBLOCK;
begin
     CloseHandle(mb_list.hProc);

     while mb_list<>ptr(0) do
      begin
           mb := mb_list;
           mb_list := @mb_list.next;
           free_memblock(mb);
     end;
end;

procedure update_scan(mb_list: PMEMBLOCK; condition: SEARCH_CONDITION; val: cardinal);
var
 mb: PMEMBLOCK;
begin
     mb := mb_list;
     while mb<>ptr(0) do
     begin
           update_memblock(mb, condition, val);
           mb := @mb.next;
     end;
end;


procedure dump_scan_info(mb_list: PMEMBLOCK);
var
 mb: PMEMBLOCK;
 i: integer;
begin
     mb := mb_list;
     while mb<>ptr(0) do
     begin
           writeln(Format('0x%08x %d',[mb.addr, mb.size]));

           for i := 0 to mb.size do
           begin
               writeln(Format('%02x',[mb.buffer[i]]));
           end;
           writeln('');

           mb := @mb.next;
     end;
end;

procedure poke(hProc:THANDLE; data_size: integer; addr: cardinal; val: cardinal);
var
 write: cardinal;
begin
 if not ReadProcessMemory(hProc, pointer(addr), @val, data_size, write) then
  writeln('poke failed');
end;

function peek(hProc: THandle; data_size: integer; addr: cardinal):cardinal;
var
 val: cardinal;
 write: cardinal;
begin
 val := 0;

 if not ReadProcessMemory(hProc, pointer(addr), @val, data_size, write) then
   writeln('poke failed');


 result := val;
end;

procedure print_matches(mb_list: PMEMBLOCK);
var
 offset: cardinal;
 mb: PMEMBLOCK;
 val: cardinal;
begin
     mb := mb_list;

     while mb<>ptr(0) do
     begin
           offset:=0;
           while (offset<mb.size) do
           begin

               if IS_IN_SEARCH(mb, offset) then begin
                  val := peek(mb.hProc, mb.data_size, dword(dword(mb.addr) + offset));
                  writeln(format('0x%08x: 0x%08x (%d)',[dword(dword(mb.addr) + offset), val]));
               end;

           Inc(offset, mb.data_size);
           end;

           mb := @mb.next;
     end;
end;

function get_match_count(mb_list: PMEMBLOCK): integer;
var
 mb: PMEMBLOCK;
 count: integer;
begin
    mb := mb_list;
    count := 0;

    while mb<>ptr(0) do
    begin
          count :=+ mb.matches;
          mb := @mb.next;
    end;

    Result := count;
end;

function ui_new_scan: PMEMBLOCK;
var
 scan: PMEMBLOCK;
 pid: dword;
 data_size: integer;
 start_val: cardinal;
 start_cond: SEARCH_CONDITION;
 s: array [0..19] of char;
begin
 scan := nil;

 while 1<>0 do
 begin
  writeln('Digite o pid: ');
  readln(s);
  pid := strtoint(s);
  writeln('Enter the data size: ');
  readln(s);
  data_size := strtoint(s);
  writeln('Enter the start value, or ''u'' for unknown:  ');
  readln(s);
  if s[0] = 'u' then begin
   start_cond := COND_UNCONDITIONAL;
   start_val := 0;
  end else
  begin
   start_cond := COND_EQUALS;
   start_val := strtoint(s);
  end;
   scan := create_scan (pid, data_size);
   if scan<>ptr(0) then break;
   writeln('Invalid scan');
 end;
   update_scan(scan, start_cond, start_val);
   writeln(Format('%d matches found', [get_match_count(scan)]));

   Result := scan;
end;

procedure ui_poke(hProc: THandle; data_size: integer);
var
 addr: cardinal;
 val: cardinal;
 s: array [0..19] of char;
begin        
  writeln('Enter the address: ');
  readln(s);
  addr := strtoint(s);
  writeln('Enter the value: ');
  readln(s);
  val := strtoint(s);
  writeln('');
  poke(hProc, data_size, addr, val);
end;

function CaseOfString(s: string; a: array of string): Integer;
begin
  Result := 0;
  while (Result < Length(a)) and (a[Result] <> s) do
    Inc(Result);
  if a[Result] <> s then
    Result := -1;
end;

procedure ui_run_scan;
var
 val: cardinal;
 s: array [0..19] of char;
 scan: PMEMBLOCK;
begin
 scan := ui_new_scan();

 while 1<>0 do
 begin
   writeln('Enter the next value or');
   writeln('[i] increased');
   writeln('[d] decreased');
   writeln('[m] print matches');
   writeln('[p] poke address');
   writeln('[n] new scan');
   writeln('[q] quit');

   readln(s);

   if s[0] = 'i' then begin
    update_scan(scan, COND_INCREASED, 0);
    writeln(Format(' %d matches found', [get_match_count(scan)]));
    break;
   end;  

   if s[0] = 'd' then begin
    update_scan(scan, COND_DECREASED, 0);
    writeln(Format(' %d matches found', [get_match_count(scan)]));
    break;
   end;

   if s[0] = 'm' then begin
    print_matches(scan);
    break;
   end;

   if s[0] = 'p' then begin
    ui_poke (scan.hProc, scan.data_size);
    break;
   end;

   if s[0] = 'n' then begin
     free_scan(scan);
     scan := ui_new_scan();
    break;
   end; 

   if s[0] = 'q' then begin
    free_scan(scan);
    exit;
   end;

   if s[0] = 'p' then begin
    ui_poke (scan.hProc, scan.data_size);
    break;
   end;

   if (s[0]<>'i') and (s[0]<>'d') and (s[0]<>'m') and (s[0]<>'p') and (s[0]<>'n') and (s[0]<>'q') then begin
     val := strtoint(s);
     update_scan(scan, COND_EQUALS, val);
     writeln(Format('%d matches found', [get_match_count(scan)]));
     break;
   end;
 end;
end;

procedure Main;
begin
 ui_run_scan();
end;

Please, can anyone just check if is the conversion correct? Thank you so much.

\$\endgroup\$
3
  • \$\begingroup\$ Welcome to Code Review - please check out the FAQ. We ask that you put your code in the post, because it makes it a lot easier for us to review it. For example, I can't even get to your code right now - blocked. \$\endgroup\$
    – Michael K
    Apr 3 '12 at 12:42
  • \$\begingroup\$ Do you have unit tests on the old code? Obviously you can't just run the old tests against the new code, but they could give you a set of tests to write. \$\endgroup\$
    – Michael K
    Apr 3 '12 at 12:43
  • \$\begingroup\$ Dear Michael, Unfortunetly, I'm with problems... Every time returns "Invalid scan" :( \$\endgroup\$
    – paulohr
    Apr 3 '12 at 12:58
3
\$\begingroup\$

First problem: MEMBLOCK::next in C is a pointer to a single MEMBLOCK, but in your Delphi code, it's an array of pointers. Declare it as a PMemBlock instead.

The C definition of WRITABLE combines flags with the or operator, but your Delphi code uses and, virtually guaranteeing that the result will be zero instead of whatever combination of bits it's supposed to be.

Please don't use Ptr(0) when Delphi already has a perfectly good value to represent the null pointer. Use nil instead.

If you're going to use malloc in Delphi, then you can't use it to assign special Delphi-managed types like dynamic arrays. A dynamic array isn't just a pointer to a block of bytes. The block of bytes requires a specific structure, and the pointer isn't even to the start of the block. If you use malloc, then change the declarations of addr, buffer, and searchmask to have type PByte. (This especially applies to addr since it gets assigned an ordinary pointer, not an array.)

If this code requires binary compatibility with the C code — that is, if this code is going to be used in combination with code that's already compiled to use the C code, so everything the Delphi code produces has to have the same layout in memory — then you can' use dynamic arrays at all. However, if you're just translating this code for use in a Delphi project and don't require identical layout, then you can keep the dynamic arrays and reduce your use of malloc instead. In create_memblock, for example, you could use New and SetLength:

function create_memblock(hProc: THandle; meminfo: MEMORY_BASIC_INFORMATION; data_size: integer): PMemBlock;
var
  x: integer;
begin
  x := meminfo.RegionSize div 8; // don't use floating-point division if you don't have to
  try
    New(Result);
    Result.hProc := hProc;
    Result.addr := meminfo.BaseAddress;
    Result.size := meminfo.RegionSize;
    SetLength(Result.buffer, meminfo.RegionSize);
    SetLength(Result.searchmask, x);
    memset(mb.searchmask, $ff, x);
    Result.matches := meminfo.RegionSize;  
    Result.next := nil; // "Null" isn't what you think it is in Delphi
    Result.data_size := data_size;
  except
    on EOutOfMemory do
      Result := nil;
  end;
end;

Depending on how fancy you want to get, you could even make MemBlock be a class, and then turn create_memblock into a MemBlock.Create constructor.

Be careful about your use of free. You haven't shown the definition of malloc in your Delphi code, but if it's anything other than a thin wrapper for GetMem, then you're in for some problems because System.Free expects plain memory blocks allocated with GetMem, not whatever malloc returns. If you're importing malloc from the C runtime library, then you need to make sure you're calling the free function from that same library, not Delphi's Free. I'd import free with a different name, if that's the case.

Speaking of free, the C version of free_memblock calls free(mb), whereas your Delphi version just assigns nil to it, which is particularly ineffective since mb is a local variable that goes out of scope at the next instruction, so you not only fail to free the memory, but also assign a value into a memory location that ceases to exist anymore. Call Free(mb) instead. Also, free is always safe to call on null pointers, so you don't need to check before calling it. The C code makes the same mistake.

The C code uses the conditional operator to assign to bytes_to_read in update_memblock, but in Delphi, it can be written more concisely with the Min function from the Math unit:

bytes_to_read := Min(SizeOf(tmpbuf), bytes_left);

Instead of temporary variables and Round, you can just use the div operator. It works the same way as C's / operator on integers.

The += operator in mb->matches += bytes_read increments the left operand by the right operand. You've translated it as :=+, which isn't the same at all. Use Delphi's Inc instruction instead:

Inc(mb.matches, bytes_read);

The block after the C code's first call to IS_IN_SEARCH extends all the way to include both the following switch statements and the if, but your Delphi code ends the block after just the two assignment statements. That's just sloppy. Make sure you proofread your code.

Do not call break instead a Delphi case statement. It's necessary in the C switch statement because control will "fal through" into the next case, but that doesn't happen in Delphi, so the break actually applies to the while loop instead. Delphi will break out of the case statement automatically, so don't use break there.

You've incorrectly translated *((unsigned char*)&mb->buffer[total_read+offset]) to PBYTE(mb.buffer[total_read+offset])^. The C code has an extra pointer reference, which you omit in the Delphi code. In this case, the casting isn't necessary at all since buffer is already an array of bytes, but it's important in the subsequent cases where the pointer gets type-cast to a larger type. Use the @ operator where the C code uses & to get this: PBYTE(@mb.buffer[total_read+offset])^.

The memcpy call near the bottom of update_memblock occurs in an entirely different place in the two versions of the function. Again, proofreading.

In create_scan, you're using = where the original code used &. Those are two completely different tests. You're testing for equality when you should be performing a bitwise mask. Write (meminfo.State and MEM_COMMIT) <> 0 to check whether the State field shares any of the same bits as are in MEM_COMMIT. Likewise for Protect and WRITABLE.

You assign mb.next := @mb_list, which is wrong. The next field shouldn't get a pointer to the mb_list variable; it should get the contents of the variable, as the C code does. The same when you assign mb_list := @mb_list.next. The compiler can help you find such errors. Go to your compiler options and turn on the "typed @ operator" setting.

The for loop in dump_scan_info goes one element too far, and inside the loop, you call writeln when you should call write; you're adding line breaks where the C code never printed them.

In ui_run_scan, you've gotten confused by the C code's use of characters in the switch statement. Delphi can do the same thing because one-character strings are really Char, so they're ordinal types and thus acceptable inside case statements. You can write your code the same as the C code (but without the break statements, remember):

case s[0] of
  'i': begin
    update_scan(scan, COND_INCREASED, 0);
    writeln(Format(' %d matches found', [get_match_count(scan)]);
  end;
  'd': begin
    update_scan(scan, COND_DECREASED, 0);
    writeln(Format(' %d matches found', [get_match_count(scan)]);
  end;
  'm': print_matches(scan);
  'p': ui_poke(scan.hProc, scan.data_size);
  'n': begin
    free_scan(scan);
    scan = ui_new_scan;
  end;
  'q': begin
    free_scan(scan);
    exit;
  end;
  else begin
    val = StrToInt(s);
    update_scan(scan, COND_EQUALS, val);
    writeln(Format(' %d matches found', [get_match_count(scan)]);
  end;
end;
\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.