Jump to content

aehimself

Members
  • Content Count

    1030
  • Joined

  • Last visited

  • Days Won

    22

Posts posted by aehimself


  1. 9 hours ago, PeterPanettone said:

    TZipFile Update to the form, removed unused button and added label to show the… 19 days ago

    Were there any changes to TZipFile alltogether? I'd love to see native LZMA support and the ability to open some "corrupted" ZIP files too (like what 7Zip does).

    I have a file which was compressed by a C# code. Delphi either throws a "Invalid central header signature" exception, or manages to open the archive but sees no files in it.


  2. I read here on DelphiPraxis that the correct way to get a stack trace for anything is just to extract the stack addresses and translate those back to function names on the developers machine. I could achieve this with the suggestion here and with a custom .map file parser I can get the function names back but unfortunately there's too much trash. I also don't really understand this area, my parser was built by trial-and-error... better to let the experts handle this kind of thing.

    I know I could alter how DebugEngine actually displays the stack trace but it still needs a .map file (right next to the .exe or integrated as .smap) which is not just making it easier to attack the executable but easily adds ~40% to the size.

     

    I guess the question is... does DebugEngine support this already and if no would it be complicated to implement it?


  3. I'm using this code called from various places (e.g. WM_SIZE):

    Procedure TDBGrid.UpdateScrollBar;
    Var
     dataset: TZAbstractRODataSet;
     si: TScrollInfo;
    Begin
     dataset := Self.DataSource.DaaSet;
     If Assigned(dataset) Then
     Begin
       If Not dataset.Active Or (dataset.RecordCount <= Self.RowCount - 1) Then
         ShowScrollBar(Self.Handle, SB_VERT, False)
       Else
         Begin
           ShowScrollBar(Self.Handle, SB_VERT, True);
           If Win32MajorVersion >= 6 Then
             SetWindowPos(Self.Handle, 0, 0, 0, 0, 0, SWP_NOSIZE Or SWP_NOMOVE Or SWP_NOZORDER Or SWP_NOACTIVATE Or SWP_NOOWNERZORDER Or SWP_NOSENDCHANGING Or SWP_FRAMECHANGED);
           si.cbSize := sizeof(si);
           si.nMin := 1;
           si.nMax := dataset.RecordCount;
           si.nPos := dataset.RecNo;
           si.fMask := SIF_POS Or SIF_RANGE;
           SetScrollInfo(Self.Handle, SB_VERT, si, True);
         End;
       End
     Else
       ShowScrollBar(Self.Handle, SB_VERT, False);
    End;

    This should show the position correctly. To make it actually scroll the dataset, do

    Procedure TDBGrid.WMHScroll(Var Msg: TWMVScroll);
    Var
     dataset: TZAbstractRODataSet;
     si: TScrollInfo;
    Begin
     If (Msg.ScrollCode = SB_THUMBTRACK) Or
        (Msg.ScrollCode = SB_THUMBPOSITION) Then
     Begin
       dataset := Self.DataSource.DataSet;
       If Assigned(dataset) Then
       Begin
         si.cbSize := SizeOf(si);
         si.fMask := SIF_ALL;
         If Not GetScrollInfo(Self.Handle, SB_VERT, si) Then
           RaiseLastOSError;
         dataset.MoveBy(si.nTrackPos - dataset.RecNo);
         Msg.Result := 0;
       End
       Else
         inherited;
     End
     Else
       inherited;
    End;

    I think these two were necessary. If it doesn't work let me know and I'll check what else I added which changes this behavior.
     

    Edit: Misread the question, this still won't scroll while you are dragging. I'll leave the code here anyway - it might be useful for some.

     

    Edit-Edit: Extended my code with the suggestion of @Uwe Raabe, now it does update properly while the scrollbar is being dragged. Thank you!


  4. I don't know what causes this, but sometimes (even within the same project) this header menu item won't show correctly - neither of the draw methods are called. By experimenting I found out that turning OwnerDraw on on the popup menu itself fixes it on those affected.

    Anyone has any ideas? How come some menus work correctly without and some required OwnerDraw to call the menu items drawing methods?

     

    Edit: Also, assigning an imagelist fixes this, even if no menu items are using any image whatsoever.


  5. 2 hours ago, Anders Melander said:

    Given the minimal market share of XP

    What about Server 2003? Also, most built-in machines are still on XP (older ones can be even on 2k).

     

    What I loved about Delphi until now is that if you write the code thoughtfully it runs on Win2k up. And while I can understand the business decision behind this it still hurts a little 🙂

    • Like 1

  6. 1 hour ago, Ian Branch said:

    Error Handling - Not worth it in this case.  This may get used once a month, if that.

    It is intended to repeat every 60 secs as long as the message.txt lives.  Exiting the message.txt creating App deletes the file.

    Try-Finally bloc - Yup, will do that.

    TFileStream - Will look at.

     

    Thank you for your input/suggestions.

     

    Ian

    Sorry for my previous post being so blunt - I just had different matters to attend to and wanted to leave my comments.

     

    With the reappearance the issue is that if the user leaves his PC for half an hour, 30 dialogs will be shown as not even a modal window "blocks" processing further WM_TIMER messages. In these cases I'm usually wrapping the whole OnTimer event in a

    Timer.Enabled := False;
    Try
      [...]
    Finally
     Timer.Enabled := True;
    End;

    to make sure I'm not rendering my app in an unwanted state.

     

    As for the error handling even if this functionality is being used once in a lifetime it worths to add those extra 2-3 lines. Anything is more beautiful than the standard application error dialog 🙂

     

    Just my 2 cents.


  7.  

    On 9/12/2021 at 12:43 AM, Ian Branch said:

    Hi David,

    I ended up writing a little App to write a 'message.txt' file to the Apps root directory.  It deletes it when I exit the App.

     

    I then added the following code in a TTimer event..

    This code is completely missing error handling and does not consider access sharing and will read only the first line of the message. As an extra if the file is not deleted it will pop back up every 60 seconds.

     

    If {$I-}, use ERRORLEVEL to determine if the Reset was successful, if {$I+} swallow (or just politely indicate) the error.

    Wrap the Reset...ReadLn...Close to a Try-Finally bloc to ensure the file will be closed no matter what.

    As for access sharing you might want to use TFileStream instead with fmShareDenyNone.


  8. It seems so far that I solved the issue, the Internal Errors are gone - at least I can not reproduce them no matter how hard I abuse switching branches (where the component suite is the old) or building-installing.

    What I ended up doing was to have a runtime package, a design time package for component installation in the IDE and one more design time package for the property editors.

     

    This didn't work until I realized I set the required package of the property editors to the runtime package. In the moment I changed this so the property editors "only" require the first design time package, all started to work.

    During the trial process I also trashed several old units which function is now covered by Delphi itself and corrected some programming issues too but the error itself went away by changing the required package.

     

    I don't know what caused the issue at the first place (and more importantly why it went away...?) but this can be a possible solution too.


  9. I ended up combining the code of @chkaufmann and @Lars Fosdal plus added the always-disabled property. The end result fully supports VCL styles and looks awesome!

     

    image.png.24dbfb3db9f1edffc8d93b9cfea60ab1.png image.png.c2c322b1a072d35321eca2302ec5767b.pngimage.png.5acc5506b66c9ea8cedb604d492db7ea.png 

     

    The full code became:

    Unit uHeaderMenuItem;
    
    Interface
    
    Uses Vcl.Menus, Vcl.Graphics, WinApi.Windows, System.Classes;
    
    Type
     THeaderMenuItem = Class(TMenuItem)
     strict private
      Procedure SetEnabled(Const inEnabled: Boolean);
      Function GetEnabled: Boolean;
     protected
      Procedure AdvancedDrawItem(ACanvas: TCanvas; ARect: TRect; State: TOwnerDrawState; TopLevel: Boolean); Override;
      Procedure DoAdvancedDrawItem(Sender: TObject; ACanvas: TCanvas; ARect: TRect; State: TOwnerDrawState);
      Procedure Loaded; Override;
     Public
      Constructor Create(AOwner: TComponent); Override;
     published
      Property Enabled: Boolean Read GetEnabled Write SetEnabled;
     End;
    
    Implementation
    
    Uses Vcl.Themes, System.SysUtils;
    
    Procedure THeaderMenuItem.AdvancedDrawItem(ACanvas: TCanvas; ARect: TRect; State: TOwnerDrawState; TopLevel: Boolean);
    Begin
     Self.DoAdvancedDrawItem(Self, ACanvas, ARect, State);
    End;
    
    Constructor THeaderMenuItem.Create(AOwner: TComponent);
    Begin
     inherited;
    
     Self.Enabled := False;
     OnAdvancedDrawItem := DoAdvancedDrawItem;
    End;
    
    Procedure THeaderMenuItem.DoAdvancedDrawItem(Sender: TObject; ACanvas: TCanvas; ARect: TRect; State: TOwnerDrawState);
    Begin
     ACanvas.Brush.Color := TStyleManager.ActiveStyle.GetStyleColor(scPanelDisabled);
     ACanvas.FillRect(ARect);
     ACanvas.Font.Color := TStyleManager.ActiveStyle.GetStyleFontColor(sfWindowTextNormal);
     ACanvas.Font.Style := [fsBold];
     ACanvas.TextRect(ARect, ARect.Left + 3, ARect.Top + 3, StripHotkey(Caption));
    End;
    
    Function THeaderMenuItem.GetEnabled: Boolean;
    Begin
     Result := inherited Enabled;
    End;
    
    Procedure THeaderMenuItem.Loaded;
    Begin
     inherited;
    
     Self.Enabled := False;
    End;
    
    Procedure THeaderMenuItem.SetEnabled(Const inEnabled: Boolean);
    Begin
     inherited Enabled := False;
    End;
    
    End.

    • Like 4
    • Thanks 5

  10. My theory doesn't seem to work. I created a second design-time package and moved the property editors there as some property editors were using components which are to be installed in the very same package... no luck.

    Now the component package installs just fine, the package containing the property editors are throwing the errors.

     

    I read that the code in property editors have to be extra clean (no WITH statements, no "confusing" parts for the compiler) so I made a cleanup there too.


  11. @chkaufmann This looks awesome!

     

    Btw add Vcl.Themes to your uses list and use TStyleManager.ActiveStyle.GetStyleColor and GetStyleFontColor to add VCL style support to your code.

     

    Questions, though:

    - If you hover your mouse on the header does it get highlighted? I guess not because state is ignored in general but worth to ask...

    - This is my bigger issue: clicking on a header will close the menu, right? Maybe this can be fixed by overriding protected methods of the TMenuItem / TPopupMenu


  12. 34 minutes ago, Lajos Juhász said:

    Instead of adding the units from the runtime package into the design time you should add the runtime package as required. (The 32 bit version of the runtime package must inside the path).

    I just went to doublecheck, the runtime package is already included in the Requires section of my designtime package. Seems I added it, I just forgot 🙂


  13. Hello,

     

    We had a large legacy component suite which I managed to split into Runtime and Design time packages in preparation to be able to build our application in 64 bit. I don't have much experience, so what I did was, basically:

    - Created a new package, set it as runtime only, moved all contains and requires section from the old suite

    - Created a new package, set it as design time only

    - Attempt to compile the runtime package

    - Move units to the design time package which blocks compilation (has references to designide, etc)

    - Repeat until both packages compiled error free

    - Added "implicitly imported" units to design time package

     

    All works fine, except one strange issue. Delphi chooses a seemingly random unit and throws an Internal Error when I want to install the package (compiling works fine both in 32 bit Debug / Release).

    Here's the twist: if I close Delphi, modify the unit with VS code and add a line break to the end of the unit (or remove one - basically change something completely insignificant) and save, reopen and install - all works just fine.

     

    I'm wondering if I missed something when creating the packages? Did anyone face this before? Does anyone has any tips I can check?

     

    Thank you!


  14. 5 minutes ago, Lars Fosdal said:

    Have you checked if your app receives any notification after the installation of the font?

    There is no automatic notification as far as I'm aware, but the app receives the WM_FONTCHANGE message which was broadcasted. In the discussion on GitHub I mentioned that if I put a label on the form, set the font name to the same as in the ListView and paste some characters it shows up correctly without PostMessage / Sleep. This makes me believe that the installation is successful, only GDI+ needs some time before it can access a freshly installed font (or implementation is not correct). Unfortunately I have zero experience with any graphic-related stuff so can not confirm / debug :(

    10 minutes ago, Lars Fosdal said:

    A sleep seems so random... what if the system is REALLY busy so that the sleep is too short?

    This is why it's not even viable as a workaround imo.


  15. Is it just me, or even the demo application does not import the font file properly when started for the first time?

     

    image.thumb.png.7ee843c7cdfa6bffe6b48152c9d1fc9c.png

     

    If the font is installed on the system (manually or by AddFontResource due to the first run) everything appears correctly.

     

    I tried Screen.ResetFonts and ImageList.RecreateBitmaps after the SendMessage, without success. Dumping everything on the disk with .SaveToPngFiles also saves the rectangles only.

     

    I'm using the latest snapshot from Git directly.


  16. My forever favorite stays this:

    Function GetUserID(APageIndex: Integer): Integer;
    Begin
     Case APageIndex Of
       0: Result := -1;
       1: Result := -1;
       2: Result := -1;
       3: Result := -1;
       [...]
       50: Result := -1;
       Else Result := -1;
    End;

    Probably it had functionality a long time ago, but this method was still called from a live part of the code when I found it...!

     

    There were also some fancy fails (mainly memory leaks), including but not limited to:

    TMyClass = Class(TObject)
    private
     FOwner: TComponent;
    public
     Constructor Create(AOwner: TComponent); ReIntroduce;
    End;
    
    Constructor TMyClass.Create(AOwner: TComponent);
    Begin
     FOwner := AOwner;
    End;

    Or the other, which was probably a typo but took me a while to finally realize the issue:

    TMyClass = Class(TComponent)
    public
      Constructor Create(AOwner: TComponent); Override;
    End;
    
    Constructor TMyClass.Create(AOwner: TComponent);
    Begin
     inherited Create(Owner);
    End;

     

    • Like 1
×