Search code examples
delphirecorddelphi-10-seattle

C to Delphi: Struct not is filled


I'm trying translate a piece of code from C to Delphi, that have as goal fill a struct until max limit allowed previous defined. I tried make the Delphi version more near of C code (even so not be a professional programmer).

But i noted that in my Delphi code the seems struct is filled only with 0 values (result of FillMemory()) and not is being filled with correct values.

How i can solve it? below i show only the relevant code.

C: (code of reference)

struct Client
{
   SOCKET connections[2];
   DWORD  uhid;
   HWND   hWnd;
   BYTE  *pixels;
   DWORD  pixelsWidth, pixelsHeight;
   DWORD  screenWidth, screenHeight;
   HDC    hDcBmp;
   HANDLE minEvent;
   BOOL   fullScreen;
   RECT   windowedRect;
};

static Client g_clients[256];


static Client *GetClient(void *data, BOOL uhid)
{
   for(int i = 0; i < 256; ++i)
   {
      if(uhid)
      {
         if(g_clients[i].uhid == (DWORD) data)
            return &g_clients[i];
      }
      else
      {
         if(g_clients[i].hWnd == (HWND) data)
            return &g_clients[i];
      }
   }
   return NULL;
}

BOOL recordClient()
{
  Client *client = NULL;
  BOOL   found = FALSE;
  DWORD  uhid;


uhid = 27650; // Some value, only as example here
memset(g_clients, 0, sizeof(g_clients));

client = GetClient((void *) uhid, TRUE);

 if(client)
   return FALSE;

    for(int i = 0; i < 256; ++i)
    {
      if(!g_clients[i].hWnd)
      {
         found = TRUE;
         client = &g_clients[i];
      }
    }

    if(!found)
    {
      wprintf(TEXT("User %S kicked max %d users\n"), "185.242.4.203", 256);
      return FALSE;
    }

   return TRUE;
}

Delphi:

type
  PClient = ^Client;

  Client = record
    Connections: array [0 .. 1] of TSocket;
    uhId, 
    pixelsWidth, 
    pixelsHeight, 
    screenWidth, 
    screenHeight: Cardinal;
    _hWnd: HWND;
    Pixels: PByte;
    hDcBmp: HDC;
    minEvent: THandle;
    fullScreen: Boolean;
    windowRect: TRect;
  end;


var
  Clients: array [0 .. 255] of Client;

//...

function GetClient(Data: Pointer; uhId: Boolean): PClient;
var
  I: Integer;
begin
  Result := nil;
  for I := 0 to 255 do
  begin
    if uhId then
    begin
      if Clients[I].uhId = Cardinal(Data) then
      begin
        Result := @Clients[I];
        Break;
      end;
    end
    else
    begin
      if Clients[I]._hWnd = HWND(Data) then
      begin
        Result := @Clients[I];
        Break;
      end;
    end;
  end;
end;

function recordClient: Boolean;
var
  _client: PClient;
  _uhId: Cardinal;
  found: Boolean;
  I: Integer;
begin
  Result := True;

  FillMemory(@Clients, SizeOf(Clients), 0);

  _uhId := 27650; // Some value, only as example here
  _client := GetClient(@_uhId, True);

  if _client <> nil then
  begin
    Result := False;
    Exit;
  end;

  found := False;

  for I := 0 to 255 do
  begin
    if Clients[I]._hWnd = 0 then
    begin
      found := True;
      _client := @Clients[I];
    end;
  end;

  if not found then
  begin                                            
    Writeln(Format('Client %s rejected, max allowed is %d clients.' + #13,
      ['185.242.4.203', 256])); // Only example values
    Result := False;
    Exit;
  end;
end;

