Jump to content

PeterBelow

Members
  • Content Count

    468
  • Joined

  • Last visited

  • Days Won

    13

Posts posted by PeterBelow


  1. Well, TRunner.TCallback is closer in scope, so I would expect the compiler to use it instead of the global TCallback, so that does look like a bug. Should be easy enough to work around, though, just specify TRunner.TCallback as type for the property and its field.

     

    Of course it's a bit problematic to have this kind of nameing conflict in the first place, not (only) for the compiler but also for a programmer trying to make sense of the code 😉.

     

    Delphi 10.3 Version 26.0.33219.4899 still shows this behaviour, by the way.

    • Like 1

  2. I did something similar in the past but have stopped since it does not work that well if you let the IDE's code completion or a tool like Modelmaker Code Explorer (which I simply cannot live without) create the methods for you. I find it more useful to stick to a good naming convention for methods and event handlers and also use MMX or the structure view to navigate around a unit.

    • Like 5

  3. 21 hours ago, PeterPanettone said:

    Every multi-form VCL Application has a MAIN-FORM which is labeled in the Project Options dialog:

     

    Unfortunately, in the Project Explorer panel, there is no indication which is the unit associated with the MAIN FORM:

     

    Wouldn't it be useful if such an indication would be automatically shown by the IDE in the Project Explorer panel? (For example, with a different font color of the specific unit).

     

    If you want to submit a feature request please do so on quality.embarcadero.com. Posting such requests here has no effect other than spawning endless discussions which serve no purpose, IMO, since this is often mostly about a purely personal preference.

    • Like 3

  4. Well, if you call GetCompressedFilesize repeatedly and the returned size does not change for a certain time anymore the compression is finished. :classic_biggrin:.

     

    Since the compression runs in a different process (service) completely separate from yours I see no way to get informed directly. There is ReadDirectoryChangesW, which allows you to monitor the folder for changes in a file size, but that would probably have the same problem you are having now: you don't know if the change notification is the last one you will get for the file.

     


  5. 4 hours ago, dummzeuch said:

    I have got two programs, both written in Delphi using the VCL. Program1 excecutes Program2 using CreateProcess, passing some parameters. In some circumstances I would like Program2 to return a string to Program1.

     

    Since CreateProcess only returns an exit code, which is a number, this requires some additional communication.

     

    Converting program2 into a DLL or Package is not an option in this case, neither is integrating the source code of program2 to program1.

     

    The simplest way would probably be that program1 passes a file name to program2, program2 creates that file, writes the string to it and exits.

     

    It could of course be implemented much more complicated, e.g. via sockets, Windows Messages, Shared Memory or even WriteProcessMemory.

     

    Have you done something like this? If yes, which method did you use and what was your experience?

     

     

    A fairly simple method is to pass a window handle to program2 on the command line an then have that program sent its result back in a WM_COPYDATA message to that window. Only caveat: program1 must not wait on program2 to finish in a manner that blocks message processing of the main thread.

    • Like 2

  6. 19 hours ago, Stefan Glienke said:

    A singleton is never a good solution - it might be the easy one in the middle of a DI unfriendly architecture but that's it.

     

    Singletons do not only couple pieces together that don't have to but they also allow all kinds of crazy and hard to find errors - as every global state does.

    It all depends on what type of application you write. Singletons are, in my opinion, a good and easy to implement solution for apps that require some global state and are fairly small and focused on specific tasks, i. e. a typical one-user desktop application. They would certainly not be a good solution for a large distributed application with many modules and build by a whole team of developers. There are no panaceas in software development, be pragmatic, not dogmatic 😉.


  7. 21 hours ago, Rollo62 said:

    @PeterBelow I prefer the same, and use it in many places like that.

    But not all the time (usually these classes are called seldomly), but there is always a tiny chance that these singletons might crash because they are not threadsafe.

    I never had such case, but its always on my mind that it could in some cases, where those failures would be hard to find.

    Would you recommend or not recommend to make such simple data storage classes generally threadsafe ?

     

    I have a code template for creating a singleton that uses a thread-safe factory method, and making the interface methods thread-safe is also no big deal, since all the code is hidden in the implementation section of the unit. I don't do that by default, though, only when the singleton is actually used by several threads.


  8. 21 hours ago, Mike Torrettinni said:

    Thank you, interesting. And this is singleton, right?

    In a way, yes. The class itself exists only once, so all its class vars also exist only once in the application memory. The beauty is that it is impossible to create a second "instance" of the data, even if you were to create an object of that class it would still only access the class variables.

     

    The singleton pattern is classically implemented using a class of which only one instance can be created, which will typically live as long as the application is running. Using a "normal" class for that has its problems, since such classses are designed to allow the creation of any number of instances (objects) of that class. It is also hard to prevent code using the singleton object from destroying it. Using class variables eliminates all these problems, and using the interface to a hidden object method does this as well, although malicious code can in fact prematurely destroy the singleton object by calling _Release on the interface, at least if lifetime management by reference counting is used (hidden class derived from TInterfacedObject). But that is easy enough to prevent as well, just by using a class with a implementation of the IInterface methods that does not use reference counting for lifetime control.


  9. 2 hours ago, Mike Torrettinni said:

    Ok, lets assume we call method/property SetData1to set Data1 value... then how do I access same Data1 value from Main Form and Check form? Do I need to use someLocalVar := TDataStore.Data1everywhere or is someLocalVar actually global variable, gGlobalDataStore?

    No, you just use TDatastore.Data1 whereever you need the value stored in that field. Basically the class vars of the TDatastore class are your global variables, they are just neatly packaged and hidden in the class.

    • Like 1

  10. 19 minutes ago, Mike Torrettinni said:

    Aha, I thought singleton is just 'then way you use class' thing. I use records for what you described above - a data container (global variable) without needed for creating an instance, while classes are used with .Create, so I guess this means I always uses classes as created instances.

    So, are you describing a record (with properties, methods...)? I need to access it from Main Form and Check form, and perhaps other units, too.

    A record is about equivalent to using class variables. The main difference is the syntax you use to access the data.

    // a record as global storage
    var
      gDataStore: record
        Data1: string;
        ....
        end;
        
    // accessed as
    //  someLocalVar :=  dDataStore.Data1;
    
    // class as global storage
    type
      TDataStore = class
      private
      class var
        FData1: string;
        ...
      public
        class property Data1: string read FData1 write FData1;
        ...
      end;
      
    // uses as
    // someLocalVar := TDataStore.Data1;
    
        
        

    As you can see there is no global variable, and using the Delphi syntax rules it is clear that you accessing a class here. You can also better control access to the data and use setter and getter methods if necessary.


  11. 21 hours ago, limelect said:

    No i do not have RAD SERVER on my pallet.

    There is a project i wanted to see that uses that component.

     

    Latter I found a demo project that is using it "E:\Delphi_Programs\Delphi_DEMO\Object Pascal\Database\EMS\CustomLogin\CustomLoginPackage.dproj"

    in it there is a dpk but then i have a new problem  emsserverapi;

    well i am stack. it is a mess.

    The RAD Server stuff is only available in the higher RAD Studio SKUs (Architect, Enterprise).


  12. While it is generally a good idea to avoid global variables there are cases where they can be useful, and your case is one of them. Do you know what a singleton object is?

     

    A singleton is a good solution for a scenario where you need to store some data internally in your application that you have to access from several different places in your code (different units, for instance). You place the class into a unit of its own. The unit is then used by all other units that need access to the singleton.

     

    There are different ways to implement a singleton object. The simplest one is to actually never create an instance of the class at all. Instead you use class variables and class properties to hold the data. That works well if all data you need available are simple or compiler-managed types (ordinal types, numeric types, strings). It works less well if you need more complex types, e.g. other objects. This can be handled now that Delphi has class constructors and class destructors, however.

     

    My preferred way to implement singletons is to only expose an interface type that has the necessary properties and methods to store and retrieve the data, and a factory method that returns an instance of the interface. The class implementing the interface is private to the unit (declared and implemented in its implementation section). The factory method creates an instance of the class on the first call to it and stores the interface obtained from it in a variable only visible in the unit implementation section. The unit gets a finallization section that sets the interface to nil to finally destroy the singleton.

     

    • Like 1

  13. 46 minutes ago, limelect said:

    @PeterBelow  No DPK no BPL? I have to make my own package? How come?

    Then which components are in C:\Program Files (x86)\Embarcadero\Studio\19.0\source\data\rest

    No "REGISTER" in any PAS file

    any link to procedure to register.

    And is this the only component in the above source?

     Although i am with Delphi since #1 never needed to do it that way 

    I have no idea what this TEMSProvider is, sorry, so just gave you the stock answer for installing a component.

     

    OK, I see this component in the dclemsclient260.bpl (for Rio), which appears as "Rad Server client components" in the installed package list. Do you see this package in the Components-> Install package dialog? I see the component in the palette under the RAD Server item. Keep in mind that the palette is context-sensitive, you need to have a form, data module or such open in the designer to see most items.

     

    1.PNG


  14. 1 hour ago, limelect said:

    Delphi 10.2.3

    I do not have TEMSProvider on my component pallet.

    Although i have the source.

    How to add it to component pallet ? 

    You have to add it to a designtime package and install that. The Components->Install component menu calls up a dialog that steps you through the process.


  15. 12 hours ago, dummzeuch said:

    No, the ordinal values must be correct. These numbers are passed as parameters to a DLL written in C.

    See for example https://www.geeksforgeeks.org/enumeration-enum-c/

    If i understand that correctly the ordinals should be

     

    type
      VmbPixelLayout = (
        VmbPixelLayoutMono,        {0}
        VmbPixelLayoutMonoPacked,  {1}
        VmbPixelLayoutRaw,         {2}
        VmbPixelLayoutRawPacked,   {3}
        VmbPixelLayoutRGB,         {4}
        VmbPixelLayoutBGR,         {5}
        VmbPixelLayoutRGBA,        {6}
        VmbPixelLayoutBGRA,        {7}
        VmbPixelLayoutYUV411,      {8}
        VmbPixelLayoutYUV422,      {9}
        VmbPixelLayoutYUV444,      {10}
        VmbPixelLayoutMonoP,       {11}
        VmbPixelLayoutMonoPl,      {12}
        VmbPixelLayoutRawP,        {13}
        VmbPixelLayoutRawPl,       {14}
        VmbPixelLayoutYYCbYYCr411, {15}
        VmbPixelLayoutCbYYCrYY411 = VmbPixelLayoutYUV411, {8}
        VmbPixelLayoutYCbYCr422,                          {9}
        VmbPixelLayoutCbYCrY422 = VmbPixelLayoutYUV422,   {9}
        VmbPixelLayoutYCbCr444,                           {10}
        VmbPixelLayoutCbYCr444 = VmbPixelLayoutYUV444,    {10}
    
        VmbPixelLayoutLAST        {11}
        );

    which shows that the person that extended the enum after the RawP1 element did not understand the rules, since VmbPixelLayoutLAST is now definitely not the highest value in the enumeration.


  16. Delphi actually supports C-style enums, although they are supposed to be used only in code that needs to interface with  C Dlls. The  compiler creates no RTTI for them, so they cannot be used in published properties, for instance. But this compiles without problem:

     

    type
      VmbPixelLayout = (
        VmbPixelLayoutMono,
        VmbPixelLayoutMonoPacked,
        VmbPixelLayoutRaw,
        VmbPixelLayoutRawPacked,
        VmbPixelLayoutRGB,
        VmbPixelLayoutBGR,
        VmbPixelLayoutRGBA,
        VmbPixelLayoutBGRA,
        VmbPixelLayoutYUV411,
        VmbPixelLayoutYUV422,
        VmbPixelLayoutYUV444,
        VmbPixelLayoutMonoP,
        VmbPixelLayoutMonoPl,
        VmbPixelLayoutRawP,
        VmbPixelLayoutRawPl,
        VmbPixelLayoutYYCbYYCr411,
        VmbPixelLayoutCbYYCrYY411 = VmbPixelLayoutYUV411,
        VmbPixelLayoutYCbYCr422,
        VmbPixelLayoutCbYCrY422 = VmbPixelLayoutYUV422,
        VmbPixelLayoutYCbCr444,
        VmbPixelLayoutCbYCr444 = VmbPixelLayoutYUV444,
    
        VmbPixelLayoutLAST
        );

     


  17. Go to the project options dialog, Application -> Manifest node. Do you have the "enable run-time themes" checkbox checked?  (Caption may be different, i'm extrapolating from a german IDE here). If you use a custom manifest for the application it needs to contain the equivalent entry for that.


  18. 13 hours ago, Steve Maughan said:

    Hi Everyone,

     

    This could well be a complete "noob" question as I'm not that experienced with the parallel library.

     

    My objective is to utilize a parallel "for loop" in my optimization algorithm. Here's the code:

    
        TParallel.&For(0, fCriteria.Population - 1, procedure(i: integer)
          var
            xNode: TOptNode;
          begin
    
            //-- Get the latest node
            TThread.Synchronize(nil,
              procedure
              begin
                xNode := PopNode;
              end);
    
            //-- Get the new centers
            xNode.GenerateNewCenters;
    
            //-- Evaluate new centers
            xNode.Evaluate;
    
            //-- Push the node back onto the stack
            TThread.Synchronize(nil,
              procedure
              begin
                PushNode(xNode);
              end);
          end);

    Each iteration of the loop tests a new scenario (xNode.GenerateNewCenters) and stores the best one found (xNode.Evaluate). The TOptNode holds all the data that needs to be optimized. It's a large object and takes significant time to be created.  So I've created a TStack of TOptNode object, and only create them when needed. I need to be able to "pop" the xNode objects off the stack and "push" them back on in a thread safe way. I would have thought the code above would work, instead it just freezes when it comes to the "for" loop.

     

    What's the best way to "push" and "pop" in a thread safe manner inside of a parallel "for loop"?

     

    If you execute the TParallel.For loop in the main thread then it would probably block the Synchronize call, since that tries to execute code in the main thread. The code can only be executed when the main thread reaches a "safe" state, which, in a typical VCL application, is the message loop. Your code does not get there until the complete loop has been finished.

     

    What you need here is a thread-safe stack class, or you have to use a standard TStack<T> in a thread-safe manner, i. e. use a TCriticalSection object, which you enter before each pop or push call on the stack and leave when the call has returned (using try finally!). The loop will still block your main thread until it is done, though.


  19. 4 minutes ago, Anders Melander said:

    I believe you, but that makes absolutely no sense from a usability perspective.

     

    You're saying that the Design packages list in project options is working on the same settings as the Design packages list in the Component, Install Packages dialog (which is where one used to install packages globally).

    [checking...] You're right. The dialog even says "Project options". Amazing! :classic_huh:

    Oh, it makes perfect sense. This feature makes it possible to work on a project with only the component packages loaded that this project requires. That reduces the IDE memory print, especially if you have a lot of 3rd-party packages installed (these things tend to breed if you don't look 😉), of which the current project only uses a small subset. That was certainly more important in the early times of Delphi (D1, Win16!) but can still make a difference today.

    You can drastically reduce the IDE start time, for example, by using a default package set that is the absolute minimum, basically only what is needed for every project you work on. Other packages are then only enabled for the project that needs them.

    • Like 1

  20. 10 hours ago, santiago said:

    @PeterBelow

    Our program is leaking memory. If I perform a certain calculation, there are some left-over objects that should no longer be referenced, but are alive

    ....

    Unfortunately our base classes inherit directly from TInterfacedObject. There are also many, many classes that inherit directly from TInterfacedObject. That is why I would need to change many classes to take them all into account.


    Maybe I just need to bite the bullet and build in a common base class. That would would make it really easy...

    Looks like a reference counting problem. Do you have classes where an object referenced by another also has to keep a backreference to the object that references it? That is the most common cause of such problems if the backreference is not declared as weak, but you probably know that already. Another problem scenario is passing interface references across a module boundary where it may be necessary to call _addref and _release manually, that's easy to screw up.

×