Jump to content

Anders Melander

Members
  • Content Count

    2312
  • Joined

  • Last visited

  • Days Won

    119

Posts posted by Anders Melander


  1. 15 minutes ago, Stano said:

    resourcestring aa = 'bbb';

    If you are not actually using that string anywhere then it's probably being eliminated by the linker.

    Resourcestrings are only ever loaded from STRINGTABLE resources and the STRINGTABLE resources (and the .drc file) are produced by the linker based on the units linked into the application.

     

    If you add a ShowMessage(aa) to the above example then I bet the resourcestring will appear.

     

    Regardless, I think we can conclude that this isn't a BTM problem.


  2. Can you see the resourcestring in the .drc file?

     

    [edit] Btw, have you remembered to update the translation project after these changes?

    image.png.e80886c2a405f0d926238b20868af6d9.png

    If you don't update the translation project it will only contain the strings that were in your project when you created the translation project.


  3. 40 minutes ago, Stano said:

    I have: amTranslationManagerInstall-2.0.8370.39904 - year 2019 

    That's the newest release; It's from December 2022. I don't know where you you got the year 2019 from.

     

    25 minutes ago, Stano said:

    No, it's not there. The point is that it's a custom navigator drop on the form.
    Maybe something needs to be done in component.

    Nothing special needs to be done.

     

    If the resourcestring is implemented in unit XXX and you drop a component from XXX onto a form in unit YYY of project ZZZ, then the IDE will include unit XXX in unit YYY's uses clause and when you compile ZZZ, the resourcestring will appear in the ZZZ.drc file (it's a text file) located the sample place as ZZZ.exe.

    If you don't have ZZZ.drc then you need to configure your project to produce that file (see the project linker options) - but BTM should complain if it can't find the file.


  4. I'm still not sure what you're saying - or asking.

     

    You hide rows by filtering them out: Hover over the Status column header, click the button that appears in the header. Select the statuses that should be visible. Like in my screenshots.

     

    17 hours ago, Stano said:

    My point is whether the custom component can be translated.

    That's not really a question, but anyway: If your component strings appear in the string grid, then they can be translated; All resourcestrings and published component string (and string list) properties can be translated.


  5. I doubt that it's DevExpress that's slowing your project load down. I always have it installed and do not have any problems with it.

     

    It's more likely the livebindings design-time support that's the culprit (at least it used to be a common cause of slow downs). Try disabling the livebindings design time packages and see if that helps. The attached .reg file does that for Delphi 10.3, 10.4, and 11.x

    You may need to reinstall DevExpress afterward as I believe some of their packages have dependencies on the livebindings packages.

    disable delphi livebindings.reg


  6. 2 hours ago, angusj said:

    If you're only searching by filename or file type (*.jpg;*.png; etc) then the filesystem would suffice.

    Why would that make a difference? The whole directory/tree would need to be scanned anyway, even if he's only interested in the image files.

    [edit] Oh, I guess you mean select files based on the filename as opposed to the file content.

     

    I would probably go for an in-memory database (e.g. SQLite or even just a TFDMemTable) for the index but store the files on disk (but don't put all files in a single folder - that will suck). That said, if you have 50K files averaging 30Kb each, that's only 1,5 Gb total (+ overhead) so you could actually fit the whole thing in memory.


  7. 52 minutes ago, David Schwartz said:

    I think there's also a book by Ray Litchke.

    Ray Lischner. He wrote 3 Delphi books, AFAIR, none of them about component design. I've got "Delphi in a Nutshell" (basically just a reference book) and "Hidden Paths of Delphi 3" (about the old open tools API). Both had horrible binding and fell apart right away.


  8. 17 hours ago, weirdo12 said:

    Was that meant as a dis of SQLite - did I read that right?

    It was aimed at SQLite but it was not meant as a dis. As long as the limitations and risks are taken into account it's a fine embedded database engine.

     

    I haven't used it in a while but I have just read through the technical documentation and I can see that a lot has been done with regard to reliability since then. Still, after having read the docs I couldn't help but feel that there were problem areas that were brushed over or simply left out.


  9. You (mostly) just need to derive your class from TComponent:

    type
      TFruit = class(TComponent)
      private
        FColor: string;
      protected
      public
        constructor Create(AOwner: TComponent); override;
      published
        property Color: string read FColor write FColor;
      end;

    ...and then you also need to register your component:

    procedure Register;
    begin
      RegisterComponents('Cool Stuff', [TFruit]);
    end;

     

    I suggest you read the documentation.

    • Like 1

    1. Create the TFDConnection in code (e.g. in the DM constructor).
    2. Open the connection after the DM has been created.

    For complex applications, I use a design where the application startup is divided into stages. The stage progression is centrally controlled and broadcast to all interested parties.

    Something like this:

    // The following could be in the .dpr file
    type
      TRunStageBoot = bsInit..bsReady;
      TRunStageShutdown = bsShutdown..bsShutdown;
    begin
      // Broadcast startup progression
      for var Stage := Low(TRunStageBoot) to High(TRunStageBoot) do
        RunStageNotify(Stage);
          
      Application.Run;
      
      // Broadcast shutdown progression
      for var Stage := Low(TRunStageShutdown) to High(TRunStageShutdown) do
        RunStageNotify(Stage);
    end.

    ...and the run stage management:

    type
      TRunStage = (
        bsInit,			// Whatever needs to run before the DMs are created. E.g. load config.
        bsCreateModules,		// Create DMs
        bsConnectDatabase,		// Connect to database
        bsLoadDatabaseSchema,	// Validate and update database schema
        bsLogin,			// Perform application login
        bsInitUI,			// Create main UI (e.g. mainform)
        bsReady,			// Show UI
        bsShutdown			// Application shutdown
       );
      
      IRunStageSubscriber = interface
        {...GUID...}
        procedure RunStageNotify(Stage: TRunStage);
      end;
    
      TRunStageDelegate = reference to procedure(Stage: TRunStage);
    
    procedure RunStageNotify(Stage: TRunStage);
    
    procedure RegisterRunStageHandler(Delegate: TRunStageDelegate); overload;
    procedure RegisterRunStageHandler(const Subscriber: IRunStageSubscriber); overload;
    // ...similar for unsubscribe...
    
    implementation
    
    var
      // Create on demand in RegisterRunStageHandler. Free in finalization.
      RunStageSubscribers: TList<IRunStageSubscriber>; 
      RunStageDelegates: TList<TRunStageDelegate>;
      
    procedure RegisterRunStageHandler(Delegate: TRunStageDelegate);
    begin
      RunStageDelegates.Add(Delegate);
    end;
    
    procedure RegisterRunStageHandler(const Subscriber: IRunStageSubscriber);
    begin
      RunStageSubscribers.Add(Subscriber);
    end;
    
    procedure RunStageNotify(Stage: TRunStage);
    begin
      for var Subscriber in RunStageSubscribers do
        Subscriber.RunStageNotify(Stage);
        
      for var Delegate in RunStageDelegates do
        Delegate(Stage);
    end;
    ...

    ...and the DM with the connection would then look something like this:

    type
      TDataModuleDatabase = class(TDataModule, IRunStageSubscriber)
      private
        FConnection: TFDConnection;
      private
        // IRunStageSubscriber
        procedure RunStageNotify(Stage: TRunStage);
      public
        constructor Create(AOwner: TComponent); override;
      end;
    
    var
      DataModuleDatabase: TDataModuleDatabase;
    
    implementation
    
    constructor TDataModuleDatabase.Create(AOwner: TComponent);
    begin
      inherited;
      FConnection := TFDConnection.Create(Self);
      // Setup params on connection
      ...
    
      // Register so we will be notified when the connection should be opened
      RegisterRunStageHandler(Self);
    end;
    
    procedure TDataModuleDatabase.RunStageNotify(Stage: TRunStage);
    begin
      case Stage of
        bsConnectDatabase:
          FConnection.Open;
      end;
    end;
    
    procedure RunStageNotify(Stage: TRunStage);
    begin
      case Stage of
        bsCreateModules:
          DataModuleDatabase := TDataModuleDatabase.Create(Application);
      end;
    end;
    
    initialization
      // Register so we will be notified when the DM should be created
      RegisterRunStageHandler(RunStageNotify);
    end;

     

    • Like 2

  10. 15 minutes ago, Willicious said:

    I take it VTune is the Profiler... what is the MAP2PDB for?

    Did you read the page linked to? First paragraph states:

    Quote

    map2pdb is a tool used to convert the MAP files produced by the Delphi and C++ Builder compilers to Microsoft PDB files for use in tools that support that format.

    [edit] I guess you don't know what the PDB file is for.

    The PDB file is used by the profiler to map the addresses in the application being profiled to source files, function names, and line numbers. Without that information, the profiler would only be able to show you the raw addresses.

     

    15 minutes ago, Willicious said:

    Not sure where to start.

    1. Download and install VTune.
    2. Download map2pdb, extract the exe, and save it somewhere of your choice. For example c:\tools\map2pdb\map2pdb.exe
    3. Add a menu item in the Delphi IDE via Tools -> Configure Tools...
      image.thumb.png.a1e3d211c2e66ad52835eb79e136db49.png
    4. The parameters in the above are: -debug -v -pause -bind:$EXENAME $PATH($EXENAME)$NAMEONLY($EXENAME).map -include:0001
    5. Make sure the compiler are generating a full map file:
      image.thumb.png.61144d5409219b54b19e65c42e2245cc.png
    6. Compile your project.
    7. Execute the map2pdb tool action.
    8. Launch VTune and create a profiler project for your exe.
    9. Profile the project in VTune.
    10. Profit!
    • Like 1

  11. 8 hours ago, David Heffernan said:

    How?????  

    The trigger is the presence of the "⁄" character anywhere in the text. It's the Unicode "Fraction Slash".

    It can be reproduced with the GDI ExtTextOut function, which is how I accidentally discovered it.

    image.thumb.png.890b6039b7dad8644b61206a42764d18.pngimage.thumb.png.0bc04d7c0bb8396cfbb617729140e5d3.png

     

    I suspect that this is actually a bug in GDI because as far as I can tell there's nothing in the font tables that should require that character to be present before ligatures are applied. It could also be a bug in the font that triggers a bug in GDI; There are a lot of bugs in Cascadia and Fira.

     

    Normally, in an OpenType shaper, the fraction slash triggers hardcoded logic ("hardcoded" as in "logic not defined in the OpenType tables") that converts numeric fractions from the form 1/2 to ½ but that requires the 'frac' feature to be enabled which it isn't by default.

    image.thumb.png.42c2490a3f8e59bdbd3c62067bd31956.png


  12. On 6/29/2023 at 9:11 AM, David Heffernan said:

    Hyoerthreading is probably useless. I've never found a task which benefits from it. I guess they must exist though, or is it just pure marketing?

    Marketing.

    I don't think they originally intended it as such but since it at best doesn't hurt performance, that's what it became.

    1 hour ago, David Heffernan said:

    Doesn't memory already handle all of this? I mean, the paging system does all of this already surely? 

    Yes, it does.

    47 minutes ago, A.M. Hoornweg said:

    I really don't know how it behaves if you try to allocate one huge chunk that is bigger than what the machine has physically.

    Maybe now would be a good time to read up on what virtual memory is.

    You don't have to allocate beyond physical memory before virtual memory comes into play. You just have to allocate beyond the process' working set. The working set is the part of your process' virtual memory that is backed by physical memory. The working set can grow and shrink depending on memory access and global resource pressure but there's always an upper and lower limit. Of course, it's a bit more complicated than that (there are more layers than what I have described) but that's the basic overview.

    In general, I would recommend that one doesn't try to outsmart things one doesn't fully understand. Be it threading, memory management, or women 🙂

    • Like 2

  13. In the end, I had to abandon PUCU as the author never bothered to react to my bug reports.

    Instead, I tried to adapt the JEDI implementation: I removed all dependencies and fixed the worst bugs and performance issues. Finally, I ran the code against my unit tests. The result was a big disappointment; While it didn't crash like PUCU, it failed even more of the test cases. The test suite uses the 19,000 NFC (compose) and NFD (decompose) normalization test cases published by the Unicode consortium.

     

    So back to square one again. Comparing the algorithms used by the JEDI library against countless (I've looked at over a hundred) other Unicode libraries didn't reveal the cause. They all used the same algorithms. Blogs and articles that described the algorithm also matched what was being done. I was beginning to suspect that Unicode's own test cases were wrong, but then I finally got around to reading the actual Unicode specification where the rules and algorithms are described, and guess what - Apart from Unicode's own reference library and a few others, they're all doing it wrong.

     

    I have now implemented the normalization functions from scratch based on the Unicode v15 specs and all tests now pass.

    The functions can be found here, in case anyone needs them: https://gitlab.com/anders.bo.melander/pascaltype2/-/blob/master/Source/PascalType.Unicode.pas#L258

    Note that while the functions implement both canonical (NFC/NFD) and compatible (NFKC/NFKD) normalization, only the canonical variants have been tested as they are the only ones I need.

    • Like 1
    • Thanks 4

  14. 8 hours ago, Patrick PREMARTIN said:

    Thanks for having opened an issue, it will be easier to follow at https://quality.embarcadero.com/browse/RSP-41896

    The bitmap in that issue is a version 1 BMP in BI_RGB format so the problem I mentioned does not apply.

     

    Issue RSP-37651 might be related. According to that issue, it's fixed in 11.2 but as far as I can tell from looking at the source in 11.2 it hasn't been fixed. At least not in the way suggested by the reporter.


  15. I don't have time to look at the source but if the bitmap being pasted is a 16 or 32-bit BMP bitmap with BI_BITFIELDS encoding then the problem can be that Delphi's TBitmap doesn't really support the nuances of that format.

    The BI_BITFIELDS format uses 3 (or 4, depending on the BMP version) mask values that specify the layout of the RGB channels in the pixel values and AFAIR TBitmap ignores the mask values and instead assumes a certain layout.

×