Rectangle 27 2

TBall3DArray = array of TBall3D;

That is a dynamic array. Which is a Delphi data type which is not appropriate for interop. You can use dynamic arrays to hold the data, but not as parameters across the interop boundary. In any case, a dynamic array variable is a pointer to the first element. But you are passing the address of that pointer which is one level of indirection too many.

Declare the import like this:

TBSL2_ModelBallFlight = function(
  Cam_X: Single;
  Cam_Y: Single;
  Cam_Z: Single;
  ball_data_in: PBall3D;
  NFramesIn: Integer;
  ball_data_out: PBall3D;
  var NFramesOut: Integer
): Integer; cdecl;

This is a direct translation of the C++ code. Where the C++ code uses Ball3d*, a pointer to Ball3d, you use PBall3D, a pointer to TBall3D.

Note also the nuance of the final parameter. In the C++ code it is int &n_balls_out. That is a reference to int. So make it a var parameter in Delphi.

In order to call the code you can use your dynamic array type. Declare variables for the in and out data:

var
  ball_data_in, ball_data_out: TBall3DArray;

You will need to initialise the arrays with calls to SetLength. And then when you pass the parameters do so either with @ball_data_in[0] or PBall3D(ball_data_in). And likewise for the out parameter.

I don't know the precise protocol for the function, since a prototype is seldom enough, but the call might look like this:

SetLength(ball_data_in, NFramesIn);
SetLength(ball_data_out, NFramesOut);
retval := bsl2_ModelBallFlight(..., PBall3D(ball_data_in), NFramesIn, 
  PBall3D(ball_data_out), NFramesOut);

+1. Nicely written. I much prefer the readability and clarity of PBall3D(ball_data_in) rather than the @ball_data_in[0] syntax.

Thank you @Ken. Not original. I learnt it here on the stack from Remy or Arnaud, can't remember which. Possibly from both of them! Learning things like that is why I'm here.

calling function with array parameters in c++ dll from Delphi - Stack ...

c++ arrays delphi dll
Rectangle 27 6

Try initializing the WideStrings (s1,s2,s3,s4, and maybe even o). If I recall correctly, they are dynamic in Delphi and nil (000000000) before you set them up.

You rock MarkusQ! Thanks a lot. I would have given you 100 votes if I could. :)

Nice job! That was what I spotted when I looked at it, too. @Hermant: For future use, remember that local vars (declared in a method body) are for the most part (strings excepted) not initialized and can contain anything. Vars declared globally or as member fields of a class are set to defaults.

.net - Using a COM DLL in delphi - Access violation in MSVCR80D.dll er...

.net delphi com dll delphi-2006
Rectangle 27 6

Use Copy(A, 0, 2) instead of Slice(A, 2). The point is that either you need an "open array parameter" (in which case you need Slice) or you need a regular array, in which case Copy will provide a good solution. share|improve this answer edited Jun 25 '14 at 8:54 David Heffernan 484k317151101 answered Jun 25 '14 at 8:51 Daniel 984513
Slice()

delphi - How to slice a dynamic array? - Stack Overflow

delphi delphi-xe6
Rectangle 27 3

For a partial page refresh, you can use JavaScript / Ajax, for example with a Framework like jQuery. There are many examples on the web for dynamic page updates with Ajax.

The Ajax call submits the request to the HTTP server as a HTTP GET or POST request. The code in IdHTTPServerCommandGet checks if the request matches the URL and HTTP method, and then builds and returns partial HTML code.

On the client side, the JavaScript code places the received partial HTML in the specified document tree location.

Even without AJAX, the OnCommandGet handler still needs to look at the URL being requested and then return the appropriate content as needed, whether that be the original HTML webform or the student data.

sql - How can I call a Delphi procedure to generate HTML page content ...

html sql delphi indy
Rectangle 27 0

Instead of CopyMemory, try using the Move routine, like so:

Move(indexdata[1], text[1], reserved);

(Yes, without the @ symbols.) That should solve problem #2. As for problem #1, that's between you and the server. You need to have some way to know what the upper bound is on the size that it will return, and make your buffer at least that large. You should either be able to find this in the documentation, or call another API first that will give you the size of the incoming data.

