Jump to content

Martin Wienold

Members
  • Content Count

    28
  • Joined

  • Last visited

  • Days Won

    2

Posts posted by Martin Wienold


  1. Using BLOBs implies that you are storing binary data in a database table.

     

    This is data that can't effectifly be queried by the database using SQL alone, you always have to load it into an application.

    I'm not saying this is bad, I just want to make sure that you know what the implications are.

     

    Another potential problem you may face is having different versions of this data in you database.

    Right now, you are saving Level, Text, ImageIndex and Data. If this list is expanded or the meaning of a value (example ImageIndex may shift) changes you have to have an application loading, converting and storing it.


  2. 2 hours ago, Lars Fosdal said:

    To check your current TPM status, Win+R and start tpm.msc

    To check your UEFI status, Win+R and start msinfo32.exe - look at BIOS mode

     

    There seems to be some loopholes with regards to TPM, but too early to be definitive about it.

     

    Edit: It seems that some BIOS firmware based solutions are accepted?
    https://www.windowscentral.com/best-trusted-platform-modules-tpm

    Does that list the TPM Version?
    My PC at home doesn't have TPM available, I can't check.

    My PC at work does and I used PowerShell with WMI to get the version

    foreach($instance in Get-WmiObject -Namespace Root\CIMV2\Security\MicrosoftTpm -Class Win32_Tpm)
    {
        $instance | Select-Object -Property * | Format-List
    }

    https://docs.microsoft.com/en-us/windows/win32/secprov/win32-tpm

    https://trustedcomputinggroup.org/resource/tpm-library-specification/


  3. At work, we have two Git Repositories.

     

    One for the components and one for our actual application.

    Our build environment takes care of syncing both to the correct branch (with a fallback to just develop for the component repository).

     

    The result is that every developer has a local working directory for the components with prebuild binaries to minimize the buildtimes.

    In theory, every develop could have a different location for it, in practice we have it below a folder in %PUBLIC% (example C:\Users\Public\Documents\SomeFolder\Comps).

    Our git server (we use Gitlab) notifies everyone for any change in the component repository, keeping errors due to mismatching components down to a minimum.

     

    So back to your question:

    Put it anywhere you want as long as its a local copy and you have a "global" copy, preferable in your version control of your choice.

    %PUBLIC% is user independant place, but every other folder is also fine.

    • Like 2

  4. Maybe using Low Level Keyboard Hooks
    MSDN LowLevelKeyboardProc

     

    But the thing is, there are more ways to make a Screenshot than just using these Shortcuts, even without third party tools:

    • Microsoft Snipping Tools
    • Windows Key + Shift + S
    • Print and MS Paint to cut the Screenshot

    You should ask yourself if you actually need to do this and save yourself the time and money.

    • Like 2

  5. 1 hour ago, Juande said:

    [..] In Rad Studio 10.4.2 where is the Delphi Compiler option Generate Android App Bundle in project Options? [..]

    Isn't it just renamed to "Generate Android 32-bit and 64-bit binaries (armeabi-v7a + amd64-v8a)"?

    I've never developed for Android, I'm just guessing.


  6. Here is an example for how to use the Spring4D multicast events:

    type
      TEventSource = class
      private
        // record type here
        // for the generic parameter T you can use any Event type you used before,
        //  for this example I just use TNotifyEvent
        fOnChanged: Event<TNotifyEvent>; 
        // getter for the property
        procedure GetOnChanged: IEvent<TNotifyEvent>; 
        // internal method to just trigger the OnChange event as shorthand
        procedure DoChanged;
      public
        property Number: Integer read fNumber write SetNumber;
        
        // event to which you subscribe to
        // interface type here
        property OnChanged: IEvent<TNotifyEvent> read GetOnChanged; 
      end;
      
    procedure TEventSource.GetOnChanged: IEvent<TNotifyEvent>;
    begin
      // the record type has implicit operators that will 
      //  lazy initialize its internals and return it as an interface reference
      // internaly in TEventSource, you should access the field member and
      //  not the property since the implicit operator does not need
      //  to run every time
      Resut := fOnChanged; 
    end;
    
    procedure TEventSource.DoChanged;
    begin
      // CanInvoke only returns true if there are any listeners on the event
      // the parameters of Invoke will change depending on the generic parameter T 
      //  of the field member 
      if fOnChanged.CanInvoke then
        fOnChanged.Invoke(Self); 
    end;
    
    procedure TEventSource.SetNumber(const Value: Integer);
    begin
      if fNumber <> Value then
      begin
        fNumber := Value;
        DoChanged;
      end;
    end;
    type
      TEventListener = class
      private
        fSource: TEventSource;
        
        procedure HandleChanged(Sender: TObject);
      public
        constructor Create;
        destructor Destroy; override;
        
        procedure Something;
      end;
      
    constructor TEventListener.Create;
    begin
      inherited;
      fSource := TEventSource.Create;
      // add an event handler to the multicast event
      fSource.OnChanged.Add(HandleChanged);
    end;
    
    destructor TEventListener.Destroy;
    begin
      // remove the event handler from the multicast event
      // if the source has a longer lifetime than the listener, 
      //  you should always make sure to remove the handler.
      // if you do not, there will be a dangling pointer inside
      //  of the multicast event, pointing to your freed listener
      fSource.OnChanged.Remove(HandleChanged);
      fSource.Free;
      inherited;
    end;
    
    procedure TEventListener.HandleChanged(Sender: TObject);
    begin
      
    end;
    
    procedure TEventListener.Something;
    begin
      fSource.Number := 1;
    end;

    I'm sorry if there are any compile errors, I don't have access to a compiler at the moment.

    • Like 4

  7. 1 minute ago, dummzeuch said:

    It does, but unfortunately only on a daily basis which would mean that it starts on weekends (and doesn't shut down so it runs all weekend). WOL is probably the easiest option for me (now that I know that it works) since I log on to an ssh server first thing anyway, so I can simply call a script that wakes up my PC. I could even automate via .profile it but that would mean that PC starts every time I log on even if I don't need it.

    Or you could just have a scheduled task call shutdown on weekends.


  8. The difference is that terminating a process does not affect your current process from which you are calling the termination.

    Terminating a thread has the posibility to do just that, it may corrupt the process memory you are running it in. (This heavily depends on what is going on in the thread you are terminating and your gues is as good as mine)

     

    As this thread asked for best practice for what to do with a stalled thread:

    Do nothing, let it finish or try to build in a way for it to eventually finish without terminating it.

    If this is not a possibility and you just have to have a way to end it forcefully, let it run in a different process, isolated from your own.

    • Like 1

  9. Do not terminate a Thread as it may lead to all kind of strange behaviour.

    MSDN: TerminateThread function

    Quote

    TerminateThread is a dangerous function that should only be used in the most extreme cases. You should call TerminateThread only if you know exactly what the target thread is doing, and you control all of the code that the target thread could possibly be running at the time of the termination.

     

    You could explore refactoring the logic of your thread into a small exe and call this instead, if this one stalls you can terminate its process.


  10. You can design a more native looking dialog using TTaskDialog.

    Here is an short example and a few more tweaks can be found here Inofficial TTaskDialog Documentation, Andreas Rejbrand, 2011-02-13

      with TTaskDialog.Create(Self) do
      try
        Caption := 'File info';
        Title := 'File created';
        Text := 'c:\temp\Projections_Q3.csv';
        VerificationText := 'Do not show message when creating files';
        MainIcon := tdiInformation;
        CommonButtons := [tcbClose];
        DefaultButton := tcbClose;
        with Buttons.Add() as TTaskDialogButtonItem do
        begin
          Caption := 'Open file';
          ModalResult := 1000;
        end;
        with Buttons.Add() as TTaskDialogButtonItem do
        begin
          Caption := 'Locate file';
          ModalResult := 1001;
        end;
        if Execute then
          case ModalResult of
            1000: ShowMessage('Open file');
            1001: ShowMessage('Locate file');
          else
            ShowMessage('Cancel');
          end;
      finally
        Free;
      end;

     

    TaskDialog.png

    • Like 2
    • Thanks 1

  11. Indy Callbacks are declared with of object modifier, that means you have to have a method in an object and not a standalone procedure.

     

    TCallback1 = procedure (const Arg1: Integer);
    TCallback2 = procedure (const Arg1: Integer) of object;
    TCallback3 = reference to procedure (const Arg1: Integer);

    TCallback1 is used with standalone procedures.

    TCallback2 is used with methods from objects.

    TCallback3 can be used with anonymous methods.

×