Jump to content

aehimself

Members
  • Content Count

    1053
  • Joined

  • Last visited

  • Days Won

    23

Everything posted by aehimself

  1. Did TZipFile ever got a proper update? Although it's good to have something built in, https://github.com/ccy/delphi-zip adds LZMA and probably ZIP64 support. I myself forked that too to fix a memory leak and make it open some corrupted ZIP files too. I wonder if I can drop Zip2 in my projects and to use the built-in version again.
  2. A long time ago I wrote an application where I was forced to push specific long-running operations into background threads to keep the UI responsive. Stupidly enough, each method wrapper kept the control away from the VCL thread and returned only when the background process finished. This was a quick and dirty solution so not much of the code had to be changed. For example: myclass := TMyClass.Create; // Setup myclass // Instead of myclass.DoWork, now it looks like this: WorkWithBackgroundThread(myclass); // Get the results out of myclass FreeAndNil(myclass); Where in WorkWithBackgroundThread lies the evil: workthread := TWorkThread.Create; // setup workthread workthread.Start; While Not workthread.Finished Do Begin Application.ProcessMessages; Sleep(10); End; This worked for a while, up until I updated a component the application is using and now it started to throw invalid pointer operations. Long story short, the execution pointer / counter jumps in-and-out of different methods called by window messages, corrupting some Strings in the process (in the debugger the value quickly changes to "inaccessible value") so yeah... I am thinking on re-writing the whole thing to be event driven, but unfortunately far too many logic already depend on not receiving the control back. Is there a way doing something like this in modern Delphi (10.2+) ? I noticed that now we have a System.Threading unit with some task implementations, but ITask.Wait also blocks the caller thread (and this unit does not have a high reputation as far as comments went). The other bad thing about these implementations is exceptions and freeing an object up: Var sl: TStringList; x: ITask; begin sl := TStringList.Create; Try Try x := TTask.Create(Procedure Begin Sleep(10000); sl.Add('eeeee'); End); task.Start; // task.Wait; // will cause the UI to hang up Except On E:Exception Do ShowMessage(E.Message); End; Finally FreeAndNil(sl); End; Which will throw a nice and cozy nullpointer exception and is not getting caught in the except block... see my issue I suppose. So my question is: is there an easier salvation for me rather than the full refactor? I'd prefer not to use any 3rd party libraries to keep external dependency as low as possible.
  3. aehimself

    While Not _thread.Finished Do Application.ProcessMessages;

    The UI is a simple tabbed interface. One tab can be "blocked" (by disabling all buttons and actions when a BG operation starts; re-enabled when ends) but the others (and with that - the whole UI) must stay unblocked. Furthermore, a nice spinning loading indicator with a "Cancel" button looks and feels more "professional" than a frozen, whitened form what you only can close with the task manager. Edit: As I already took a shortcut with the While xx Do Application.ProcessMessages method and seeing where it lead to - I am already in the process of rewriting the whole "action" logic to pure event based. It's a nightmare. To any future reader: don't be like me. Write your code clean, so you have to write it only once πŸ™‚
  4. I can double on both. I started to learn Git on the very same tutorials and they are indeed very informative and easy to understand. And yeah, those tools... πŸ™‚
  5. aehimself

    While Not _thread.Finished Do Application.ProcessMessages;

    I'm completely new to System.Threading (I was told it exists today by one of my colleagues) and always used TThread descendants until now. I'll see what exactly this method does; thank you for the suggestion! The main purpose of this change is to get rid of the Application.ProcessMessages call in a loop, so this is not an option unfortunately.
  6. aehimself

    While Not _thread.Finished Do Application.ProcessMessages;

    Yes, this will definitely get rid of the nullpointer but will still "swallow" all exceptions happening inside. During the past years I also grew to feel uncomfortable creating a local class without a Try...Finally block; however sometimes there's no way around. There is an other issue I forgot to mention - nested calls. Procedure1 calling procedure2, which starts a task and returns immediately. The issue is, Procedure1 will expect the data/action to be ready as it regains the program flow. So I guess there's no easy solution; I reap what I sow. One has to pay for his former mistakes πŸ™‚ Ps: I never really liked this implementation anyway.
  7. aehimself

    Database for Cloud and Offline

    I was experimenting with this once but found that the merge when your app goes back online is not that easy if the data can be changed at multiple locations. Effectively you'll have to have a local database and keep your own transaction log (can be the raw SQL queries) of all the work which was done offline. When the connection is back up, replay that transaction log on the remote database. But if the database was changed by someone else on the remote location you'll have to automatically decide what to do with each failed query, and it will get annoying after a while. Furthermore, you already have a local database, which is only kept in-sync with the remote one... seems to be unnecessary. At the end I created my own datastore with classes and simply stored everything in a local JSON file. It was even easier to merge the modification sessions, as I had a full log of what happened and I did not want to change a value which I knew was deleted two weeks ago. If this is not an option for you, set up a local database with SQLite or alike... that will have the least overhead I can think of. You can also use a more advanced local database engine and use it's built-in replication to get the dirty work done.
  8. Aren't those two are effectively the same thing? Afaik, .MultiThreaded := True only means the socket will use it's internal message pump. You easily can create a deadlock in any VCL application if you have two "While xxx Do Application.ProcessMessages" blocks running "simultaneously". Maybe this is the case here...?
  9. That was my initial thought when I started to read this thread. In cases like this I try to disable as much 3-rd party dependencies as I possibly can to see if the problem still occurs. SSL would be my first to go in this case.
  10. At work most of my colleagues prefer SourceTree. I find the UI sluggish and hard to complete simple tasks. I personally prefer VS Code's implementation (having it installed as the default text editor on all of my PCs might be a bias-factor, though). For me, Git handling is really easy, fast and easy to understand. As others already pointed out it's all a matter of taste. Some of my colleagues are still starting up Visual Studio for a simple pull, so... πŸ™‚
  11. aehimself

    New annoying IDE malfunction

    There is that little beauty! I was not aware that we have a user fly-out menu until now:
  12. aehimself

    New annoying IDE malfunction

    There is an ignore list on this forum?! Where? I never seen it!
  13. I have a project, with multiple source files added from other projects. For a while now I switched from TRTLCriticalSection to TMonitor as it requires no additional unit imports and should be more cross-platform (?) than the prior. Now; most of the said imported files are using TMonitors the usual way: TMonitor.Enter(Self); Try // Do stuff Finally TMonitor.Exit(Self); End; Works like a charm. I added a new VCL form and a private worker thread implementation. In this new unit, I can not use TMonitor.Enter as the compiler says the method does not exist! Ctrl-clicking on TMonitor in the working and the non-working source file both redirects me to the same TMonitor implementation; System.pas:817. Hovering the mouse shows the same tooltip - record, declared in System.pas. Which is even more strange, the project can not even be compiled if I leave the underlined TMonitor calls in this one source file so I suspect it's not only LSP. At the moment I changed TMonitors to TCriticalSections in this file and it is working fine this way. Has anyone seen this issue so far? Any tips how I can make it to work?
  14. aehimself

    Delphi 10.4 compiler going senile

    We have a winner. The only thing which bugs me now, if I look up the class declaration, why it redirects me to System.TMonitor in this case...? This is why I did not even think about a different class with the same name in a different unit.
  15. aehimself

    Problem closing forms..

    I swear I had "random" access violations when an application was closed which was caused by freeing something owned by the form... then, when the form was closed it tried to free it again. Now, on Delphi 10.4 I simply can NOT reproduce the issue, no matter how hard I try. Checking the destructor code of TComponent: destructor TComponent.Destroy; begin Destroying; RemoveFreeNotifications; DestroyComponents; if FOwner <> nil then FOwner.RemoveComponent(Self); // THIS LINE FObservers.Free; inherited Destroy; end; Was THIS LINE always there? If I'm not mistaken the bug mentioned happened on Delphi 10 Seattle, before we made the upgrade... is it possible that it was implemented inbetween? If not, how exactly it can be reproduced?! Parents of mentioned components were frames, if it makes any difference
  16. ConvertToUTF8.7z Using the ZIP2 component (but unit can be renamed to Zip to use the Delphi default) for creating backup copies. Finished 3000+ files in 90 seconds in our project at work. It checks for BOM existence; so if you have actual UTF8 files without BOM it can cause issues.
  17. aehimself

    Problem closing forms..

    You are creating the form with the owner of your main form. When you close your main form therefore (as it owns your subform) it attempts to free it. But since it is already done in the onClose event (Action := caFree) it is trying to free a non-existing object resulting an access violation. Try to create your subform like TMyForm.Create(nil); Or don't use caFree in the onClose event. You should consider using MyForm := TMyForm.Create(nil); Try MyForm.sFormID := '3'; MyForm.ShowModal; Finally MyForm.Free; End; if applicable.
  18. aehimself

    Delphi 10.4 PATCH 2 experiences

    And here I though, that the CommandLine is internally using a ConHost process (Windows Console Host) which is provided by the operating system with AllocConsole for example. I must be wrong. In that, we definitely agree.
  19. aehimself

    Delphi 10.4 PATCH 2 experiences

    Obviously. I forgot that the one and only way to start a batch file is Windows Explorer. Why are we paying sysadmins, if the answer is always so easy...?
  20. aehimself

    Delphi 10.4 PATCH 2 experiences

    There is no such thing as hardwired to File Explorer; it is just an application which requires elevated privileges due to it unzips files to the Program Files folder. I suggest you to take a look at how UAC works on Vista+ and how you can auto-elevate everything if it disturbs you that much. While I completely admit that this "patch tool" is utterly useless, don't blame Emba because of how UAC works.
  21. aehimself

    How to detect the active app

    I should pay more attention to the details; I thought I used one of these functions before. As I checked my sources - you are right. GetForegroundWindow it is.
  22. aehimself

    Centered message?

    While the idea clearly works, there's a huge flaw with it: I don't like tea.
  23. aehimself

    Patch 2 for RAD Studio 10.4 now available

    Am I wrong to expect that the PatchTool is simply unzipping the Patch2.zip file? On an isolated test machine with no Internet available I unzipped the patch manually and simply overwrote the files. Patch1 worked this way. The appearance of PatchTool made me wonder...
  24. aehimself

    Anybody up for an ethics question?

    I'd simply re-throw exceptions in an understandable way; you now can even use RaiseOuterException to include the data from the first one. When I am working in a service application which should operate 24/7 without interruptions, I'm placing a Try ... Except in the worker thread only. It picks an item to process from the queue, if it fails, it logs why and places it back to the end of the queue. Once an item failed to process 3 times it is discarded. Specifications (even if given by the client) are only specifications. Our client keeps sending invalid XMLs for us to process, even though they created the validating XSD for that very document. So yes, expect bad data; no matter what. But depending on the needs - don't change values and/or swallow errors because the code looks... cleaner. I'd suggest TryStrToInt and it's counterparts, or simply Val. That way you know if/where the expected data is malformed and can Rase Exception.Create('The length of your shoes must be a number, not "' + s + '"');
  25. aehimself

    How to detect the active app

    GetTopWindow or GetActiveWindow, depending on your needs function SecondsIdle: DWord; var liInfo: TLastInputInfo; begin liInfo.cbSize := SizeOf(TLastInputInfo) ; GetLastInputInfo(liInfo) ; Result := (GetTickCount - liInfo.dwTime) DIV 1000; end;
Γ—