Also put some check on there so that if it returns something larger than your buffer, it immediately raises an exception. If your buffer is overrun, you should assume that your program is under attack and react accordingly.

the "move" fails with an exception: access violation of address xxxxx.... read of address yyyyy

Did you call SetLength first? If you called SetLength, and you're not using @s, and you're not exceeding the size of text, then that shouldn't happen.

@Jessica: Please notice that the lack of the "@"'s is not the only difference between CopyMemory and move -- the two first arguments comes in different order, (Destionation, Source) versus (Source, Destination)!

thanks. I saw that, it was very clear on the comments Mason wrote.

Move and CopyMemory should behave identically in every way since the latter is implemented with the former. If any problem was fixed by using one instead of the other, then the problem lay deeper than either one of them.

windows - dynamic arrays and wininet in delphi? - Stack Overflow

windows delphi arrays wininet
Rectangle 27 0

Try initializing the WideStrings (s1,s2,s3,s4, and maybe even o). If I recall correctly, they are dynamic in Delphi and nil (000000000) before you set them up.

You rock MarkusQ! Thanks a lot. I would have given you 100 votes if I could. :)

Nice job! That was what I spotted when I looked at it, too. @Hermant: For future use, remember that local vars (declared in a method body) are for the most part (strings excepted) not initialized and can contain anything. Vars declared globally or as member fields of a class are set to defaults.

.net - Using a COM DLL in delphi - Access violation in MSVCR80D.dll er...

.net delphi com dll delphi-2006
Rectangle 27 0

This seems to be the cause of the wrong results

for i := 0 to sourceData.Count -1 do
   for j := 0 to sourceData.Count -1 do
    begin
     Dem[i][j] := StrToInt(tmpGrid.Strings[i]);
    end;

You have moved the actual data from SourceData to tmpGrid, which is not needed. Instead, assign one line at a time from SourceData to tmpRow, then read the values one at a time from tmpRow, and assign to the value array:

for i := 0 to SourceData.Count-1 do
begin
  tmpRow.DelimitedText := SourceData[i];
  for j := 0 to tmpRow.Count-1 do
    Dem[i,j] := StrToInt(tmpRow[j]);
end;

delphi - How to parse delimited TStringlist to dynamic multidimensiona...

arrays delphi parsing delphi-xe7 tstringlist
Rectangle 27 0

  • linked list of dynamic arrays

The best approach will depend on the task

Anyone, may be even static array with total items count variable.

For large lists I will choose: - dynamic array, if I need a lot of access by the index or search for specific item - hash table, if I need to search by the key - linked list of dynamic arrays, if I need many item appends and no access by the index

dynamic array will eat less memory. But the question is not about overhead, but about on which number of items this overhead become sensible. And then how to properly handle this number of items.

dynamic array may dynamically grow, but on really large number of items, memory manager may not found a continous memory area. While linked list will work until there is a memory for at least a cell, but for cost of memory allocation for each item. The mixed approach - linked list of dynamic arrays should work.

Which is best to minimize access time for accessing the entire list from first to last?

On this basis (or any others), which data structure would be preferable?

You may think that small lists are not worthwhile to optimize, but what if I have 10,000 different small lists? Their total performance will be significant so I should use the most optimal data structure for them all.

No, I does not think so. What I really think, that we talk about "cubic horse in the vacuum" <g> Describe your task and data access pattern, then it will be possible to give you an exact answer ...

data structures - TStringList, Dynamic Array or Linked List in Delphi?...

delphi data-structures linked-list tstringlist dynamic-arrays
Rectangle 27 0

Your question contains two Delphi declarations for the external function. One of them uses TArray<T> as a parameter. That is completely wrong. Don't do that. You cannot use a Delphi dynamic array as an interop type. The reason being that TArray<T> is a complex managed type that can only be created and consumed by Delphi code.

You need to do as I do below, and as I explained in my answer to your previous question, and declare the array parameter as pointer to element type. For example, PInteger, PDouble, etc.

