Jump to content

Leaderboard


Popular Content

Showing content with the highest reputation on 04/24/19 in all areas

  1. Lars Fosdal

    Using Indy for cross-platform TCP/IP

    My favorite approach is to have a connection thread handler that implements the "protocol" for the connection - using a input queue and an output queue to communicate with the owning thread, which in this case could be the main thread. This pattern is often called using mailboxes. I.e. the main thread posts a "task" to the thread input queue aka inbox, the thread loops with a small sleep to poll the inbox and deals with connects/disconnects and sends whatever needs to be sent over Indy to the remote host, collects the answer, and places it in the output queue aka outbox. The outbox can be polled in the main thread, or you can design the queue to post a message to the main thread, which then polls the outbox on receving the message. Protocol errors can also be posted as outbox events.
  2. dummzeuch

    Components form not sizeable

    Yes, that's a bug. It works fine up to Delphi 10.2. And it makes sense, at least to allow the user to make the dialog higher for long lists (e.g. the Interbase components), otherwise I would not have bothered. Yes, Please file a bug report. (But the "fix" will probably be to disable this functionality for Delphi 10.3+. I'm really getting tired of working around newly introduced bugs and "features" in the Delphi IDE, especially since I don't use it because of all the bugs.)
  3. It was pretty much dead, except for "new component spam".
  4. PeterPanettone

    Components form not sizeable

    Delphi 10.3.1: Components -> Install Packages -> Click on the "Components" button: As you can see, the dialog has the text overlay "Form made sizable by GExperts". However, the dialog is not resizable at all (which IMO would not make much sense in this specific case). Is this a bug? If yes, I will add it to the GExperts bug list.
  5. PeterPanettone

    Components form not sizeable

    Thomas, thanks for the information. Bug filed. Have you already filed quality reports at Embarcadero for those bugs?
  6. Lars Fosdal

    How to clone settings ?

    From what point of view? The standard XML parser barfs when a property appears that it is not aware of, while the TJson parser simply ignores it - so in that respect, Json appears as more resilient than XML. Edit: FYI, We generally pass most, if not all, numeric values as a string, since that gives us the NULL we need for numeric values as well.
  7. freeman35

    How to clone settings ?

    I think I found that :) under this reg key. All datas there. Export and import will be enough. ofcourse need install firstime. HKEY_CURRENT_USER\Software\Raabe Software
  8. David Heffernan

    On-demand ARC feature discussed

    Well, typical C++ code has automatic memory management too using the RAII principle. So that argument falls down I think.
  9. Remy Lebeau

    Using Indy for cross-platform TCP/IP

    TIdTCPClient.Connect() is a blocking operation, so you should not be calling it in your UI thread. Call it in a worker thread as well. I would suggest changing your reading thread to call Connect() before entering its reading loop, and then call Disconnect() when the loop is finsihed. Also, do not call TIdTCPClient.Connected() in a different thread than TIdIOHandler.ReadLn(). Connected() performs a read operation, so it may read bytes that ReadLn() is expecting, or worse, having 2 threads reading from the same socket may cause the TIdIOHandler.InputBuffer to store the read bytes in the wrong order. Never perform reading operations across thread boundaries, unless you synchronous the threads. In any case, the demo you based your code on was written for Delphi 2007, which only supports Windows development. On non-Windows platforms (Android is Java running on top of Linux), closing a socket in one thread is not *guaranteed* to abort a blocking socket operation in another thread (though it *should* since Indy shuts down the socket before closing it, and a shut down should abort a socket operation in progress). However, on Nix-based systems at least, where sockets are just file descriptors, it is *possible* that the act of closing a socket descriptor allows that descriptor to be reused right away for another socket, or even a file, thus you *might* be performing data I/O on something that you are not expecting. In your case, a simple fix I would suggest for you is to call ReadLn() with a timeout (either via its own ATimeout input parameter, or via the TIdIOHandler.ReadTimeout property), and then you can check the TIdIOHandler.ReadLnTimedOut property whenever ReadLn() exits, if needed. Then you can simply signal your thread to terminate, and it will do so when the current timeout elapses and control returns to the 'while' loop. Try this: procedure TMainForm.CreateTCPIPConnection; begin if not Assigned(ZPReadThread) then begin IdTCPClient.Host := AddressEdit.Text; IdTCPClient.Port := StrToIntDef(PortEdit.Text, 4769); try ZPReadThread := TReadingThread.Create(IdTCPClient); try ZPReadThread.OnData := DataReceived; ZPReadThread.Start; except FreeAndNil(ZPReadThread); raise; end; except on E: Exception do begin {$IFDEF TRACEDEBUG}AddDebugEntry('TCP/IP exception creating read thread : '+E.Message);{$ENDIF} end; end; end; end; procedure TReadingThread.Execute; begin {$IFDEF TRACEDEBUG}AddDebugEntry('Read thread created');{$ENDIF} try FClient.ConnectTimeout := 10000; // <-- use whatever you want... FClient.Connect; except on E: Exception do begin {$IFDEF TRACEDEBUG}AddDebugEntry('TCP/IP connect exception : '+E.Message);{$ENDIF} raise; end; end; try FClient.IOHandler.ReadTimeout := 5000; // <-- use whatever you want... while not Terminated do begin {$IFDEF TRACEDEBUG}AddDebugEntry('Read thread ReadLn (before)');{$ENDIF} try FData := FClient.IOHandler.ReadLn; except on E: Exception do begin {$IFDEF TRACEDEBUG}AddDebugEntry('TCP/IP IOHandler.ReadLn exception : '+E.Message);{$ENDIF} raise; end; end; //FClient.IOHandler.ReadBytes(AData, sizeof(TWaveFormSample), False); {$IFDEF TRACEDEBUG}AddDebugEntry('Read thread ReadLn (after)');{$ENDIF} if (FData <> '') and Assigned(FOnData) then Synchronize(DataReceived); //Sleep(1); end; finally FClient.Disconnect; end; end; procedure TReadingThread.DoTerminate; begin {$IFDEF TRACEDEBUG}AddDebugEntry('Read thread terminating');{$ENDIF} inherited; end; procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction); begin if Assigned(ZPReadThread) then begin {$IFDEF TRACEDEBUG}AddDebugEntry('Terminating Read thread');{$ENDIF} ZPReadThread.Terminate; {$IFDEF TRACEDEBUG}AddDebugEntry('Waiting for read thread termination');{$ENDIF} ZPReadThread.WaitFor; {$IFDEF TRACEDEBUG}AddDebugEntry('Finished waiting for read thread termination');{$ENDIF} FreeAndNil(ZPReadThread); end; end; Another option would be to have your UI thread shut down the socket directly, thus aborting the read. Let the reading thread close the socket when ready. procedure TMainForm.CreateTCPIPConnection; begin if not Assigned(ZPReadThread) then begin IdTCPClient.Host := AddressEdit.Text; IdTCPClient.Port := StrToIntDef(PortEdit.Text, 4769); try ZPReadThread := TReadingThread.Create(IdTCPClient); try ZPReadThread.OnData := DataReceived; ZPReadThread.Start; except FreeAndNil(ZPReadThread); raise; end; except on E: Exception do begin {$IFDEF TRACEDEBUG}AddDebugEntry('TCP/IP exception creating read thread : '+E.Message);{$ENDIF} end; end; end; end; procedure TReadingThread.Execute; begin {$IFDEF TRACEDEBUG}AddDebugEntry('Read thread created');{$ENDIF} try FClient.ConnectTimeout := 10000; // <-- use whatever you want... FClient.Connect; except on E: Exception do begin {$IFDEF TRACEDEBUG}AddDebugEntry('TCP/IP connect exception : '+E.Message);{$ENDIF} raise; end; end; try while not Terminated do begin {$IFDEF TRACEDEBUG}AddDebugEntry('Read thread ReadLn (before)');{$ENDIF} try FData := FClient.IOHandler.ReadLn; except on E: Exception do begin {$IFDEF TRACEDEBUG}AddDebugEntry('TCP/IP IOHandler.ReadLn exception : '+E.Message);{$ENDIF} raise; end; end; //FClient.IOHandler.ReadBytes(AData, sizeof(TWaveFormSample), False); {$IFDEF TRACEDEBUG}AddDebugEntry('Read thread ReadLn (after)');{$ENDIF} if (FData <> '') and Assigned(FOnData) then Synchronize(DataReceived); //Sleep(1); end; finally FClient.Disconnect; end; end; procedure TReadingThread.DoTerminate; begin {$IFDEF TRACEDEBUG}AddDebugEntry('Read thread terminating');{$ENDIF} inherited; end; type TIdStackBSDBaseAccess = class(TIdStackBSDBase) end; procedure TMainForm.FormClose(Sender: TObject; var Action: TCloseAction); begin if Assigned(ZPReadThread) then begin {$IFDEF TRACEDEBUG}AddDebugEntry('Terminating Read thread');{$ENDIF} ZPReadThread.Terminate; try {$IFDEF TRACEDEBUG}AddDebugEntry('Shutting down socket');{$ENDIF} TIdStackBSDBaseAccess(GBSDStack).WSShutdown(IdTCPClient.Socket.Binding.Handle, Id_SD_Both); finally {$IFDEF TRACEDEBUG}AddDebugEntry('Waiting for read thread termination');{$ENDIF} ZPReadThread.WaitFor; {$IFDEF TRACEDEBUG}AddDebugEntry('Finished waiting for read thread termination');{$ENDIF} FreeAndNil(ZPReadThread); end; end; end;
  10. Dalija Prasnikar

    How to clone settings ?

    But not very resilient to changes.
  11. Dalija Prasnikar

    Add support for High-DPI gdiScaling

    To achieve what you want you can also use custom manifest instead of automatically generated one. Also, your request is a bit confusing - System (Enhanced) scaling in application properties dialog has nothing to do with System Aware setting you can choose for manifest. Auto generated manifest sets only dpiAware and dpiAwareness elements and you want ability to include gdiScaling element.
  12. Stefan Glienke

    MMX Beta 14.1 available

    One of the reasons I never really got into MMX despite everyone telling me that it is a must have was its overloaded UI with all the toolbars and stuff after you installed it. Yes, you can turn off most of it but it would really pleasant if there was a simple option to switch between something like a "light" and "full" version easily (or even more different presets) - possiibly selectable during setup.
  13. Marco Cantu

    Directions for ARC Memory Management

    That is part of the plan... we have some experimental demos, could evolve into a full feature
×