Jump to content

Stéphane Wierzbicki

Members
  • Content Count

    230
  • Joined

  • Last visited

Posts posted by Stéphane Wierzbicki


  1. 10 hours ago, Stefan Glienke said:

    If you mean to move the items then you need to loop or use .ToArray on the TList as the IList interface does not offer any overloads accepting a TList<T> or TEnumerable<T> from System.Generics.Collections and that will not change.

    Thanks for your reply. Object's lifetime cycle is actually handle by Aurelius' manager. Object's stored within TList are only queried for additional checks, needs to see TList acting like a cache. 

     

    I'll then use .ToArray and then free TList.

     

    Ps: @Wagner Landgraf it will be nice allowing TMS Biz products using Spring4D library 😄

     

     


  2. 38 minutes ago, limelect said:

    At the list, your site should be translated.

    You meant "At the least"?

     

    I agree, if he want to attract more users, it is more than necessary to have English content.


  3. 3 hours ago, vhanla said:

    Thanks, actually changing GWL_EXSTYLE with SetWindowLong is for hiding it from Alt Tab list. Tried that too, it still shows the taskbar button for a very little amount of time, then it disappears. Unlike VCL applications, FMX applications somehow still tries to show its taskbar icon.

     

    `ApplicationHWND` itself without even creating form neither running it, shows its taskbar icon.

     

    e.g. in projects file (dpr) I uncomment Application.CreateForm... and Application.Run;

    but add var Handle := ApplicationHWND; after Application.Initialize; the taskbar icon is created and obviously hidden since application terminates after that.

    image.png.0ed52ee52288420dde4cf462b9063337.png

    When that incompleted FMX application is launched, current foreground application (e.g. explorer) is lost and focuses on a non visible application (our app) just to return to the original foreground window (since it terminates), weird thing is taskbar still shows its icon "flashing" to fastly disappear.

    image.png.27af619ef255f4f988f37593b7d39e87.pngimage.png.134f884f92ae859b6e3091b86d6a0d99.png

    Another interesting thing is, that creating a FMX application (in this case 2D mutidevice application) it always creates a Unit2 /TForm2 as main initial form even though there is no Unit1, at least here on my Delphi 10.3 Update 3 Rio installation.

     

    So debuggin it with IDA shows a call to  FMX::Platform::Win::TPlatformWin::CreateAppHandle which indeed calls Winapi.Windows.ShowWindow just by calling ApplicationHWND function.

    image.thumb.png.86c9ecb514c9d3d43d16e09c11d6650a.png

    Notice the icon in the taskbar, it belongs to that FMX application.

     

    Anyhow, I tried using the non ApplicationHWND method, which is the one finding the current process id window to hide, which also works.

    Calling HideAppInTaskbar(Form Handle) from FormCreate shows that before even processing that call, its icon is already added to explorer's taskbar.

    image.thumb.png.08a198fc170401d5949243ae200b593f.png

    This procedure does what is expected, to hide the taskbar's icon, but it doesn't avoid its creation in the first place, so it is always visible after launching, at least for a very short period of time.

    That's because after Application.Run, FMX.Platform.Win.TPlatformWin.Run procedure calls Fmx.Forms.TApplication.RealCreateForms, which also calls Fmx.Forms.TApplication.CreateForm -> Fmx.Forms.TCommonCustomForm.Create -> public Fmx.Forms.TCommonCustomForm.InitializeNewForm -> Fmx.Forms.TCommonCustomForm.CreateHandle which as similar as ApplicationHWND it is called from Fmx::Platform::Win::TPlatformWin::CreateWindow GetApplicationHWND -> Fmx.Platform.Win.TPlatformWin.UpdateApplicationHwnd ends up calling Fmx.Platform.Win.TPlatformWin.CreateAppHandle 

    image.thumb.png.fe8a4b0fe81af7dee4b80437d21aba42.png

    Which indeed calls ShowWindow with nCmdShow parameter using argument 1 (SW_SHOWNORMAL), then it follows other calls to finally end up with FormCreate procedure in our main form, so those suggested tricks to hide the taskbar icon are finally applied, after it was shown in the first place.

     

    However, since every application is a binary, it can be patched, so I tried patching it in the binary to 0 (SW_HIDE) and it worked, no more issues.

    push 1 in hex 6a 01 (BA 01 00 00 00 in x64), just replaced with 64 00 in the binary/executable using a hex editor, and voilà it finally worked as I was requiring. No more tiny little amount of time showing the taskbar icon just to hide it afterwards.

     

    Notice that it might differ in your project, but mine was located at this hex pattern location in my binary/executable (which was not found more than once).

    ff 8b d8 6a 01 53 e8 so I just look for it and patch after each build. Only 32 bit builds.

    48 89 4d 70 ba 01 00 00 00 e8 in x64 builds (debug&release mode). At least with Delphi Rio 10.3.3

     

     

     

    Finally, the culprit seems to be function TPlatformWin.CreateAppHandle: HWND in FMX.Platform.Win.pas file, which calls Winapi.Windows.ShowWindow(Result, SW_SHOWNORMAL) instead of SW_HIDE). However it was called from TPlatformWin.CreateWindow function when ParentWnd = 0, which means no parents are found.

    Then it follows ParentWnd := ApplicationHWND; <--- this function, as mentioned before, leads to create and show a non visible window, just to get the application handle, the procedure in question is TPlatformWin.UpdateApplicationHwnd when there is no parent handle. But modifying those delphi source code files don't work, so I ended patching it after the binary is created.

     

    [Update]

    Thanks to this answer at SO

    https://stackoverflow.com/a/10471855/537347 

    the solution was just a matter to copy the FMX.Platform.Win.pas file to your project's directory and make the changes to CreateAppHandle function:

     

    
    function TPlatformWin.CreateAppHandle: HWND;
    var
     ...
    begin
      ...
      Result := CreateWindowEx(WS_EX_WINDOWEDGE or WS_EX_APPWINDOW, FMAppClass.lpszClassName, PChar(FTitle),
                               WS_POPUP or WS_GROUP, 0, 0, 0, 0, GetDesktopWindow, 0, hInstance, nil);
      if FApplicationHWND = 0 then // this is checked by ApplicationHWND function
    	Winapi.Windows.ShowWindow(Result, SW_HIDE) // make sure our application never shows in taskbar icon in this case
      else
    	Winapi.Windows.ShowWindow(Result, SW_SHOWNORMAL);
    end;                         

    Originally, there is no conditional and uses the SW_SHOWNORMAL argument only, this fixes that.

     

    Now, I'm not worried about patching the created binary/exe anymore. Just remember to remove it from public repositories as it is a copyrighted material.

     

    However, I left the patching method incase your Delphi license/edition doesn't include FMX source code.

    Would you mind creating a quality entry on Embarcadero website? Btw are you working with which Delphi version?


  4. 1 hour ago, Stano said:

    I have several events that are identical in content. I only use a different component there every time. In the example, I have dbmlmnsrMultiMonth.
    And I want to use this event for other components that do the same thing. Only with another dbxxx.
    .
    So now I have 10 x SpineditxxxChange. And I want a single SpineditxxxChange event! Every time I need to get the right dbxxx component there.

    Why don't you just create one metWhySpineditxxxChange event and bind it to all your components change event? This can be done at design time as well as runtime.


  5. 2 hours ago, Wagner Landgraf said:

    In the case of TMS Aurelius Nullable type, specifically, there are helper methods for you to use that do the job for you. It's TMappingExplorer.GetMemberValue and SetMemberValue. Here is some info:

    https://support.tmssoftware.com/t/how-to-get-a-property-by-its-name/7777/2

     

    But in general, you do what @Attila Kovacs mentioned: get the whole record, modify its fields via RTTI, and then set the record back to the field/property. That's what Aurelius does.

    Thanks, looks like I need either some good sleep or vacation !


  6. Hello,

     

    I'm trying to disable IDE Theme (because it is damn slow).

     

    Setting Computer\HKEY_CURRENT_USER\Software\Embarcadero\BDS\21.0\Theme\Enabled entry to Value: 0 brings me hope but :

     

    IDE start with an exception:

    image.png.af11689249e4ae3f25d1b2cfbf8776ff.png

     

    and there are some disgraceful black painted controls and IDE 

    image.thumb.png.66d2c59a14a103de5d90897633ebd300.png

     

    Is there maybe another way to get rid of this ?

    I seen a lot of people complaining about VCL Theme speed and IDE slow down.... Why the hell Embarcadero do not listen to their customers?

     

    BTW I'm working with Delphi Sydney 10.4.1 + all available patches


  7. Hello everyone,

     

    I hope this message finds you all in good health! This year and really weird.... But anyway, let's get back to the point.

    I recently found a little nugget on the Internet developed by the brilliant @Uwe Raabe : it's a Dataset helper that automatically fills in the properties (or even fields) of an object. The source code can be found at this address :

    https://www.uweraabe.de/Blog/2017/02/09/dataset-enumerator-reloaded/

     

    I have slightly adapted the source code to use TMS Aurelius attributes (using "Column" attribute instead of "DBField" one provided bu Uwe). The Dataset helper works perfectly well "simple" classes such 


     

      TCustomer = class
      private
        [Column('CustNo')]
        FCustNo: Double;
        FCompany: string;
    
       FAddress1: string;
      public
        [DBField('Addr1')]
        property Address1: string read FAddress1 write FAddress1;
        property Company: string read FCompany write FCompany;
      end;

     

    But it gets more difficult as soon as my fields are declared this way:

     

      TCustomer = class
      private
        [Column('CustNo')]
        FCustNo: Nullable<Double>;;
        FCompany: Nullable<String>;;
        FAddress1: string;
        FEntity: TObject;
      public
        [DBField('Addr1')]
        property Address1: string read FAddress1 write FAddress1;
        property Company: string read FCompany write FCompany;
        property Entity: TObject read FEntity write FEntity;
      end;

     

    At runtime application is throwing "Invalid Type Typecast" exception on every TRTTI.GetValue or TRRTI.SetValue

     

    procedure TDataSetHelper.TDataSetRecord<T>.TFieldMapping.LoadFromField(var Target: T);
    begin
     FRTTIField.SetValue(GetPointer(Target), TValue.FromVariant(FField.Value));
    end;
    
    procedure TDataSetHelper.TDataSetRecord<T>.TFieldMapping.StoreToField(var Source: T);
    begin
      FField.Value := FRTTIField.GetValue(GetPointer(Source)).AsVariant;
    end;
    
    procedure TDataSetHelper.TDataSetRecord<T>.TPropMapping.StoreToField(var Source: T);
    begin
      FField.Value := FRTTIProp.GetValue(GetPointer(Source)).AsVariant;
    end;
    
    procedure TDataSetHelper.TDataSetRecord<T>.TPropMapping.LoadFromField(var Target: T);
    begin
      FRTTIProp.SetValue(GetPointer(Target), TValue.FromVariant(FField.Value));
    end;

    I guess this is happening because of either reading/writing values from a Record or an Object.

    I searched (maybe not enough nor thoroughly) the Internet but I wasn't able to solve this by myself.

     

    Can someone helps me sorting this out adapting attached unit to handle simple properties types (integer, double, date, string, boolean....) values as well Nullable one ! (and rejects complex types too 🙂 )

    I'll really appreciate some help.

     

    Kind regards,

     

    Stéphane

     

    Ps: I have attached modified Uwe's unit file.

    Ps2: I'm working with Delphi Sydney

     

     

     

    Aurelius.Dataset.helper.pas


  8. 1 hour ago, FredS said:

     

    Yup, this thinking suggests that all those usability, compile and stability issues where fine as long as Andy fixed 'em..

     

    I do not fully agree. I was able to live without IDE FixPack until XE area, when unit scope was introduced. At that time IDE were barely usable, took a lot of time displaying forms at design time, compiling project (the more directories in the search path the worse the IDE react)...

    • Like 1
×