There's quite a lot of confusion here, and needless complexity. What you need is the simplest possible example that shows how to pass an array from your Delphi code to C code.

//testarray.c

void printDouble(double d); // linker will resolve this from the Delphi code

void test(double *arr, int count)
{
    int i;
    for (i=0; i<count; i++)
    {
        printDouble(arr[i]);
    }
}
program DelphiToC;

{$APPTYPE CONSOLE}

uses
  Crtl;

procedure _printDouble(d: Double); cdecl;
begin
  Writeln(d);
end;

procedure test(arr: PDouble; count: Integer); cdecl; external name '_test';

{$L testarray.obj}

var
  arr: TArray<Double>;

begin
  arr := TArray<Double>.Create(1.0, 2.0, 3.0, 42.0, 666.0);
  test(PDouble(arr), Length(arr));
  Readln;
end.

Compile the C code using, for example, the Borland C compiler like this:

And the output is:

Note that I linked to the C code statically because that was easier for me. Nothing much changes if you put the C code in a DLL.

The conclusion is that the code I gave you in my answer to your previous, and that I repeat here, is correct. That approach succeeds in passing an array from Delphi code to C. It looks like your diagnostics and debugging is in error.

You are only inspecting A[0] so it's hardly surprising that you only see one value. If only you would look at A[1], A[2], ... , A[n-1] you would see that that all the values are being passed correctly. Or perhaps your debugging was carried out on the erroneous declaration of the external function that used TArray<T> as a parameter.

I know that it's something wrong on my side, and trying out the "different" ways of passing the arrays in delphi code showed me that it isn't the array itself that's the problem (since none of them work). The problem is I'm new to dlls and interfacing and not sure what to test next, which is why I was asking for some other issues I could troubleshoot. The minimal examples (both this one and the one I did) work (no surprise there, really). As for the struct, that was a typo in the question (I fixed it); it has always worked in my code, it's still only the arrays.

So, what are you looking for here? I've shown you how to pass an array, twice now. I'm guessing here, but my guess is that your array is passed fine but you don't know how to display it on the C side of the fence. You neglected to show the C side of your interface. What type are your array parameters? Are they int*. Naturally if you look at *A, say, then you only see one value. But what about A[0], A[1] etc. Again, please remove complexity. The code in your question should work with a single array. Get rid of the struct, it is just distracting. Simplify.

Delphi-to-C dll: Passing Arrays - Stack Overflow

c delphi dll delphi-xe3
Rectangle 27 0

I'm generating a runtime string and returning the string as a response to a HTTP Server component (ICS). Is it possible to apply TEncoding into a string?

Yes. A Delphi String is a UnicodeString in XE. Delphi has had native support for UTF-8 encoded strings since D2009.

One thing you can do is simply assign the original UnicodeString to a UTF8String variable and let the RTL encode the Unicode data to UTF-8 for you, then you can send the raw bytes of the UTF8String to the client:

Another option is to send the UTF-8 data as a TStream. You can place a UTF8String into a TMemoryStream:

var 
  myHTML: string;  
  myHTMLUtf8: UTF8String;
  strm: TMemoryStream;

myHTML := ...
myHTMLUtf8 := myHTML;

strm := TMemoryStream.Create;
strm.Write(myHTMLUtf8[1], Length(myHTMLUtf8) * SizeOf(AnsiChar));
strm.Position := 0;
// send strm as-is...
strm.Free;
UnicodeString
TStringStream
TEncoding.UTF8
var 
  myHTML: string;  
  strm: TStringStream;

myHTML := ...

strm := TStringStream.Create(myHTML, TEncoding.UTF8);
// send strm as-is...
strm.Free;

Thank you. I believe this is the cleanest approach to the problem. Regarding the ICS HTTPServer component, they provide a AnswerStream too, so the stream approach will work. The UTF8String won't unless you use a UTF8ToAnsiStr conversion and then the performance will suffer from the double conversion.

