Jump to content

programmerdelphi2k

Members
  • Content Count

    1406
  • Joined

  • Last visited

  • Days Won

    22

Posts posted by programmerdelphi2k


  1. 13 minutes ago, hackbrew said:

    On an app close or device power off/on, what happens to data in an on-device local SQLite table?

    let's imagine a "regular case" = no critical-crash on the system!

    • the app, would try receive the "message": hey app goes down! then, the form/app/OnClose...Destroy will be trigged
      • this can be seen on MSWindows because it's more easy, on Android it's necessary more knowledge about how happens... I dont know! but you can do the tests...
    • then, if you have the events "OnClose" (for example), you can to do some "quick"-task ... not save 1BILLION records of course!
    • SQLite it's a DB one-file with many internal resource, then, you need read the documentation about your doubts.
    20 minutes ago, hackbrew said:

    Do you know if this is a known bug in Delphi 11.3 for Android apps

    maybe not, maybe yes... maybe your code be the "bug"... needs more details/code and somebody that know how Android works behind the scenes...

     

    your code, how do you call the another app into your app? it's possible show the code?


  2. 25 minutes ago, David P said:

    NewChild.Top = HeightofCurrentContents + 50;

    NewChild.Parent = myScrollbox;

    NewChild.Align = alTop

    sometimes, it's necessary ALIGN = NONE!!! then with your "PARENT" defined, now you can put on the position out this control! you see? after this, you can (again) re-align to TOP or BOTTOM, as you need

    1. first, define the Parent
    2. later, define align=none
    3. position=x  (out this control, maybe   xControl.Top (absolute position on screen) + xControl.Height + NNNN)  -> if your xControl is into a another control, use this control-parent to get the values)
    4. re-define align to Top or Bottom

  3. 10 minutes ago, hackbrew said:

    If the OnSaveState event is added to the MainForm, when I exit the mapping app, I'm returned to the Home screen, not to my app which is a problem.

    and if you "assign" to current FORM active? unassign for any other... or be, only when you go to MAPs, you assign it, later unassign it!

    • the app above is a FMX in MSWindows, not VCL!!!! then when app end, the SaveState is called as expected

  4. @David P

     

    did you try, before insert the items, define the property position "Y" (or X if horizontally), before that define the "alingment"?

    for example:   -(value out of screen) (negative or positive) value to position?


  5. Another thing:

    • as you use FDMemTable (I think), then, you can save your data on JSON/XML file using the properties for that:
      • ResourceOptions ->PersistentFileName + Persistent=true
      • then, when you re-open your table, the data should be there!

  6. 28 minutes ago, hackbrew said:

     Is the data wiped from the memory table and/or embedded database (SQLite) if the app were to say crash/lose focus/device reset?

    by default, the all "SaveState" is transitory (tmp), then, you can try save it permanently on disk using:  xxSaveState;Name := 'xxxxx';   xxSaveState.StoragePath := 'xxxx';

    like this:

    • create your FOLDER before save it!!!!
    • ALL components should exists on form as exists on SaveState file!!!
    // here Im not take care about "AV" ok?  do it yourself...
    
    implementation
    
    {$R *.fmx}
    
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      // you can use this on "OnCreate" from "form1"... or any place that you desire!
      //
      SaveState.Name        := 'mySaves.TMP';
      SaveState.StoragePath := 'd:\mytmpSaveStateDir';
      //
      if SaveState.Stream.Size > 0 then
        begin
          for var i: integer := 0 to (ComponentCount - 1) do
            SaveState.Stream.ReadComponent(Components[i]); // reading...
          //
          ShowMessage('SaveState size on disk: ' + SaveState.Stream.Size.ToString);
        end
      else;
    end;
    
    procedure TForm1.FormSaveState(Sender: TObject);
    begin
      // 1º FormCloseQuery
      // 2º FormClose
      // 3º FormSaveState <----
      // 4º FormDestroy
      // ...
      SaveState.Stream.Clear;
      SaveState.Name        := 'mySaves.TMP'; // in disk, it will be  [ ~project1_ + "your name to SaveState" ]
      SaveState.StoragePath := 'd:\mytmpSaveStateDir';
      //
      for var i: integer := 0 to (ComponentCount - 1) do
        SaveState.Stream.WriteComponent(Components[i]); // saving all components on "Form1"
      //
      ShowMessage('FormSaveState fired');
    end;
    
    end.

     

    bds_3EHxt4AeAL.gif   image.png.ae264fe78968e6367660d470a68ffc0d.png


  7. 14 hours ago, Bart Kindt said:

    Uh, I have never heard of "

    
    LLocationForegroundPermission

    Have you seen this in my code?

     

    ...
    
    initialization
    
    LLocationForegroundPermission := [             {  ARRAY }
      'android.permission.ACCESS_COARSE_LOCATION', { }
    'android.permission.ACCESS_FINE_LOCATION'      { }
      ];
    //
    LLocationBackgroundPermission := [                { ARRAY }
      'android.permission.ACCESS_BACKGROUND_LOCATION' { in Android 11, you'll can see your "Allow all the time" option!!! }
      ];

     


  8. @Bart Kindt

     

    1. by default, in Android 11+++ you CANNOT ASK "foreground/background" permissions at same time!!!
      1. first one, later other!  Otherwise, the Android dont use anyone!!!

    that way, you can :

    procedure TForm1.BtnForegroundClick(Sender: TObject);
    begin
      TPermissionsService.DefaultService.RequestPermissions( { }
      LLocationForegroundPermission,                         { }
      MyReqPerms,                                            { }
      MyRatDisplay                                           { }
        );
    end;
    
    procedure TForm1.BtnBackgroundClick(Sender: TObject);
    begin
      TPermissionsService.DefaultService.RequestPermissions( { }
      LLocationBackgroundPermission,                         { }
      MyReqPerms,                                            { }
      MyRatDisplay                                           { }
        );
    end;
    
    initialization
    
    LLocationForegroundPermission := [             { }
      'android.permission.ACCESS_COARSE_LOCATION', { }
    'android.permission.ACCESS_FINE_LOCATION'      { }
      ];
    //
    LLocationBackgroundPermission := [                { }
      'android.permission.ACCESS_BACKGROUND_LOCATION' { in Android 11, you'll can see your "Allow all the time" option!!! }
      ];

     


  9. 22 minutes ago, Mike Warren said:

    but it's not what I'm after.

    no problem... dont forget that you can move the elements beyond the containers ( negative or positive positions), background or foreground


  10. did you read this: 

     https://developer.android.com/training/location/background

    https://developer.android.com/training/location/permissions

    Quote

    Note: The Google Play store has updated its policy concerning device location, restricting background location access to apps that need it for their core functionality and meet related policy requirements. Adopting these best practices doesn't guarantee Google Play approves your app's usage of location in the background.

    Learn more about the policy changes related to device location.

     


  11. @Mike Warren

     

    what about this idea...

    • 1 TLayout (or any other container to Image/Rectangle) = HitTest = TRUE!
      • then you can use Layout client-area to expand your rectangle and no needs to do nothing in Timage... doubleclick on rectangle to expand for all client-area from TLayout/container
    ...
      private
        FMouseMoving                : boolean;
        FControlMouseClickPositionXY: TPointF;
        FRectangleSizeDefault       : TRectF;
      public
    ...
    implementation
    
    {$R *.fmx}
    { TForm1 }
    
    procedure TForm1.FormCreate(Sender: TObject);
    begin
      FRectangleSizeDefault := Rectangle1.BoundsRect;
    end;
    
    procedure TForm1.Layout1MouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
    begin
      FControlMouseClickPositionXY := PointF(X, Y);
      TControl(Sender).AutoCapture := true;
      FMouseMoving                 := true;
    end;
    
    procedure TForm1.Layout1MouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
    begin
      TControl(Sender).AutoCapture := false;
      FMouseMoving                 := false;
    end;
    
    procedure TForm1.Layout1MouseMove(Sender: TObject; Shift: TShiftState; X, Y: Single);
    var
      XY: TPointF;
    begin
      if FMouseMoving then
        begin
          XY                          := TControl(Sender).LocalToAbsolute(PointF(X - FControlMouseClickPositionXY.X, Y - FControlMouseClickPositionXY.Y));
          TControl(Sender).Position.X := XY.X;
          TControl(Sender).Position.Y := XY.Y;
        end;
    end;
    
    procedure TForm1.Rectangle1DblClick(Sender: TObject);
    begin
      if (Rectangle1.Align = TAlignLayout.Client) then
        begin
          Rectangle1.Align      := TAlignLayout.Right;
          Rectangle1.BoundsRect := FRectangleSizeDefault;
        end
      else
        Rectangle1.Align := TAlignLayout.Client;
    end;
    
    end.

     

     

    bds_tgWUVn66ou.gif   image.thumb.png.4ad5e288106cd5ebe0c3bf5320e1c698.png


  12. 38 minutes ago, Jud said:

    . It seems that thread.queue is NOT thread-safe for doing this.

    "Queue" put on queue and go back to next command-line (code)... then when possible, your command (queued) will be executed.

    Quote

    Queue causes the call specified by AMethod to be asynchronously executed using the main thread, thereby avoiding multi-thread conflicts.

    Quote

    If you are unsure whether a method call is thread-safe, call it from within the Synchronize or Queue methods to ensure that it executes in the main thread.

    Quote

    Unlike Synchronize, execution of the current thread is allowed to continue. The main thread will eventually process all queued methods.

     

    https://docwiki.embarcadero.com/Libraries/Alexandria/en/System.Classes.TThread.Queue


  13. @pyscripter

     

    I has this case, normally, Code-Editor/LSP assistence stop code-complition work:

    Example:

    1. im creating a new unit to create a class (any) basic nothing advanced. 1create 1 destroy, 1 method any
    2. then, I decide use "interface" in my new class, then...
    3. I create a new unit for my new "interface"... ok
    4. now, I go back to my unit class and add my unit-interface in my uses and add my interface in my class declaration (TInterfacedObject, ImyInterf....) as usual
    5. now, I try use new class-INTERFACED (now) in my form1 test, and the code-complition does not works anymore... (already known "red-lines" in Editor)
    6. summary: I need close the project, and re-opent it and all it's ok
    7. sometimes I see on window Messages: LSP starting

    did you try this too?


  14. @pyscripter

    • If the test is "Ctrl+click" in "Test;   (procedure)", in my IDE (RAD11.3 patch 1), the cursor goes to "procedure TForm1.Test;" as expected
    • when I click in "Winapi.Messages,"  (in uses clauses), the cursor goes to your new "Winapi.Messages.pas" in your project too!
      • if I delete this from "uses clauses", the cursor goes to "Winapi.Messages.pas in RAD sources folder" (as expected by default) and Ctrl+click in "Tests" still working as expected too
    • if is this, then all works as expected

  15. @Jud

     

    try this way if works for you

    • using "Queue" no order will be used, but in "Parallel" you cannot control the flow (calls) too (by default)
    implementation
    
    {$R *.dfm}
    
    uses
      System.Threading;
    
    var
      LTask: ITask;
    
    procedure MyProcToParallelFor(AValue: integer);
    begin
      TThread.Queue(nil,
        procedure
        begin
          Form1.Memo1.Lines.Add(                                                       { }
            Format('Thread: %d, AValue: %d', [TThread.CurrentThread.ThreadID, AValue]) { }
            );
        end);
      //
      sleep(50); // for responsive tests...
    end;
    
    procedure TForm1.Button1Click(Sender: TObject);
    var
      LStart, LEnd: integer;
    begin
      LStart := 1;
      LEnd   := 1000;
      //
      LTask := TTask.Create( { }
        procedure
        begin
          TParallel.For(LStart, LEnd, MyProcToParallelFor);
        end);
      //
      LTask.Start;
    end;
    
    procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    begin
      CanClose := (LTask = nil);
      //
      if not CanClose then
        CanClose := not(LTask.Status in [TTaskStatus.Running, TTaskStatus.WaitingToRun, TTaskStatus.WaitingForChildren]);
      //
      if not CanClose then
        Caption := 'Task in process... ' + TimeToStr(now);
    end;
    
    initialization
    
    ReportMemoryLeaksOnShutdown := true;

     

    bds_1ja0uIvl43.gif


  16. 27 minutes ago, KodeZwerg said:

    No need to do all that what @programmerdelphi2k wrote at all.

    as I said: the code is from internet... I just checked the ParentID!

    of course, that exists API functions for better checking!

     

    now test your code for:  as I did in my code above... same step-by-step

    1. Run the app as usual
    2. now, re-run this same app using 
    3. procedure TForm1.Btn_Run_ME_againClick(Sender: TObject);
      begin
        // run me again... by myself!
        ShellExecute(0, PWideChar(''), PWideChar('project1.exe'), PWideChar(''), PWideChar(''), sw_normal);
      end;
    4. now, on first app run your code again

     

    summary: 

    • the 2 session app will be showing that it was load by itself!!! --> but the first app (session) was called by BDS.exe or Explorer,  and 2nd app was called by 1st App
    • then, your code is fail too!  only the 2nd session was loaded by itself ... the 1st session was loaded by BDS.exe!!!
    • each session has a ID distinct, because it is process distincts
    •  

    chrome_Oqoo2wvmuT.gif


  17. @robertjohns

     

    you would can some like this... 

    • You could check the "processID" of the "parent" that ran the current process. Normally, when running an application, "MSExplorer" is the "parent" (but not necessarily).
    • So, if Exe2 executed Exe1, "Exe2" would have to be the "parent" of "Exe1", naturally, this might not be true at all, as there are ways to bypass this task.

    here is a very easy code to find on the internet, and that I just did some checks to try to find the answer

    • im PROJECT1.exe ...
    • see the "2nd" Project1.exe on left Memo and the right Memo = ProcessID from 1º and  ParentID from 2º
      • we'll have 2 instance of "Project1.exe" = 1 with BDS.exe and 1 with "Project1.exe" (from "run me" button)
    • now, just do the changes and clean the code not necessary... the code is not mine! ok

    implementation
    
    {$R *.dfm}
    
    uses
      Winapi.ShellAPI,
      Winapi.PsAPI,
      Winapi.TlHelp32;
    
    function SearchParentProcessFrom(const PID: cardinal): string;
    var
      hProcess: THandle;
      path    : array [0 .. MAX_PATH - 1] of char;
    begin
      result   := '... Parent empty ...';
      hProcess := OpenProcess(PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, false, PID);
      //
      if hProcess <> 0 then
        try
          if (GetModuleFileNameEx(hProcess, 0, path, MAX_PATH) <> 0) then // RaiseLastOSError;
            result := PID.ToString + '=' + ExtractFileName(path);         // get Exename/Module
        finally
          CloseHandle(hProcess)
        end
      else
        result := '.... ERROR hProcess = 0 = No-Opended file = no problem at all';
    end;
    
    function CheckProcessOnMemory: TArray<string>;
    const
      PROCESS_TERMINATE = $0001;
    var
      ContinueLoop         : BOOL;
      FSnapshotHandle      : THandle;
      FProcessEntry32      : TProcessEntry32;
      ListOfProcessOnMemory: TStringList;
      LArrIDandName        : TArray<string>;
      LProcessID           : cardinal;
      LProcessParentID     : cardinal;
      i, LCounter          : integer;
      LText                : string;
    begin
      result := [];
      //
      ListOfProcessOnMemory := TStringList.Create;
      try
        FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
        try
          FProcessEntry32.dwSize := SizeOf(FProcessEntry32);
          Process32First(FSnapshotHandle, FProcessEntry32);
          //
          while Process32Next(FSnapshotHandle, FProcessEntry32) do
            ListOfProcessOnMemory.AddPair( { a=b=c }                                                                { }
              FProcessEntry32.th32ProcessID.ToString + '=' + FProcessEntry32.th32ParentProcessID.ToString,          { }
              FProcessEntry32.szExeFile);
          //
          Form1.Memo1.Lines.AddStrings(ListOfProcessOnMemory.ToStringArray);
        finally
          CloseHandle(FSnapshotHandle);
        end;
        //
        i        := ListOfProcessOnMemory.Count;
        LCounter := 0;
        //
        while (LCounter < i) do
          begin
            LArrIDandName := ListOfProcessOnMemory[LCounter].Split(['=']); // 3 items (a=b=c) above...
            //
            if (length(LArrIDandName) = 3) then
              begin
                LProcessID       := StrToIntDef(LArrIDandName[0], 0); // processID
                LProcessParentID := StrToIntDef(LArrIDandName[1], 0); // parentID
                //
                // if (LProcessID <> 0) then // "0" = "System"
                begin
                  LText := SearchParentProcessFrom(LProcessParentID); // find parentID name
                  //
                  // parentID + processName
                  if not(LText.IsEmpty) and LText.Contains(LArrIDandName[1]) and (LText.Contains(LArrIDandName[2])) then
                    LText := LText + ' = load by itself';
                  //
                  Form1.Memo2.Lines.Add(LArrIDandName[0] + '=' + LArrIDandName[2] + ' Parent: ' + LArrIDandName[1] + '  -> Search: ' + LText);
                end;
              end;
            //
            LCounter := LCounter + 1;
          end;
      finally
        ListOfProcessOnMemory.Free;
      end;
    end;
    
    procedure TForm1.Btn_All_Process_On_MemoryClick(Sender: TObject);
    begin
      CheckProcessOnMemory;
    end;
    
    procedure TForm1.Btn_Run_ME_againClick(Sender: TObject);
    begin
      // run me again... by myself!
      ShellExecute(0, PWideChar(''), PWideChar('project1.exe'), PWideChar(''), PWideChar(''), sw_normal);
    end;

     

     

     

     

    bds_NUccFH5QCV.gif

×