Solution

  • You have shown no code, on either the C side or the Delphi side, that actually tries to fill the array with data. Looking at the original C code, it populates a found array element with data inside of the ClientThread() function. You didn't translate those pieces of C code, which explains why the array in your Delphi code has no data in it:

    static DWORD WINAPI ClientThread(PVOID param)
    {
       Client    *client = NULL;
       SOCKET     s = (SOCKET) param;
       ...
    
       if(connection == Connection::desktop)
       {
          client = GetClient((void *) uhid, TRUE);
          if(!client)
          {
             closesocket(s);
             return 0;
          }
          client->connections[Connection::desktop] = s;
    
          ...
    
          for(;;)
          {
             ...
    
             if(recv(s, (char *) &client->screenWidth, sizeof(client->screenWidth), 0) <= 0)
                goto exit;
             if(recv(s, (char *) &client->screenHeight, sizeof(client->screenHeight), 0) <= 0)
                goto exit;
             ...
    
                if(client->pixels && client->pixelsWidth == ... && client->pixelsHeight == ...)
                {
                   for(...)
                   {
                      ...
                      client->pixels[i] = newPixels[i];
                      client->pixels[i + 1] = newPixels[i + 1];
                      client->pixels[i + 2] = newPixels[i + 2];
                   }
                   ...
                }
                else
                {
                   free(client->pixels);
                   client->pixels = newPixels;
                }
    
                ...
                DeleteDC(client->hDcBmp);
                client->pixelsWidth = width;
                client->pixelsHeight = height;
                client->hDcBmp = hDcBmp;
    
                ...
             }
             ...
          }
    exit:
          ...
          return 0;
       }
       else if(connection == Connection::input)
       {
          ...
    
             client = GetClient((void *) uhid, TRUE);
             if(client)
             {
                closesocket(s);
                ...
                return 0;
             }
             ...
    
             BOOL found = FALSE;
             for(int i = 0; i < gc_maxClients; ++i)
             {
                if(!g_clients[i].hWnd)
                {
                   found = TRUE;
                   client = &g_clients[i];
                }
             }
             if(!found)
             {
                wprintf(TEXT("User %S kicked max %d users\n"), ip, gc_maxClients);
                closesocket(s);
                return 0;
             }
    
             client->hWnd = CW_Create(uhid, gc_minWindowWidth, gc_minWindowHeight);
             client->uhid = uhid;
             client->connections[Connection::input] = s;
             client->minEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
    
          ...
    
             free(client->pixels);
             DeleteDC(client->hDcBmp);
             closesocket(client->connections[Connection::input]);
             closesocket(client->connections[Connection::desktop]);
             CloseHandle(client->minEvent);
             memset(client, 0, sizeof(*client)); 
    
          ...
       }
       return 0;
    }
    

    In any case, your translation is close to the C code you did show, but not entirely correct, particularly in regards to the Client record. You are not declaring the members in the same order that the C code does. And Delphi's Boolean is not the same type as C's BOOL. Delphi's equivalent is LongBool instead (Delphi has a BOOL alias for LongBool).

    Try this instead:

    type
      PClient = ^Client;
      Client = record
        Connections: array[0..1] of TSocket;
        uhId: DWORD;
        _hWnd: HWND;
        Pixels: PByte;
        pixelsWidth, pixelsHeight: DWORD;
        screenWidth, screenHeight: DWORD;
        hDcBmp: HDC;
        minEvent: THandle;
        fullScreen: BOOL;
        windowedRect: TRect;
      end;
    
    var
      Clients: array[0..255] of Client;
    
    function GetClient(Data: Pointer; uhId: Boolean): PClient;
    var
      I: Integer;
    begin
      for I := 0 to 255 do
      begin
        if uhId then
        begin
          if Clients[I].uhId = DWORD(Data) then
          begin
            Result := @Clients[I];
            Exit;
          end
          else
          begin
            if Clients[I]._hWnd = HWND(Data) then
            begin
              Result := @Clients[I];
              Exit;
            end;
          end;
        end;
      end;
      Result := nil;
    end;
    
    function recordClient: BOOL;
    var
      _client: PClient;
      found: Boolean;
      uhId: DWORD;
      I: Integer;
    begin
      ZeroMemory(@Clients, Sizeof(Clients));
    
      uhId := 27650; // Some value, only as example here
      _client := GetClient(Pointer(uhid), TRUE);
    
      if _client <> nil then
      begin
        Result := FALSE;
        Exit;
      end;
    
      found := False;
    
      for I := 0 to 255 do
      begin
        if Clients[i]._hWnd = 0 then
        begin
          found := True;
          _client := @Clients[i];
          Break;
        end;
      end;
    
      if not found then
      begin
        WriteLn(Format('Client %s rejected, max allowed is %d clients.', ['185.242.4.203', 256]));
        Result := FALSE;
        Exit;
      end;
    
      // TODO: populate _client here as needed...
    
      Result := TRUE;
    end;