UTF8ToAnsiStr() would only make sense if the HTTPServer makes you assign an AnsiString for output. And in fact, in XE, System.Utf8ToAnsi() decodes a UTF8String back to a UnicodeString, so it would not be worth using a UTF8String at all, unless you use the TStream appraoch, or send the UTF8String bytes manually.

Generating dynamic HTML page with UTF8 in Delphi - Stack Overflow

delphi delphi-xe
Rectangle 27 0

Delphi is not a complete garbage collection language, user-defined types should be manually allocated and deallocated. It only provide automatic collection, for a few built-in types, such as strings, dynamic arrays and interfaces for ease of use.

But you can use interfaces which uses reference counting for garbage collection for some extent.

Also worth to mention is the fact that anything deriving from TComponent takes an owner pointer via the constructor, which causes the object to get destroyed together with its owner.

Sign up for our newsletter and get our top new questions delivered to your inbox (see an example).

Garbage Collection in Delphi - Stack Overflow

delphi garbage-collection
Rectangle 27 0

Have you tried to set the Frame.Autosize to true? Or you would need to resize the frame when the mouse moves. So that the contained object could expand while staying within the boundaries of the container.

Update: some simple code that works with a regular TPanel to resize horizontally...

type
  TFrame5 = class(TFrame)
    Panel1: TPanel;
    procedure Panel1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    procedure Panel1Resize(Sender: TObject);
  end;

implementation

{$R *.dfm}

procedure TFrame5.Panel1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
  with Sender as TPanel do
  if ssLeft in Shift then
  begin
    Width := X;
  end;
end;

procedure TFrame5.Panel1Resize(Sender: TObject);
begin
  with Sender as TPanel do
  begin
    (Parent as TFrame).Width := Width + 2*Left;
  end;
end;

Yes, I did try that. What I found was that while the panel was sizing, the autosize functionality of the frame would not kick in (maybe it was waiting until the panel resize was complete), so it did not work. Additionally, though, I need a "buffer border" around the panel; not flush against it.

Try with my sample code, it works with a regular TPanel. You might have to modify your TLMDSimplePanel component though.

Additionally for the "buffer border", you can play with the padding property of the Frame or the Margins of the Panel...

Agreed. Padding is a much better way to do buffers around controls than surrounding it with other controls as spacers. That can get real ugly real fast.

Dynamic resizing of frames and forms in Delphi - Stack Overflow

delphi forms frames
Rectangle 27 0

Array doesn't have useful methods for adding/inserting/deleting/sorting/searching, TList does.

TList<T>

TList<T>[i] actually returns a copy of its element. So you can't write something like TList<TMyRec>[idx].SomeField := foo. Instead, you have to use temporary variable. Array obviously allows such expression.

TList<T>.List
  • System.Generics.Collections unit could add plenty of binary size to a project that wasn't using System.Classes unit before.

For myself I wrote TRecordList<T> class which operates items as pointers (like classic TList does).

TList<T>.List is the dyn array, so no need for copies. In perf terms, dyn array has no advantage.

TRecordList<T>

Indeed, if you wait until program finish, then there's not much point in freeing it at all 'cos the system will claim it back.

@David Heffernan: thanks for mentioning TList<T>.List, it was added only in XE3 while I'm still on XE2. @jpfollenius, you're surely right. @David Heffernan: maybe it's bad for caches but it's good for item inserting/sorting etc.

What are the pros and cons of using dynamic array of records vs. TList...

arrays delphi storage record
Rectangle 27 0

  • All array elements are contiguous in memory: yes

When the array size is increased, the array will be copied. From the doc: ...memory for a dynamic array is reallocated when you assign a value to the array or pass it to the SetLength procedure.

So yes, increasing the size of a dynamic array does have consequences for pointers referencing existing array elements.

If you want to keep references to existing elements, use their index in the array (0-based).

Comments by Rob and David prompted me to check the initialization of dynamic arrays in Delphi5 (as I have that readily available anyway). First using some code to create various types of dynamic arrays and inspecting them in the debugger. They were all properly initialized, but that could still have been a result prior initialization of the memory location where they were allocated. So checked the RTL. It turns out D5 already has the FillChar statement in the DynArraySetLength method that Rob pointed to:

