Jump to content

Anders Melander

Members
  • Content Count

    2280
  • Joined

  • Last visited

  • Days Won

    117

Everything posted by Anders Melander

  1. Anders Melander

    Delphi compiler need to be opensourced

    It's not possible to downvote in JIRA.
  2. Anders Melander

    Use graphics32 to draw rounded rectange with gradient + border

    And have you looked at the Polygon and Gradient examples?
  3. @Dalija Prasnikar I agree with your characterization but in some cases I find that composition is better suited than inheritance even though inheritance would be more natural. For example if I were to create a list of TSomething it would be tempting to use TList<T> as a base class, Problem is that it might give me too much. If I only need an Add method, a Count and an array property, then composition is probably better (I guess one could call it inheritance through composition). I've seen too many examples of inheritance (not just from TList) where most of the inherited methods doesn't make any sense and would break the application if used.
  4. Anders Melander

    Check for override

    OK then, let me spell it out; In regular applications or even simple libraries individual braking changes are probably relatively easy to locate and fix. The TStream change for example could almost have been made with search/replace, but I guess they thought that the backward compatibility solution was safe enough that they didn't need to make it breaking. In retrospect, although I never personally got bitten by it, they should have marked the old overload as deprecated to flag that ppl should fix their code or else. FWIW I don't think the TStream method is fragile. From what I can see it's very robust. For a large framework the situation can be different. A framework has an API and therefore a contract with the users of the framework. A breaking change in the RTL that lies below the framework can mean that the break propagates to the API of the framework. For example I just yesterday finished updating my local copy of a framework that sits on top of DevExpress from a two year old version of DevExpress to the latest version. DevExpress changed the type of some properties from TBitmap to TdxSmartGlyph and since the framework exposed those same properties as TBitmap it got stuck on that old version. If the framework had followed suit and also changed the type, then it again would have broken the code of hundreds of customers (the users of the framework) with no gain to them. The company that with this particular framework is still stuck on that old version of DevExpress since they no longer have have the in-house expertise to solve the problem and you can bet they would have preferred a non-breaking change. Another example is systems with a plethora of applications and millions of LOC. A breaking change here can be hugely costly because of the accumulated time it takes to evaluate, fix and test each required change. In some cases the people that wrote the original code have moved on and nobody knows or understand what it does anymore. I see that daily (not the break, the lack of knowhow). Anyway, I don't think there much point in flogging this much more so I'll let you have the last word - I know you want it 🙂
  5. Anders Melander

    Check for override

    Ehem.. I think you should speak for yourself and not put these labels on the motives of other developers you know nothing about. Breaking backward compatibility is easy. Maintaining it is often very hard. I have seen many examples of projects that have stranded on old versions of 3rd party libraries because it was simply to costly to locate and fix breaking changes. That said I naturally agree that one should strive to move code forward and eliminate dependencies on backward compatibility.
  6. Anders Melander

    Check for override

    Are you saying that it wasn't worth it back when the change was made or that it isn't worth it anymore (i.e. today)? IMO the change was definitely worth it at the time because it didn't break backward compatibility and AFAIR didn't introduce new problems. They could have marked the old methods deprecated at some point and eventually retired it completely. AFAIK the change didn't introduce any new problems in older TStream descendants with 2+Gb files - it just made them possible going forward. If you have examples of bugs then I'd love to hear of them.
  7. Anders Melander

    Check for override

    Good thing you're not in charge of the RTL then. IRL backward compatibility matters.
  8. Anders Melander

    Check for override

    You're missing the point. The purpose was to provide backward compatibility for existing descendants of TStream - not existing code using TStream.
  9. Anders Melander

    Check for override

    ...or just see TStream.Seek(Longint, Word) in classes.pas.
  10. Anders Melander

    Trouble with (very) simple XML-parsing

    Why do you have this test? I would think that the second variant (LDocument.getElementsByTagName) would be good enough... I also think it would be safer if you used XPath or specified the path in your search criteria: LDocument.getElementsByTagName('/BkToCstmrStmt/Stmt/Acct/Id/IBAN');
  11. Anders Melander

    Right Process for Changing an Application's Icon?

    A word of warning to those (I'm counting 50 since yesterday) that downloaded this version: If your resources contains bitmaps that were created by older versions of Delphi (or rather applications built with older versions of Delphi) then the resource editor might corrupt them on save. It appears that a bug was introduced in TBitmap between Delphi 2009 and 10.2. Here's the short version: The format of a windows bitmap is basically 1) Header, 2) Color table, 3) Pixel data. For bitmaps with PixelFormat>pf8bit the color table is optional. The Header specifies the number of colors in the color table (the TBitmapInfoHeader.biClrUsed field). Older versions of Delphi sometimes saved bitmaps in pf24bit/pf32bit format with a color table and the corresponding value in the biClrUsed field. This was unnecessary but harmless and perfectly legal according to the bitmap specs. Here's an example of what such a bitmap might look like: [File header] [Bitmap header, biClrUsed=16, biBitCount=32] [Pixel data] These bitmaps can be read by newer versions of Delphi, but when the bitmaps are written again they become corrupt. Delphi keeps the value in the biClrUsed field but fails to write the corresponding color table. The result is that the pixel data ends up at the wrong file offset. Here's an example of a corrupt bitmap: [File header] [Bitmap header, biClrUsed=16, biBitCount=32] [Pixel data] The reason why this is a problem for the resource editor is that it is built with Delphi 10.2. I have a fix for the problem but I'm not ready to release a new version with the fix. Here's the fix btw: // Fix for bug in TBitmap. // Saving bitmap with PixelFormat>pf8bit with biClrUsed>0 fails to save the color table // leading to a corrupt bitmap. type TBitmapColorTableBugFixer = class helper for TBitmap type TBitmapImageCracker = class(TBitmapImage); public function FixColorTable: boolean; end; function TBitmapColorTableBugFixer.FixColorTable: boolean; begin if (TBitmapImageCracker(FImage).FDIB.dsBmih.biBitCount > 8) and (TBitmapImageCracker(FImage).FDIB.dsBmih.biClrUsed <> 0) then begin TBitmapImageCracker(FImage).FDIB.dsBmih.biClrUsed := 0; Result := True; end else Result := False; end; The problem appears to be the same one reported here: Setting TBitmap.PixelFormat can lead to later image corruption or EReadError
  12. Anders Melander

    Right Process for Changing an Application's Icon?

    Only because I've just uploaded a new version 🙂. It's been gone for at least 5 years. My ISP keeps flagging it as a virus (probably because it's built with Delphi) and taking it offline.
  13. Anders Melander

    Right Process for Changing an Application's Icon?

    It's my own. You can get it here: http://melander.dk/download/ResourceEditor20190309a.zip
  14. Anders Melander

    Right Process for Changing an Application's Icon?

    1) I don't know of any "approved process" apart from specifying an icon in the project options and, as you have discovered, that doesn't always work. Here's why: The default icon to use as the application icon is determined by Windows. Delphi has no control over it. Windows simply selects "the first icon" as the default application icon. The order of icons are determined by their resource ID/name (AFAIR this is only true for Delphi because Delphi sorts the resources at link time (which is actually a good thing as the alternative would means we had no control over what icon got selected (as we have no control over the order))). The Delphi project icon is always named (by Delphi) "MAINICON". If you add another icon to the project, and the name of that icon is sorted before MAINICON, then this icon will be ordered before MAINICON and will be selected by Windows as the application icon. For this reason I usually name my application icon "A" and add it as an external resource file to my projects. This way I don't have to worry about what other icons there might be added by 3rd parties (or other developers) and what their names are. The MAINICON I just ignore or load with the same icon as the "A" icon. 2) The icon size used for the forms depends on the size of the windows caption area, which depends on scaling/zoom, font sizes and so on. The icon is selected by Windows from the different sizes available in your application icon (or whatever icon you have associated with the form). -- See also: forms.pas (search for WM_SETICON and WM_GETICON)
  15. Then you shouldn't have mentioned it. If you post something as an example of a lock free implementation and it's clearly not thread safe, then I think it's fair that people are warned about that fact.
  16. You have a problem so you decide to use threads. you problems.2 have Now
  17. If you can live with FIFO LIFO/FILO/stack semantics then you can use Windows SLists. They're lock free and can be used with multiple readers and writers.
  18. There's at least one race condition. Stopped reading once I spotted it: if InterlockedDecrement(FActiveWriters) = 0 then FActiveWritersZeroEvent.SetEvent;
  19. Anders Melander

    How to identify problem remotely

    MadExcept: Main thread freeze checking http://help.madshi.net/HowToUseMadExcept.htm
  20. Anders Melander

    Version Control System

    I'd recommend SVN or GIT - and since someone dared to mention it, I'd also like to warn against TFS. It's an abomination and just a tiny improvement over VSS. In my experience the learning curve, if coming from VSS, is much smaller for SVN than for GIT. IMO the DVCS aspect of GIT is mostly hype since nobody uses it that way, but it does make it easy to work with local feature branches. If you need your source hosted in the cloud I think GIT is the best solution. There are SVN hosting solutions but in my experience they aren't very good. I personally prefer SVN as it matches the way I think better. I do use GIT but I really have to think hard about what I'm doing every time I need to do something with it. I can picture what I want to do in my head but have a hard time translating that to the available actions. For SVN I use TortoiseSVN and for GIT TortoiseGIT. I also have SourceTree v1 (v2 is a bad joke) but it's really slow to work with - and buggy. I didn't know there was a newer version, so I'll check that out.
  21. I believe this was addressed recently in Graphics32: TBitmap32 constructor access violation FWIW @Shrinavat you should have been able to determine the cause of the AV on your own by just looking at the call stack in the debugger. If this is beyond you then multi threading is not for you.
  22. Here's how I would solve it - in theory: Assign each tile a sequential number. Since you know the size of the target bitmap (TargetSizeX*TargetSizeY) and you know the size of each tile (TileSizeX*TileSizeY), calculating the tile number is simple: TileCountX := ((TargetSizeX + TileSizeX-1) div TileSizeX); TileCountY := ((TargetSizeY + TileSizeY-1) div TileSizeY); TileCount := TileCountX * TileCountY; // Tile number goes from 0 to TileCount-1 // Tile coords from Tile number TileX := (TileNumber mod TileCountX) * TileSizeX; TileY := (TileNumber div TileCountY) * TileSizeY; The job of reading a tile from the database can be delegated to one or more tasks, depending on how you choose to partition the workload. A DB tasks reads a request from a (threadsafe) queue, performs the database request, stores the result in the request object and notifies the requestor that the result is ready. The request object contains: 1) Tile number, 2) Result bitmap and 3) Signal object (e.g. an event handle). Create a number of tasks to render the tiles. Each task grabs a Tile Number (just use a InterlockedIncrement() on a shared integer), creates a DB request object, queues it and waits for the result. Once the result is ready the task draws the tile onto the target bitmap (*) and starts over. To avoid cache conflicts it would be best if the Tile Numbers currently being worked on are as far apart as possible, but I guess the DB overhead will make this optimization irrelevant. *) A TBitmap32 is just a chunk of sequential memory and since none of the tile tasks will write to the same memory it is not necessary to lock the target bitmap. So in short: One thread pool to render the tiles and one thread pool to read from the database. A work queue in between them. However like @Cristian Peța said, unless you are using some super fast ninja science fiction database, there's no reason to try to optime the rendering much. All the tiles can probably be rendered in the time it takes to make a single database request. In fact, using graphics32, a thread context switch will take far longer that drawing a single tile. So in practice I would probably just do away with the DB tasks and execute the database request directly from the rendering tasks.
  23. Anders Melander

    See content of a resource

    Not possible. Only the resource ID, type and content is stored in the executable. In other words: After a resource has been linked into an application there's no way of knowing where it came from.
  24. Hey, good idea: https://github.com/DelphiPraxis/The-Drag-and-Drop-Component-Suite-for-Delphi
  25. Anders Melander

    Microsoft Team Foundation System and Delphi

    For a minimal setup to use TFSV I suggest you use Team Explorer. It's basically just the VS shell with the TFS plugin. Here's the download: https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=TeamExplorer&amp;rel=15# And here's a brief intro of how to use it: https://docs.microsoft.com/en-us/azure/devops/user-guide/work-team-explorer?view=vsts @David Schwartz TFSV has always supported branching. It just isn't very good at it - like everything else in TFS. We use TFS with TFSV where I work ATM but I would gladly pay for JIRA licenses out of my own pocket if that would get them to switch away from TFS. It's horrible.
×