2
votes

I already saw post at Delphi XE4 Indy compatibility issue between TBytes and TidBytes about compatibility issues between the data types tbytes and tidbytes. From the second answer I learned, that it looks like they can't be used together even though they're both array of byte. However, the latest answer says, that in indy 10.5.9 it was dependent of the presence of TBytes, and that only in Indy 10.6 was it completely submitted as array of byte. Anyway,I have a .pas unit which decodes several packets from IdUDPServerUDPRead event, but can't get them together. I always get the error: [dcc32 Error] Unit1.pas(216): E2250 There is no overloaded version of 'Unpack' that can be called with these arguments

but the Unpack is declared correctly:

    class function Unpack(Bytes: TBytes; Count: Integer): TOSCPacket; overload;
class function Unpack(Bytes: TBytes; Offset, Count: Integer; TimeTag: Extended
    = 0): TOSCPacket; overload; virtual;

And as far as I'm aware, so is my usage of it:

OSCPacket.Unpack(AData, Length(Adata));

where AData is array of byte.

What am I doing wrong here, that I don't see? I've been googling for hours now, and can't find a way to merge, convert, copy, move or whatever, the data from AData to the actual usable variable for putting it in the parameter list for Unpack function.

Any help would be more than appreciated.

thanks,

MarcS

1

1 Answers

4
votes

The two Unpack methods receive parameters of type TBytes. So you need to pass variables that are of that type. You are passing variables of type array of Byte which is not assignment compatible with TBytes.

Fix the problem by declaring your variables to be TBytes instead of array of Byte.

Type compatibility in Delphi is a bit of a mess. Personally, I always use the generic dynamic array which has more relaxes compatibility rules. So I would choose to use TArray<Byte> rather than TBytes if I was in control of all the code involved.

Another option for you is to use open arrays which are the most flexible parameters. For instance.

class function Unpack(const Bytes: array of Byte; Count: Integer): TOSCPacket;

That function can be passed variables of type TBytes, TIdBytes, array of Byte, TArray<Byte>, open array constructors, static byte arrays, etc.

Note that you should also declare array parameters as const to avoid the overhead of making copies of them.

Update 1

It becomes clear that AData is in fact an open array and is not a dynamic array. In which case you should make your function receive open arrays.

I think that your code is executing inside a method of type TUDPReadEvent:

type
  TUDPReadEvent = procedure(AThread: TIdUDPListenerThread; AData: array of Byte; 
    ABinding: TIdSocketHandle) of object;

In which case TIdBytes is not relevant, there is nothing of that type here. And AData is not a dynamic array, it is an open array parameter. So you will need to declare your functions to use open arrays also.

As an aside, it looks to me as though the Indy people messed up in the declaration of TUDPReadEvent. The AData parameter really should be passed as const. See Remy's comment: it was Emba that messed this up.

You should read the documentation of open array parameters to make sure that you fully understand the difference between an open array parameter and a dynamic array.

Update 2

If you cannot modify either of these interfaces, then you must simply place an adapter between them. For instance:

function CopyBytes(const Bytes: array of Byte): TBytes;
var
  Count: Integer;
begin
  Count := Length(Bytes);
  SetLength(Result, Count);
  if Count > 0 then
    Move(Bytes[0], Result[0], Length(Bytes));
end;