2

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

Community
  • 1
  • 1
That Marc
  • 1,134
  • 3
  • 19
  • 42

1 Answers1

4

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;
David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • The problem here is that I'm not declaring the variable to be array of byte. Indy does. It's AData variable that indy passes on read procedure: IdUDPServerUDPRead(AThread: TIdUDPListenerThread; AData: array of Byte; ABinding: TIdSocketHandle); So, how can I covert that, or how can I solve the issue? :/ – That Marc Oct 16 '13 at 11:42
  • Use an open array. That's what `AData` is. That was not clear in your question. – David Heffernan Oct 16 '13 at 11:45
  • +1, what situations would cause you to not use open arrays as parameters, besides when you need to allocate/deallocate array items or the structure itself? – LU RD Oct 16 '13 at 12:08
  • 1
    @LURD My rule is that open arrays should always be used if at all possible, because they accept the widest range of actual parameters. – David Heffernan Oct 16 '13 at 12:11
  • Thanks for that concrete reply. I'm not sure yet if I understand all of it completely, but I'm working on that. I wasn't aware of open array, and yes, the last sentence is the way: I'll look up about that. I also notified the author of the file, which has Unpack functions, to check the thread out, and hopefully configure them to use open arrays instead. It's because that file is OSC protocol decoder, and I'm not really sure what can and can't be safely changed as a type used...! Will be hearing back when finding an solution or further problem. Thanks so far, David!!! – That Marc Oct 16 '13 at 12:11
  • So, from what I've tried on my own, I can't just change type in OSCUtils.pas to open array, since then it becomes incompatible with IdGlobal unit and it's functions/procedures. Anyway, if there's anyone willing to give it a minute on a thing, here's raw file that Mr. Joreg from vvvv team wrote: https://raw.github.com/vvvv/DelphiOSCUtils/master/OSCUtils.pas My code here doesn't even play a role... Hoewver, when TIdUdpServerUdpRead event called on IdUdpServer (Indy10) component event will be able to interact with TOscPacket.Unpack function, that'll probably be it. Thanks if anyone'd do it. – That Marc Oct 16 '13 at 13:40
  • And thanks David for clearance, that there's a problem globally with the Indy+OSCUtils itself... :) – That Marc Oct 16 '13 at 13:41
  • You clearly cannot change Indy. If you cannot change Unpack you need to adapt to it. You'll have to create a TBytes, populate it from AData, and call Unpack. That will make 3 copies of the data in total, when it could be done with 0 copies! – David Heffernan Oct 16 '13 at 13:52
  • Well, as far as I saw, I can't change it because on line 216 it uses IdGlobal where TArray is needed, and if I understand correctly, that's the TBytes type, isn't it? Anyway, David, what is the easiest way of doing that adoption? How can I populate TBytes from array of byte? I've tried that before with copy and move commands, where I thought that was suggested for my case, but I guess it's not that easy, is it? – That Marc Oct 16 '13 at 14:14
  • I'm lost. You cannot change Indy. Can you change Unpack? If not then you must make yet another copy. – David Heffernan Oct 16 '13 at 14:16
  • I'm not trying to change Indy here. The Unpack is part of OSCUtils.pas. There's another function in OSTUtils.pas which calls IdGlobal.CopyTIdBytes(Bytes, Offset, Result, 0, Length(Result)); and so also uses Bytes, which can't be 'array of bytes'. So I wasn't saying that I want to change IdGlobal here.... Am I still unclear here? :/ I'm not sure if I can. I tried and failed. As said, it is in the OSCUtils.pas, which you can see here: h.t.t.p.s.: raw.github.com/vvvv/DelphiOSCUtils/master/OSCUtils.pas Yet another copy of the Unpack function? – That Marc Oct 16 '13 at 14:28
  • I've no idea what OSCUtils is. Anyway, I'll repeat for a third time what I said. If you cannot change the type of `AData` (and you cannot) and you cannot change the signature of `Unpack`, then you'll need to adapt. My answer shows you how to do that. – David Heffernan Oct 16 '13 at 14:30
  • OSCUtils is encoder and decoder unit for OSC (Open Sound Control) protocol, which is based on UDP connection with hardware. This unit is basically the only one I've found to send and receive (well, so far send only) OSC commands from my delphi app. This is what it is... :) It's not a part of delphi by default... Yes, I understood that I'll need to adapt. I just didn't know how to. I see now your Update 2, and will try that. THANKS! – That Marc Oct 16 '13 at 14:36
  • 3
    FYI, [**Embarcadero** screwed up `TUDPReadEvent` in XE3](http://www.indyproject.org/Sockets/Blogs/ChangeLog/20120905.aspx) (amongst other things), **NOT** the Indy dev team. The open array issue was resolved in a later Indy update. – Remy Lebeau Oct 16 '13 at 15:48