Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


Everything posted by PeterBelow

  1. Using threads to do thing in parallel obviously only works efficiently if the "things" do not depend on each other. As soon as a thread has to wait on the results of another the processing slows down and the chance of deadlocks goes up. Also, using more threads than the hardware has cores/cpus quickly gets you to a point of diminishing returns, since the OS has some administrative overhead to manage the threads. So, don't overdo it, especially in a scenario like a parallel for loop, where the code can only continue after the loop has finished completely it may be more efficient to split the loop into several and run each in its own thread. If the loop does not have that many iterations and executes each round fairly quickly setting up the individual tasks in a parallel for may consume more time than you gain by doing stuff in parallel. There is no substitute for thorough testing and timing in such a scenario.
  2. No, you can operate on several canvases (of offline bitmaps or metafiles) in parallel, its is just a little bit less efficient since each canvas has to create its own font, pen, brush instead of using an existing one from the VCL sharing pool.
  3. If you work with a TCanvas in background threads always wrap your code in canvas.lock; try ...operate on canvas here finally canvas.unlock; end; The VCL has a build-in mechanism to optimize use of GDI objects, which is shared between all TCanvases used, and his mechanism is not thread-safe. Locking the canvas makes sure it does not use this mechanism while it is locked.
  4. PeterBelow

    multi forms with thread in each

    If you want to use a database that requires COM (e.g. via dbGo) inside a thread you have to call CoInitialize at the start of the execute method and CoUninitialize at the end. You are not doing that, your InitializeDatabase method calls CoUnInitialize, so any subsequent use of the database connection may not work as intended. You thread Execute method does not contain a loop, after one pass through the code the thread will exit. Also keep in mind that database connections are usually bound to the thread that created them, so using a dataset bound to the connection created by the thread in another thread (e.g. in the main thread through a Synchronize call) may either not work or involve some internal thread synchronization done by the framework you are using (COM objects using appartment threading are such a case) that may block until the code returns to the message loop. Something else that may foul your design: Creating a datamodule inside a thread is not a problem per se, but if you have design-time links of components on forms, frames, other datamodules to stuff on this datamodule (or vice versa) the way the VCL streaming mechanism resolves them may torpedo your intent. This mechanism is not thread-safe, and it resolves the links using the Name of the component linked to, and it looks for the container (form etc.) in a global list, where it will only find the first created instance of the container, even if you have created several.
  5. PeterBelow

    RIO: Start Debug Session changes source

    Thanks for sharing the solution.
  6. PeterBelow

    RIO: Start Debug Session changes source

    This is not normal behaviour, i have never encountered that myself with Rio. Do you also get that if you do a build before starting the debug session?
  7. PeterBelow

    Why control methods (OnClick) can't be defined in Form Private section?

    The form streaming process relies on run-time type information (the old styele), and that is only generated for published members of a class.
  8. PeterBelow

    Importing Excel2016 Type library into Delphi

    If you execute the import component dialog and select "import type library" you should get a list of the installed type libraries on the next page of the wizard. Don't you see a "Microsoft Excel xx.x Object Library" in that list?
  9. PeterBelow

    Funny Code in System.Types

    The point is that the code is plain wrong, the last else in both if trees needs to cast value.x and value.y, respectively, not result.x/y, which has not been set at those points!
  10. PeterBelow

    redefined anonymous method - bug or my mistake?

    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.
  11. PeterBelow

    How do you organize units, forms?

    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.
  12. PeterBelow

    Marking of the main form in a multiform VCL Application

    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.
  13. PeterBelow

    How to wait for a file compression to finish?

    Well, if you call GetCompressedFilesize repeatedly and the returned size does not change for a certain time anymore the compression is finished. . 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.
  14. PeterBelow

    Passing back a string from an external program

    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.
  15. 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 😉.
  16. Singletons are no problem for unit tests, you just need to make them implement an additional interface that resets all the singleton fields to the startup state for the test build. That is the called from the Setup method of the test case.
  17. 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.
  18. 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.
  19. 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.
  20. 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.
  21. PeterBelow

    No TEMSProvider on my component pallet

    The RAD Server stuff is only available in the higher RAD Studio SKUs (Architect, Enterprise).
  22. 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.
  23. PeterBelow

    Multi-screen misbehavior

    Keep in mind that the IDE uses a different desktop while in debug mode. Move the IDE back to the other monitor and then save the desktop and make it the default debug desktop, that should fix the problem.
  24. PeterBelow

    No TEMSProvider on my component pallet

    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.
  25. PeterBelow

    No TEMSProvider on my 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.