Jump to content


Popular Content

Showing content with the highest reputation since 10/28/20 in all areas

  1. Hi all, I just wanted to let you know my (long-awaited) FMX book is now available (actually it is rolling out on Packt and Amazon so availability may be different across different countries). If you like to read some details you can read my latest blog post: https://blog.andreamagni.eu/2020/10/book-delphi-gui-programming-with-firemonkey-now-available/ I really hope the book will be useful to spread Delphi and FMX as development platform. Thanks for the attention, Andrea
  2. I'd like to advertise the Sempare Template Engine for Delphi. The Sempare Template Engine for Delphi allows for flexible text manipulation. It can be used for generating email, html, source code, xml, configuration, etc. It is available on github via https://github.com/sempare/sempare-delphi-template-engine It is also available via Delphinus (https://github.com/Memnarch/Delphinus) Simply add the 'src' directory to the search path to get started. Sample usage: program Example; uses Sempare.Template; type TInformation = record name: string; favourite_sport : string; end; begin var tpl := Template.parse('My name is <% name %>. My favourite sport is <% favourite_sport %>.'); var information : TInformation; information.name := 'conrad'; information.favourite_sport := 'ultimate'; writeln(Template.eval(tpl, information)); end. Features include: statements if, elif, else statements for and while statements include statement with statement function/method calls expressions simple expression evaluation (logical, numerical and string) variable definition functions and methods calls dereference records, classes, arrays, JSON objects, TDataSet descendants and dynamic arrays ternary operator safety max run-time protection customisation custom script token replacement add custom functions strip recurring spaces and new lines lazy template resolution parse time evaluation of expressions/statements allow use of custom encoding (UTF-8 with BOM, UTF-8 without BOM, ASCII, etc) extensible RTTI interface to easily dereference classes and interfaces (current customisations for ITemplateVariables, TDictionary, TJsonObject) There are numerous unit tests that can be reviewed as to how to use the various features. Happy for all to play with it. Released under GPL and Commercial License. Any feedback welcome.
  3. FPiette

    How do I enumerate all properties of a Variant?

    Yes, you can. Basically, you have to call GetTypeInfoCount(), GetTypeInfo(), GetTypeAttr() and other functions (All documented by Microsoft). Here is a function to list all method names including property getter/setter. Similar code can enumerate argument list, argument data types and return value data type. procedure DisplayMethodNames( const DispIntf : IDispatch; const IntfName : String; Strings : TStrings); var Count : Integer; TypeInfo : ITypeInfo; TypeAttr : PTypeAttr; FuncDesc : PFuncDesc; HR : HRESULT; I : Integer; FuncName : WideString; begin if IntfName <> '' then Strings.Add(IntfName); Count := 0; HR := DispIntf.GetTypeInfoCount(Count); if Failed(HR) or (Count = 0) then Exit; HR := DispIntf.GetTypeInfo(0, 0, TypeInfo); if Succeeded(HR) and (TypeInfo <> nil) then begin TypeAttr := nil; HR := TypeInfo.GetTypeAttr(TypeAttr); if Succeeded(HR) and (TypeAttr <> nil) then begin for I := 0 to TypeAttr.cFuncs - 1 do begin FuncDesc := nil; HR := TypeInfo.GetFuncDesc(I, FuncDesc); if Succeeded(HR) and (FuncDesc <> nil) then begin TypeInfo.GetDocumentation(FuncDesc.memid, @FuncName, nil, // DocString, nil, // HelpContext nil); // HelpFile if Length(FuncName) <> 0 then Strings.Add(Format(' %-3d %s', [I, FuncName])); TypeInfo.ReleaseFuncDesc(FuncDesc); end; end; TypeInfo.ReleaseTypeAttr(TypeAttr); end; end; end;
  4. Yaron

    My open-source portfolio

    I released quite a bit of interesting code to github over the years: YouTube DATA API v3 parsing: https://github.com/bLightZP/Delphi-YouTube-Channel-parsing-plugin-for-Zoom-Player Basic RSS feed parsing code: https://github.com/bLightZP/Delphi-RSS-feed-parsing-plugin-for-Zoom-Player TheAudioDB MetaData/Image scraping code: https://github.com/bLightZP/Delphi-theaudiodb.com-Zoom-Player-media-scraping-plug-in TheMovieDB MetaData/Image scraping code: https://github.com/bLightZP/Delphi-themoviedb.org-Zoom-Player-media-scraping-plug-in OpenSubtitles.org subtitle search & scrape code: https://github.com/bLightZP/Delphi-OpenSubtitles.org-API-support-for-Zoom-Player A basic cross-platform calculator https://github.com/bLightZP/ElegantCalculator https://play.google.com/store/apps/details?id=com.inmatrix.ElegantCalculator Adapted old code to work as cross-platform pure-pascal image scaling with filters (bicubic, bilinear, etc): https://github.com/bLightZP/ImageInterpolation Adapted old code to work as a cross-platform drawing of an anti-aliased circle (can be modified to draw rount-rect as well): https://github.com/bLightZP/AntiAliasedCircle I forked a QRCode generating source code and greatly optimized it (~ x50 faster): https://github.com/bLightZP/DelphiZXingQRCode The original Delphi scanline color-conversion implementation was very slow, so I optimized it: https://github.com/bLightZP/OptimizedDelphiFMXScanline
  5. Hi All For those who are interested, I have made some progress on this project, and have uploaded an installer with the command line tool and IDE plugins for XE2-10.4 - it's still very much an alpha version (not feature complete or stable) but at least shows the direction I'm heading in. I have added some quick notes on how to get started with dpm https://github.com/DelphiPackageManager/DPM/blob/master/GettingStarted.md The installer can be found here https://github.com/DelphiPackageManager/DPM The IDE plugin is still a bit rough around the edges but reasonably stable. Note that installing design time packages is still being worked on. Most of my open source projects have package binaries under the releases tab (the getting started notes show what to do with them). It's still some way from being ready for production use, we are still working on a website/package repository. If you are a library author, please do take a look. Creating packages is not at all difficult.
  6. In case someone wants to use the LibPhonenumber library from Google in Delphi. I've written a wrapper for the C # port of this library. Support for 32 bit and 64 bit. https://github.com/landrix/LibPhonenumber-for-Delphi
  7. Jim McKeeth

    Outdated Delphi Roadmap

    Coming soon to a website near you.
  8. Tired of all those programs which install lots of additional stuff I have been using more and more so called “Portable Apps”. “Portable” in this context means: You can put them anywhere, even on a portable storage device and start them from there. These Programs are still Windows only. And of course nobody prevents you from putting them in a folder on the system harddisk, usually c:\PortableApps. All files these programs need are inside this one folder, so in order to move or copy them, you simply move/copy that folder. There is a dedicated launcher and updater for these types of programs at portableapps.com, which is written in Delphi btw. and the source code is available. One thing that has irked me all the time is that these programs don’t show up in the Windows start menu, unless I add them manually, which I usually don’t. Today I had enough and wrote PortableAppsToStartMenu, a tool which given a PortableApps directory collects all the executables stored there and creates shortcuts in the Windows Start Menu for them. Read on in the blog post.
  9. David Heffernan

    Object created in a Try block???

    try Foo := TFooBar.Create; ... finally Foo.Free; end; Consider the above. Suppose that TFooBar.Create raises an exception. In that case the finally block is executed, and `Foo.Free` is called on an uninitialised variable (Foo). That leads to undefined behaviour. So the correct pattern is Foo := TFooBar.Create; try ... finally Foo.Free; end; Here, if TFooBar.Create raises an exception, the try is never reached, and so the finally block never executes. Now another pattern was also mentioned Foo := nil; try Foo := TFooBar.Create; ... finally Foo.Free; end; This is also valid, because Foo is initialised before the try executes. And so in case of constructor exception we would call Free on a nil reference which is fine. However, this pattern is pointless and should be avoided in the scenario here where there is just a single object. It is useful sometimes if there are multiple objects and you want to avoid deep nesting. A better example of using this pattern is if the object is created conditionally: Foo := nil; try if someTest then begin Foo := TFooBar.Create; ... end; ... finally Foo.Free; end;
  10. 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.
  11. FinalBuilder is a fully featured automated build tool, which supports Delphi 3 to 10.4, along with C++Builder 4 or later. FinalBuilder makes it simple to automate your entire build process, from compiling your Delphi projects to compiling and uploading installers, creating ISO's. There are over 600 built in actions, with support for Git, Mercurial, Perforce, Subversion, TFS and many other version control systems. Unlike xml or batch file based systems, with FinalBuilder you can easily debug your build process, with breakpoints, step over, step into etc. Of course FinalBuilder also integrates with Continua CI - our continuous integration server product, and with other CI servers such as Jenkins. Thousands of Software Developers rely on FinalBuilder to automate the build, test and release process. If you are not using FinalBuilder to automate your builds, you are missing out. Download a fully functional 30 day trial version today.
  12. Cristian was the first to spot the blog article: https://blogs.embarcadero.com/delphi-compiler-and-lsp-patch-for-rad-studio-10-4-1/
  13. Carlos Tré

    Tools API - Changing Key Assignment

    I wrote it myself a few years ago, based on an article written by Cary Jensen that you can find here. Attached is the code for the expert in its current state, the changing of the format source key assignment is still a work in progress. Editor.zip
  14. Marat1961

    Having fun with Delphi

    unit Uri; interface uses System.SysUtils; type PxUri = ^TxUri; TxUri = record private FScheme: string; FPort: Cardinal; FHost: string; FUserName: string; FPassword: string; FPath: string; FQuery: string; FFragment: string; public function Init(const Scheme, Path: string; Port: Cardinal = 0): PxUri; function Host(const Value: string): PxUri; function UserName(const Value: string): PxUri; function Password(const Value: string): PxUri; function Path(const Value: string): PxUri; function Query(const Value: string): PxUri; function Fragment(const Value: string): PxUri; function ToString: string; end; implementation function TxUri.Init(const Scheme, Path: string; Port: Cardinal): PxUri; begin Result := @Self; Self := Default(TxUri); FScheme := Scheme; FPath := '/' + Path; FPort := Port; end; function TxUri.Host(const Value: string): PxUri; begin Result := @Self; FHost := Value; end; function TxUri.UserName(const Value: string): PxUri; begin Result := @Self; FUserName := Value; end; function TxUri.Password(const Value: string): PxUri; begin Result := @Self; FPassword := Value; end; function TxUri.Path(const Value: string): PxUri; begin Result := @Self; FPath := FPath + Format('/%s', [Value]); end; function TxUri.Query(const Value: string): PxUri; begin Result := @Self; if FQuery = '' then FQuery := Format('?%s', [Value]) else FQuery := FQuery + Format('&%s', [Value]); end; function TxUri.Fragment(const Value: string): PxUri; begin Result := @Self; FFragment := Format('#%s', [Value]); end; function TxUri.ToString: string; var sb: TStringBuilder; begin sb := TStringBuilder.Create; try sb.Append(FScheme); sb.Append(':'); if FHost <> '' then begin sb.Append('//'); if FUserName <> '' then sb.AppendFormat('%s:%s@', [FUserName, FPassword]); sb.Append(FHost); if FPort <> 0 then sb.AppendFormat(':%d', [FPort]); end; sb.Append(FPath); if FQuery <> '' then sb.Append(FQuery); if FFragment <> '' then sb.Append(FFragment); Result := sb.ToString; finally sb.Free; end; end; end. procedure TForm2.Button1Click(Sender: TObject); var uri: TxUri; begin uri.Init('http', 'Mammalia', 8080) .UserName('yourname') .Password('TopSecret') .Host('www.website.com') .Path('Theria') .Path('Carnivora') .Path('Felidae') .Path('Lynx_pardinus') .Query('showall') .Query('yearstart=1990') .Fragment('StartReadingHere'); Label1.Caption := uri.ToString; end; http://yourname:TopSecret@www.website.com:8080/Mammalia/Theria/Carnivora/Felidae/Lynx_pardinus?showall&yearstart=1990#StartReadingHere 005FD859 68901F0000 push $00001f90 005FD85E 8D45D8 lea eax,[ebp-$28] 005FD861 B92CD95F00 mov ecx,$005fd92c 005FD866 BA4CD95F00 mov edx,$005fd94c 005FD86B E8C8F8FFFF call TxUri.Init 005FD870 BA64D95F00 mov edx,$005fd964 005FD875 E856F9FFFF call TxUri.UserName 005FD87A BA84D95F00 mov edx,$005fd984 005FD87F E874F9FFFF call TxUri.Password 005FD884 BAA4D95F00 mov edx,$005fd9a4 005FD889 E81AF9FFFF call TxUri.Host 005FD88E BAD0D95F00 mov edx,$005fd9d0 005FD893 E888F9FFFF call TxUri.Path 005FD898 BAECD95F00 mov edx,$005fd9ec 005FD89D E87EF9FFFF call TxUri.Path 005FD8A2 BA0CDA5F00 mov edx,$005fda0c 005FD8A7 E874F9FFFF call TxUri.Path 005FD8AC BA28DA5F00 mov edx,$005fda28 005FD8B1 E86AF9FFFF call TxUri.Path 005FD8B6 BA50DA5F00 mov edx,$005fda50 005FD8BB E8ECF9FFFF call TxUri.Query 005FD8C0 BA6CDA5F00 mov edx,$005fda6c 005FD8C5 E8E2F9FFFF call TxUri.Query 005FD8CA BA98DA5F00 mov edx,$005fda98 005FD8CF E8B8FAFFFF call TxUri.Fragment TestUri.pas.42: Label1.Caption := uri.ToString; 005FD8D4 8D55D4 lea edx,[ebp-$2c] 005FD8D7 8D45D8 lea eax,[ebp-$28] 005FD8DA E835FBFFFF call TxUri.ToString 005FD8DF 8B55D4 mov edx,[ebp-$2c] 005FD8E2 8B45FC mov eax,[ebp-$04] 005FD8E5 8B80D4030000 mov eax,[eax+$000003d4] 005FD8EB E8F446F4FF call TControl.SetText
  15. FPiette

    Can 32bit dll with Form/Frame be used in 64 bit project?

    Long time ago, I wrote an application which hosted forms from another application, both are exe files. The host application run the child application and find the handle of the form to be embedded, then it change his parent. Windows will make the child window appear in the host application as child! In your case, you write both applications. The host is 64 bit and the child is 32 bit wrapping the 32 bit ActiveX. You can even ease the communication between the two instead of using API to enumerate process and windows to find what you need and transfer data between the two applications.
  16. Dalija Prasnikar

    Outdated Delphi Roadmap

    Yes. It can have huge impact. If some feature is scheduled for improvement, that means it will be looked at, but the more work feature needs, the more chances is that some parts will not be done right or some accidental bugs might creep in. Also public API can change only at major releases. If some API gets designed in a wrong way, it must stay like that until the next major release. I personally don't use floating point much, so I don't know how broad are required changes to improve performance and whether this will be some compiler tweaking or changes involved require significant API changes, too. In any way, it is always hard to predict different use cases and most important pain points, so having feedback from people that are experts in the area and that know what they need is crucial. Subscription is needed for regular users, but there are also exceptions for cases where people are invited because they can provide valuable feedback in certain areas.
  17. Stefan Glienke

    do any git tools work like this?

    Must be very unproductive and frustrating the way you handle things - it is known that humans are terrible at context switching.
  18. Anders Melander

    do any git tools work like this?

    Once again: As far as I can tell there's nothing special in the work flow your describe. It's perfectly normal to have a branch per ticket, to change branch several times a day, to get interrupted while you're working on something that hasn't yet been committed, etc. The problems with Git you describe (changes disappearing, etc) are not problems with Git but with the way you use it; It will not overwrite your uncommitted changes unless you force it to. It is unclear to me what benefits your tool provides. It sounds like the problems it solves are already handled by the existing GUI Git clients.
  19. Please don't misuse "tag" for pointers. I'd rather use a tDictionary<tcomponent, tSomethingelse> to store associations between components and objects. It's much more universal and transparent.
  20. Renate Schaaf

    Project Bitmaps2Video on GitHub

    This is my video-project on GitHub: https://github.com/rmesch/Bitmaps2Video I am presenting it here, because it is useful as it is, but could use some ideas for improvement. Features: A Delphi-class to support encoding of a series of bitmaps and video clips to a video file Requires the ffmpeg-library and is intended as an easy to use interface to this library Versions for Win32/Win64 and a cross-platform version currently supporting Win32/Win64/Android32/Android64 Most popular file formats and codecs supported, more codecs contained in FFMpeg can be registered Rudimentary support for adding an audio-stream Demos for both versions, set up to compile and run "out of the box", as library files and support for their deployment to Android are included There are some problem areas though, the most important one in my opinion being threading issues with TBitmap under Android. For more see the readme and the demos. Critique, ideas, bug reports most welcome, maybe someone would even like to contribute, that would be delightful. There have been valuable contributions so far, but there are some areas which could use the input of an expert. Thanks for reading, Renate
  21. Remy Lebeau

    Why do these 2 statments produce different results ?

    '#$02' (w/ quotes) is a string literal consisting of 4 distinct characters: '#', '$', '0', '2'. The string you are searching, 'bla,bla,#$02,bla', contains that 4-char substring in it, hence the result is > 0. #$02 (w/o quotes) is a single Char whose numeric value is 2. The string you are searching does not contain that character in it, hence the result is 0.
  22. Anders Melander

    Interlocked API and memory-mapped files

    Okay, here you go. Source and simple demo attached. Usage: Producer var FRingBuffer := TSharedMemoryRingBuffer.Create('FooBar', 1024*1024); // 1Mb ... // String FRingBuffer.Enqueue('Hello world'); // Raw bytes var Buffer: TBytes; ... FRingBuffer.Enqueue(Buffer); Consumer var FRingBuffer := TSharedMemoryRingBuffer.Create('FooBar', 1024*1024); // 1Mb ... // Strings while (True) do begin // Just remove the WaitFor to use polling instead if (FRingBuffer.WaitFor(100) = wrSignaled) then begin var s. string; if (FRingBuffer.Dequeue(s)) then ...do something with string... end; ... end; // Raw bytes while (True) do begin // Just remove the WaitFor to use polling instead if (FRingBuffer.WaitFor(100) = wrSignaled) then begin var Buffer: TBytes; if (FRingBuffer.Dequeue(Buffer)) then ...do something with buffer... end; ... end; amSharedMemory.pas SharedMemory.zip
  23. Mahdi Safsafi

    Interlocked API and memory-mapped files

    No! CS is not designed to work with inter-process. It may look from the first sight that putting it into a shared memory will do the trick ... but in fact things are more complex than what you think because there is a signaling mechanism involved usually a semaphore that has a local(private) visibility. @Kas Ob. WaitOnAddress apparently works only with threads in the same process.
  24. Kas Ob.

    Multiple two UInt64 modulo

    OK, Please provide explanation of what on earth are you are trying to do ? Your solution is impossible to be judge unless you elaborate, but looking at you the so called revised 1) you don't need to zero RDX before division. 2) the parameter "a" is in RCX and your first line "MOV RCX, m" is overwriting it a with m. 3) WHAY, i mean why your sample in two posts insist on using m=$FFFFFFFFFFFFFFFF, that value is exactly "m= UInt64(-1)", in other words it is the highest value for UInt64, means the modulus x in "x = a mod m" when "m= highestvalue" will always be "x=a" unless a=m then it will be "x=0", so no need for mod for that value to begin with, a simple compare will do if you need "mod highestvalue". again explain what are you trying to achieve? as Marat1961 assumed you are trying to implement a random number generator, while i assumed you are trying to implement multiplication in a Galois field. So before answering any more question, spare us the guessing and help yourself by format your questions in meaningful manner.
  25. Arnaud Bouchez

    Multiple two UInt64 modulo

    What counts is that in x86_64 asm, MUL and DIV are 128-bit. https://www.felixcloutier.com/x86/mul states: REX.W + F7 /4 MUL r/m64 M Valid N.E. Unsigned multiply (RDX:RAX ← RAX ∗ r/m64). and https://www.felixcloutier.com/x86/div reports: REX.W + F7 /6 DIV r/m64 M Valid N.E. Unsigned divide RDX:RAX by r/m64, with result stored in RAX ← Quotient, RDX ← Remainder So my guess is that this code is correct, and the fastest possible on the target. Only if m is known in advance (as a constant), you may be able to make the division faster by using a reciprocal multiplication or a bits shift. From https://www.agner.org/optimize/instruction_tables.pdf on a modern CPU, 64-bit MUL takes around 3 cycles, and 64-bit DIV 10 cycles. Difficult to make it faster with any other algorithm. As a small optimization, you can omit the stack frame: function MulModASM(a, b, m: UInt64): UInt64; {$ifdef FPC}nostackframe; assembler; asm {$else} asm .noframe {$endif FPC} MOV rax, a MOV rcx, m MUL b DIV rcx MOV rax, RDX end; https://ideone.com/KUsgMi About register conventions, for windows/posix: rcx/rdi=a rdx/rsi=b r8/rdx=m so it should be fine. Just to be tested with a lot of values and high 64-bit limits.