

Kas Ob.
Members-
Content Count
535 -
Joined
-
Last visited
-
Days Won
9
Everything posted by Kas Ob.
-
@#ifdef Well i can't compile your project nor i have an idea what TControlList is, yet from your last post i can deduce the problem. Se, same behavior is visible with Windows Notepad, you can try it, open a big text file something around few MBs and make sure that Word Wrap is enabled, and see for your self, same behavior, disabling the Word Wrap will make it fast like it was few lines. Calculating the height of paragraph is demanding process, because it only possible with a font and a width, after that rendering will happen again with the font applying device context parameters, so it might be doable but not like that it must involve caching. The only components i know of that do this right (or lets say fast) is the controls from Delphi HTML components. Yet, there is may be a workaround in your case, which is switching to virtual drawing, and rendering only what should be visible while emulating the scrollbar position at side, in other words you need to switch to owner draw and draw text manually what is enough to fill the control.
-
Thank you !
-
I am sorry too, but look at this code as example type TFileCopyClass = class private fFileSrc: TFileStream; fFileDst: TFileStream; public constructor Create(const Source, Destination: string); destructor Destroy; override; end; { TFileCopyClass } constructor TFileCopyClass.Create(const Source, Destination: string); begin fFileSrc := TFileStream.Create(Source, fmOpenRead); fFileDst := TFileStream.Create(Source, fmOpenWrite); end; destructor TFileCopyClass.Destroy; begin fFileDst.Free; fFileSrc.Free; inherited; end; What are the value at the "begin" in that constructor ? The answer is arbitrary and random even if you see it as nil most the time, these are unmanaged fields/variables. So if TFileStream raised an exception then the value of lets say fFileSrc is undefined and might be not nil, hence causing another unknown exception in the TFileCopyClass.Destroy; Am i right there or i am missing something ?
-
or: https://stackoverflow.com/a/39110161 You are missing the point of best practice to ensure memory integrity, Yes if an exception is raised in the constructor then the class itself is nil and will not leak memory, as pointed by @Dalija Prasnikar but if it is already allocated/created stuff then this stuff will leak so instead of depending on extra work to ensure non of the "stuff" had leaked just use best practice. On other hand, what pointed by @dummzeuch and @Dalija Prasnikar it does ignore the fact that that FSomeHelperObject is not managed variable hence it might have any value initially (random from the memory), rendering the following worst case scenario by raising unexplained and hard to track exceptions if Assigned(FSomeHelperObject) then FSomeHelperObject.Free; In other words, when an exception is raised in the constructor, you can't control or know where the stopping point was, unless considered this at designing, thus if you want to raise exception in the constructor then you need to do the extra work, like assigning FSomeHelperObject to nil before creating it ! and live with the compiler complaining about useless line and most likely the compiler will remove it, again rendering the code vulnerable to unexplained exception.
-
Because there is a very popular of miss practice with Pascal and Delphi which is (ab)using the constructor and destructor for everything, i do it, and every one is doing it, even the RTL since Borland is did it .. and to be clear the ones that should be used for any sort memory initialization, object creation, or what ever other than initialize values for the unmanaged object fields are procedure AfterConstruction; virtual; procedure BeforeDestruction; virtual; These should be used for creating object fields/variables and/or initializing values for managed fields...etc , with these you are free to raise what ever you want, a nice exception will be raised and a nice memory leaks will be reported, in other words the fail will be graceful and easy to locate. Another approach: Also as in OP class above, if you need to raise an exception then in my opinion the class design can be written better by separate Create and adding an Init (or Start...), Create to just create and another for functionality that might fail, this will %100 be memory leak proof no matter what is the case, and if you think about it, create doesn't raise and will not fail, while the failure might come form something like an Init procedure, here failed or exception raised or what ever happen, Create didn't (and will not) break the logic flow of the application and Free is guaranteed to work. In case of wondering what will happen with Out of Memory, then either Create will fail from the RTL, or will not fail because we don't allocate or create anything in the constructor, and that is the point of this suggestion.
-
Hi, Don't concern yourself with this one, it is irrelevant to your code, you should for/at the calls after it. Both allocation are reported from this line This where you registered packages being loaded, this means it might be one package (or two) had been loaded and not unloaded in orderly manner, or/and this package had allocated memory in its initialization and never freed it. Find the runtime package you are using and fix it. Also as @Tommi Prami pointed, try to not raise exception in constructors and destructor. Your TTCPEchoDaemon code you pasted is irrelevant to the memory leak, but if you are doubting it then i inclined to remind you, to check how and where are declared and initialize this EchoDaemon, it could be the leak as the size of the leak is conveniently close enough to the size of your class. In other and short words, the leak is happening in initialization section in one unit (most likely one unit).
-
Threadvar "per object"
Kas Ob. replied to chkaufmann's topic in Algorithms, Data Structures and Class Design
Well, i still can't see how threadvar will help here. I mean you wrote "I call DisableNotifications", how and from where ? see, again threadvar are invisible to other threads and to reach them you need this thread to get some value in like receiving signal (notified to update) or reading from somewhere fixed or predefined, or accessing a already known list, to get the needed value then store it in threadvar. again in that case and after going through all this troubles to get these values, threadvar is not providing any thing useful, because you already implemented the data passage and sharing/signaling/locking to the specific thread. As a solution then just have a list or an array with objects or records, example : an object like your TBSItemProvider that is created by the main thread (the origin doesn't matter) and attached/passed to the thread, this will simplify the whole thread communication process. Of course you need to take care of thread synchronization in case you will do access them randomly, but again in case of threadvar will work for you then such a record or object will be the same. -
Threadvar "per object"
Kas Ob. replied to chkaufmann's topic in Algorithms, Data Structures and Class Design
Threadvar(s) are invisible to anything else than this thread (current), and each thread have its copy. So if you are going to use them from different thread like the main or whatever, you need to store them or store a reference to them somewhere and this somewhere will definitely need a thread locking or thread safe storage, thus this storage will negate all the trouble to use them in first place, use global list or something, by global i mean centralized list or container with adequate thread safety. in other words You don't store data block per thread and per object at the same time, attach one and reference the other. -
No, and LIB files is not supported by Delphi for good reason, which is hell of naming and scope, doable though. LIB files are merely a package of object files (.o or .obj), which does have COFF format only with files/sections, in other words it is an uncompressed container of list of files, and that is it. You can use LIB in Delphi but you need to do some conversion first: 1) unpack all the object files form the LIB, there is many tools on the net to do so, there is many tools to do so but you need to search for them and try the one that work with your lib file as different compilers tend to produce a little different lib format or tweaks, while most such tools are built for specific format/tweaks. 2) link the unpacked objects files into one object file, many linkers do this with the command -relocatable (or -r) , though not all linkers support wildcard like *.o and you need to list all the names of object files, and the -o parameter will give you the one linked (combined) one object. 3) use the one object file from (2) same as you use o files, in this case it is the lib itself. extra info https://stackoverflow.com/questions/3811437/whats-the-format-of-lib-in-windows
-
Hi, @Jim McKeeth The survey is missing Nexus Quality Suite ! Edit: didn't notice that there is a special field for the missed ones.
-
Changes in System.sysutils.pas were not reflecting in other unit in Delphi 11
Kas Ob. replied to sp0987's topic in General Help
Well, bugs happen and knowing more about edge cases will save time, it is good thing to know more. Learning English is important, learning programing on deeper level is importanter. -
Changes in System.sysutils.pas were not reflecting in other unit in Delphi 11
Kas Ob. replied to sp0987's topic in General Help
Right as (2) Because on Win64 the default calling convention is the same for Windows OS API and Delphi 64bit, stdcall does nothing, the stack is not used for the first 4 parameters. -
Changes in System.sysutils.pas were not reflecting in other unit in Delphi 11
Kas Ob. replied to sp0987's topic in General Help
Well, this is sort of bugs are the worst because in some context they stay hidden for long time even for ever, and then one change in the code (a correct, innocent and valid) in different place might trigger this one to show its face wasting hours of bug hunting in the wrong places. Take an example of this code {$APPTYPE CONSOLE} {$R *.res} uses System.SysUtils; type TDoSomethingProc = procedure(var Value: TDateTime); stdcall; procedure DoSomething(var Value: TDateTime); stdcall; begin Value := 1; end; procedure DoSomething2(var Value: TDateTime); begin Value := 2; end; procedure Test; var dt: TDateTime; Proc1,Proc2:TDoSomethingProc; begin Proc1 := @DoSomething; Proc2 := @DoSomething2; Proc1(dt); Proc2(dt); end; begin Test; Readln; end. As you said it is wrong and should not work, yet this code on my Delphi XE8 does work fine with no problem. The stack is clearly broken in Test() right after Proc2(dt) and in theory returning to main form Test() should be broken, yet it does return like nothing happen ! The secret is Stack Framing and this is one of the power of not depending on the stack in the first place but on a pointer to it with minimum or no push/pop at all ( unless it is needed), to get the big picture we need to look at the assembly for this code and the stack been fixed right in place. So in this case no harm detected and that because proc2 does need the parameter in eax and in fact it is there, because the compiler used eax on push. When this can go wrong and break ? we i can think of at least two (other of course do exist) 1) If Test() has more local variable or just more code, and the compiler did use different register other than eax to load the pointer to the variable dt and push it on the stack. 2) Any code after Proc2() will have the stack (the real stack on esp) broken, so calling functions after it and their func/proc called from there might raise unexplained exceptions or show undefined behavior or logic. ps: this use of ebp as stack storage is not exclusive to Delphi neither its invention, but in Delphi we don't have the extreme optimization setting like in Visual Studio when remove this protection to gain speed, hence exposing such bugs right away. -
Changes in System.sysutils.pas were not reflecting in other unit in Delphi 11
Kas Ob. replied to sp0987's topic in General Help
Not sure about this, but the following works fine var windows_GetLocalTime: procedure(var st: TSystemTime); stdcall; procedure getTbtTime(var st: TSystemTime); stdcall; var dt: TDateTime; begin dt := strtodatetime('12/06/2025'); DateTimeToSystemTime(dt, st); //DecodeDateTime(dt, st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, // st.wSecond, st.wMilliseconds); end; procedure TForm10.Button1Click(Sender: TObject); var dt, value: TDateTime; s: string; begin dt := Now; Memo1.Lines.Add('before hook:- ' + datetimetostr(dt)); windows_GetLocalTime := InterceptCreate(@GetLocalTime, @getTbtTime); // if it is only for local (here and now) then we need to clean it up locally try dt := Now; // Returns error "Invalid date to Encodedate" s := FormatDateTime('mm/dd/yyyy : hh:nn:ss.zzz - ', dt); Memo1.Lines.Add(s); finally InterceptRemove(@windows_GetLocalTime); // cleanup the hook and restore end; end; procedure TForm10.FormCreate(Sender: TObject); begin windows_GetLocalTime := GetLocalTime; end; See that stdcall modifier for getTbtTime, it is essential here when intercepting Windows API, without it all the parameters are wrong. -
Hi @Uwe Raabe , I saw this bad behavior from MMX code explorer for years now, yet it didn't annoy me that much as i do restart my IDE frequently, but today was with a client sharing his desktop with me, while i am helping him to track a bug in his project on his PC and on his client PC who was also sharing his desktop, so the process went for some times and among few tools being used one reported something that caught my eye, so at the end of this semi-teaching session i tried to confirm that behavior (the one i am familiar with) on his Delphi 10.3. Now to the details, my IDE is XE8 and i have MMCE v13.1.0 build 2220 while his IDE was 10.3 and i forgot to write his MMCE version and build but it was v15 for sure, he said it was the latest, but after visiting https://www.mmx-delphi.de/ i can't know what is what and where is the latest version or if there is beta and stable.... Anyway, to the problem at hand : any already opened then closed file using the IDE MMX will keep tracking and monitoring its datetime, and here i mean it will do it only if closed after opening, this accumulate with what looks like no limit, i opened 50 files and opened and closed many different projects and the IDE with nothing opened keep checking these file datetime (namely FileAge) exactly every 1 minute, and on top of that the same query for FileAge happen every time the IDE was activated (like restored or even had focus after losing it) Again the following on my XE8 and the deprecated v13, yet i saw the same behavior on v15 and newer version but i couldn't ask my client to waste time for something might not concern him. This capture is the simplest using Process Monitor and one opened and closed file after activating the IDE and this does show the 1 minute timer triggered FileAge These are with one file opened and closed, also i can't make much sense from the call stack !!! I mean triggered by DoActivate makes sense, yet these are closed files and should not be monitored, because they are monitored, here an example of that file being renamed then opened and closed then renamed back About the stack and make sense, this sequence AddClipboardFormatListener -> TDataModule.WriteHeight ???!!!!!!!(WTF) -> MMCE then MMCE even with non existed file keep trying to query its information, though there is a hook and the timed query should not be needed to be begin with, ( not with a timer and not on IDE activation) Something wrong here and there is no clipboard what so every on my PC now, and to be honest i not sure if the stack is correct at this point. Anyway, hope i am not wasting your time and please forgive me if i am missing something obvious like some settings for such caching and keep it even after closing, as i couldn't find settings to control this behavior . PS : today i had blackout twice and every time lost around half an hour of debugging session deep into the IDE and MMCE, so i gave up and decide to report it, between these files query, there is a loop and to walk the files but one forward and the other downward (may be while-do vs for-to) the code responsible for FileAge in knownache or chached ... etc i really can't remember, and doubt it is useful, as going after FileAge should be more than enough. PS2: I am not expecting any update on v13 also don't have the right to ask for, but it might help v15 users if the mentioned here problem is in fact a problem and still exist in the latest version. PS3: i successfully solved or removed the my problem on v13 by hooking, though not sure what did break if any, no signs of MMCE failure with few restarts and few fast tests. PS4: there is difference in the call stack for these closed files may be about 30 seconds then it will revert to different stack call (deeper/longer one) Hope that is not waste of time.
-
Is there a way to check is the "user Idle" (no interaction)
Kas Ob. replied to Tommi Prami's topic in Windows API
Well, their makers lost their compass and bloating it with useless tools, so i strip them to the skeleton first then re-add my needs. here how my Windows 10 looks when after booting few months ago had to reinstall windows store and many similar components for a project, it was even cleaner than now 😡 -
Is there a way to check is the "user Idle" (no interaction)
Kas Ob. replied to Tommi Prami's topic in Windows API
There is even better example, IIS ! I think you are overthinking the whole saving battery, sleep, hibernate... see, in Windows Server OS the Sleep and Hibernate are disabled by default by policy group, these might cause lot of problem if they kicked in, while on personal PC the thing is completely different due the different tasks priority or lets say different default tasks required from the PC to do, one have zero dependency on user input, the other in general is to handle and process direct user interaction, input, output or even playing music...etc Well don't know what to say more about that, but i can suggest a neat solution for such Use Awake from Microsoft PowerToys, https://learn.microsoft.com/en-gb/windows/powertoys/awake https://learn.microsoft.com/en-gb/windows/powertoys/?WT.mc_id=twitter-0000-docsmsft https://github.com/microsoft/PowerToys -
Is there a way to check is the "user Idle" (no interaction)
Kas Ob. replied to Tommi Prami's topic in Windows API
Browsing the code i have thoughts 1) from SendInput https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-sendinput 2) This class TAEKeepMeAwake is somehow asynchronous, in other words it has its own timer and doesn't depend on application logic to be triggered or executed, it depends on OS timer, so when things go wrong that exceptions raising RaiseLastOSError, might cause havoc like endless messages every 1 second. 3) I hate raising exception specially if they are not needed, and in this case its like : ok, let some other part of the application handle this, here take an exception,... Exceptions are not signaling mechanism, notice here with (the mentioned above function) the exception will be generic and useless, and if the application error reporting failed to capture the stack, then application might end up showing funny messages like "exception was caught.. last error (or last operation) was success". I would suggest to remove exception raising and replace them with OnError event, in my opinion this is less intrusive method and more useful (less ticking bombs), also this class and before calling such event it should disable its timer, leaving the decision to reenable the developer. Sorry if Off-topic. -
How to debug a Not Responding program element
Kas Ob. replied to Willicious's topic in Delphi IDE and APIs
Also i missed to point this thought about this, missed writing it in the above post while writing slowly and fixing gramer type TColor32Array = array [0..0] of TColor32; TMyStuff = record FirstPixel: TColor32; TheRestOfThePixels: TColor32Array; end; PMyStuff = ^TMyStuff; This doesn't save any time, shorten the code or makes it clearer (if clearer is a word), for simple fact : the length of data in that array is 1 for the compiler and any manipulation with such declared var (rec) will only copy one element "like assigning with := ", and an extra var/field contains the actual length should be saved somewhere, on top of that, there must be a manually code written to perform the actual copy of the elements, so... !! again my opinion. -
How to debug a Not Responding program element
Kas Ob. replied to Willicious's topic in Delphi IDE and APIs
This exactly the point, this type should not be used ! (no variable or field should be declared as such) I searched GR32 source and it is in fact not used anywhere, because it should not appear anywhere, such static array can be used just to make the virtual declaration of it (pointer to) available. Think about it, your example TMyStuff and even in many Windows SDK structures need such type, the easy way is to declare it as [0..0] to cast the header of record, and this exactly what make these structures not memory safe, alas there is no workaround it, though the only approach is to have two versions, or may be in case of such record then prevent the declaration of xxArr version and declare your own with "[0..0] of yyyy", this will prevent the developer from confusing these static arrays, ensuring best practice. In other words, both these declaration TColor32Array = array [0..0] of TColor32; TColor32Array = array [0.. MaxInt div SizeOf(TColor32) -1 ] of TColor32; Can be dangerous, yet the second can't be used !, makes it safer and force you to declare your own need in place, while the first one has zero help from the compiler in protecting memory overflow at runtime, both are tuples, both have their lengths known before hand by the compiler and no runtime protection at all, one is not allowed the other is can be falling knife. I am sounding is my opinion, and that is it. ps : Wish if Pascal syntax had a modifier to force or at least warn with some type when used like TColor32Array = array [0..0] of TColor32; varprohibited; // can't be used in as field or var, yet allowed to be used in other types declaration like below. TColor32Array = array [0.. MaxInt div SizeOf(TColor32) -1 ] of TColor32; prohibited; // same as above PColor32Array = ^TColor32Array; // this is allowed TUnsafeColArr = TColor32Array; // this is allowed -
How to debug a Not Responding program element
Kas Ob. replied to Willicious's topic in Delphi IDE and APIs
A lot being said above, and you need to start and fig deeper and learn why and how. Anyway, this issue is also easy to fix, the cause is this declaration in GR32.pas PColor32Array = ^TColor32Array; TColor32Array = array [0..0] of TColor32; // pain in the back, and will trigger overflow check TArrayOfColor32 = array of TColor32; And the fix or another slap work around without testing but again using my extra power procedure TRenderer.ApplyRemovedTerrain(X, Y, W, H: Integer); type TTempHackColor32Arr = array [0.. MaxInt div SizeOf(TColor32) -1 ] of TColor32; PTempHackColor32Arr = ^TTempHackColor32Arr; var //PhysicsArrPtr, TerrLayerArrPtr: PColor32Array; PhysicsArrPtr, TerrLayerArrPtr: PTempHackColor32Arr; cx, cy: Integer; MapWidth: Integer; // Width of the total PhysicsMap begin // This has two applications: // - Removing all non-solid pixels from rlTerrain (possibly created by blending) // - Removed pixels from PhysicsMap copied to rlTerrain (called when applying a mask from LemGame via RenderInterface) PhysicsArrPtr := PTempHackColor32Arr(PhysicsMap.Bits); TerrLayerArrPtr := PTempHackColor32Arr(fLayers[rlTerrain].Bits); The best is to fix GR32 with the following, but don't do that on your own, this is up to Anders PColor32Array = ^TColor32Array; //TColor32Array = array [0..0] of TColor32; TColor32Array = array [0.. MaxInt div SizeOf(TColor32) -1 ] of TColor32; TArrayOfColor32 = array of TColor32; -
How to debug a Not Responding program element
Kas Ob. replied to Willicious's topic in Delphi IDE and APIs
@Willicious I am sorry ! I just tried tried again to build the code for this one https://github.com/Willicious/SuperLemmixPlayer assuming it is the one we are talking about, the readme for this one pointing that Graphics32 is needed and it is, but Graphics32 is not compatible with XE8 or 10, it does have inline variables and recent version of generics that i don't have a clue when they are supported. I don't know even the of the game is compliable with my IDEs, so i can't help beyond eyeballing the code in the IDE, even these IDEs are failing to navigate and i had to use search and that is it. Will produce performance hit, but like that easy to find and fix memory leak, they will prevent such and many many more bugs, so you don't need to enable them all the time, if the performance hit is huge then you can disable them for production or release, yet i like to keep them enabled and disable them in critical parts, but this and from what i see, is too soon, so keep them enabled and fix every exception raised with them is good for now. Though from your screenshot and the CPU usage i don't think these checks performance hit will be noticeable in this application. -
How to debug a Not Responding program element
Kas Ob. replied to Willicious's topic in Delphi IDE and APIs
Well, you are in for a ride ! These runtime checks might be triggered many times, as the code never or may be for long times evolved without being checked against these. Anyway, each and every case can be fixed, just take your time with them. For this case : 1) GetTickCount is Cardinal (DWORD), thing to remember. 2) That loop is easy to understand and rewrite performing such subtraction or just slap a workaround around it like this while (RemainingTime >= 0) do begin if (RemainingTime <> OldRemainingTime) then begin ScreenImg.Bitmap.MasterAlpha := MulDiv(255, RemainingTime, MAX_TIME); ScreenImg.Update; OldRemainingTime := RemainingTime; end else Sleep(1); if GetTickCount > EndTickCount then // prevent integer overflow Break; RemainingTime := EndTickCount - GetTickCount; <--------------------------------------- this line here end; Application.ProcessMessages; end; You are in for a ride, and definitely worth it. -
How to debug a Not Responding program element
Kas Ob. replied to Willicious's topic in Delphi IDE and APIs
Found this, and this have be understood and remembered when developing for Windows https://learn.microsoft.com/en-us/windows/win32/win7appqual/preventing-hangs-in-windows-applications Off-topic: the last two lines in that article are most fascinating, because C++ exceptions are similar to Delphi exceptions in their dissimilarity to C exceptions, exceptions in callbacks are freaking fatal, and most the time are obscure and untraceable due the failed unwinding (unroll) process. -
How to debug a Not Responding program element
Kas Ob. replied to Willicious's topic in Delphi IDE and APIs
I don't see any strange behavior here, there is no CPU load or any bottle necks, on the contrary the cpu is relaxed and if there is not responding then it is either Sleep or long process that can be moved into a background thread and make it do it fast. I explained my position and opinion about depending or even using Sleep in main thread, and yes i looked at the code and i know what i am talking about. My suggestion is to entertain or research the possibility of removing the dependency on Application Idle handler to either background thread that post messages to the main thread or simple timer doing the same as that Idle Handler, aka emulate it in timer, this should not huge deal at all, on contrary it will make sure of best practice in developing for Windows, remember that ApplicationOnIdle is triggered when no other message seen at this moment, while executing any thing in OnIdle there is no OS message handling, while Windows OS will consider application freeze and no responding after only 5 seconds if the application main thread is did empty/grab message(s) from the message queue, yes 5 seconds. After all these posts in this thread, i may be out of date on what is the top priority bug/problem to fix, is it still non responding menu level selection window or something else, Keep the good work and good luck.