C в Delphi: структура не заполнена

#delphi #record #delphi-10-seattle

#delphi #запись #delphi-10-Сиэтл

Вопрос:

Я пытаюсь перевести фрагмент кода с C на Delphi, целью которого является заполнение структуры до максимально допустимого предела, определенного ранее. Я попытался сделать версию Delphi более близкой к C-коду (даже если это не профессиональный программист).

Но я отметил, что в моем коде на Delphi кажется, что структура заполнена только значениями 0 (результат FillMemory() ) и не заполняется правильными значениями.

Как я могу это решить? ниже я показываю только соответствующий код.

C: (ссылочный код)

 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 amp;g_clients[i];
      }
      else
      {
         if(g_clients[i].hWnd == (HWND) data)
            return amp;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 = amp;g_clients[i];
      }
    }

    if(!found)
    {
      wprintf(TEXT("User %S kicked max %d usersn"), "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;
  

Комментарии:

1. Похоже, это ответ, почему ваш getClient вернул nil в вашем предыдущем (удаленном) вопросе.

Ответ №1:

Вы не показали никакого кода ни на стороне C, ни на стороне Delphi, который фактически пытается заполнить массив данными. Просматривая исходный код C, он заполняет найденный элемент массива данными внутри ClientThread() функции. Вы не перевели эти фрагменты кода C, что объясняет, почему массив в вашем коде Delphi не содержит данных:

 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 *) amp;client->screenWidth, sizeof(client->screenWidth), 0) <= 0)
            goto exit;
         if(recv(s, (char *) amp;client->screenHeight, sizeof(client->screenHeight), 0) <= 0)
            goto exit;
         ...

            if(client->pixels amp;amp; client->pixelsWidth == ... amp;amp; 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 = amp;g_clients[i];
            }
         }
         if(!found)
         {
            wprintf(TEXT("User %S kicked max %d usersn"), 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;
}
  

В любом случае, ваш перевод близок к коду C, который вы показали, но не совсем корректен, особенно в отношении Client записи. Вы не объявляете элементы в том же порядке, что и код C. И тип Delphi Boolean отличается от типа C BOOL . Эквивалент Delphi — LongBool вместо (в Delphi есть BOOL псевдоним для LongBool ).

Попробуйте это вместо:

 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;