// Set the new memory to all zero bits
  FillChar((PChar(p) + elSize * oldLength)^, elSize * (newLength - oldLength), 0);

In current implementations, new array elements are initialized to zero. That's merely an implementation detail, though; there's no guarantee it will continue to work that way, and I'm pretty sure that in older versions, it didn't work that way.

@Rob: did you find that in the VCL/RTL? Interested coz if your statement is based on observation, it could be related to your machine. I remember once having an app working fine on one machine and crashing with an AV on another the only difference being the processor and/or the way memory was initialized by the OS...

FillChar
System.DynArraySetLength

delphi - What happens when increasing the size of a dynamic array? - S...

delphi
Rectangle 27 0

You've got a one-off error in these lines. Consider the first time you add an element to SubImages. The length of SubImages is 1, but the only element in the array is SubImages[0]. You set RegionMask[X,Y] to 1, and then use that value to index the array. So you are trying to access one item beyond the end of the array.

SetLength(SubImages,Length(SubImages)+1);

      RegionMask[X,Y] := Length(SubImages);

      SubImages[RegionMask[X,Y]].LeftBound := X;

Thanks for your answer. I just figured that out a fw minutes back when David asked me if I used Range Checkings. I haven't used them. SO after enabling them I quickly realized my mistakes. But still I don't know how this could affect destruction of the TImage component.

Once you start changing memory out of range you can affect any aspect of anything that is stored in memory. Where is your array in memory? What's just beyond it?

delphi - Keep getting AV when closing my application after imputing so...

delphi multidimensional-array dynamic-arrays delphi-xe3
Rectangle 27 0

So, basically everybody suggests to create an array of array instead of using a TList. Well, I already have done that. I just wanted to "upgrade" from 'array of array' to a TList since it has Add(). It looks like I will return to my original code. Thank you all and +1 for each answer.

Well, Allen suggest the new Delphi which makes this sort of code way cleaner.

Yes. I know. But I don't have it. So, this solution is not at hand (for me).

i suggested to use a TObjectList

... and I just created a wrapper around any dynamic array to add Add() methods and such... :)

delphi - How to store dynamic arrays in a TList? - Stack Overflow

delphi delphi-7
Rectangle 27 0

You will not be able to send the record as-is, so in fact you don't even need to use a record at all. You must serialize your data into a flat format that is suitable for transmission over a network. For example, when sending a string, send the string length before sending the string data. Likewise, when sending an array, send the array length before sending the array items. As for the items themselves, since TValue is dynamic, you have to serialize it into a flat format as well.

Try something like this on the sending side:

procedure TServerClass.SendBufToSocket(const vmName: TVMNames; const vmArgs: Array of TValue);
var
  I: integer;

  procedure SendRaw(Data: Pointer; DataLen: Integer);
  var
    DataPtr: PByte;
    Socket: TCustomWinSocket;
    Sent, Err: Integer;
  begin
    DataPtr := PByte(Data);
    Socket := ServerSocket.Socket.Connections[idxSocket];
    while DataLen > 0 do
    begin
      Sent := Socket.SendBuf(DataPtr^, DataLen);
      if Sent > 0 then
      begin
        Inc(DataPtr, Sent);
        Dec(DataLen, Sent)
      end else
      begin
        Err := WSAGetLastError();
        if Err <> WSAEWOULDBLOCK then
          raise Exception.CreateFmt('Unable to sent data. Error: %d', [Err]);
        Sleep(10);
      end;
    end;
  end;

  procedure SendInteger(Value: Integer);
  begin
    Value := htonl(Value);
    SendRaw(@Value, SizeOf(Value));
  end;

  procedure SendString(const Value: String);
  var
    S: UTF8string;
    Len: Integer;
  begin
    S := Value;
    Len := Length(S);
    SendInteger(Len);
    SendRaw(PAnsiChar(S), Len);
  end;

begin
  SendString(GetEnumName(TypeInfo(TVMNames), Integer(vmName)));
  SendInteger(Length(vmArgs));
  for I := Low(vmArgs) to High(vmArgs) do
    SendString(vmArgs[I].ToString);
