Jump to content

Anders Melander

Members
  • Content Count

    2312
  • Joined

  • Last visited

  • Days Won

    119

Posts posted by Anders Melander


  1. 1 hour ago, Fr0sT.Brutal said:

    Thanks! I'm now making my own translation system and already got used to res strings incl pointers to them. However, AFAIU there's a drawback in their organization - their codes are consistent only within single binary, any change in their order or number and rebuilding causes part of them to shift. So these numbers couldn't be used as IDs in translation files. Of course DRC file could help but some automated check must be run to control translation files consistency or just use built-in values as keys (I'm now building the latter approach).

    If only someone had already solved all those problems...

     

    1 hour ago, Fr0sT.Brutal said:

    While currently I don't need another platforms but in theory it could be Linux. I'm curious what people do with res strings on that platform?

    I haven't tried it but I would just compile for Linux and see what it produces.


  2. On 6/21/2023 at 11:04 AM, Fr0sT.Brutal said:

    How is best to have them localized?

    Like this:

    https://bitbucket.org/anders_melander/better-translation-manager/src/f96e7dcdba22667560178d32aebb5137484107f0/Source/amLocalization.Model.pas?at=master#lines-578

    // -----------------------------------------------------------------------------
    //
    // Strings
    //
    // -----------------------------------------------------------------------------
    resourcestring
      sTranslationValidationWarningEmptyness        = 'Source or translation is empty and the other is not';
      sTranslationValidationWarningAccelerator      = 'Accelerator count mismatch';
      sTranslationValidationWarningFormatSpecifier  = 'Format specifier count mismatch';
      sTranslationValidationWarningLineBreak        = 'Linebreak count mismatch';
      sTranslationValidationWarningLeadSpace        = 'Leading space count mismatch';
      sTranslationValidationWarningTrailSpace       = 'Trailing space count mismatch';
      sTranslationValidationWarningTerminator       = 'Translation is terminated differently than source';
      sTranslationValidationWarningPipe             = 'Pipe character count mismatch';
      sTranslationValidationWarningSurround         = 'Surround character mismatch';
    
    const
      // Note: Must use PResStringRec or values will be of the language active at the time System._InitResStrings was called,
      // which means that the user language selection will not affect the values as it should.
      sTranslationValidationWarnings: array[TTranslationWarning] of PResStringRec = (
        @sTranslationValidationWarningEmptyness,
        @sTranslationValidationWarningAccelerator,
        @sTranslationValidationWarningFormatSpecifier,
        @sTranslationValidationWarningLineBreak,
        @sTranslationValidationWarningLeadSpace,
        @sTranslationValidationWarningTrailSpace,
        @sTranslationValidationWarningTerminator,
        @sTranslationValidationWarningPipe,
        @sTranslationValidationWarningSurround);

     and then use the strings like this:

    https://bitbucket.org/anders_melander/better-translation-manager/src/f96e7dcdba22667560178d32aebb5137484107f0/Source/amLocalization.Dialog.Main.pas?at=master#amLocalization.Dialog.Main.pas-2600

    Item.Caption := LoadResString(sTranslationValidationWarnings[Warning]);

     

    FWIW, I believe this is also the way the VCL/RTL itself does it.

    • Like 1

  3. 2 hours ago, Brandon Staggs said:

    You would use a docking system instead

    The problem with docking is that most users don't understand how to use it. I mean, if they have problems with maximized MDI forms, docking isn't going to be easy to understand.

     

    That said, one could use docking with manual docking disabled. That way it's just used to organize the forms into a fixed layout.


  4. I used to work on a project that allowed the user to switch between SDI and MDI. We used DevExpress, FWIW.

     

    As far as I can see from the code, all I did to make it work was set Visible=False on the child form before changing FormStyle and set Visible=True after.

    You'll also need to adjust the size/position and maybe also the BorderIcons; In our application, we hid the Maximize button in MDI mode because the maximized form would hide the MDI icons (the buttons representing the other, minimized, MDI children) and the user would get confused. As far as I recall we also manually managed the layout of child-forms in MDI mode.

     

    Also, and I'm working from 6-7 year old memory here, I believe you need to have Formstyle=fsMDIForm on the main form and keep it that way. MDI child forms are made visible in their constructor (TCustomForm.Create probably) or when FormStyle is set. To avoid that, in the child form constructor, you need to Include(FFormState, fsCreating) before setting FormStyle, set FormStyle and then Exclude(FFormState, fsCreating). You also need to Exclude(FFormState, fsVisible) to avoid the form being shown when the constructor exits.


  5. On 6/3/2023 at 9:36 PM, Patrick PREMARTIN said:

    Cary's book is still the reference, even if it's old and some things have changed in FireDAC. It remains the best resource for understanding the framework and the interactions between its components.

    In my opinion, the online help is better.

    I bought the book a few years ago when I was about to transition a system from ADO to FireDAC and I found the book to be completely useless. It covers the basics, but so does the help and the help is up to date. Advanced topics are barely covered at all.

    • Like 1

  6. 13 minutes ago, Jan Rysavy said:

    Well done, you're only one bit away from success!

    On offset 0x1000 set bit 0x00000008:

    Ah... That must be this block:

      // Write an empty block just so our layout matches LLVM.
      // This can be removed once our output is validated.
      FWriter.BeginBlock;
      FWriter.Write(Byte(0));
      FWriter.EndBlock;

    The block doesn't appear in any stream so it must be marked free. It's block #3 = bit 3 = 0x00000008

    I'll try to remove the block instead first. Stay tuned...

     

    Btw, I think I now know what checkInvariants is doing.

    What threw me was that it appeared to be modifying the FPM and I couldn't understand the purpose of that since it would have made the FPM unusable afterwards. I think it's working on a copy of the FPM; It marks all blocks found in a stream as free (in the FPM copy) and once it has done that for all the streams it checks if all blocks are now marked free.

     

    And well done, yourself!

     

    This looks interesting 🙂

    image.png.6e2228722cb19dec14e22aefc736a1fc.png

    • Thanks 1

  7. 16 minutes ago, Anders Melander said:

    By the way, stream #0 is reserved for "a copy of the previous version of the stream directory". It should be empty, so there is no "first page" in it.

    Output from : llvm-pdbutil dump -summary -streams -stream-blocks <pdbfile>

                              Summary                           
    ============================================================
      Block Size: 4096
      Number of blocks: 85
      Number of streams: 47
      Signature: 0
      Age: 1
      GUID: {CDAF4F74-CCFB-6F40-A551-C2BEE853FBEF}
      Features: 0x1
      Has Debug Info: true
      Has Types: true
      Has IDs: true
      Has Globals: true
      Has Publics: true
      Is incrementally linked: false
      Has conflicting types: false
      Is stripped: false
    
    
                              Streams                           
    ============================================================
      Stream  0 (    0 bytes): [Old MSF Directory]
                 Blocks: []
      Stream  1 (   75 bytes): [PDB Stream]
                 Blocks: [65]
      Stream  2 (   56 bytes): [TPI Stream]
                 Blocks: [66]
      Stream  3 ( 5527 bytes): [DBI Stream]
                 Blocks: [80, 81]
      Stream  4 (   56 bytes): [IPI Stream]
                 Blocks: [82]
      Stream  5 (58764 bytes): [Module "System"]
                 Blocks: [4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18]
      Stream  6 ( 2392 bytes): [Module "SysInit"]
                 Blocks: [19]
      Stream  7 (   56 bytes): [Module "System.Types"]
                 Blocks: [20]
      Stream  8 (   64 bytes): [Module "System.UITypes"]
                 Blocks: [21]
      Stream  9 ( 1132 bytes): [Module "Winapi.Windows"]
                 Blocks: [22]
      Stream 10 (   56 bytes): [Module "System.SysConst"]
                 Blocks: [23]
      Stream 11 (   88 bytes): [Module "Winapi.PsAPI"]
                 Blocks: [24]
      Stream 12 (   56 bytes): [Module "System.RTLConsts"]
                 Blocks: [25]
      Stream 13 (12756 bytes): [Module "System.Character"]
                 Blocks: [26, 27, 28, 29]
      Stream 14 (   28 bytes): [Module "System.Internal.ExcUtils"]
                 Blocks: [30]
      Stream 15 (24016 bytes): [Module "System.SysUtils"]
                 Blocks: [31, 32, 33, 34, 35, 36]
      Stream 16 (  132 bytes): [Module "TestMAP2PDB"]
                 Blocks: [37]
      Stream 17 (  248 bytes): [Module "System"]
                 Blocks: [38]
      Stream 18 (   72 bytes): [Module "SysInit"]
                 Blocks: [39]
      Stream 19 (   72 bytes): [Module "System.UITypes"]
                 Blocks: [40]
      Stream 20 (   88 bytes): [Module "Winapi.Windows"]
                 Blocks: [41]
      Stream 21 (   72 bytes): [Module "Winapi.PsAPI"]
                 Blocks: [42]
      Stream 22 (   72 bytes): [Module "System.Character"]
                 Blocks: [43]
      Stream 23 (   64 bytes): [Module "System.Internal.ExcUtils"]
                 Blocks: [44]
      Stream 24 (  864 bytes): [Module "System.SysUtils"]
                 Blocks: [45]
      Stream 25 (  136 bytes): [Module "TestMAP2PDB"]
                 Blocks: [46]
      Stream 26 (   28 bytes): [Module "System"]
                 Blocks: [47]
      Stream 27 (   28 bytes): [Module "SysInit"]
                 Blocks: [48]
      Stream 28 (   28 bytes): [Module "Winapi.Windows"]
                 Blocks: [49]
      Stream 29 (   28 bytes): [Module "System.Internal.ExcUtils"]
                 Blocks: [50]
      Stream 30 (   28 bytes): [Module "System.SysUtils"]
                 Blocks: [51]
      Stream 31 (   28 bytes): [Module "System"]
                 Blocks: [52]
      Stream 32 (   28 bytes): [Module "SysInit"]
                 Blocks: [53]
      Stream 33 (   28 bytes): [Module "System.UITypes"]
                 Blocks: [54]
      Stream 34 (   28 bytes): [Module "Winapi.Windows"]
                 Blocks: [55]
      Stream 35 (   28 bytes): [Module "Winapi.PsAPI"]
                 Blocks: [56]
      Stream 36 (   28 bytes): [Module "System.Character"]
                 Blocks: [57]
      Stream 37 (   28 bytes): [Module "System.Internal.ExcUtils"]
                 Blocks: [58]
      Stream 38 (   28 bytes): [Module "System.SysUtils"]
                 Blocks: [59]
      Stream 39 (   28 bytes): [Module "TestMAP2PDB"]
                 Blocks: [60]
      Stream 40 (   28 bytes): [Module "System"]
                 Blocks: [61]
      Stream 41 (   28 bytes): [Module "System.SysUtils"]
                 Blocks: [62]
      Stream 42 (  212 bytes): [Module "* Linker *"]
                 Blocks: [63]
      Stream 43 (  436 bytes): [Named Stream "/names"]
                 Blocks: [64]
      Stream 44 (30880 bytes): [Symbol Records]
                 Blocks: [67, 68, 69, 70, 71, 72, 73, 74]
      Stream 45 (   16 bytes): [Global Symbol Hash]
                 Blocks: [75]
      Stream 46 (15288 bytes): [Public Symbol Hash]
                 Blocks: [76, 77, 78, 79]

     


  8. 3 hours ago, Jan Rysavy said:

    In our case we fail with sn == 0 (first stream) and spn == 0 (first page of first stream)

    By the way, stream #0 is reserved for "a copy of the previous version of the stream directory". It should be empty, so there is no "first page" in it.

     

    9 minutes ago, Attila Kovacs said:

    free page number

     

    image.thumb.png.03bb9de525b97fe58fbad07ed1bd2201.png


  9. 3 hours ago, Jan Rysavy said:

    There are these two loops visible in disassembler

    
    assert(validPn(pn));
    assert(!fpm.isFreePn(pn));
    assert(!fpmFreed.isFreePn(pn));
    assert(!fpmInUse.isFreePn(pn));
    fpmInUse.freePn(pn);

     

    I can't match that with my assumption that I've incorrectly marked a block as allocated (i.e. the corresponding bit is set).

    As far as I can tell that code verifies that the block number is valid and that the block is marked as allocated. I have no idea about what the call to FreePn does.


  10. 1 minute ago, Jan Rysavy said:

    I don't understand exactly what you mean, can you elaborate on this point? I'd be happy to help...

    Like you did here:

    Quote

    Another idea: I found what part of PDB they are reading in loc_1800FCE71, instruction mov     rax, qword ptr [r14+rax*8].

    It is on offset 0x1008 of attached PDB, see TestMAP2PDB.zip. Does it help?

     

    I'm assuming the function that tests the bit is passed a block number which it then translates to an offset into a qword array (BlockNum and (not 63)) and a bit number into the qword (BlockNum and 63). Where does this block number come from?

    I.e. if you could apply your magic 🧙 and find out what offset in the PDB file is supplying the block number then we will have a better idea of what the problem is.


  11. 5 hours ago, Berocoder said:

    So I tried to compile it with Optimization on as that is a cheap way to increase performance.

    I'm surprised that something like ERP would benefit much from that. Do you have any numbers?

     

    Apart from that, like David, I have good experience with madExcept: No problems with optimization being on.

    • Like 2

  12. 4 hours ago, Jan Rysavy said:

    In memory they are accessing FPM bit-field using QWORDs in x64 and DWORDs in x86

    Yes. I understood the scheme; I was more concerned about if we are addressing the same bits.

    What got me a little confused is that I'm doing a lot of work with big-endian data (TrueType fonts) on another project at the moment where the QWORD/BYTE size would have mattered. However, since we are both using little-endian addressing that's not a problem here.

     

    No, I think the problem is that I'm marking a block as allocated even though it's free.
    When setting the bits that mark a block as allocated I'm taking advantage of the fact that I have no free blocks in the physical file. I write everything sequentially and only once. Since I keep a count of how many blocks the file contains (that's recorded in the header/superblock at the end), I can simply set the required amount of bits once everything has been written.
    One possible problem here is that I might be using the wrong block concept for the block numbers in the bitmap. There are physical blocks that have a direct and linear mapping to their position in the file and then there are logical blocks that exclude stuff like the superblock and the free page maps (FPM). Since the position of the superblock and the FPMs are fixed it would make sense to exclude them from the bitmap (i.e. it maps to logical blocks).

    I can try and see if it makes any difference to use logical instead of physical block numbers in the FPM.

     

    In your test case, the bit in the MAP2PDB PDB is set (i.e. block is allocated) and in the MSVC PDB the bit is clear (i.e. block not allocated).
    We cannot expect the same bits to be set since we are storing different data in the two files, however, since it seems the failure occurs because the bit is set in our file msdia140.dll apparently expect the bit to be clear so the problem must be that I have marked a block as allocated even though it doesn't appear in any stream (or rather in any stream directory).

     

    If you can find out where in the PDB file the bit address (i.e. the block number) being tested comes from, I should be able to narrow the cause down even more.


  13. 2 hours ago, Jan Rysavy said:

    Another idea: I found what part of PDB they are reading in loc_1800FCE71, instruction mov     rax, qword ptr [r14+rax*8].

    It is on offset 0x1008 of attached PDB, see TestMAP2PDB.zip. Does it help?

    As far as I can tell it's the Free Page Map. This matches with the fact that the asm is doing bit tests.

    image.thumb.png.b6bc94756a872d0367bd8c7bf1b1a123.png

     

    If it's blocking the bitmap into qwords then that might be the problem. I'm blocking it into bytes.

    To mark block 1 as allocated I would set bit 0 of the first byte, block 9 would be bit 0 of the second byte, etc. It could be that I should be using another bit-layout.

     

    It could also be that I'm simply not marking all the blocks allocated that I should - or too many.

     

×