Jump to content

Dalija Prasnikar

Members
  • Content Count

    1058
  • Joined

  • Last visited

  • Days Won

    91

Everything posted by Dalija Prasnikar

  1. Dalija Prasnikar

    Why does a stack overflow cause a VCL application to terminate?

    As the name says, stack overflow overflows the memory buffer reserved for stack. In other words, it writes data in memory that does not belong to the particular stack buffer. This can corrupt parts of memory used for something else and this is also why stack overflow exception is not recoverable and can crash the application.
  2. Dalija Prasnikar

    Creating multiple threads in a DLL

    Your thread class Execute method is basically empty. Is there any other code in there you didn't show? If not then that is the reason your code is running sequentially, as threads don't do anything. Also using lower priority for threads can make threads wait longer to get the CPU slice.
  3. Dalija Prasnikar

    How many people use Delphi?

    There are always other requirements besides speed. If the vendor requires support for many platforms then Electron is one of the available options that fits. Other requirements may be based on developers they have and their skillsets, as well as application features and target audience. For instance VSCode being written in Electron is foundation of their thriving plugin system not only because underlying technology is very suitable for that, but also because there is vast number of developers that can write those plugins.
  4. Dalija Prasnikar

    How many people use Delphi?

    Are you sure that poor speed is acceptable on desktop applications? What about applications that need to load complex forms where opening such form can take half a minute or more? Or when you need to create plenty of business objects, or when you need to do some textual processing. Good compiler means a lot in such cases. In last few Delphi releases @Stefan Glienke has continuously submitted hand crafted code to improve speed of some widely used RTL routines that have impact on overall performance. With better compiler that would not be necessary. Not only that, but with better compiler all other code we write would be faster and when speed matters we wouldn't have to bend over backwards, writing horribly unreadable code just to get the speed we need. We could just write the clean and readable and maintainable code and leave the dirty work to the compiler. Speed always matters. Now, Delphi still might be fast enough for many purposes, but for many that is simply not enough. Once it was state of the art compiler, now it is seriously falling behind.
  5. Dalija Prasnikar

    Using TIdHTTP in a thread

    I am sorry, but snippets of code where it is not clear what happens at which point and how everything is created and called are also not enough to figure out what exactly is wrong with your code. One of the things does sound suspicious: you say the thread is stuck in the limbo when timeout occurs and you have Sleep call which will cause thread to sleep if it is not terminated, Maybe there is a problem?
  6. Dalija Prasnikar

    Using TIdHTTP in a thread

    It is impossible to say what is going on without seeing your code.
  7. Dalija Prasnikar

    Stop/Abort Form creation..

    Your code logic sounds backward. You should run code in FormCreate inside the calling form and then depending on the result create TChangesLogForm or not. Or if the code really belongs to TChangesLogForm, you should not run that code within FormCreate, but after the form is shown (along with some indication that there is a work in progress) and then if there is an error retrieving the data, you can show error message and close the form in that moment.
  8. Following code would do the job procedure TUExtractForm.LoadURLAsyncPOST(const AURL, AText: string); const CONST_TIMEOUT = 1000; begin TTask.Run( procedure var HttpClient: TNetHTTPClient; HTTPRequest: TNetHTTPRequest; ParamsStream: TBytesStream; begin ParamsStream := nil; try HttpClient := TNetHTTPClient.Create(nil); try HttpClient.ConnectionTimeout := CONST_TIMEOUT; // Timeout HttpClient.ResponseTimeout := CONST_TIMEOUT; // Timeout HTTPRequest := TNetHTTPRequest.Create(HttpClient); HTTPRequest.Client := HttpClient; HTTPRequest.OnRequestCompleted := HTTPRequestCompleted; HTTPRequest.OnRequestError := HTTPRequestError; HTTPRequest.CustomHeaders['Content-Type'] := 'application/x-www-form-urlencoded'; ParamsStream := TBytesStream.Create(TEncoding.UTF8.GetBytes('input=' + TNetEncoding.URL.Encode(AText))); HTTPRequest.Post(AURL, ParamsStream); finally HttpClient.Free; ParamsStream.Free; end; except on E: Exception do begin TThread.Queue(nil, procedure begin ShowMessageFmt('Error: %s', [E.Message]); end); end; end; end); end; procedure TUExtractForm.HTTPRequestCompleted(const Sender: TObject; const AResponse: IHTTPResponse); var Content: string; begin if AResponse.StatusCode = 200 then begin Content := AResponse.ContentAsString; // replace #$A with new line Content := StringReplace(Content, #$A, sLineBreak, [rfReplaceAll]); URLMemo.Text := Content; end; end; procedure TUExtractForm.HTTPRequestError(const Sender: TObject; const AError: string); begin ShowMessageFmt('Error: %s', [AError]); end; However, your timeout setting is very low - one second, and this can cause issues if the server does not respond timely. I would just use default settings.
  9. TTask.Run already runs in background thread and that thread will not finish before HTTP client completes its work or times out. You don't need to run another thread inside task and you don't need to run a loop simulating timeout.
  10. I am not sure about that. THTTPClient has built in support for timeout. What are you trying to accomplish with your timeout implementation? Your code is needlessly complicated.
  11. If you want to use asynchronous mode for HTTP requests you should use TNetHTTPClient instead of THTTPClient. TNetHTTPClient is a wrapper that implements all the gory details in the background and leaves easy to use API for the developer. https://docwiki.embarcadero.com/Libraries/Sydney/en/System.Net.HttpClientComponent.TNetHTTPClient As far as synchronizing events is concerned, in THTTPClient they will run in the context of the background thread, so you need to synchronize them with main thread if you need to access the UI. TNetHTTPClient has property SynchronizeEvents and depending on its value events will run synchronized with the main thread or not. Default value is True, so events will run in the context of the main thread. If you drop TNetHTTPclient on the form you can use it in asynchronous mode with just few lines: Client.Asynchronous := True; Client.OnRequestCompleted := HTTPRequestRequestCompleted; Client.Get(’http://....’); However, asynchronous mode is hard to debug and control, and I would suggest using simpler approach using background threads or tasks. TTask.Run( procedure var Client: THTTPClient; Response: IHTTPResponse; begin Client := THTTPClient.Create; try Response := Client.Get('...'); finally Client.Free; end; // process response in background thread ... // or pass it to the main thread TThread.Queue(nil, procedure begin Memo.Lines.Add(Response.ContentAsString); end); end);
  12. Well in that case you should do what the warning suggests. Add {M+} compiler directive before the class declaration or you can inherit from TPersistent which has RTTI generation turned on. type {$M+} TisEventHandler = class published procedure isPrintScreenClick(Sender: TObject); end;
  13. Usually published directive is used in Delphi component streaming system for properties in components that will be set in design time and saved as part of form, frame or data module. You have used it for declaring a method and this is not a common use case (unless you want to find and invoke the method by using its name through RTTI). You probably wanted to use public directive instead of published in your code. This will remove the warning.
  14. To tell what is wrong, we need to see your class declaration and implementation - in this case most likely constructor is what matters. Showing TTimer code is not very helpful. So when you ask for help, you should post your code first. However, knowing that your code works when you construct component directly and it does not when you drop it on a form, narrows down potential cause and most likely culprit is that you didn't add override directive to your component constructor. When you call constructor directly specifying its class then your constructor will run and create timer component, but when you drop it on a form original virtual constructor chain from TComponent will run, but it will skip calling your constructor because it is not marked as part of the chain (missing override directive). type TMyComponent = class(... ... public constructor Create(AOwner: TComponent); override; ens; If that is the case, you would also see warning W1010 Method 'Create' hides virtual method of base type... This warning tells you that something is wrong with your declaration and that you most likely forgot to add override directive (there are other scenarios besides this one, but in your case this is the one that matters)
  15. Maybe someone here had similar issue, but the fastest way to get help would be to contact support like the message says. You can do that through web. Make sure you choose Registration & Instalaltion https://www.embarcadero.com/support
  16. Dalija Prasnikar

    E2137 Method not used in base class

    Override is used when you want to override virtual or dynamic method from the base class and change its behavior https://docwiki.embarcadero.com/RADStudio/Alexandria/en/Methods_(Delphi)#Virtual_and_Dynamic_Methods
  17. Dalija Prasnikar

    Not Threadsafe??

    Like @Remy Lebeau already said, both his and mine solution will do that. Your UI will be responsive as VCL main message pump will keep running while your thread is doing work in the background. If you are confused by DisableUI/EnableUI method names, code in those methods will not block that message pump either unless you put some infinite loop there on purpose. Both can be completely empty. You should put there code that will show/hide progress spinner or you can disable/enable some buttons so that user cannot start some other operation while backup is running.
  18. Dalija Prasnikar

    Not Threadsafe??

    Yes, it is a good idea to show user the reason why form cannot be closed.
  19. Dalija Prasnikar

    Not Threadsafe??

    While more complicated scenario with multiple threads could require more sophisticated code, this approach would work without issues even if there are multiple tasks that require running in background thread. There would be no chaos because only single thread can run at the time. This is what "if Processing then Exit" is here for. User will not be able to start another thread as long as some thread is already running. Only when thread finishes, new thread can be started.
  20. Dalija Prasnikar

    Not Threadsafe??

    Application.ProcessMessages in not thread-safe means you cannot call it from the background thread. Since you are calling it from main thread that alone is not a problem in your code. However, one of the points of using threads is to keep application responsive to messages so you don't have to use Application.ProcessMessages which is not the best practice for many reasons. There are many ways for handling threads, and which one you choose depends on what particular thread does and the application logic. Since your code actually waits until the operation completes, then the simplest code that would achieve what you want with threads would be something like this: TMainForm = class(TForm) private Processing: Boolean; procedure EnableUI; procedure DisableUI; ... end; procedure TMainForm.BtnClick(Sender: TObject); begin if Processing then Exit; Processing := True; try DisableUI; TThread.CreateAnonymousThread( procedure begin try // do work here finally TThread.Queue(nil, procedure begin EnableUI; Processing := False; end); end; end).Start; except EnableUI; Processing := False; end; end; procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); begin CanClose := not Processing; end; In EnableUI and DisableUI methods you can put whatever code you need to show the user that you are doing some work or disable/enable some actions. The rest is pretty simple - if user tries to start processing again, code will not let it do that (that is something you should have even when you use Application.ProcessMessages as it allows reentrancy and user could start same operation while previous one is not finished). When thread is done (regardless of whether it completes successfully or not), it will enable UI (this needs to be called from the main thread and this is why there is TThread.Queue (or you can use TThread.Synchronize here - the main difference is that Queue is non blocking call and Synchronize is blocking). You can also catch exceptions and show message to user in similar manner. Thread will self-destruct after it is finished so you don't have to worry about its memory management. To avoid complicated cleanup and potentially breaking unfinished work thread is doing, the simplest way is to prevent user from closing form while thread is working in FormCloseQuery event. Note: Running DBSBackup.Execute opens the question about thread-safety of that code - in other words whether main thread can use DBSBackup instance and anything directly related while thread is running - which would not be thread-safe to do. But that part is another story.
  21. Yes, those two stream classes can be safely used in background threads if they are not shared.
  22. Dalija Prasnikar

    E2137 Method not used in base class

    This error happens when you add override directive to the method and method with same name does not exist in the class hierarchy from which you are inheriting. If you just wanted to add new method which does not exists, then remove override. The "check spelling" suggestion comes from the most common mistake when overriding existing method is that you mistype the name, so the name does not match to the name of existing method in base class which you want to override.
  23. Generally any kind of stream should be suitable for using in background threads, but also they cannot be simultaneously accessed and shared between threads. Just look at it logically - how can you use stream that holds a state (if nothing else than current position that changes as you read and write) be thread-safe? While you could in theory protect simultaneous access with locks and share stream across threads, you wouldn't gain much from that as stream would have to be locked and accessible to one thread at the time. If you think you could speed some operation by sharing stream and using is in parallel, you will only slow the whole process down, not speed it up. When using TCompressionStream and TDecompressionStream in background thread, OpProgress event handler will run in the context of background thread and you need to take that into account if you want to show progress in the UI and synchronize code.
  24. Why? iOS users know how to move application to the background using Home button. Such functionality does not belong in the iOS application. Just remove the Exit button or hide it on the iOS and avoid calling problematic code on iOS with compiler directives.
  25. iOS does not support terminating application, so Delphi does not have that support either. If Delphi previously implemented Terminate on iOS it was most likely removed as such functionality would cause rejection on the AppStore. See https://stackoverflow.com/questions/355168/proper-way-to-exit-iphone-application
×