end;
type
  TValueArray := array of TValue;

procedure TServerClass.ReadBufFromSocket(var vmName: TVMNames; var vmArgs: TValueArray);
var
  Cnt, I: integer;
  Tmp: String;

  procedure ReadRaw(Data: Pointer; DataLen: Integer);
  var
    DataPtr: PByte;
    Socket: TCustomWinSocket;
    Read, Err: Integer;
  begin
    DataPtr := PByte(Data);
    Socket := ClientSocket.Socket;
    while DataLen > 0 do
    begin
      Read := Socket.ReceiveBuf(DataPtr^, DataLen);
      if Read > 0 then
      begin
        Inc(DataPtr, Read);
        Dec(DataLen, Read);
      end
      else if Read = 0 then
      begin
        raise Exception.Create('Disconnected');
      end else
      begin
        Err := WSAGetLastError();
        if Err <> WSAEWOULDBLOCK then
          raise Exception.CreateFmt('Unable to read data. Error: %d', [Err]);
        Sleep(10);
      end;
    end;
  end;

  function ReadInteger: Integer;
  begin
    ReadRaw(@Result, SizeOf(Result));
    Result := ntohl(Result);
  end;

  function ReadString: String;
  var
    S: UTF8String;
    Len: Integer;
  begin
    Len := ReadInteger;
    SetLength(S, Len);
    ReadRaw(PAnsiChar(S), Len);
    Result := S;
  end;

begin
  vmName := TVMNames(GetEnumValue(TypeInfo(TVMNames), ReadString));
  Cnt := ReadInteger;
  SetLength(vmArgs, Cnt);
  for I := 0 to Cnt-1 do
  begin
    Tmp := ReadString;
    // convert to TValue as needed...
    vmArgs[I] := ...;
  end;
end;

With that said, note that socket programming is more complex than this simple example shows. You have to do proper error handling. You have to account for partial data sends and receives. And if you are using non-blocking sockets, if the socket enters a blocking state then you have to wait for it to enter a readable/writable state again before you can attempt to read/write data that is still pending. You are not doing any of that yet. You need to get yourself a good book on effective socket programming.

Update: if you are trying to utilize the OnRead and OnWrite events of the socket components, you have to take a different approach:

And then on the receiving side:

procedure TServerClass.ClientConnect(Sender: TObject; Socket: TCustomWinSocket);
begin
  Socket.Data := TMemoryStream.Create;
end;

procedure TServerClass.ClientDisconnect(Sender: TObject; Socket: TCustomWinSocket);
begin
  TMemoryStream(Socket.Data).Free;
  Socket.Data := nil;
end;

procedure TServerClass.ClientRead(Sender: TObject; Socket: TCustomWinSocket);
var
  InBuffer: TMemoryStream;      
  Ptr: PByte;
  OldSize, Pos, Read: Integer;

  function HasAvailable(DataLen: Integer): Boolean;
  being
    Result := (InBuffer.Size - InBuffer.Position) >= DataLen;
  end;

  function ReadInteger(var Value: Integer);
  begin
    Result := False;
    if HasAvailable(SizeOf(Integer)) then
    begin
      InBuffer.ReadBuffer(Value, SizeOf(Integer));
      Value := ntohl(Value);
      Result := True;
    end;
  end;

  function ReadString(var Value: String);
  var
    S: UTF8String;
    Len: Integer;
  begin
    Result := False;
    if not ReadInteger(Len) then Exit;
    if not HasAvailable(Len) then Exit;
    SetLength(S, Len);
    InBuffer.ReadBuffer(PAnsiChar(S)^, Len);
    Value := S;
    Result := True;
  end;

  function ReadNames: Boolean;
  var
    S: String;
    vmName: TVMNames;
    vmArgs: TValueArray;
  begin
    Result := False;
    if not ReadString(S) then Exit;
    vmName := TVMNames(GetEnumValue(TypeInfo(TVMNames), S));
    if not ReadInteger(Cnt) then Exit;
    SetLength(vmArgs, Cnt);
    for I := 0 to Cnt-1 do
    begin
      if not ReadString(S) then Exit;
      // convert to TValue as needed...
      vmArgs[I] := ...;
    end;
    // use vmArgs as needed...
    Result := True;
  end;

