Jump to content

Leaderboard


Popular Content

Showing content with the highest reputation on 04/06/23 in all areas

  1. Remy Lebeau

    Indy TCP client

    There is usually no need to ever use ReuseSocket on a client, unless you use its BoundIP and BoundPort properties to make it connect from a specific local IP/Port pair, AND you are connecting to the same remote IP/Port pair as a previous connection from the same local IP/Port. By default, a client socket connects from a random local port. ReuseSocket is more commonly used only on servers instead. When a server gets shutdown and restarted quickly, ReuseSocket can can allow it to listen on the same local IP/Port as the previous run, in case the OS hasn't released the local IP/Port yet. You are using the InputBuffer the wrong way. After you Write() out your wBuffer, you are waiting in an endless loop until a reply arrives. Why are you using a loop at all? That is not necessary. Indy's reading behavior is designed to block the calling thread waiting for requested data to arrive. Most of the IOHandler's reading methods get their data from the InputBuffer only, not from the socket directly. CheckForDataOnSource() reads directly from the socket and saves whatever it receives into the InputBuffer. So, if you ask a reading method (ie, in this case, ReadBytes()) to read something (ie, in this case, 65 bytes), the method does not exit until all of the bytes for that something are available in the InputBuffer, or until the ReadTimeout elapses (which is infinite by default). In your case, when you do eventually get a reply, you are reading it from the InputBuffer into your rBuffer, but then you are ignoring rBuffer that you just read into and instead you are checking the InputBuffer directly to see if it has any buffered bytes that you have NOT read yet, and only if it DOES then you are flagging yourself to make the next Write() call. But if the InputBuffer is EMPTY (because you have already read everything that was in it) then you are NEVER calling Write() again, and you end up stuck in your reading loop waiting for CheckForDataOnSource() to receive new bytes from the socket which you are NEVER requesting the server to send. You have over-complicated your thread logic. You don't need all of that InputBuffer handling at all. Just call Write(), then ReadBytes() (letting it block), and repeat. That being said, there are some other issues with your code, too. You are not calling Disconnect() after Connect() is successful. You are accessing the InputBuffer in the main threadd while your worker thread may also be accessing it at the same time. And you are not capturing the Exception when calling TThread.Queue(), so the Exception will be destroyed long before the main thread has a chance to access its Message. With all of that said, try this instead: inherited Create(True); TCPClient := TIdTCPClient.Create; TCPClient.Host := AHost; TCPClient.Port := APort; TCPClient.ConnectTimeout := 5000; TCPClient.ReadTimeout := ...; // infinite by default ... // a separate procedure is needed so that TThread.Queue() can // capture and extend the lifetime of the String. See the // documentation for more details: // https://docwiki.embarcadero.com/RADStudio/Sydney/en/Anonymous_Methods_in_Delphi // procedure DisplayMessageInUI(const AMsg: string); begin TThread.Queue(nil, procedure begin Form2.mmo1.Lines.Add(AMsg); end); end; ... SetLength(wBuffer, 6); //write some bytes into wBuffer SetLength(rBuffer, 65); while not Terminated do begin try TCPClient.Connect; except on E: Exception do begin DisplayMessageInUI('Exception: ' + e.Message); for i := 1 to 5 do begin if Terminated then Exit; Sleep(1000); end; Continue; end; end; try try i := 1; while not Terminated do begin TCPClient.IOHandler.Write(wBuffer); TCPClient.IOHandler.ReadBytes(rBuffer, 65, False); // waits for reply // { Alternatively, if you want to keep checking Terminated while waiting: while TCPClient.IOHandler.InputBufferIsEmpty do begin TCPClient.IOHandler.CheckForDataOnSource(100); TCPClient.IOHandler.CheckForDisconnect; if Terminated then Exit; end; TCPClient.IOHandler.ReadBytes(rBuffer, 65, False); } DisplayMessageInUI('Reply received'); //do some stuff with rBuffer Inc(i); Sleep(1000); end; finally TCPClient.Disconnect; end; except on E: Exception do begin DisplayMessageInUI('Exception: ' + e.Message); if Terminated then Exit; Sleep(1000); end; end; end;
  2. William23668

    Unable to execute '"C:\Program Files\Java\jdk-17.0.1\bin\java.exe" 

    yes this was the problem. but I now get this error Solved I uninstalled the app from the phone and now it open Thanks
  3. Dave Nottage

    Unable to execute '"C:\Program Files\Java\jdk-17.0.1\bin\java.exe" 

    Is this a project created in an earlier version of Delphi? If so, you may need to follow the step described here.
  4. Anders Melander

    Does C++ Builder have an input - message box?

    ...and InputBox and InputQuery
  5. from what I see here, your problem lies in the plane of python and not Delphi Your error says that the ElementNamespaceClassLookup field of the etree object has not been properly initialized why it happened is hard to say based on the fact that the problem occurs at the time of import, we can assume a problem with the version of the library I'm sorry, I didn't carefully read the condition under which your problem occurs. there could also probably be a problem with initializing some Python object that is logically meant to be a singleton, a resource access violation (which implies exclusive ownership) or something like that try also rewriting the code so that imports are called from Delphi only once to change your logic You can learn how to pass variables and events between Python and Delphi in the webinar examples. P.S. IMHO debugging problems like this is the Achilles heel of nested Python (Python4Delphi is great but it may be tricky to debug python issues) P.P.S. it seems to me that your task could be solved by the "classic" means of Delphi, although my knowledge may be outdated https://blogs.embarcadero.com/create-word-docs-using-the-direct-office-component-in-delphi-on-windows/ http://delphiprogrammingdiary.blogspot.com/2018/09/ms-word-automation-in-delphi.html P.P.P.S. this is definitely a matter of taste but I would store the multiline python script in an external py file (and load it with a-la TStringList.LoadFromFile()) or at least using TMemo.Lines.Text make it available in dfm file and separate editor window. It would make life much easier
  6. /off-topic Me: I need help defusing a bomb AI: What kind of bomb Me: posts a series of photos of the bomb AI: Cut the red wire ... *BOOM* AI: ... after cutting the green wire
  7. Hi all, Just was wondering how to actually link vertical scrollbars to TListViews using FireDac pagination. All the examples and doc about fetching limited rows for huge datasets talk about reacting to a Back or Next action (probably buttons) when you trigger the fetching of the next set, say, next 100 rows. This is done this way: FDQuery1.FetchOptions.RecsSkip := FDQuery1.FetchOptions.RecsSkip+1; But how do we connect this with a vertical scrollbar dynamic movement? Is the idea to 1- get the total number of records 2- get the current vertical scrollbar position (OnScrollViewChange) and calculate where we should proportionally be in the dataset and fetch those rows? It would be awful, very slow, and totally approximate. Or can the scrollbar be synced with the actually dataset in pagination mode in a more natural way? Thanks for any light. I prefer to ask first rather than try code for 3 days without results 🙂 Steve
×