

PeterBelow
Members-
Content Count
560 -
Joined
-
Last visited
-
Days Won
13
Everything posted by PeterBelow
-
Are you calling the DLL from a Delphi app or some other environment? Anyway, even if you use a DLL from a host app made with the same Delphi version it is not safe to pass data types to the DLL for which the compiler does automatic memory management (string, dynamic arrays, objects that internally use such data types, e.g. TStringlist). At minimum you have to use the SimpleShareMem or ShareMem unit on both sides to get both modules to use the same memory manager. This may not be enough if the DLL implements forms or datamodules, since these use global VCL variables like Application and Screen, of which each module has its own instance. The only way to make both modules share the same VCL instance is to build both with the core RTL and VCL run-time packages.
-
Changes in System.sysutils.pas were not reflecting in other unit in Delphi 11
PeterBelow replied to sp0987's topic in General Help
If you changed the interface section (bad idea, really) that means that every RTL and VCL unit using system.sysutils needs to be recompiled in addition to your own units and the resulting dcus need to be put in a folder where they replace the dcus that come with the Delphi installation. And remember that said installation has different dcus for debug and release and different platforms, something D7 did not have. Best reevaluate the original cause for this change in D7 and see wether you can avoid it in D11 completely. -
Looks like the design-time package in the D11 folder (22.0 is the folder for that version) is in fact the version for D12, that is, should be in the 23.0 branch. But it may also be the correct version but tries to load a run-time package from the wrong folder. That is a common problem if the packages are not named properly with a version tag (280 for D11, 290 for D12). Run-time packages are loaded using Window's search strategy for DLLs (since they are DLLs in fact), which includes searching folders on the PATH. If you have several RAD Sudio versions installed each will have its BPL folder on the path, so the search may find the wrong version of a package if they all have the same filename. A possible cure is to move the run-time package in question to BIN folder of the matching Delphi version (where bds.exe resides), since Windows searches that folder first. Another is to start the IDE not via the start menu links the installer created but from a batch (cmd) file where you first redefine the PATH to only contain the folders for this Delphi version. Oh, and if you can rebuild the packages you can of course change the project options to use the proper version tags for the produced binaries.
-
If the DLL is COM-enabled you can use the Component -> Import component dialog from the IDE main menu: A pure .NET assembly without COM support cannot be used from Delphi with the tools available out of the box, but there are 3rd-party libraries available, some freeware. A google search for "host the .net framework in delphi" turns up this for example. I have no personal experience with such libraries.
-
12.1 IDE start up error personality not supported
PeterBelow replied to bdw_nz20's topic in Delphi IDE and APIs
Have you configured the IDE to load the last open project at start? The message may be caused by a corrupted dproj file. If you get the error without loading a project check the registry key Computer\HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Embarcadero\BDS\23.0\Personalities. It should look like this: Depending on your licence you have more entries, but the one after "(Standard)" is what counts here. There is a matching key for the current user: Computer\HKEY_CURRENT_USER\SOFTWARE\Embarcadero\BDS\23.0\Personalities. It should have the same content. -
The reason is quite simple: the component is based on a Windows common control which is intended to serve as storage for small images/icons used for menu items, buttons, listview items. To reduce the consumption of GDI handles the control merges all added bitmaps into one large bitmap for storage. That's the reason all bitmaps added are forced to the same size, this way the imagelist can calculate where on the combined bitmap each image resides and then paint that part to the target location. There is a maximum size to a GDI bitmap, so this puts limits on the size and number of the images you can put into a TImagelist. Looks like the control is simply not suitable for your task.
-
Stretching bitmaps to a larger size (e.g. a 16x16 bitmap to 64x64) has this effect. The Windows API function used by the VCL is not very good at reducing the unavoidable degradation in image quality by interpolating the new pixels added between the original ones. You get much better results using vector formats like SVG as source, which can be rendered to practically any size without quality loss as long as the aspect ratio is not too far off the original. For bitmaps used for UI elements (buttons, menus, listview items etc.) Delphi offers TImageCollection and TVirtualImagelist. The former can store multiple versions (different sizes) of an image and the latter is used to then pick the best fitting version for a particular screen resolution.
-
Works for me without problems (Win32 project with debug build, halted on a breakpoint). But dcc32270.dll does not belong to Delphi 12.1, that uses dcc32290.dll. 270 would be Delphi 10.3 if memory serves. Check the registry key HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Embarcadero\BDS\23.0\Debugging\Embarcadero Debuggers\Evaluators, that names the defaullt debug evaluator.
-
CompareString function for UTF8 strings or buffers?
PeterBelow replied to MarkShark's topic in RTL and Delphi Object Pascal
Depends on what you need to compare for. Equality is easy, that is a simple memory comparison. Larger/smaller implies a collation sequence, which is language-specific. Here converting to UTF-16 first is, in my opinion, the only practical way. Same if you need case-insensitive comparison, since case conversion is also language-specific and may not be applicable for the language in question at all (e.g. chinese). -
Delphi and "Use only memory safe languages"
PeterBelow replied to Die Holländer's topic in General Help
Consequent use of interface references (with rerf counting for lifetime control) instead of object references avoids that problem completely. -
Best Practices for Database Development in Delphi with Firebird
PeterBelow replied to Noor's topic in VCL
Oy, that's a really open-ended subject. The RAD approach (using data-aware controls and connection/query components you create and configure at design-time) gets you results (= working application) fast but it tends to get messy fast as well, with business logic mixed into form and data moduls, poor reuse of code (unless you plan well ahead). This approach makes proper separation of application layers harder and is excellent at producing apps that are a nightmare to maintain and document. Code can be written to be self-documenting and serve as source for project documentation as well, but how do you deal with all the stuff set at designtime and scattered across dozens or even hundreds of dfm files? In my opinion RAD is workable for smaller projects with a few database tables and a few forms as well. For anything more complex and expected to have a lifetime of many years with frequent updates it pays to use a proper layered approach (e.g. model-view-controller or similar), with a object-relational mapper (ORM) as interface to the database and a client UI that works with data objects instead of directly talking to database tables, queries, or stored procedures. All the FireDac stuff would be hidden inside the ORM. Unfortunately Delphi does not come with an ORM, but there are some 3rd-party offerings in that area, including open-source projects like MORMOT. The learning curve can be steep if you have never dealt with such a design before, but it is worth it IMO. I wrote my own ORM for a larger project at work 20 years ago, took about half a year (part time, programming was not my main task) since nothing suitable was available at that time. It has served me well and some of the programs are still in some use... As for partitioning the app into modules that can be maintained independently: that is what packages are for, but it is not as straightforward as one would hope. It's DLL hell in disguise and you have to invest some serious though into how you partition your application. Packages are all or nothing, every unit used can only be contained in one single package. All other units requiring such a unit have to get it from the (shared) package, so you have to deploy not only your own packages but also all used RTL and VCL (or FMX) and 3rd-party packages. As long as you do not change anything in the interface part of a packaged unit you can replace the build package in the production app with an updated package. If you change an interface you have to rebuild all packages using the modified one, plus the host app. Since forms etc. are declared in a unit interface that severely limits what you can change in such a form unit without major hassle. Note that this applies to units you want to use from other packages directly. It does not apply to units only used internally by a package. So it is possible to achieve a better isolation of modules if the only exposed part is a factory function for an interface the host app then uses to talk to the internal stuff of the package. In this scenario you can get away with only building with the core RTL and VCL packages and one shared package declaring the interface types used, and actually you can use DLLs (build with packages) instead of full-fledged packages. But this can still degenerate into a maintenance nightmare if you are nor careful... -
GlobalAlloc rounds the requested size up to the next multiple of 8 (at least), so it is normal for GlobalSize to return more than the requested size if that is not a multiple of the used granularity. In fact the MS docs for GlobalAlloc explicitely state that GlobalSize should be used to get the allocated size of the block requested. Depending on the use of the block you may have to store the actual data size with the data itself if the extra bytes allocated by GlobalAlloc may cause a problem for the data recipient. Note that the granularity used may depend on OS version, Microsoft is pretty vague on this.
-
It may not be logical but Windows has a lot of these little inconsistencies that have accumulated over time by bolting more functionality on existing control classes. TButton is a wrapper around the Windows button control, and its behaviour is determined by the set of button control styles, in this case the BS_MULTILINE style, which the Multiline property surfaces.
-
Delphi should let me use a const array reference as a constant
PeterBelow replied to PiedSoftware's topic in RTL and Delphi Object Pascal
A typed constant (that's what your IfTkns constant is) is actually implemented as a compiler-initialized variable, and that's the reason you cannot use it as a constant expression. It may be counter-intuitive but that's the way it works and you have to live with it. -
Oh, I'm farther behind the times than I was aware of . Didn't know these properties exist now...
-
The control (a Windows common control under the VCL surtace) has no real concept of an "empty" state. The usual way to use it is to set the shown date to Today (it does that by default if memory serves) and accept that if the user does not change it. If your requirements really need a way to detect that the user has entered a date you can use an additional TCheckbox that disables the picker unless it is checked.
-
You can experiment with the ScaleBy method all TWinControl descendants inherit, including forms.
-
Anonymous methods as interfaces
PeterBelow replied to EugeneK's topic in RTL and Delphi Object Pascal
But that's the way it currently works! Of course you can design your own interface + implementor that acts exactly like anonymous methods act now, but that would still not be the same implementation the compiler creates behind the curtain now. -
But the compiler error message should pinpoint the uses clause the (now missing) unit appears in, no?
-
Casting an untyped pointer to a typed when using with New() and Dispose()
PeterBelow replied to PeaShooter_OMO's topic in RTL and Delphi Object Pascal
It will work but there is no point in doing it this way. Declare LPointer as type PMyRec and work with that. Don't use C idioms with Delphi, that only confuses things. -
If this is for VCL: I centralize such code by overriding the UpdateActions method of the form and updating the control states from there. Much easier than fiddling with multiple event handlers or live bindings.
-
This has come up before. Microsoft changed the UI guidelines and now recommends to not show an icon for confirmation dialogs. D12's vcl.dialogs unit was modied accordingly.
-
You should not show a dialog inside a BeginUpdate/EndUpdate block in my opinion. That may be the source of your problem and it also serves no purpose i can see here.
-
You cannot, it is only possible for TWinControl descendants.
-
You cannot, subcomponents in a custom component are created in an overridden constructor. But there is an alternative: Create a new frame in the designer and place groupbox and edits on it. Save the frame unit (after changing the Name property of the frame to something descriptive), best into a folder where you stash code units you want to reuse in other projects. To use the frame in another project just add its unit to the project. A frame behaves much like a component, you can drop multiple instances of it on forms, panels or other containers. But it can also hold code like a form, in event handlers or methods, and this code is shared between all frame instances. You can modify properties of the controls on the frame in the designer for each instance separately.