begin
  InBuffer := TMemoryStream(Socket.Data);

  Read := Socket.ReceiveLength;
  if Read <= 0 then Exit;

  OldSize := InBuffer.Size;
  InBuffer.Size := OldSize + Read;

  try
    Ptr := PByte(InBuffer.Memory);
    Inc(Ptr, OldSize);
    Read := Socket.ReceiveBuf(Ptr^, Read);
  except
    Read := -1;
  end;

  if Read < 0 then Read := 0;
  InBuffer.Size := OldSize + Read;
  if Read = 0 then Exit;

  InBuffer.Position := 0;

  repeat
    Pos := InBuffer.Position;
  until not ReadNames;

  InBuffer.Position := Pos;
  Read := InBuffer.Size - InBuffer.Position;
  if Read < 1 then
    InBuffer.Clear
  else
  begin
    Ptr := PByte(InBuffer.Memory);
    Inc(Ptr, InBuffer.Position);
    Move(Ptr^, InBuffer.Memory^, Read);
    InBuffer.Size := Read;
  end;
end;

i'm aware that i'm not sending a record as-is, i have the SAME record on both server/client, and what i did is the FIRST member is a BYTE type which holds the record ID (which tells the client where the manipulation goes) i have the SAME record on both sides, so lets say i send the record to the client and i only filled the 2nd member of it, in the 1st member (which is the ID and is first read) i then know what to do with the record

You did not show any of that in your question. Next time, please explain what you are actually doing when you ask for help.

I would also say that TValue itself is not a simple type but sometimes a secondary pointer to real data as well. So, @0x90, please do serialization. For example blog.synopse.info/post/2011/03/12/TDynArray-and-Record-compare/ and another exaple is JSON progdigy.com/?page_id=6

TCP is a byte stream. There is no 1:1 relationship between send() and recv(), like with UDP. recv() can return fewer bytes than requested. You have to call it in a loop until you read all of the bytes you are expecting. When using a non-blocking socket, the OnRead event occurs when the socket has data to read. If you finish reading what is available and need more bytes, you have to wait until the OnRead event occurs again.

Each time you do a read, if you have a complete "message" (based on the protocol you are implementing - in this case HTTP, so you have to look for the line breaks between HTTP headers and body, and then parse the headers to know how many additional bytes to read), then process it and save whatever bytes are left over so they can be used with later bytes to handle the next "message".

delphi - Sending a Dynamic array (Inside a record) through Socket? - S...

delphi sockets winsock
Rectangle 27 0

I think you forgot to use the second index on the second dimension;

Your code should probably read like this :

if Length(List) < (x + 1) then
   SetLength(List, x + 1);
if Length(List[x]) < (y + 1) then
   SetLength(List[x], y + 1);

Note the use of 'x' as the first dimension index when growing the second dimension.

You should be aware of the fact that Delphi uses reference-counting on dynamic arrays too (just like how it's done with AnsiString). Because of this, growing the array like above will work, but any other reference to it will still have the old copy of it!

The only way around this, is keeping track of these array's with one extra level of indirection - ie. : Use a pointer to the dynamic array (which is also a pointer in itself, but that's okay).

Also note that any of those 'external' pointers should be updated in any situation that the address of the dynamic array could change, as when growing/shrinking it using SetLength().

You only have to call SetLength on a subdimension (i.e. SetLength(List[X], ...)) if you want to create ragged arrays - arrays where different indices have different subdimension lengths. Plus that would create twodimensional array to be inserted at List[x] (hopefully compiler would complain).

Using Length() with multi-dimensional dynamic arrays in Delphi - Stack...

delphi arrays
Rectangle 27 0

The following code demonstrates multidimensional array resizing.

{$APPTYPE CONSOLE}

uses
  SysUtils;

var
  List: array of array of integer;

begin
  //set both dimensions
  SetLength(List, 3, 2);
  Writeln('X = ', Length(List), ', Y = ', Length(List[0])); //X = 3, Y = 2
  //set main dimension to 4, keep subdimension untouched
  SetLength(List, 4);
  Writeln('X = ', Length(List), ', Y = ', Length(List[0])); //X = 4, Y = 2
  //set subdimension to 3, keep main dimenstion untouched
  SetLength(List, Length(List), 3);
  Writeln('X = ', Length(List), ', Y = ', Length(List[0])); //X = 4, Y = 3
  //all List[0]..List[3] have 3 elements
  Writeln(Length(List[0]), Length(List[1]), Length(List[2]), Length(List[3])); //3333
  //you can change subdimension for each List[] vector
  SetLength(List[0], 1);
  SetLength(List[3], 7);
  //List is now a ragged array
  Writeln(Length(List[0]), Length(List[1]), Length(List[2]), Length(List[3])); //1337
  //this does not even compile because it tries to set dimension that does not exist!
//  SetLength(List[0], Length(List[0]), 12);
  Readln;
end.

The Delphi help also explains this quite nicely (Structured Types, Arrays).

type TMessageGrid = array of array of string; var Msgs: TMessageGrid;

declares a two-dimensional array of strings. To instantiate this array, call SetLength with two integer arguments. For example, if I and J are integer-valued variables,

allocates an I-by-J array, and Msgs[0,0] denotes an element of that array.

You can create multidimensional dynamic arrays that are not rectangular. The first step is to call SetLength, passing it parameters for the first n dimensions of the array. For example,

var Ints: array of array of Integer; SetLength(Ints,10);

allocates ten rows for Ints but no columns. Later, you can allocate the columns one at a time (giving them different lengths); for example

makes the third column of Ints five integers long. At this point (even if the other columns haven't been allocated) you can assign values to the third column - for example, Ints[2,4] := 6.

The following example uses dynamic arrays (and the IntToStr function declared in the SysUtils unit) to create a triangular matrix of strings.

var A : array of array of string; I, J : Integer; begin SetLength(A, 10); for I := Low(A) to High(A) do begin SetLength(A[I], I); for J := Low(A[I]) to High(A[I]) do A[I,J] := IntToStr(I) + ',' + IntToStr(J) + ' '; end; end;

Thanks for pointing this out; I'm so used to using ragged array's, that it never occurred to me that Delphi also allows cube-like arrays. Still, reading back the question, it seems that ragged arrays where the topic, so my comment still holds, if only after a little fixup (pfew!) Cheers!

I agree - question wording seems to be a probleme here. It is completely possible that your interpretation of the question is correct.

Using Length() with multi-dimensional dynamic arrays in Delphi - Stack...

delphi arrays
Rectangle 27 0

SetLength
System.DynArraySetLength
Delphi 5
#0
// Set the new memory to all zero bits
FillChar((PChar(p) + elSize * oldLength)^, elSize * (newLength - oldLength), 0);

I assume this behavior has not changed in more recent versions of Delphi.

+1 this is true in Delphi 7 - whatever the doc says, the code in System.pas DOES initialize the dynamic array data with zero bytes.

True but you can't really rely on that. It's not part of the specifications (contrary to initialized types) and can change without notice.

True but what is the alternative? Initializing it yourself, knowing it to be a wast of time? I would rely on it and add a testcase verifying it each day with our daily builds. Should it change (without notice), the daily build picks it up.

you're right. EMB won't change this, because they know it'll break a lot of softwares built with Delphi. And they need to initialize the strings and dynamic arrays to 0 before using it, so filling the whole array with 0 is the fastest way of doing it. Fillchar is fast, and some faster code can be found in the fastcode project.

Yes, if your code is dependent on it being initialized. The documentation says "the content of newly allocated space is undefined", and because they happen to define something now is not to be relied upon. Until the documentation changes, your only reliance is that you can't depend on the content being anything but junk.

string - What's in the memory of a dynamic array when used with SetLen...

arrays string delphi