Archive
Hydra, what’s the big deal anyway?
RemObjects Hydra is a product I have used for years in concert with Delphi, and like most developers that come into contact with RemObjects products – once the full scope of the components hit you, you never want to go back to not using Hydra in your applications.
Note: It’s easy to dismiss Hydra as a “Delphi product”, but Hydra for .Net and Java does the exact same thing, namely let you mix and match modules from different languages in your programs. So if you are a C# developer looking for ways to incorporate Java, Delphi, Elements or Freepascal components in your application, then keep reading.
But let’s start with what Hydra can do for Delphi developers.
What is Hydra anyways?
Hydra is a component package for Delphi, Freepascal, .Net and Java that takes plugins to a whole new level. Now bear with me for a second, because these plugins is in a completely different league from anything you have used in the past.
In short, Hydra allows you to wrap code and components from other languages, and use them from Delphi or Lazarus. There are thousands of really amazing components for the .Net and Java platforms, and Hydra allows you compile those into modules (or “plugins” if you prefer that); modules that can then be used in your applications like they were native components.

Hydra, here using a C# component in a Delphi application
But it doesn’t stop there; you can also mix VCL and FMX modules in the same application. This is extremely powerful since it offers a clear path to modernizing your codebase gradually rather than doing a time consuming and costly re-write.
So if you want to move your aging VCL codebase to Firemonkey, but the cost of having to re-write all your forms and business logic for FMX would break your budget -that’s where Hydra gives you a second option: namely that you can continue to use your VCL code from FMX and refactor the application in your own tempo and with minimal financial impact.
The best of all worlds
Not long ago RemObjects added support for Lazarus (Freepascal) to the mix, which once again opens a whole new ecosystem that Delphi, C# and Java developers can benefit from. Delphi has a lot of really cool components, but Lazarus have components that are not always available for Delphi. There are some really good developers in the Freepascal community, and you will find hundreds of components and classes (if not thousands) that are open-source; For example, Lazarus has a branch of Synedit that is much more evolved and polished than the fork available for Delphi. And with Hydra you can compile that into a module / plugin and use it in your Delphi applications.
This is also true for Java and C# developers. Some of the components available for native languages might not have similar functionality in the .Net world, and by using Hydra you can tap into the wealth that native languages have to offer.
As a Delphi or Freepascal developer, perhaps you have seen some of the fancy grids C# and Java coders enjoy? Developer Express have some of the coolest components available for any platform, but their focus is more on .Net these days than Delphi. They do maintain the control packages they have, but compared to the amount of development done for C# their Delphi offerings are abysmal. So with Hydra you can tap into the .Net side of things and use the latest components and libraries in your Delphi applications.
Financial savings
One of coolest features of Hydra, is that you can use it across Delphi versions. This has helped me leverage the price-tag of updating to the latest Delphi.
It’s easy to forget that whenever you update Delphi, you also need to update the components you have bought. This was one of the reasons I was reluctant to upgrade my Delphi license until Embarcadero released Delphi 10.2. Because I had thousands of dollars invested in components – and updating all my licenses would cost a small fortune.
So to get around this, I put the components into a Hydra module and compiled that using my older Delphi. And then i simply used those modules from my new Delphi installation. This way I was able to cut cost by thousands of dollars and enjoy the latest Delphi.

Using Firemonkey controls under VCL is easy with Hydra
A couple of years back I also took the time to wrap a ton of older components that work fine but are no longer maintained or sold. I used an older version of Delphi to get these components into a Hydra module – and I can now use those with Delphi 10.3 (!). In my case there was a component-set for working closely with Active Directory that I have used in a customer’s project (and much faster than having to go the route via SQL). The company that made these don’t exist any more, and I have no source-code for the components.
The only way I could have used these without Hydra, would be to compile them into a .dll file and painstakingly export every single method (or use COM+ to cross the 32-bit / 64-bit barrier), which would have taken me a week since we are talking a large body of quality code. With Hydra i was able to wrap the whole thing in less than an hour.
I’m not advocating that people stop updating their components. But I am very thankful for the opportunity to delay having to update my entire component stack just to enjoy a modern version of Delphi.
Hydra gives me that opportunity, which means I can upgrade when my wallet allows it.
Building better applications
There is also another side to Hydra, namely that it allows you to design applications in a modular way. If you have the luxury of starting a brand new project and use Hydra from day one, you can isolate each part of your application as a module. Avoiding the trap of monolithic applications.

Hydra for .Net allows you to use Delphi, Java and FPC modules under C#
This way of working has great impact on how you maintain your software, and consequently how you issue hotfixes and updates. If you have isolated each key part of your application as separate modules, you don’t need to ship a full build every time.
This also safeguards you from having all your eggs in one basket. If you have isolated each form (for example) as separate modules, there is nothing stopping you from rewriting some of these forms in another language – or cross the VCL and FMX barrier. You have to admit that being able to use the latest components from Developer Express is pretty cool. There is not a shadow of a doubt that Developer-Express makes the best damn components around for any platform. There are many grids for Delphi, but they cant hold a candle to the latest and greatest from Developer Express.
Why can’t I just use packages?
If you are thinking “hey, this sounds exactly like packages, why should I buy Hydra when packages does the exact same thing?“. Actually that’s not how packages work for Delphi.
Delphi packages are cool, but they are also severely limited. One of the reasons you have to update your components whenever you buy a newer version of Delphi, is because packages are not backwards compatible.

Delphi packages are great, but severely limited
A Delphi package must be compiled with the same RTL as the host (your program), and version information and RTTI must match. This is because packages use the same RTL and more importantly, the same memory manager.
Hydra modules are not packages. They are clean and lean library files (*.dll files) that includes whatever RTL you compiled them with. In other words, you can safely load a Hydra module compiled with Delphi 7, into a Delphi 10.3 application without having to re-compile.
Once you start to work with Hydra, you gradually build up modules of functionality that you can recycle in the future. In many ways Hydra is a whole new take on components and RAD. This is how Delphi packages and libraries should have been.
Without saying anything bad about Delphi, because Delphi is a system that I love very much; but having to update your entire component stack just to use the latest Delphi, is sadly one of the factors that have led developers to abandon the platform. If you have USD 10.000 in dependencies, having to pay that as well as buying Delphi can be difficult to justify; especially when comparing with other languages and ecosystems.
For me, Hydra has been a tremendous boon for Delphi. It has allowed me to keep current with Delphi and all it’s many new features, without losing the money I have already invested in components packages.
If you are looking for something to bring your product to the next level, then I urge you to spend a few hours with Hydra. The documentation is exceptional, the features and benefits are outstanding — and you will wonder how you ever managed to work without them.
External resources
Disclaimer: I am not a salesman by any stretch of the imagination. I realize that promoting a product made by the company you work for might come across as a sales pitch; but that’s just it: I started to work for RemObjects for a reason. And that reason is that I have used their products since they came on the market. I have worked with these components long before I started working at RemObjects.
.NetRocks, you made my day!
A popular website for .Net developers is called dot-net-rocks. This is an interesting site that has been going for a while now; well worth the visit if you do work with the .Net framework via RemObjects Elements, VS or Mono.
Now it turns out that the guys over at dot–net-rocks just did an episode on their podcast where they open by labeling me as a “raving lunatic” (I clearly have my moments); which I find absolutely hilarious, but not for the same reasons as them.
Long story short: They are doing a podcast on how to migrate legacy Delphi applications to C#, and in that context they somehow tracked down an article I posted way back in 2016, which was meant as a satire piece. Now don’t get me wrong, there are serious points in the article, like how the .Net framework was modeled on the Delphi VCL, and how the concepts around CLR and JIT were researched at Borland; but the tone of the whole thing, the “larger than life” claims etc. was meant to demonstrate just how some .Net developers behave when faced with alternative eco-systems. Having managed some 16+ usergroups for Delphi, C#, JavaScript (a total of six languages) on Facebook for close to 15 years, as well as working for Embarcadero that makes Delphi -I speak from experience.
It might be news to these guys that large companies around Europe is still using Delphi, modern Delphi, and that Object Pascal as a language scores well on the Tiobi index of popular programming languages. And no amount of echo-chamber mentality is going to change that fact. Heck, as late as 2018 and The Walt Disney Company wanted to replace C# with Delphi, because it turns out that bytecodes and embedded tech is not the best combination (cpu spikes when the GC kicks in, no real-time interrupt handling possible, GPIO delays, the list goes on).
I mean, the post i made back in 2016 is such obvious, low-hanging fruit for a show their size to pound on. You have this massive show that takes on a single, albeit ranting (and probably a bit of a lunatic if I don’t get my coffee) coder’s post. Underlying in the process how little they know about the object pascal community at large. They just demonstrated my point in bold, italic and underline 😀
Look before you shoot
DotNetRocks is either oblivious that Delphi still have millions of users around the world, or that Pascal is in fact available for .Net (which is a bit worrying since .Net is supposed to be their game). The alternative is that the facts I listed hit a little too close to home. I’ll leave it up to the reader to decide. Microsoft has lost at least 10 Universities around Europe to Delphi in 2018 that I know of, two of them Norwegian where I was personally involved in the license sales. While only speculation, I do find the timing for their podcast and focus on me in particular to be, “curious”.
And for the record, the most obvious solution when faced with “that legacy Delphi project”, is to just go and buy a modern version of Delphi. DotNetRocks delivered a perfect example of that very arrogance my 2016 post was designed to convey; namely that “brogrammers” often act like Delphi 7 was the last Delphi. They also resorted to lies to sell their points: I never said that Anders was dogged for creating Delphi. Quite the opposite. I simply underlined that by ridiculing Delphi in one hand, and praising it’s author with the other – you are indirectly (and paradoxically) invalidating half his career. Anders is an awesome developer, but why exclude how he evolved his skills? Ofcourse Ander’s products will have his architectural signature on them.
Not once did they mention Embarcadero or the fact that Delphi has been aggressively developed since Borland kicked the bucket. Probably hoping that undermining the messenger will somehow invalidate the message.

Porting Delphi to C# manually? Ok.. why not install Elements and just compile it into an assembly? You don’t even have to leave Visual Studio
Also, such an odd podcast for professional developers to run with. I mean, who the hell converts a Delphi project to C# manually? It’s like listening to a graphics artist that dont know that Photoshop and Illustrator are the de-facto tools to use. How is that even possible? A website dedicated to .Net, yet with no insight into the languages that run on the CLR? Wow.
If you want to port something from Delphi to .Net, you don’t sit down and manually convert stuff. You use proper tools like Elements from RemObjects; This gives you Object-Pascal for .Net (so a lot of code will compile just fine with only minor changes). Elements also ships with source-conversion tools, so once you have it running under Oxygene Pascal (the dialect is called Oxygene) you either just use the assemblies — or convert the Pascal code to C# through a tool called an Oxidizer.

The most obvious solution is to just upgrade to a Delphi version from this century
The other solution is to use Hydra, also a RemObjects product. They can then compile the Delphi code into a library (including visual parts like forms and frames), and simply use that as any other assembly from within C#. This allows you to gradually phase out older parts without breaking the product. You can also use C# assemblies from Delphi with Hydra.
So by all means, call me what you like. You have only proved my point so far. You clearly have zero insight into the predominant Object-Pascal eco-systems, you clearly don’t know the tools developers use to interop between arcetypical and contextual languages — and instead of fact checking some of the points I made, dry humor notwithstanding, you just reacted like brogrammers do.
Well, It’s been weeks since I laughed this hard 😀 You really need to check before you pick someone to verbally abuse on the first date, because you might just bite yourself in the arse here he he
Cheers
Using multiple languages is the same project
Most compilers can only handle a single syntax for any project, but the Elements compiler from RemObjects deals with 5 (five!) different languages -even within the same project. That’s pretty awesome and opens up for some considerable savings.
I mean, it’s not always easy to find developers for a single language, but when you can approach your codebase from C#, Java, Go, Swift and Oxygene (object pascal) at the same time (inside the same project even!), you suddenly have some options. Especially since you can pick exotic targets like WebAssembly. Or what about compiling Java to .net bytecodes? Or using the VCL from C#? It’s pretty awesome stuff!
Check out Marc Hoffmans article on the Elements compiler toolchain and how you can mix and match between languages, picking the best from each — while still compiling to a single binary of llvm optimized code:
Check out RemObjects Remoting SDK
RemObjects Remoting SDK is one of those component packages that have become more than the sum of it’s part. Just like project Jedi has become standard equipment almost, Remoting SDK is a system that all Delphi and Freepascal developers should have in their toolbox.
In this article I’m going to present the SDK in broad strokes; from a viewpoint of someone who haven’t used the SDK before. There are still a large number of Delphi developers that don’t know it even exists – hopefully this post will shed some light on why the system is worth every penny and what it can do for you.
I should also add, that this is a personal blog. This is not an official RemObjects presentation, but a piece written by me based on my subjective experience and notions. We have a lot of running dialog at Delphi Developer on Facebook, so if I read overly harsh on a subject, that is my personal view as a Delphi Developer.
Stop re-inventing the wheel
Delphi has always been a great tool for writing system services. It has accumulated a vast ecosystem of non-visual components over the years, both commercial and non-commercial, and this allows developers to quickly aggregate and expose complex behavior — everything from graphics processing to databases, file processing to networking.
The challenge for Delphi is that writing large composite systems, where you have more than a single service doing work in concert, is not factored into the RTL or project type. Delphi provides a bare-bone project type for system services, and that’s it. Depending on how you look at it, it’s either a blessing or a curse. You essentially start on C level.
So fundamental things like IPC (inter process communication) is something you have to deal with yourself. If you want multi-tenancy that is likewise not supported out of the box. And all of this is before we venture into protocol standards, message formats and async vs synchronous execution.
The idea behind Remoting SDK is to get away from this style of low-level hacking. Without sounding negative, it provides the missing pieces that Delphi lacks, including the stuff that C# developers enjoy under .net (and then some). So if you are a Delphi developer who look over at C# with smudge of envy, then you are going to love Remoting SDK.
Say goodbye to boilerplate mistakes
Writing distributed servers and services is boring work. For each function you expose, you have to define the parameters and data-types in a portable way, then you have to implement the code that represents the exposed function and finally the interface itself that can be consumed by clients. The latter must be defined in a way that works with other languages too, not just Delphi. So while server tech in it’s essential form is quite simple, it’s the infrastructure that sets the stage of how quickly you can apply improvements and adapt to change.
For example, let’s say you have implemented a wonderful new service. It exposes 60 awesome functions that your customers can consume in their own work. The amount of boilerplate code for 60 distributed functions, especially if you operate with composite data types, is horrendous. It is a nightmare to manage and opens up for sloppy, unnecessary mistakes.
This is where Remoting SDK truly shines. When you install the software, it integrates it’s editors and wizards closely with the Delphi IDE. It adds a ton of new project types, components and whatnot – but the most important feature is without a doubt the service designer.

Start the service-designer in any server or service project and you can edit the methods, data types and interfaces your system expose to the world
As the name implies, the service designer allows you to visually define your services. Adding a new function is a simple click, the same goes for datatypes and structures (record types). These datatypes are exposed too and can be consumed from any modern language. So a service you make in Delphi can be used from C#, C/C++, Java, Oxygene, Swift (and visa-versa).
Auto generated code
A service designer is all good and well I hear you say, but what about that boilerplate code? Well Remoting SDK takes care of that too (kinda the point). Whenever you edit your services, the designer will auto-generate a new interface unit for you. This contains the classes and definitions that describe your service. It will also generate an implementation unit, with empty functions; you just need to fill in the blanks.
The designer is also smart enough not to remove code. So if you go in and change something, it won’t just delete the older implementation procedure. Only the params and names will be changed if you have already written some code.

Having changed a service, hitting F9 re-generates the interface code automatically. Your only job is to fill in the code for each method in the implementation units. The SDK takes care of everything else for you
The service information, including the type information, is stored in a special file format called “rodl”. This format is very close to Microsoft WSDL format, but it holds more information. It’s important to underline that you can import the service directly from your servers (optional naturally) as WSDL. So if you want to consume a Remoting SDK service using Delphi’s ordinary RIO components, that is not a problem. Visual Studio likewise imports and consumes services – so Remoting SDK behaves identical regardless of platform or language used.
Remoting SDK is not just for Delphi, just to be clear on that. If you are presently using both Delphi and C# (which is a common situation), you can buy a license for both C# and Delphi and use whatever language you feel is best for a particular task or service. You can even get Remoting SDK for Javascript and call your service-stack directly from your website if you like. So there are a lot of options for leveraging the technology.
Transport is not content
OK so Remoting SDK makes it easy to define distributed services and servers. But what about communication? Are we boxed into RemObjects way of doing things?
The remoting framework comes with a ton of components, divided into 3 primary groups:
- Servers
- Channels (clients)
- Messages
The reason for this distinction is simple: the ability to transport data, is never the same as the ability to describe data. For example, a message is always connected to a standard. It’s job is ultimately to serialize (represent) and de-serialize data according to a format. The server’s job is to receive a request and send a response. So these concepts are neatly decoupled for maximum agility.
As of writing the SDK offers the following message formats:
- Binary
- Post
- SOAP
- JSON
If you are exposing a service that will be consumed from JavaScript, throwing in a TROJSONMessage component is the way to go. If you expect messages to be posted from your website using ordinary web forms, then TROPostMessage is a perfect match. If you want XML then TROSOAPMessage rocks, and if you want fast, binary messages – well then there is TROBinaryMessage.
What you must understand is that you don’t have to pick just one! You can drop all 4 of these message formats and hook them up to your server or channel. The SDK is smart enough to recognize the format and use the correct component for serialization. So creating a distributed service that can be consumed from all major platforms is a matter of dropping components and setting a property.

If you double-click on a server or channel, you can link message components with a simple click. No messy code snippets in sight.
Multi-tenancy out of the box
With the release of Rad-Server as a part of Delphi, people have started to ask what exactly multi-tenancy is and why it matters. I have to be honest and say that yes, it does matter if you are creating a service stack where you want to isolate the logic for each customer in compartments – but the idea that this is somehow new or unique is not the case. Remoting SDK have given users multi-tenancy support for 15+ years, which is also why I haven’t been too enthusiastic with Rad-Server.
Now don’t get me wrong, I don’t have an axe to grind with Rad-Server. The only reason I mention it is because people have asked how i feel about it. The tech itself is absolutely welcome, but it’s the licensing and throwing Interbase in there that rubs me the wrong way. If it could run on SQLite3 and was free with Enterprise I would have felt different about it.

There are various models for multi-tenancy, but they revolve around the same principles
To get back on topic: multi-tenancy means that you can dynamically load services and expose them on demand. You can look at it as a form of plugin functionality. The idea in Rad-Server is that you can isolate a customer’s service in a separate package – and then load the package into your server whenever you need it.
The reason I dislike Rad-Server in this respect, is because they force you to compile with packages. So if you want to write a Rad-Server system, you have to compile your entire project as package-based, and ship a ton of .dpk files with your system. Packages is not wrong or bad per-se, but they open your system up on a fundamental level. There is nothing stopping a customer from rolling his own spoof package and potentially bypass your security.
There is also an issue with un-loading a package, where right now the package remains in memory. This means that hot-swapping packages without killing the server wont work.
Rad-Server is also hardcoded to use Interbase, which suddenly bring in licensing issues that rubs people the wrong way. Considering the price of Delphi in 2019, Rad-Server stands out as a bit of an oddity. And hardcoding a database into it, with the licensing issues that brings -just rendered the whole system mute for me. Why should I pay more to get less? Especially when I have been using multi-tenancy with RemObjects for some 15 years?
With Remoting SDK you have something called DLL servers, which does the exact same thing – but using ordinary DLL files (not packages!). You don’t have to compile your system with packages, and it takes just one line of code to make your main dispatcher aware of the loaded service.
This actually works so well that I use Remoting SDK as my primary “plugin” system. Even when I write ordinary desktop applications that has nothing to do with servers or services – I always try to compartmentalize features that could be replaced in the future.
For example, I’m a huge fan of ElevateDB, which is a native Delphi database engine that compiles directly into your executable. By isolating that inside a DLL as a service, my application is now engine agnostic – and I get a break from buying a truck load of components every time Delphi is updated.
Saving money
The thing about DLL services, is that you can save a lot of money. I’m actually using an ElevateDB license that was for Delphi 2007. I compiled the engine using D2007 into a DLL service — and then I consume that DLL from my more modern Delphi editions. I have no problem supporting or paying for components, that is right and fair, but having to buy new licenses for every single component each time Delphi is updated? This is unheard of in other languages, and I would rather ditch the platform all together than forking out $10k ever time I update.

A DLL server can be used for many things if you are creative about it
While we are on the subject – Hydra is another great money saver. It allows you to use .net and Java libraries (both visual and non-visual) with Delphi. With Hydra you can design something in .net, compile it into a DLL file, and then use that from Delphi.
But — you can also compile things from Delphi, and use it in newer versions of Delphi. Im not forking out for a Developer Express update just to use what I have already paid for in the latest Delphi. I have one license, I compile the forms and components into a Hydra Module — and then use it from newer Delphi editions.

Hydra, which is a separate product, allows you to stuff visual components and forms inside a vanilla DLL. It allows cross language use, so you can finally use Java and .net components inside your Delphi application
Bonjour support
Another feature I love is the zero configuration support. This is one of those things that you often forget, but that suddenly becomes important once you deploy a service stack on cluster level.
Remoting SDK comes with support for Apple Bonjour, so if you want to use that functionality you have to install the Bonjour library from Apple. Once installed on your host machines, your RemObjects services can find each other.
ZeroConfig is not that hard to code manually. You can roll your own using UDP or vanilla messages. But getting service discovery right can be fiddly. One thing is broadcasting an UDP message saying “here I am”, it’s something else entirely to allow service discovery on cluster level.
If Bonjour is not your cup of tea, the SDK provides a second option, which is RemObjects own zero-config hub. You can dig into the documentation to find out more about this.
What about that IPC stuff you mentioned?
I mentioned IPC (inter process communication) at the beginning here, which is a must have if you are making a service stack where each member is expected to talk to the others. In a large server-system the services might not exist on the same, physical hardware either, so you want to take height for that.
With the SDK this is just another service. It takes 10 minutes to create a DLL server with the functionality to send and receive messages – and then you just load and plug that into all your services. Done. Finished.
Interestingly, Remoting SDK supports named-pipes. So if you are running on a Windows network it’s even easier. Personally I prefer to use a vanilla TCP/IP based server and channel, that way I can make use of my Linux blades too.
Building on the system
There is nothing stopping you from expanding the system that RemObjects have established. You are not forced to only use their server types, message types and class framework. You can mix and match as you see fit – and also inherit out your own variation if you need something special.
For example, WebSocket is an emerging standard that has become wildly popular. Remoting SDK does not support that out of the box, the reason is that the standard is practically identical to the RemObjects super-server, and partly because there must be room for third party vendors.
Andre Mussche took the time to implement a WebSocket server for Remoting SDK a few years back. Demonstrating in the process just how easy it is to build on the existing infrastructure. If you are already using Remoting SDK or want WebSocket support, head over to his github repository and grab the code there: https://github.com/andremussche/DelphiWebsockets
I could probably write a whole book covering this framework. For the past 15 years, RemObjects Remoting SDK is the first product I install after Delphi. It has become standard for me and remains an integral part of my toolkit. Other packages have come and gone, but this one remains.
Hopefully this post has tickled your interest in the product. No matter if you are maintaining a legacy service stack, or thinking about re implementing your existing system in something future-proof, this framework will make your life much, much easier. And it wont break the bank either.
You can visit the product page here: https://www.remotingsdk.com/ro/default.aspx
And you can check out the documentation here: https://docs.remotingsdk.com/
30% discount on all RemObjects products!
This is brilliant. RemObjects is giving a whopping 30% discount on all products!
This means you can now pick up RemObjects Remoting Framework, Data Abstract, Hydra or the Elements compiler toolchain – with a massive 30% saving!
These are battle-hardened, enterprise level solutions that have been polished over years and they are in constant development. Each solution integrates seamlessly into Embarcadero Delphi and provides a smooth path to delivering quality products in days rather than weeks.
But you better hurry because it’s only valid for one week (!)
Use the coupon code: “DelphiDeveloper”
Calling node.js from Delphi
We got a good question about how to start a node.js program from Delphi on our Facebook group today (third one in a week?). When you have been coding for years you often forget that things like this might not be immediately obvious. Hopefully I can shed some light on the options in this post.
Node or chrome?
Just to be clear: node.js has nothing to do with chrome or chromium embedded. Chrome is a web-browser, a completely visual environment and ecosystem.
Node.js is the complete opposite. It is purely a shell based environment, meaning that it’s designed to run services and servers, with emphasis on the latter.
The only thing node.js and chrome have in common, is that they both use the V8 JavaScript runtime engine to load, JIT compile and execute scripts at high speed. Beyond that, they are utterly alien to each other.
Can node.js be embedded into a Delphi program?
Technically there is nothing stopping a C/C++ developer from compiling the node.js core system as C++ builder compatible .obj files; files that can then be linked into a Delphi application through references. But this also requires a bit of scaffolding, like adding support for malloc_, free_ and a few other procedures – so that your .obj files uses the same memory manager as your Delphi code. But until someone does just that and publish it, im afraid you are stuck with two options:
- Use a library called Toby, that keeps node.js in a single DLL file. This is the most practical way if you insist on hosting your own version of node.js
- Add node.js as a prerequisite and give users the option to locate the node.exe in your application’s preferences. This is the way I would go, because you really don’t want to force users to stick with your potentially outdated or buggy build.
So yes, you can use toby and just add the toby dll file to your program folder, but I have to strongly advice against that. There is no point setting yourself up for maintaining a whole separate programming language, just because you want JavaScript support.
“How many in your company can write high quality WebAssembly modules?”
If all you want to do is support JavaScript in your application, then I would much rather install Besen into Delphi. Besen is a JavaScript runtime engine written in Freepascal. It is fully compatible with Delphi, and follows the ECMA standard to the letter. So it is extremely compatible, fast and easy to use.
Like all Delphi components Besen is compiled into your application, so you have no dependencies to worry about.
Starting a node.js script
The easiest way to start a node.js script, is to simply shell-execute out of your Delphi application. This can be done as easily as:
ShellExecute(Handle, 'open', PChar('node.exe'), pchar('script.js'), nil, SW_SHOW);
This is more than enough if you just want to start a service, server or do some work that doesn’t require that you capture the result.
If you need to capture the result, the data that your node.js program emits on stdout, there is a nice component in the Jedi Component Library. Also plenty of examples online on how to do that.
If you need even further communication, you need to look for a shell-execute that support pipes. All node.js programs have something called a message-channel in the Javascript world. In reality though, this is just a named pipe that is automatically created when your script starts (with the same moniker as the PID [process identifier]).
If you opt for the latter you have a direct, full duplex message channel directly into your node.js application. You just have to agree with yourself on a protocol so that your Delphi code understands what node.js is saying, and visa versa.
UDP or TCP
If you don’t want to get your hands dirty with named pipes and rolling your own protocol, you can just use UDP to let your Delphi application communicate with your node.js process. UDP is practically without cost since its fundamental to all networking stacks, and in your case you will be shipping messages purely between processes on localhost. Meaning: packets are never sent on the network, but rather delegated between processes on the same machine.
In that case, I suggest you ship in the port you want your UDP server to listen on, so that your node.js service acts as the server. A simple command-line statement like:
node.exe myservice.js 8090
Inside node.js you can setup an UDP server with very little fuzz:
function setupServer(port) { var os = require("os"); var dgram = require("dgram"); var socket = dgram.createSocket("udp4"); var MULTICAST_HOST = "224.0.0.236"; var BROADCAST_HOST = "255.255.255.255"; var ALL_PORT = 60540; var MULTICAST_TTL = 1; // Local network socket.bind(port); socket.on('listening', function() { socket.setMulticastLoopback(true); socket.setMulticastTTL(MULTICAST_TTL); socket.addMembership(multicastHost); if(broadcast) { socket.setBroadcast(true); } }); socket.on('message', parseMessage); } function parseMessage(message, rinfo) { try { var messageObject = JSON.parse(message); var eventType = messageObject.eventType; } catch(e) { } }
Note: the code above assumes a JSON text message.
You can then use any Delphi UDP client to communicate with your node.js server, Indy is good, Synapse is a good library with less overhead – there are many options here.
Do I have to learn Javascript to use node.js?
If you download DWScript you can hook-up the JS-codegen library (see library folder in the DWScript repository), and use that to compile DWScript (object pascal) to kick-ass Javascript. This is the same compiler that was used in Smart Mobile Studio.
“Adding WebAssembly to your resume is going to be a hell of a lot more valuable in the years to come than C# or Java”
Another alternative is to use Freepascal, they have a pas2js project where you can compile ordinary object-pascal to javascript. Naturally there are a few things to keep in mind, both for DWScript and Freepascal – like avoiding pointers. But clean object pascal compiles just fine.
If JavaScript is not your cup of tea, or you simply don’t have time to learn the delicate nuances between the DOM (document object model, used by browsers) and the 100% package oriented approach deployed by node.js — then you can just straight up to webassembly.
RemObjects Software has a kick-ass webassembly compiler, perfect if you dont have the energy or time to learn JavaScript. As of writing this is the fastest and most powerful toolchain available. And I have tested them all.
WebAssembly, no Javascript needed
You might remember Oxygene? It used to be shipped with Delphi as a way to target Microsoft CLR (common language runtime) and the .net framework.
Since then Oxygene and the RemObjects toolchain has evolved dramatically and is now capable of a lot more than CLR support.
- You can compile to raw, llvm optimized machine code for 8 platforms
- You can compile to CLR/.Net
- You can compile to Java bytecodes
- You can compile to WebAssembly!
WebAssembly is not Javascript, it’s important to underline that. WebAssembly was created especially for developers using traditional languages, so that traditional compilers can emit web friendly, binary code. Unlike Javascript, WebAssembly is a purely binary format. Just like Delphi generates machine-code that is linked into a final executable, WebAssembly is likewise compiled, linked and emitted in binary form.
If that sounds like a sales pitch, it’s not. It’s a matter of practicality.
- WebAssembly is completely barren out of the box. The runtime environment, be it V8 for the browser or V8 for node.js, gives you nothing out of the box. You don’t even have WriteLn() to emit text.
- Google expects compiler makers to provide their own RTL functions, from the fundamental to the advanced. The only thing V8 gives you, is a barebone way of referencing objects and functions on the other side, meaning the JS and DOM world. And that’s it.
So the reason i’m talking a lot about Oxygene and RemObjects Elements (Elements is the name of the compiler toolchain RemObjects offers), is because it ships with an RTL. So you are not forced to start on actual, literal assembly level.
RemObjects also delivers a DelphiVCL compatibility framework. This is a clone of the Delphi VCL / Freepascal LCL. Since WebAssembly is still brand new, work is being done on this framework on a daily basis, with updates being issued all the time.
Note: The Delphi VCL framework is not just for WebAssembly. It represents a unified framework that can work anywhere. So if you switch from WebAssembly to say Android, you get the same result.
The most important part of the above, is actually not the visual stuff. I mean, having HTML5 visual controls is cool – but chances are you want to use a library like Sencha, SwiftUI or jQueryUI to compose your forms right? Which means you just want to interface with the widgets in the DOM to set and get values.

You probably want to use a fancy UI library, like jQuery UI. This works perfectly with Elements because you can reference the controls from your WebAssembly module. You dont have to create TButton, TListbox etc manually
The more interesting stuff is actually the non-visual code you get access to. Hundreds of familiar classes from the VCL, painstakingly re-created, and usable from any of the 5 languages Elements supports.
You can check it out here: https://github.com/remobjects/DelphiRTL
Skipping JavaScript all together
I dont believe in single languages. Not any more. There was a time when all you needed was Delphi and a diploma and you were set to conquer the world. But those days are long gone, and a programmer needs to be flexible and have a well stocked toolbox.

Knowing where you want to be is half the journey
The world really don’t need yet-another-c# developer. There are millions of C# developers in India alone. C# is just “so what?”. Which is also why C# jobs pays less than Delphi or node.js system service jobs.
What you want, is to learn the things others avoid. If JavaScript looks alien and you feel uneasy about the whole thing – that means you are growing as a developer. All new things are learned by venturing outside your comfort zone.
How many in your company can write high quality WebAssembly modules?
How many within one hour driving distance from your office or home are experts at WebAssembly? How many are capable of writing industrial scale, production ready system services for node.js that can scale from a single instance to 1000 instances in a large, clustered cloud environment?
Any idiot can pick up node.js and knock out a service, but with your background from Delphi or C++ builder you have a massive advantage. All those places that can throw an exception that JS devs usually ignore? As a Delphi or Oxygene developer you know better. And when you re-apply that experience under a different language, suddenly you can do stuff others cant. Which makes your skills valuable.

The Quartex Media Desktop have made even experienced node / web developers gasp. They are not used to writing custom-controls and large-scale systems, which is my advantage
So would you learn JavaScript or just skip to WebAssembly? Honestly? Learn a bit of both. You don’t have to be an expert in JavaScript to compliment WebAssembly. Just get a cheap book, like “Node.js for beginners” and “JavaScript the good parts” ($20 a piece) and that should be more than enough to cover the JS side of things.
Adding WebAssembly to your resume and having the material to prove you know your stuff, is going to be a hell of a lot more valuable in the years to come than C#, Java or Python. THAT I can guarantee you.
And, we have a wicked cool group on Facebook you can join too: Click here to visit RemObjects Developer.
Getting into Node.js from Delphi
Delphi is one of the best development toolchains for Windows. I have been an avid fan of Delphi since it was first released, and before that – Turbo Pascal too. Delphi has a healthy following – and despite popular belief, Delphi scores quite well on the Tiobe Index.
As cool and efficient as Delphi might be, there are situations where native code wont work. Or at the very least, be less efficient than the alternatives. Delphi has a broad wingspan, from low-level assembler all the way to classes and generics. But JavaScript and emerging web technology is based on a completely different philosophy, one where native code is regarded as negative since it binds you to hardware.
Getting to grips with the whole JavaScript phenomenon, be it for mobile, embedded or back-end services, can be daunting if all you know is native code. But thankfully there are alternatives that can help you become productive quickly, something I will brush over in this post.
JavaScript without JavaScript
Before we dig into the tools of the trade, I want to cover alternative ways of enjoying the power of node.js and Javascript. Namely by using compilers that can convert code from a traditional language – and emit fully working JavaScript. There are a lot more options than you think:

Quartex Media Desktop is a complete environment written purely in JavaScript. Both Server, Cluster and front-end is pure JavaScript. A good example of what can be done.
- Swift compiles for JavaScript, and Apple is doing some amazing things with the new and sexy SwiftUI tookit. If you know your way around Swift, you can compile for Javascript
- Go can likewise be compiled to JS:
- C/C++ can be compiled to asm.js courtesy of EmScripten. It uses clang to first compile your code to llvm bitcode, and then it converts that into asm.js. You have probably seen games like Quake run in the browser? That was asm.js, a kind of precursor to WebAssembly.
- NS Basic compiles for JavaScript, this is a Visual Basic 6 style environment with its own IDE even
For those coming straight from Delphi, there are a couple of options to pick from:
- Freepascal (pas2js project)
- DWScript compiles code to JavaScript, this is the same compiler that we used in Smart Pascal earlier
- Oxygene, the next generation object-pascal from RemObjects compiles to WebAssembly. This is by far the best option of them all.

I strongly urge you to have a look at Elements, here running in Visual Studio
JavaScript, Asm.js or WebAssembly?
Asm.js is by far the most misunderstood technology in the JavaScript ecosystem, so let me just cover that before we move on:
A few years back JavaScript gained support for memory buffers and typed arrays. This might not sound very exciting, but in terms of speed – the difference is tremendous. The default variable type in JavaScript is what Delphi developers know as Variant. It assumes the datatype of the values you assign to it. Needless to say, there is a lot of overhead when working with variants – so JavaScript suddenly getting proper typed arrays was a huge deal.
It was then discovered that JavaScript could manipulate these arrays and buffers at high speed, providing it only used a subset of the language. A subset that the JavaScript runtime could JIT compile more easily (turn into machine-code).
So what the EmScripten team did was to implement a bytecode based virtual-machine in Javascript, and then they compile C/C++ to bytecodes. I know, it’s a huge project, but the results speak for themselves — before WebAssembly, this was as fast as it got with JavaScript.
WebAssembly
WebAssembly is different from both vanilla JavaScript and Asm.js. First of all, it’s executed at high speed by the browser itself. Not like asm.js where these bytecodes were executed by JavaScript code.

Water is a fast, slick and platform independent IDE for Elements. The same IDE for OS X is called Fire. You can use RemObjects Elements from either Visual Studio or Water
Secondly, WebAssembly is completely JIT compiled by the browser or node.js when loading. It’s not like Asm.js where some parts are compiled, others are interpreted. WebAssembly runs at full speed and have nothing to do with traditional JavaScript. It’s actually a completely separate engine.
Out of all the options on the table, WebAssembly is the technology with the best performance.
Kits and strategies
The first thing you need to be clear about, is what you want to work with. The needs and requirements of a game developer will be very different from a system service developer.
Here are a couple of kits to think about:
- Mobile developer
- Implement your mobile applications using Oxygene, compiling for WebAssembly (Elements)
- RemObjects Remoting SDK for client / server communication
- Use Freepascal for vanilla JavaScript scaffolding when needed
- Service developer
- Implement libraries in Oxygene to benefit from the speed of WebAssembly
- Use RemObjects Data Abstract to make data-access uniform and fast
- Use Freepascal for boilerplate node.js logic
- Desktop developer
- For platform independent desktop applications, WebAssembly is the way to go. You will need some scaffolding (plain Javascript) to communicate with the application host – but the 99.9% of your code will be better under WebAssembly.
- Use Cordova / Phonegap to “bundle” your WebAssembly, HTML5 files and CSS styling into a single, final executable.
The most important part to think about when getting into JavaScript, is to look closely at the benefits and limitation of each technology.
WebAssembly is fast, wicked fast, and let’s you write code like you are used to from Delphi. Things like pointers etc are supported in Elements, which means ordinary code that use pointers will port over with ease. You are also not bound on hand-and-feet to a particular framework.
For example, EmScripten for C/C++ have almost nothing in terms of UI functionality. The visual part is a custom build of SDL (simple directmedia layer), which fakes the graphics onto an ordinary HTML5 canvas. This makes EmScripten a good candidate for porting games written in C/C++ to the web — but it’s less than optimal for writing serious applications.
Setting up the common tools
So far we have looked at a couple of alternatives for getting into the wonderful world of JavaScript in lieu of other languages. But what if you just want to get started with the typical tools JS developers use?

Visual Studio Code is a pretty amazing code-editor
The first “must have” is Visual Studio Code. This is actually a great example of what you can achieve with JavaScript, because the entire editor and program is written in JavaScript. But I want to stress that this editor is THE editor to get. The way you work with files in JS is very different from Delphi, C# and Java. JavaScript projects are often more fragmented, with less code in each file – organized by name.

TypeScript was invented by Anders Hejlsberg, who also made Delphi and C#
The next “must have” is without a doubt TypeScript. Personally im not too fond of TypeScript, but if ordinary JavaScript makes your head hurt and you want classes and ordinary inheritance, then TypeScript is a step up.
Next on the list is AssemblyScript. This is a post-processor for TypeScript that converts your code into WebAssembly. It lacks much of the charm and elegance of Oxygene, but I suspect that has to do with old habits. When you have been reading object-pascal for 20 years, you feel more at home there.
You will also need to install node.js, which is the runtime engine for running JavaScript as services. Node.js is heavily optimized for writing server software, but it’s actually a brilliant way to write services that are multi-platform. Because Node.js delivers the same behavior regardless of underlying operating system.
And finally, since you definitely want to convert your JavaScript and/or WebAssembly into a stand-alone executable: you will need Adobe Phonegap.
Visual Studio
No matter if you want to enter JavaScript via Elements or something else, Visual Studio will save you a lot of time, especially if you plan on targeting Azure or Amazon services. Downloading and installing the community edition is a good idea, and you can use that while exploring your options.
When it comes to writing system services, you also want to check out NPM, the node.js package manager. The JavaScript ecosystem is heavily package oriented – and npm gives you some 800.000 packages to play with free of charge.
Just to be clear, npm is a shell command you use to install or remove packages. NPM is also a online repository of said packages, where you can search and find what you need. Most packages are hosted on github, but when you install a package locally into your application folder – npm figures out dependencies etc. automatically for you.
Books, glorious books
Last but not least, get some good books. Seriously, it will save you so much time and frustration. Amazon have tons of great books, be it vanilla JavaScript, TypeScript, Node.js — pick some good ones and take the time to consume the material.
And again, I strongly urge you to have a look at Elements when it comes to WebAssembly. WebAssembly is a harsh and barren canvas, and being able to use the Elements RTL is a huge boost.
But regardless of path you pick, you will always benefit from learning vanilla JavaScript.
RemObjects VCL, mind blown!
For a guy that spends most of his time online, and can talk for hours about the most nerdy topics known to mankind – being gobsmacked and silenced is a rare event. But this morning that was exactly what happened.
Now, Marc Hoffman has blogged regularly over the years regarding the evolution of the RemObjects toolchain; explaining how they decoupled the parts that make up a programming language, such as syntax, rtl and target, but I must admit haven’t really digested the full implications of that work.
Like most developers I have kept my eyes on the parts relevant for me, like the Remoting SDK, Data Abstract and Javascript support. Before I worked at Embarcadero I pretty much spent 10 years contracting -and building Smart Mobile Studio on the side together with the team at The Smart Company Inc.

Smart Pascal gained support for RemObjects SDK servers quite early
Since both the Remoting SDK and Data Abstract were part of our toolbox as Delphi developers, those were naturally more immediate than anything else. We also added support for RemObjects Remoting SDK inside Smart Mobile Studio, so that people could call existing services from their Javascript applications.
Oxygene then
Like most Delphi developers I remember testing Oxygene Pascal when I bought Delphi 2005. Back then Oxygene was licensed by Borland under the “Prism” name and represented their take on dot net support. I was very excited when it came out, but since my knowledge of the dot net framework was nil, I was 100% relient on the documentation.
In many ways Oxygene was a victim of Rad Studio’s abhorrent help-file system. Documentation for Rad Studio (especially Delphi) up to that point had been exemplary since Delphi 4; but by the time Rad Studio 2005 came out, the bloat had reached epic levels. Even for me as a die-hard Delphi fanatic, Delphi 2005 and 2006 was a tragic experience.

Removing Oxygene was a monumental mistake
I mean, when it takes 15 minutes (literally) just to open the docs, then learning a whole new programming paradigm under those conditions was quite frankly impossible. Like most Delphi developers I was used to Delphi 7 style documentation, where the docs were not just reference material – but actually teaches you the language itself.
In the end Oxygene remained very interesting, but with a full time job, deadlines and kids to take care of, I stuck to what I knew – namely the VCL.
Oxygene today
Just like Delphi has evolved and improved radically since 2005, Oxygene has likewise evolved above and beyond its initial form. Truth be told, we copied a lot of material from Oxygene when we made Smart Pascal, so I feel strangely at home with Oxygene even after a couple of days. The documentation for Oxygene Pascal (and Elements as a whole) is very good: https://docs.elementscompiler.com/Oxygene/
But Oxygene Pascal, while the obvious “first stop” for Delphi developers looking to expand their market impact, is more than “just a language”. It’s a language that is a part of a growing family of languages that RemObjects support and evolve.
As of writing RemObjects offers the following languages. So even if you don’t have a background in Delphi, or perhaps migrated from Delphi to C# years ago – RemObjects will have solutions and benefits to offer:
- Oxygene (object pascal)
- C#
- Swift
- Java

Water is a sexy, slim new IDE for RemObjects languages on Windows. For the OS X version you want to download Fire.
And here is the cool thing: when you hear “Java” you automatically expect that you are bound hands and feet to the Java runtime-libraries right? Same also with C#, you expect C# to be purely limited to the dot-net framework. And if you like me dabbed in Oxygene back in 2005-2006, you probably think Oxygene is purely a dot-net adapted version of Object Pascal right? But RemObjects have turned that on it’s head!
Remember the decoupling I mentioned at the beginning of this post? What that means in practical terms is that they have separated each language into three distinct parts:
- The syntax
- The RTL
- The target
What this means, is that you can pick your own combinations!
Let’s say you are coming from Delphi. You have 20 years of Object Pascal experience under your belt, and while you dont mind learning new things – Object Pascal is where you will be most productive.
Well in that case picking Oxygene Pascal covers the syntax part. But you don’t have to use the dot-net framework if you don’t want to. You can mix and match these 3 parts as you see fit! Let’s look at some combinations you could pick:
- Oxygene Pascal -> dot net framework -> CIL
- Oxygene Pascal -> “VCL” -> CIL
- Oxygene Pascal -> “VCL” -> WinAPI
- Oxygene Pascal -> “VCL” -> WebAssembly
(*) The “VCL” here is a compatibility RTL closely modeled on the Freepascal LCL and Delphi VCL. This is written from scratch and contains no proprietary code. It is purely to get people productive faster.
The whole point of this tripartite decoupling is to allow developers to maximize the value of their existing skill-set. If you know Object Pascal then that is a natural starting point for you. If you know the VCL then obviously the VCL compatibility RTL is going to help you become productive much faster than calling WinAPI on C level. But you can, if you like, go all native. And you can likewise ignore native and opt for WebAssembly.
Sound cool? Indeed it is! But it gets better, let’s look at some of the targets:
- Microsoft Windows
- Apple OS X
- Apple iOS
- Apple WatchOS
- Android
- Android wearables
- Linux x86 / 64
- Linux ARM
- tvOS
- WebAssembly
- * dot-net
- * Java
In short: Pick the language you want, pick the RTL or framework you want, pick the target you want — and start coding!
(*) dot-net and Java are not just frameworks, they are also targets since they are Virtual Machines. WebAssembly also fall under the VM category, although the virtual machine there is bolted into Chrome and Firefox (also node.js).
Some example code
Webassembly is something that interest me more than native these days. Sure I love the speed that native has to offer, but since Javascript has become “the defacto universal platform”, and since most of my work privately is done in Javascript – it seems like the obvious place to start.
Webassembly is a bit like Javascript was 10 years ago. I remember it was a bit of a shock coming from Delphi. We had just created Smart Mobile Studio, and suddenly we realized that the classes and object the browser had to offer were close to barren. We were used to the VCL after all. So my work there was basically to implement something with enough similarity to the VCL to be familiar to to Delphi developer, without wandering too far away from established JS standards.
Webassembly is roughly in the same ballpark. Webassembly is just a runtime engine. It doesn’t give you all those nice and helpful classes out of the box. You are expected to either write that yourself – or (as luck would have it) rely on what language vendors provide.
RemObjects have a lot to offer here, because their “Delphi VCL” compatibility RTL compiles just fine for Webassembly. There is no form designer though, but I haven’t used a form designer in years. I prefer to do everything in code because that’s ultimately what works when your codebase grows large enough anyways. Even my Delphi projects are done mainly as raw code, because I like to have the option to compile with Freepascal and Lazarus.
My first test code for Oxygene Pascal with Webassembly as the target is thus very bare-bone. If there is something that has bugged me to no end, it’s that bloody HTML5 canvas. It’s a powerful thing, but it’s also overkill for per-pixel operations. So I figured that a nice, ad-hoc DIB (device independent bitmap) class will do wonders.
Note: Oxygene supports pointers, even under WebAssembly (!), but out of old habit I have avoided it. I want my code to compile for all the targets, without marking a class as “unsafe” in the dot-net paradigm. So I have avoided pointers and just use offsets instead.
namespace qtxlib; interface type // in-memory pixel format TPixelFormat = public ( pf8bit = 0, //___8 -- palette indexed pf15bit = 1, //_555 -- 15 bit encoded pf16bit = 2, //_565 -- 16 bit encoded pf24bit = 3, //_888 -- 24 bit native pf32bit = 4 //888A -- 32 bit native ); TPixelBuffer = public class private FPixels: array of Byte; FDepthLUT: array of Integer; FScanLUT: array of Integer; FStride: Integer; FWidth: Integer; FHeight: Integer; FBytes: Integer; FFormat: TPixelFormat; protected function CalcStride(const Value, PixelByteSize, AlignSize: Integer): Integer; function GetEmpty: Boolean; public property Width: Integer read FWidth; property Height: Integer read FHeight; property Stride: Integer read FStride; property &Empty: Boolean read GetEmpty; property BufferSize: Integer read FBytes; property PixelFormat: TPixelFormat read FFormat; property Buffer[const index: Integer]: Byte read (FPixels[&index]) write (FPixels[&index]); function OffsetForPixel(const dx, dy: Integer): Integer; procedure Alloc(NewWidth, NewHeight: Integer; const PxFormat: TPixelFormat); procedure Release(); function Read(Offset: Integer; ByteLength: Integer): array of Byte; procedure Write(Offset: Integer; const Data: array of Byte); constructor Create; virtual; finalizer; begin if not GetEmpty() then Release(); end; end; TColorMixer = public class end; TPainter = public class private FBuffer: TPixelBuffer; public property PixelBuffer: TPixelBuffer read FBuffer; constructor Create(const PxBuffer: TPixelBuffer); virtual; end; implementation //################################################################################## // TPainter //################################################################################## constructor TPainter.Create(const PxBuffer: TPixelBuffer); begin inherited Create(); if PxBuffer nil then FBuffer := PxBuffer else raise new Exception("Pixelbuffer cannot be NIL error"); end; //################################################################################## // TPixelBuffer //################################################################################## constructor TPixelBuffer.Create; begin inherited Create(); FDepthLUT := [1, 2, 2, 3, 4]; end; function TPixelBuffer.GetEmpty: Boolean; begin result := length(FPixels) = 0; end; function TPixelBuffer.OffsetForPixel(const dx, dy: integer): Integer; begin if length(FPixels) > 0 then begin result := dy * FStride; inc(result, dx * FDepthLUT[FFormat]); end; end; procedure TPixelBuffer.Write(Offset: Integer; const Data: array of Byte); begin for each el in Data do begin FPixels[Offset] := el; inc(Offset); end; end; function TPixelBuffer.Read(Offset: Integer; ByteLength: Integer): array of Byte; begin result := new Byte[ByteLength]; var xOff := 0; while ByteLength > 0 do begin result[xOff] := FPixels[Offset]; dec(ByteLength); inc(Offset); inc(xOff); end; end; procedure TPixelBuffer.Alloc(NewWidth, NewHeight: Integer; const PxFormat: TPixelFormat); begin if not GetEmpty() then Release(); if NewWidth < 1 then raise new Exception("Invalid width error"); if NewHeight 0 then result := ( (Result + AlignSize) - xFetch ); end; end.
This code is just meant to give you a feel for the dialect. I have used a lot of “Delphi style” coding here, so chances are you will hardly see any difference bar namespaces and a funny looking property declaration.
Stay tuned for more posts as I explore the different aspects of Oxygene and webassembly in the days to come 🙂
RemObjects Remoting SDK?
Reading this you could be forgiven for thinking that I must promote RemObjects products, It’s my job now right? Well yes, but also no.
The thing is, I’m really not “traveling salesman” material by any stretch of the imagination. My tolerance for bullshit is ridiculously low, and being practical of nature I loath fancy products that cost a fortune yet deliver nothing but superficial fluff.
The reasons I went to work at RemObjects are many, but most of all it’s because I have been an avid supporter of their products since they launched. I have used and seen their products in action under intense pressure, and I have come to put some faith in their solutions.
Trying to describe what it’s like to write servers that should handle thousands of active user “with or without” RemObjects Remoting SDK is exhausting, because you end up sounding like a fanatic. Having said that, I feel comfortable talking about the products because I speak from experience.
I will try to outline some of the benefits here, but you really should check it out yourself. You can download a trial directly here: https://www.remotingsdk.com/ro/
Remoting framework, what’s that?
RemObjects Remoting framework (or “RemObjects SDK” as it was called earlier) is a framework for writing large-scale RPC (remote procedure call) servers and services. Unlike the typical solutions available for Delphi and C++ builder, including those from Embarcadero I might add, RemObjects framework stands out because it distinguishes between transport, host and message-format – and above all, it’s sheer quality and ease of use.
This separation between transport, host and message-format makes a lot of sense, because the parameters and data involved in calling a server-method, shouldn’t really be affected by how it got there.
And this is where the fun begins because the framework offers you a great deal of different server types (channels) and you can put together some interesting combinations by just dragging and dropping components.
How about JSON over email? Or XML over pipes?
The whole idea here is that you don’t have to just work with one standard (and pay through the nose for the privilege). You can mix and match from a rich palette of transport mediums and message-formats and instead focus on your job; to deliver a kick-ass product.
And should you need something special that isn’t covered by the existing components, inheriting out your own channel or message classes is likewise a breeze. For example, Andre Mussche have some additional components on GitHub that adds a WebSocket server and client. So there is a lot of room for expanding and building on the foundation provided by RemObjects.
And this is where RemObjects has the biggest edge (imho), namely that their solutions shaves weeks if not months off your development time. And the central aspect of that is their integrated service designer.
Integration into the Delphi IDE
Dropping components on a form is all good and well, but the moment you start coding services that deploy complex data-types (records or structures) the amount of boilerplate code can become overwhelming.
The whole point of a remoting framework is that it should expose your services to the world. Someone working in .net or Java on the other side of the planet should be able to connect, consume and invoke your services. And for that to happen every minute detail of your service has to follow standards.
When you install RemObjects SDK, it also integrates into the Delphi IDE. And one of the features it integrates is a complete, separate service designer. The designer can also be used outside of the Delphi IDE, but I cannot underline enough how handy it is to be able to design your services visually, right there and then, in the Delphi IDE.
This designer doesn’t just help you design your service description (RemObjects has their own RODL file-format, which is a bit like a Microsoft WSDL file), the core purpose is to auto-generate all the boilerplate code for you — directly into your Delphi project (!)
So instead of you having to spend a week typing boilerplate code for your killer solution, you get to focus on implementing the actual methods (which is what you are supposed to be doing in the first place).
DLL services, code re-use and multi-tenancy
The idea of multi-tenancy is an interesting one. One that I talked about with regards to Rad-Server both in Oslo and London before christmas. But Rad-Server is not the only system that allows for multi-tenancy. I was doing multi-tenancy with RemObjects SDK some 14 years ago (if not earlier).
Remember how I said the framework distinguishes between transport, message and host? That last bit, namely host, is going to change how you write applications.
When you install the framework, it registers a series of custom project types inside the Delphi IDE. So if you want to create a brand new RemObjects SDK server project, you can just do that via the ordinary File->New->Other menu option.
One of the project types is called a DLL Server. Which literally means you get to isolate a whole service library inside a single DLL file! You can then load in this DLL file and call the functions from other projects. And that is, ultimately, the fundamental principle for multi-tenancy.
And no, you don’t have to compile your project with external packages for this to work. The term “dll-server” can also be a bit confusing, because we are not compiling a network server into a DLL file, we are placing the code for a service into a DLL file. I used this project type to isolate common code, so I wouldn’t have to copy unit-files all over the place when delivering the same functionality.
It’s also a great way to save money. Don’t want to pay for that new upgrade? Happy with the database components you have? Isolate them in a DLL-Server and continue to use the code from your new Delphi edition. I have Delphi XE3 Database components running inside a RemObjects DLL-Server that I use from Delphi XE 10.3.
In my example I was doing business-logic for our biggest customers. Each of them used the same database, but they way they registered data was different. The company I worked for had bought up these projects (and thus their customers with them), and in order to keep the customers happy we couldn’t force them to re-code their systems to match ours. So we had to come up with a way to upgrade our technology without forcing a change on them.
The first thing I did was to create a “DLL server” that dealt with the database. It exposed methods like openTable(), createInvoice(), getInvoiceById() and so on. All the functions I would need to work with the data without getting my fingers dirty with SQL outside the DLL. So all the nitty gritty of SQL components, queries and whatnot was neatly isolated in that DLL file.
I then created separate DLL-Server projects for each customer, implemented their service interfaces identical to their older API. These DLL’s directly referenced the database library for authentication and doing the actual work.

When integrated with the IDE, you are greeted with a nice welcome window when you start Delphi. Here you can open examples or check out the documentation
Finally, I wrapped it all up in a traditional Windows system service, which contained two different server-channels and the message formats they needed. When the service was started it would simply load in the DLL’s and manually register their services and types with the central channel — and voila, it worked like a charm!
Rock solid
Some 10 years after I delivered the RemObjects based solution outlined above, I got a call from my old employer. They had been victim of a devastating cyber attack. I got a bit anxious as he went on and on about damages and costs, fearing that I had somehow contributed to the situation.
But it turned out he called to congratulate me! Out of all the services in their server-park, mine were the only ones left standing when the dust settled.
The RemObjects payload balancer had correctly dealt with both DDOS and brute force attacks, and the hackers were left wanting at the gates.
Is native outdated? Debate!
Life has its ups and downs, but this one is a case that really makes me stop and think. They say the moment you reach 30, you lose your immortality. In the sense that you no longer regard yourself as immortal, infallible and a list of other power-words. It’s the age when you realize that you are no longer in the front-seat of all things new and bright, and that in fact you are heading for death.
With that gloomy intro, here is the pickle that has made me really question what programming and being a “native” developer means: Is native code outdated? I write that because the more young programmers I meet, the less native code I encounter. And it’s really scary! I mean how do you build a custom server? Not just a server that does something different, but a truly custom, never before done, truly unique and brand new – without the speed power that native code provides?
But these kids have a completely different take on it, which makes me feel so very, very old. But it also makes me want to educate them about the differences, with limited success so far.
Once in a while I meet up with younger programmers, some at work and others through IRC or Facebook to check out the latest developments. It’s mostly open forum so everyone posts ideas, links, code, references – and we all bitch and moan about what we don’t like (or envy I guess, people do that as well online).
What throws me is that native code is taking up less and less space in the minds of young programmers. Programmers who, unlike our generation I presume, have primarily grown up with free development tools and open-source libraries. So in their mind paying for anything related to programming is just not where it’s at. Perhaps this is why Microsoft has suddenly transformed into the sugar daddy of high-tech? Time will tell perhaps.
But either way, the majority of these free tools must be running on what ultimately has be, it bloody has to be (!) native code. I accept that the platform itself can be script based, perhaps generating bytecodes or p-code. But native must by virtue of how the hardware is designed, remain relevant. Right?
The p-code thing
If you don’t know the difference between byte-codes and p-codes, they are essentially the same thing. But instead of representing your commands as bytes and small records, like say java or dot net does; P-codes have bytes which represents offset values into a runtime library. So instruction $0001 would execute command #1, and $000F would execute command number 15 (or 16 if you count from zero). The downside of p-code compilers is that they are extremely fragile. If you alter even a single byte the whole system can crash, so modern implementations use CRC and checksum validation before executing.
Since a p-code represents an offset into an array of pointers, they execute extremely fast. In many cases it can be hard to distinguish native programs from well written p-code programs. It depends wildly on the language at hand naturally, but all in all p-codes just pounds every ounce of clock cycles out of the processor.
The downside is that it’s fragile like hell. A single altered byte in a p-code program can crash the program with spectacular access-violations. Hence modern implementations are often cluttered with CRC checks and identifiers. But they are fast, much faster than translating byte-codes.
Right, now back to the topic at hand.
Is the future scripted?
A part of me want to say yes, because there is more than enough power in modern script-engines to create really powerful desktop applications, services and/or games. But a script engine can’t write itself. You can’t write a script engine in JavaScript because sooner or later someone has to write JavaScript, if you get what I mean. Somewhere along the line a programmer has to use a language which compiles to native, be it C / C++, object pascal or some other native language. I even remember a guy writing his own operating system in BlitzBasic, but he used like 70% inline assembler so I’m not sure he qualifies as a basic representative.
So while it’s tempting to say yes, considering the widespread adoption of languages like python, pearl, ruby and javascript – it just can’t be true. And that statement has launched an avalanche of well-meaning but ignorant feedback from my younger friends; who doesn’t know what native is all about and as such protect their faith in scripting to the death.
So no. You can’t get through to them.
The smart thing
Since myself and the group of programmers I work with are marketing object pascal as the best language for web and cloud development; and we have adapted object pascal to be more in-tune with how development in our day and age works, like anonymous procedures, records, properties and whatnot — i should be pro 100% script right?
Well I’m not. Smart Mobile Studio represents, in my view, one of the best solutions for writing cloud based software. Primarily because you have full access to nodeJS, which in turn mean you can write both the server and client from the same codebase.
But it’s only the best solution because the medium, namely the browser and JavaScript, is so fluid and flamboyant in nature. You can do some tricks in JavaScript that would be suicide under native languages, but in the padded room of JavaScript everything goes.
But does that mean I have become sort of “anti native code”? Absolutely not. In fact I love Delphi to pieces, and C# (native mono compilation) and I even have an off the record love affair with C++. First of all because it’s the only thing I know how to do, part from JavaScript which I’m very, very good at. But I also think it’s important for all of us to get our ducks in a row.
The view I have is that scripting is not really programming is it? I mean “really” programming. Scripting for me is a bit like sculpting. You sit down and sculpt data structures and setup boundaries using a language which, subjectively speaking, is the intellectual equivalent of putty rather than brick. So it’s a bit like carving a madonna out of a piece of soap versus a solid piece of engineering forged in steel.
Or how about this: native programming is a bit like coding a gene-pool, while scripting is the same as body-building. With scripts you carve out the form, the relations and setup the pathways between them. But without the underlying generic programming, there would be no intelligence or program to carry out the build-plans to begin with.
Native languages feel more edgy to me, more solid and concrete. You can’t cheat and get away with it under native object pascal or C, because it wont even compile. You are also closer to the hardware since the code you write is ultimately the binary pattern fed to the processor. While scripting languages are.. well, fed to a dispatcher after going through a lookup table.
A young solution
I really am amazed by how the younger generation solve things, because they are – without knowing it – doing a better job than we did 20 years ago. Instead of writing a server from scratch like we would probably do for a new piece of technology, they implement the “new” bit using the protocols already in place. So they get the job done, but in a way very different from ours.
So the new server is not a new server, it’s the same old HTTP server you have been using for 15 years, except now the URL’s are command and form-fields are parameters. Things like REST was not invented by a seasoned developer, it’s actually a perversion of the HTTP protocol if you like. But it works, and it’s even turned into a standard now.
Same with python. You dont setup a cluster with C or object pascal, no you use python and it will execute parts of the same program on different computers to spread the payload. And that makes sense, since native code would be much harder to disperse over X number of nodes. So suddenly scripting makes sense over native. At least in that particular scenario.
The only real problem with “young thinking” is that it doesn’t generate money the same way we are used to. When you use only free compilers, editors and server kits – how will a young developer approach systems like Delphi?
I really want Delphi to survive and I want the object pascal language, be it Smart Pascal, FPC or Delphi or Oxygene; I want it to thrive. I want young programmers to see and experience how rich and beautiful object pascal is and how much it can do for them; and also how much they can deliver through that language.
But how can you even hope to persuade a young man or woman who makes less than $800 a month to fork out $3000 for a development system all their friends call “old and outdated”?
AppMethod is cool. It’s cheap, its affordable and students and hobbyist programmers can pick it up. It’s still a bit pricey compared to Smart Mobile Studio, but I hope Embarcadero makes enough money to keep going.
Last pondering
Smart Mobile Studio is probably more in tune with the new reality, since the kids growing up now are in fact growing up with “the cloud” as their foundation. Remember we grew up with commodore 64, Atari and those kind of things. Our children are growing up with cloud servers, JavaScript powered phones (Mozilla phone), Linux and the open source movement.
Perhaps I should just forget trying to make sense of their thinking. Trying to enumerate all the technological changes I have gone through from childhood to now is exhausting. I tried to tell my son what a modem was and how we connected to the internet no longer than 15 years ago — he just looked at me with big eyes and went “Dad. Please. Its ancient history”. And my daughter found a cassette tape and could not imagine what it was. She thought it was scotch tape 🙂
It’s just so weird realizing that my kids have no idea what a cassette tape is and will never have first hand experience of a modem!
I guess we all play our part.
My part is to try to get object pascal kicking and screaming onto the cloud. I am content with that role and think it’s a privilege to even be mentioned in the history of object pascal. But a future based on scripting? I sure hope not!
What are the kids using?
When it comes to languages, I can honestly say that the official list is wrong. Dead wrong. One language may have more source online that others, but that doesnt mean it’s less used. It depends completely on what group of people use it and what it’s used for. A language used primarily for commercial applications will by nature have less code in the public domain than a language which is free, open-source and generally available.
This is the case we see with Delphi. There are probably hundreds of thousands of companies using Delphi in the world, but they use Delphi to produce closed-source products. As such their code never leaves the house (so to speak) and you wont find it on github, sourceforge or google code.
But having talking to probably hundreds of teenagers coding lately, here is my general impression, in order of magnitude
- JavaScript
- Php
- Python
- Ruby
- Swift
- C# and dot net
- C script
- Erlang and friends
Of native languages the list havent really changed that much over the years:
- C++
- C
- Objective C
- Object Pascal
The javascript thing is the one to watch. Not just because that’s where I’ve invested my time and money, but because no other language is seeing anything near the amount of attention JS is getting. Not even close. And the two basic platforms is the browser, which for kids is regarded as the operative system itself (conceptually, not factually ofcourse). The browser IS where you experience computing and connect to the world.
The second aspect and one I find very exciting myself, is the nodeJS side of things. Here we are seeing a tremendous growth compared to other technology. And the reason is exactly because it’s connected to the first-hand experience people have. Those who master the browser and the DOM will eventually be able to reach customers and create systems which are platform independent, international and dynamic.
Do we have anything to learn from this? Bucket loads! But we should never lose sight of the fact that we also have much to teach.
And with that my pondering stops for today 🙂
Smart Mobile Update, oh man this rocks!
Do you sometimes feel a bit envious of C# programmers with all their cool IDE features? Like automatic updates, built-in package manager which downloads, installs and does all the grunt work for you? I mean, Visual Studio’s nuget package manager looks almost like appstore, but with free packages which can be installed with a click.
I know I have. Being a Delphi/FPC programmer can be tiresome. Especially when it comes to component updates, RTL updates and god knows what else you have to manually deal with.
Well then It’s with great please I assume the role of whistleblower and show you a “peek” of the upcoming Smart Mobile Studio update architecture. That’s right, while you were sleeping we were building a server infrastructure – and one of the features is about to emerge publicly!
Updates for all
Imagine this: Someone at HQ locates a bug in one of the RTL units. Today this means registering a case in fogbugz, providing reproducible code and much, much more. And depending on how critical it is – it can take a while before the ticket comes up to be fixed.
Our new system allows us to do immediate updates. So whenever we add a new feature or fix a bug, it’s fixed straight away — and it is available immediately. All you have to do is click “update” once in a while and you get all the changes, just like Visual Studio and Mono users do!
And we have channels, meaning different branches you can check out, like “Beta” and “Nightly builds” and so on. But please note that these are reserved for paying customers only. The update system takes care of license validation, tracking – updating your executables as well as the VJL + RTL codebase. So this is more or less a perfect solution for serious HTML5/Pascal programmers as you can get. And dont get me started on automatic package installation (ops! Did I say that out loud? Darn…).
I soooooo want to blow the whistle on our other features, but I can’t! Not yet. But the moment they are ready for public ears, rest assured that I’ll play the proverbial bagpipe on all of them 😀
Enjoy!
System.Interop “how to” for Smart Mobile Studio
Smart Mobile Studio and the dialect “Smart Pascal” has roots in the Object Pascal community. The compiler and toolkit is written purely using FreePascal and Delphi, and naturally the run-time library for Smart Pascal is heavily influenced by both.
Background
What is less known is that Smart Mobile Studio in general, both the IDE and the RTL architecture, is equally inspired by the Mono project. The entire layout of the IDE is almost identical to Mono-Develop as it existed 4 years ago, while the RTL and application framework borrows from MonoTouch by exposing central constructs (like TApplication) purely through partial classes. These are language features which does not exist in FreeePascal or Embarcadero Delphi.
The unit Interop.pas which is a part of the system namespace (system.interop) is inspired by the mono .NET equivalent. Under Mono the various memory and type transformation classes are spread out over many different locations. Under Smart Mobile Studio we have decided to collect and implement these .NET features in a single unit. Namely system.interop (short for: System interoperability).

The Smart RTL is seriously fast
Memory management under HTML5
JavaScript does not expose any form of memory management. The closest thing to allocating memory under JavaScript is through JArrayBuffer and JTypedArray. JArrayBuffer is an un-typed memory segment without read or write access. The buffer can only be accessed by creating a descendant of JTypedArray and connecting that to JArrayBuffer. As such:
/* Allocate memory buffer, 1024 bytes */ var memBuffer = new ArrayBuffer(1024); /* Allocate R/W access through a typed array */ var memAccess = new UInt8Array( memBuffer );
Needless to say, working with memory like this quickly becomes tiredsome, error prone and messy. Especially when coming from a FreePascal or Delphi background, where a simple call to AllocMem() is enough to reserve memory on the heap.
Memory Management under Smart Mobile Studio
The Interop unit introduces 3 different means of working directly with memory, there are:
- Streams
- Memory Buffers
- Marshaled classical memory access
Marshaled memory access
Due to the shortcomings of JavaScript the only way to expose and work directly with memory is through a technique called marshaling. It essentially means that you are abstracted from pure machine localized addresses (pointer types) and instead operate with reference objects (location objects).
Such a reference object contains two pieces of information:
- A reference (handle) to the associated JArrayBuffer
- An entrypoint (offset) into the arraybuffer
For instance, under classical object pascal the following code is quite common:
// pointer type containing the address var mBuffer: PByte; // Allocate memory mBuffer:=AllocMem(1024); try // Work with memory here finally // Release memory freemem(mBuffer); end;
Using marshaled objects Smart Mobile Studio is capable of delivering the exact same:
// pointer type containing the address var mBuffer: TAddress; // Allocate memory mBuffer:=TMarshal.allocMem(1024); try //work with memory here finally // Release memory TMarshal.freemem(mBuffer); end;
Marshaled references also have the benefit of helper functions. So advancing further into an allocated segment is done via the TAddress.Addr() function.
// pointer type containing the address var mBuffer: TAddress; // Allocate memory mBuffer:=TMarshal.allocMem(1024); try mBuffer:=mBuffer.Addr(2); //Advance reference by 2 bytes finally // Release memory TMarshal.freemem(mBuffer); end;
Since JavaScript is garbage collected we can also approach memory offsets quick and dirty, like below; Fact is we really dont need to call FreeMem() because the garbage collector will come around and clean up after us later. But sloppy code has a proven negative impact on performance (memory fragmentation leads to sudden cpu spikes as the GC get’s busy), so I strongly advice you to stick with best practices object pascal.
var mBuffer: TAddress := TMarshal.allocMem(1024).addr(2);
Access to memory with such elegance is unheard of in the world of JavaScript. Marshaled reference objects can be found in many languages, but we are the first to introduce this for JavaScript. The speed benefit is likewise phenomenal compared to other solutions. In fact, our initial read/write tests outperformed all versions of native Embarcadero Delphi prior to Delphi XE.
Memory buffers
While marshaled references and memory allocations are essential for legacy compatability, porting code from freepascal or Delphi to HTML5 – being able to directly interact with a memory segment is vital for any modern platform.
As such, the Interop unit provides the TMemory class. Using the methods of this class you can allocate, release, move, copy, export, read and write directly to memory. The class implements caching for maximal speed enhancement. All intrinsic JavaScript datatypes are supported (Int16, Int32, Float32, Float64, String, Boolean).
Special attention should be made to the class-procedure Move() and Fill() which are equal to the classical FreePascal and Delphi variations. Unlike their classical counterparts these methods accepts TMemoryHandle rather than Pointer or marshaled TAddress objects.
Using Move with Marshaled Addresses
The TAddress class exposes a property named “Segment” of type TMemoryHandle. This can be used with Move() and Fill() as demonstrated below:
var src: TAddress; dst: TAddress; TMemory.Move( src.segment, // source memory src.entrypoint, // source offset dst.segment, // target memory dst.Entrypoint, // target offset 500 //bytes to move ); TMemory.Fill( src.segment, src.entryPoint, 500, TDatatype.CharToByte("Z") );
It must be noted that the above code is just for explanation. Both Move() and FillChar() are implemented in the TMarshal class. The above demonstration is just to provide reference material on their use and how marshaled memory works.
Converting data
JavaScript is essentially type-less. The concept of “typed-arrays” was implemented a while back because they represent a significant speed boost. No matter if you are working on complex calculations or want to manipulate pixels on byte level, being able to work directly with memory is essential for inter-operability with other languages and file-formats.
Converting intrinsic (built in types) to binary can be very hard under JavaScript. As of writing, Smart Mobile Studio provides the most accurate and fastest means of doing this.
The class TDatatype provides methods for converting intrinsic datatypes to “array of bytes” and also from TByteArray back into intrinsic values. The class itself uses speed optimalization by pre-allocating conversion space when the unit is loaded into memory. This makes data conversion extremely fast, much faster than any other JavaScript solution out there.
Using TDatatype is very easy:
var x: Integer; mData: TByteArray; // convert int32 value $1200 into 4 bytes mData := TDatatype.Int32ToBytes($1200); // write bytes to the console for x:=0 to mData.length-1 do writeln(mData[x]); // Alter first byte just for fun mData[0]:=$FF; // Write modified integer value to the console Writeln( TDataType.BytesToInt32(mData) );
The following methods are provided by TDatatype for conversion of datatypes:
TDatatype = Class public class property Bits:TBitAccess; class function Int16ToBytes(Value:Integer):TByteArray; class function Int32ToBytes(Value:Integer):TByteArray; class function Float64ToBytes(Value:Float64):TByteArray; class function Float32ToBytes(Value:Float32):TByteArray; class function StringToBytes(Value:String):TByteArray; class function BooleanToBytes(Value:Boolean):TByteArray; class function BytesToInt16(const Data:TByteArray):Integer; class function BytesToInt32(const Data:TByteArray):Integer; class function BytesToFloat32(Const Data:TByteArray):Float; class function BytesToFloat64(Const Data:TByteArray):Float; class function BytesToString(const Data:TByteArray):String; class function BytesToBoolean(const data:TByteArray):Boolean; class function StrToBase64(Value:String):String; class function Base64ToStr(Value:String):String; class function ByteToChar(Const Value:Byte):String; class function CharToByte(const Value:String):Byte; class function StrToTypedArray(value:String):TJSByteClass; class function TypedArrayToStr(const value:TJSByteClass):String; end;
Working with bits
The TDatatype class exposes a class-property named TBitAccess, which contains only class methods for manipulating bits. As of writing the following methods exists:
TBitAccess = Class public class function Get(Const index:Integer;Const Value:Byte):Boolean; class function &Set(Const Index:Integer;Const Value:Byte; const Data:Boolean):Byte; class function Count(Const Value:Byte):Integer; class function ToByteString(const Value:Byte):String; class function FromByteString(const Value:String):Byte; class function Dismantle(const Value:Byte):TByteArray; class function Assemble(const Value:TByteArray):Byte; end;
Note: TMemory also exposes getBit and setBit methods for the whole allocated memory. This allows you to use a whole segment as a bit-buffer. This is often used by compression, sound generators and classes which communicates with hardware (see Smart Support for hardware platforms).
Working with Streams
While marshaled memory allocations and TMemory represents fast and direct access to raw data, RTL software typically base themselves on streams. In essence Streams and buffers represent the same thing, except that a stream maintains a cursor which is automatically updated as you advance through the content.
Smart Pascal implements the base-class “TStream” which is a purely abstract stream class, just like it exists under C#, FreePascal and Delphi. Deriving from this is TMemoryStream and TStringStream. We will no doubt add more streams to the mix at a later date, but due to the nature of HTML5 and the restrictions on JavaScript, file-streams serve little purpose at this point in time.
Using streams is done much like under FreePascal and Delphi:
var mStream: TMemoryStream; mStream:=TMemoryStream.Create; try // use stream here finally mStream.free; end;
Reading and writing to streams can either be done directly using TStream.Write() or TStream.Read(), both these methods accepts an array of byte (TByteArray). This makes streams slower to use than TMemory or TMarshal operations.
var mStream: TMemoryStream; mWriter: TStreamWriter; mStream:=TMemoryStream.Create; try mWriter:=mStream.createWriter; mWriter.WriteInt32($1200); mWriter.WriteString("This is how you write to a stream!"); mWriter.WriteFloat64(139.68504); finally mStream.free; end;
Reading is done via TStreamReader, which you can either create manually or obtain via the TStream.CreateReader() method.
Speed comparison
JavaScript is seriously fast. Much faster than you would imagine, all things considering.
In the first test, which writes 100.000 records into a pre-allocated TMemory instance, we get the following results:
mMake.Allocate(2100021); mStart:=Now; mChunk:=0; for x:=0 to 100000 do begin mMake.Write(mChunk + 0,$AAAA0000); mMake.WriteFloat32(mChunk + 4,19.24); mMake.WriteFloat64(mChunk + 8,24.18); mMake.Write(mChunk + 16,false); mMake.write(mChunk + 17,$0000AAAA); inc(mChunk, 21); end; mStop:=Now;
Time to completion: 0 seconds, 46 milliseconds
In the second test we omit pre-allocation, which will force TMemory to grow and re-allocate it’s cache quite often, depending on the size of the cache (4096 bytes in this case):
Time to completion: 0 seconds, 445 milliseconds
In the third test we do the exact same, but this time using streams and streamwriter. To fully understand what is happening here, for each write, consider the following:
- StreamWriter calls TDatatype to convert the intrinsic value into a TByteArray
- StreamWriter calls TStream to write the data
- TStream maintains a TMemory class, and calls the rather slow Write() operation
- TStream’s TMemory instance has no pre-allocation, and as such re-allocation will occur often
Time to completion: 0 seconds, 519 milliseconds
These numbers are almost ridicules. I thought something was wrong somewhere at first, and had to check that data was actually written and that it had written the data properly. But yes, the above numbers are correct and memory access under JavaScript when done right is beyond anything I have seen elsewhere.
As of writing my code is roughly two times faster than Perl and Python, it’s also faster than any native Embarcadero Delphi version except Delphi XE7. Only FreePascal and C# Mono compiled to machine-code using LLVM optimization is capable of performance like this. Which is to some degree embarrassing and humiliating for Delphi, a product costing 100 times more than Smart Mobile Studio.
On the positive side, it spells a bright future for Smart Mobile Studio, especially when interacting with nodeJS and hardware, which require powerful and fast code.
Delphi for dot net unit
I had a rather long discussion with several members of Delphi developer (Facebook) the other day, mostly in response to be becoming a full-time C# developer (and Delphi developer of-course, that’s not gonna change).
Although we started with debating C# and differences between native object-pascal versus the “curly languages” in general, I ended up saying something that clearly bugged a few, namely: We can actually implement the dot net framework as an alternative to the VCL, written in Delphi itself. There is no technical limitation against it, and it may even benefit object pascal in general – as younger developers are more familiar with dot net than they are the VCL or VJL.
As you probably guess that spawned some interesting comments (nothing bad, important to underline that) – most of the comments along the lines of the task being pointless, technically difficult or just plain impractical.
My reply to this is that you are all wrong (he said with a smile).
First of all, it is not more impractical to use clone of the most evolved, modern run-time-library (framework) than it is to use the VCL. Delphi is in reality suffering great injustice due to the in-grown identification of product, language and RTL as one and the same. In fact, many people are completely spellbound by the concept of object pascal being “Delphi”, that they cannot for their life imagine object pascal with a new RTL.
This is something I have had first-hand experience with, since I wrote the RTL for Smart Mobile Studio and was the first to experience the wave of feedback from both happy and unhappy users. Dont get me wrong, I absolutely love the VCL; It’s component model and class hiearcy has stood the test of time. It scales well, it’s agile – and all the other words we use to describe a living product.
Technical difficulties
Secondly, it is no more a technical challenge to implement the .net framework and use that instead of the VCL – than it would be to write the VCL to begin with. The factor which matters in this case, as it is with software development in general, is time.
But this statement does have some merit, since it’s only recently that object pascal (both Delphi and FPC) have evolved it’s RTTI functionality. This was a requirement to bring generics and “C++ and C#” type RTTI access and management to Delphi. And as always the FPC group followed suit – which we should be thankful for.
The only technical challenges that requires a fair bit of research and testing can be isolated in 3 groups:
- Fundamental differences in serialization
- Object life-time differences
- Native code lacks the ability to emit reflection and alter itself at runtime
Why do it at all?
And last but not least, to the question of why; The answer is that the dot net framework has quickly become the dominant framework. People like to believe that C++ is in the lead here, or even JavaScript which tops the code evolution charts, but that is not the case. The dot net framework is used by millions of programmers every single day, both young and old alike. No other framework has the same level of exposure; Microsoft has successfully installed their framework onto every Windows PC on the planet – and with their recently announced “open source” initiative — the dot net framework will become and important part of Unix, Linux and OS X.
Being able to offer customers a framework they already know – but with a twist: namely that it compiles to native code, fast, relentless and which is emitted as a single executable — is more effective than presenting something utterly alien to young programmers. The same can be done with ordinary .net or mono apps through the executable image tool – which generates a single .exe with no dependencies of your C# code.
Porting over important libraries from C# becomes substantially easier if at least a subset of the dot net framework can be mapped to C# in 1:1 fashion.
C# lacks many of the features which makes object pascal so attractive; A native dot net “clone” RTL, which would replace the VCL completely, would benefit from many of the already existing VCL classes — and also from the language features unique to object pascal.
Proof of concept
To make a long story short; I have implemented a handful of the fundamental dot net classes. I have only spent an afternoon on this, so dont expect miracles, but at least it implements the basic .net serialization engine (the .net framework actually has 3 engines for serialization, few people are aware of that).
And to be frank, it’s already so much more easier to use than vanilla VCL. Now dont start a flame-war because of that statement. I love the VCL and use it every single day — but one of the more time-consuming tasks I can think of, is to write persistent code (if your components expose fields of a non-standard datatype).
A second nail in the proverbial coffin is that Delphi’s persistence is exclusively binary. A lot of frameworks have alternatives for this, like mORMot, Remobjects and TMS’s Aurelius (which I really love, since it’s purely attribute based), but vanilla object pascal as delivered by Embarcadero still ships with TPersistent which havent evolved since it’s inception ages ago.
C# and other .net languages have built in serialization out of the box. It’s a very simple form of serialization, but due to it’s decoupled nature – where property identifier is separated from property data (so you can emit XML text to a binary medium) it’s very effective.
It’s also fully automatic, unless you explicitly turn it off. So under C# you can write a “normal” class as such:
/* Bog standard class. We inherit from ISerializable, and we also tag the class with the "Serializable" attribute */ [Serializable()] public class TMyClass: ISerializable { public int Value { get; set; } public string Name { get; set; } }
The above is identical to this object-pascal code. The VCL rule for persistence is that only published properties are automatically persisted by the VCL, and the property must be a non-complex type (e.g “standard datatypes like integer, string, double and so on). The problem is that you will only be able to load and in Delphi’s custom binary format, which makes it so much harder to work with high-end, industry standard, enterprise level solutions.
In the world of enterprise computing, methods typically take serialized objects as parameters. So instead of shipping in a ton of parameters – you ship in one string which contains an object exposing whatever properties you need.
Delphi does have such a system, buried deep with it’s RPC (remote procedure call) units — but the binary data cannot be made any better. It’s just base-64 encoded.
TMyClass = Class(TPersistent) private FValue:Integer; FName: String; Published Property Value:Integer read FValue write FValue; Property Name:String read FName write FName; End;
As you see from the C# code example, C# has adopted anonymous field declarations. Meaning that you dont define a property field (the actual field to hold a property’s value) by name. It remains anonymous and you simply access the exposed property name. This is a great time saver and it makes sense when you think about it. Smart Pascal implements this, so as of writing SMS is the only object-pascal compiler which allows you to write near identical pascal which maps directly to C#. It also does this without importing weird C++ syntax (let’s face it, generics sticks out like a sore thumb in Delphi). So Smart Pascal is in some ways closer to C# than BCPL; BCPL being the language pascal inherited many ideas from back in the 70’s.
Now when you want to serialize your object, which simply means that you are able to save all published properties automatically to XML, JSON, binary or whatever emitter is available, under C# you would just write:
void saveObjToStream(TMyClass mObject) { /* Use an XML serializer */ XmlSerializer ser = new XmlSerializer(typeof(TMyClass)); /* Setup target buffer */ MemoryStream mBuffer = new MemoryStream(); /* Setup our stream-writer */ TextWriter mWriter = new StreamWriter(mBuffer); /* Save object instance as XML to our memory stream */ ser.Serialize(mWriter, mObject); }
Reasonably straight forward; easy and effective. Delphi’s old TPersistent may be faster due to it’s binary format, but Delphi is suffering because of the binary-only technology which VCL represents. It would be easy to fix this for Embarcadero, but I guess they are focusing more on FMX these days.
Right, with the core .net “object” class implemented (see code below) we are now able to do something very similar:
procedure saveToStream(mObject:TMyClass) var mSerializer: TMSXMLSerializer; mBuffer: TMemoryStream; mWriter: TMSTextWriter; Begin mSerializer:=TMSXMLSerializer; end;
This is very different from how Delphi has traditionally dealt with serialization. TPersistent dispatches the job of writing data onto the component itself. This is very effective when dealing with large trees of objects and sub-objects (although stack hungry for very large structures). But be that as it may, Delphi’s TWriter and TReader is a binary affair from beginning to end. Which means Delphi serialization (as Embarcadero shipts it) cant play ball with the big-boys who exclusively use XML (even for parameters in DLL’s or ORMS).
Manual serialization
While the .net framework has the simple “automatic” serialization technique i demonstrated above, which is suitable for web services, databases and remote procedure calls — the .net framework actually has 3 different persistent serialization engines.
The second version is more hands-on and functions pretty much like Delphi’s TPersistent does. With one exception and that is a proxy object is used to register properties manually; This is where the TMSSerializationInfo class comes in.
When manually using this variation you simply derive a new class from TMSObject and implement the ISerializable interface. The system will then call on the GetObjectData() when needed to obtain a property dictionary, then that dictionary is used to either stream out RTTI information (the properties defined in the dictionary) or write properties to an instance.
Well, enough blabber from me — he is the “work in progress” code so you can see for yourself. I will probably finish it laster at some point, I am working on Smart Mobile Code at the moment.
unit qtx.system; interface uses System.Sysutils, System.Classes, System.rtti, System.TypInfo, System.Generics.Collections; type EQTXObject = Class(Exception); (* Exception classes *) EQTXObjectAlreadyRetained = Class(EQTXObject); EQTXObjectNotRetained = Class(EQTXObject); EQTXObjectRetained = Class(EQTXObject); EQTXObjectCloneFailed = Class(EQTXObject); EQTXObjectRTTIQueryFailed = Class(EQTXObject); (* Forward declarations *) TQTXObject = Class; TQTXPersistent = Class; TQTXSerializationInfo = Class; //TQTXObjectPropertyInfo = Class; //TQTXObjectPropertyInfoList = Class; TCharArray = packed array of char; TByteArray = packed array of byte; IDisposable = interface ['{56714944-F3D0-43C9-8C4B-F2F00BA5F83D}'] procedure Dispose; end; IRetainedObject = Interface ['{27B152DC-6553-4309-8C51-2B5C7D89A9EB}'] procedure RetainObject; procedure ReleaseObject; end; ICloneable = interface ['{6BAB94D0-32B9-4C4C-9D71-4C88AA9E6D0B}'] function Clone:TQTXObject; end; ISerializable = interface ['{FAD5405E-34B8-4264-8F8D-EE2A0D257213}'] function GetObjectData:TQTXSerializationInfo; end; TQTXObjectPropertyInfoList = Class; TQTXObjectPropertyInfo = Class(TObject) private FName: String; FDataType: TTypeKind; FParent: TQTXObjectPropertyInfoList; public Property PropertyName:String read FName write FName; property PropertyType:TTypeKind read FDataType write FDataType; function asString:String; constructor Create(Parent:TQTXObjectPropertyInfoList);virtual; end; TQTXObjectPropertyInfoList = class(TObjectList<TQTXObjectPropertyInfo>) private FInstance: TQTXObject; public Property Instance:TQTXObject read FInstance; function ToString:String;override; constructor Create(Instance:TQTXObject);reintroduce;virtual; end; (* IRTTIProvider = interface ['{6C3113DE-BAFD-46D1-9596-C1397991F02F}'] function queryPropertyInfo(var aList:TQTXObjectPropertyInfoList):Boolean; function getPropertyValue(aName:String;var data;buffLen:Integer):Boolean; end; *) ISomeThing = Interface function queryPropertyInfo(var aList:TQTXObjectPropertyInfoList):Boolean; function getPropertyValue(aName:String;var Data:PByte;buffLen:Integer):Boolean; end; TQTXObject = Class(TPersistent,IRetainedObject) strict private FRefCount: Integer; FRetained: Boolean; public function queryPropertyInfo(var list:TQTXObjectPropertyInfoList):Boolean; function getPropertyValue(aName:String; var data:Pointer; var buffLen:Integer):Boolean; strict protected procedure CloneProperties(aSource,aTarget:TQTXObject; Recursive:Boolean=False); class function ElfHash(const aData;aLength:Integer):LongWord;overload; class function ElfHash(const aText:String):LongWord;overload; strict protected Property RefCount:Integer read FRefCount; strict protected { IInterface } function _AddRef: Integer;virtual;stdcall; function _Release: Integer;virtual;stdcall; strict protected procedure RetainObject;virtual; procedure ReleaseObject;virtual; public function CloneMemberWise(var aClone):Boolean; procedure Finalize;virtual; class function ReferenceEquals(const ObjA,ObjB:TQTXObject):Boolean; class function GetHashCode:Longword;reintroduce; class function GetType:TClass; function ToString:String;override; Procedure Free;reintroduce;virtual; public function QueryInterface(const IID: TGUID; out Obj): HResult; virtual; stdcall; Procedure BeforeDestruction;Override; Procedure AfterConstruction;Override; end; (* See: http://msdn.microsoft.com/en-us/library/system.runtime.serialization.serializationinfo(v=vs.110).aspx For member info *) TQTXSerializationInfo = Class(TQTXObject) end; TQTXWriter = Class(TQTXObject) private FStream: TStream; strict protected procedure WriteBinary(const data;dataLen:Integer); public procedure Write(value:Boolean);overload;virtual; procedure Write(value:byte);overload;virtual; procedure Write(value:TByteArray);overload;virtual; procedure Write(value:char);overload;virtual; procedure Write(value:TCharArray);overload;virtual; procedure Write(value:String);overload;virtual; procedure Write(value:Integer);overload;virtual; procedure Write(value:word);overload;virtual; procedure Write(Value:Longword);overload;virtual; procedure Write(Value:double);overload;virtual; Procedure Write(Value:Int64);overload;virtual; constructor Create(target:TStream);virtual; destructor Destroy;Override; end; TQTXTextWriter = Class(TQTXWriter) strict protected Procedure WriteText(value:String); public procedure Write(value:Boolean);override; procedure Write(value:byte);override; procedure Write(value:TByteArray);override; procedure Write(value:char);override; procedure Write(value:TCharArray);override; procedure Write(value:String);override; procedure Write(value:Integer);override; procedure Write(value:word);override; procedure Write(Value:Longword);override; procedure Write(Value:double);override; Procedure Write(Value:Int64);override; end; TQTXReader = class(TQTXObject) end; TQTXTextReader = Class(TQTXReader) End; TQTXSerializer = Class(TQTXObject) public procedure Serialize(writer:TQTXWriter;const instance:TQTXObject);virtual;abstract; procedure DeSerialize(reader:TQTXReader;const instance:TQTXObject);virtual;abstract; end; TQTXXMLSerializer = Class(TQTXSerializer) public procedure Serialize(writer:TQTXWriter;const instance:TQTXObject);override; procedure DeSerialize(reader:TQTXReader;const instance:TQTXObject);override; end; TQTXBinarySerializer = Class(TQTXSerializer) End; TQTXPersistent = Class(TQTXObject,ICloneable,ISerializable) strict protected (* ICloneable *) function Clone:TQTXObject; strict protected (* ISerializable *) function GetObjectData:TQTXSerializationInfo;virtual; end; implementation class function TQTXObject.ElfHash(const aData;aLength:Integer):LongWord; var i: Integer; x: Cardinal; FSrc: PByte; Begin Result:=0; If aLength>0 then Begin FSrc:=@aData; for i:=1 to aLength do begin Result := (Result shl 4) + FSrc^; x := Result and $F0000000; if (x <> 0) then Result := Result xor (x shr 24); Result := Result and (not x); inc(FSrc); end; end; end; class function TQTXObject.ElfHash(const aText:String):LongWord; var FAddr: Pointer; FLen: Integer; Begin Result:=0; FLen:=Length(aText); If FLen>0 then Begin FAddr:=@aText[1]; Result:=ElfHash(FAddr^,FLen * Sizeof(Char)); end; end; //############################################################################# // TQTXObjectPropertyInfo //############################################################################# constructor TQTXObjectPropertyInfo.Create(Parent:TQTXObjectPropertyInfoList); begin inherited Create; FParent:=Parent; end; function TQTXObjectPropertyInfo.asString:String; var mStr: String; mInt: Integer; mInt64: Int64; mSize: Integer; mPTR: Pointer; mEnum: longword; mVar: Variant; begin setLength(result,0); if FParent<>NIL then begin if FParent.Instance<>NIL then Begin case FDataType of tkString, tkLString, tkUString: Begin mSize:=0; repeat inc(mSize,1024); setLength(mStr,mSize); fillchar(mStr[1],mSize,#0); mPTR:=pointer(@mStr[1]); until FParent.Instance.getPropertyValue(FName,mPTR,mSize); result:=QuotedStr(strPas(PChar(mPTR))); setLength(mStr,0); end; tkInteger: Begin mPTR:=@mInt; mSize:=SizeOf(Integer); FParent.Instance.getPropertyValue(FName,mPTR,mSize); result:=IntToStr(mInt); end; tkInt64: Begin mPTR:=@mInt64; mSize:=SizeOf(Int64); FParent.Instance.getPropertyValue(FName,mPTR,mSize); result:=IntToStr(mInt64); end; tkEnumeration: Begin mPTR:=@mEnum; mSize:=SizeOf(Longword); FParent.Instance.getPropertyValue(FName,mPTR,mSize); if mSize=SizeOf(Boolean) then result:=boolToStr(PBoolean(mPTR)^,true) else Begin result:='[Enumeration]'; end; end; tkVariant: Begin mPTR:=@mVar; mSize:=SizeOf(Variant); FParent.Instance.getPropertyValue(FName,mPTR,mSize); result:=string(mVar); end; end; end; end; end; //############################################################################# // TQTXObjectPropertyInfoList //############################################################################# constructor TQTXObjectPropertyInfoList.Create(Instance:TQTXObject); Begin inherited Create(True); FInstance:=Instance; end; function TQTXObjectPropertyInfoList.ToString:String; var x: Integer; Begin setLength(result,0); for x:=0 to Count-1 do Begin result:=result + Items[x].PropertyName + '=' + items[x].asString; if x<(count-1) then result:=result + #13; end; end; //############################################################################# // TQTXXMLSerializer //############################################################################# procedure TQTXXMLSerializer.Serialize (writer:TQTXWriter;const instance:TQTXObject); Begin if assigned(writer) then begin if assigned(instance) then Begin end; end; end; procedure TQTXXMLSerializer.DeSerialize (reader:TQTXReader;const instance:TQTXObject); Begin end; //############################################################################# // TQTXTextWriter //############################################################################# Procedure TQTXTextWriter.WriteText(value:String); Begin if length(value)>0 then Begin Value:=Value + #13#10; FStream.Write(value[1],length(value) * SizeOf(Char)); end; end; procedure TQTXTextWriter.Write(value:Boolean); Begin WriteText(BoolToStr(value,true)); end; procedure TQTXTextWriter.Write(value:byte); Begin WriteText('$' + IntToHex(Value,2)); end; procedure TQTXTextWriter.Write(value:TByteArray); var x: Integer; Begin if length(value)>0 then for x:=low(value) to high(value) do Write(Value[x]); end; procedure TQTXTextWriter.Write(value:char); Begin FStream.Write(Value,SizeOf(Char)); end; procedure TQTXTextWriter.Write(value:TCharArray); var x: Integer; Begin if length(Value)>0 then for x:=low(Value) to high(Value) do FStream.Write(Value[x],SizeOf(Char)); end; procedure TQTXTextWriter.Write(value:String); Begin WriteText(Value); end; procedure TQTXTextWriter.Write(value:Integer); Begin WriteText(IntToStr(Value)); end; procedure TQTXTextWriter.Write(value:word); Begin WriteText('$' + IntToHex(Value,4)); end; procedure TQTXTextWriter.Write(Value:Longword); Begin WriteText('$' + IntToHex(Value,8)); end; procedure TQTXTextWriter.Write(Value:double); Begin WriteText(FloatToStr(Value)); end; Procedure TQTXTextWriter.Write(Value:Int64); Begin WriteText(IntToStr(value)); end; //############################################################################# // TQTXWriter //############################################################################# constructor TQTXWriter.Create(target:TStream); Begin inherited Create; FStream:=target; end; destructor TQTXWriter.Destroy; Begin inherited; end; procedure TQTXWriter.WriteBinary(const data;dataLen:Integer); Begin FStream.Write(data,dataLen); end; procedure TQTXWriter.Write(value:Boolean); Begin WriteBinary(Value,sizeOf(Value)); end; procedure TQTXWriter.Write(value:byte); Begin WriteBinary(Value,sizeOf(Value)); end; procedure TQTXWriter.Write(value:TByteArray); Begin if length(value)>0 then WriteBinary(value,length(value)); end; procedure TQTXWriter.Write(value:char); Begin WriteBinary(Value,sizeOf(Value)); end; procedure TQTXWriter.Write(value:TCharArray); Begin if length(value)>0 then WriteBinary(Value,SizeOf(Char) * Length(Value)); end; procedure TQTXWriter.Write(value:String); Begin WriteBinary(Value,sizeOf(Value)); end; procedure TQTXWriter.Write(value:Integer); Begin WriteBinary(Value,sizeOf(Value)); end; procedure TQTXWriter.Write(value:word); Begin WriteBinary(Value,sizeOf(Value)); end; procedure TQTXWriter.Write(Value:Longword); Begin WriteBinary(Value,sizeOf(Value)); end; procedure TQTXWriter.Write(Value:double); Begin WriteBinary(Value,sizeOf(Value)); end; Procedure TQTXWriter.Write(Value:Int64); Begin WriteBinary(Value,sizeOf(Value)); end; //############################################################################# // TQTXPersistent //############################################################################# function TQTXPersistent.GetObjectData:TQTXSerializationInfo; begin result:=TQTXSerializationInfo.Create; end; function TQTXPersistent.Clone:TQTXObject; var mClass: TClass; begin result:=NIL; mClass:=getType; if mClass<>NIl then Begin (* Create instance *) result:=TQTXObject(mClass.Create); (* Do a recursive "deep-copy" of the object properties *) try cloneProperties(self,result,true); except on e: exception do begin freeAndNIL(result); Raise EQTXObjectCloneFailed.CreateFmt ('Failed to clone %s, method %s threw exception %s with message %s', [self.ClassType.ClassName,'Clone',e.ClassName,e.Message]); end; end; end; end; //############################################################################# // TQTXObject //############################################################################# Procedure TQTXObject.AfterConstruction; begin inherited; AtomicDecrement(FRefCount); end; Procedure TQTXObject.BeforeDestruction; Begin if RefCount <> 0 then Error(reInvalidPtr); Finalize; inherited; end; Procedure TQTXObject.Free; Begin if FRetained then Raise EQTXObjectRetained.Create ('Object is retained and cannot be released error'); Inherited free; end; function TQTXObject._AddRef: Integer; begin Result := AtomicIncrement(FRefCount); end; procedure TQTXObject.RetainObject; Begin (* Prevent automatic release through self-increment *) if not FRetained then FRetained:=_addRef>0 else raise EQTXObjectAlreadyRetained.Create ('Object is already marked as retained error'); end; procedure TQTXObject.ReleaseObject; Begin if FRetained then _release else raise EQTXObjectNotRetained.Create ('Object is not retained error'); end; function TQTXObject._Release: Integer; begin (* Note: Delphi calls destroy directly, but since we want to be in tune with future possible changes to the VCL/FMX where free is expanded, I decided to invoke that instead *) Result := AtomicDecrement(FRefCount); if result<1 then free; end; function TQTXObject.QueryInterface(const IID: TGUID;out Obj): HResult; const E_NOINTERFACE = HResult($80004002); begin if GetInterface(IID, Obj) then Result := 0 else Result := E_NOINTERFACE; end; (* This is the dot net variation of "beforedestruction". I have included it for completeness and compatability only. It is invoked from beforedestruction. Also, this is where IDisposable is checked for *) Procedure TQTXObject.Finalize; var mAccess: IDisposable; begin (* Release unmanaged data *) if getInterface(IDisposable,mAccess) then mAccess.Dispose; end; function TQTXObject.ToString:String; Begin result:=self.ClassType.ClassName; end; class function TQTXObject.ReferenceEquals(const ObjA,ObjB:TQTXObject):Boolean; Begin result:=(objA<>NIL) and (objB<>NIL) and (objA = objB); end; class function TQTXObject.GetHashCode:longword; begin result:=TQTXObject.ElfHash(ClassName); end; class function TQTXObject.GetType:TClass; var ctx: TRttiContext; objType: TRttiType; begin result:=NIL; ctx := TRttiContext.Create; objType := ctx.GetType(ClassInfo); if (objType<>NIL) and (objType.AsInstance<>NIL) then result:=objType.AsInstance.ClassType; end; function TQTXObject.getPropertyValue(aName:String; var Data:Pointer; var buffLen:Integer):Boolean; var numProps, I : Integer; props: PPropList; PropInfo: PPropInfo; mInfo: TQTXObjectPropertyInfo; mText: String; mLen: Integer; Begin result:=False; if (Data<>NIL) and (BuffLen>0) then Begin numProps := GetPropList(self, props); try if numProps>0 then begin for i:=0 to numProps-1 do begin PropInfo := props^[I]; if sameText(String(PropInfo^.Name),aName) then Begin case propInfo^.PropType^.Kind of tkInteger: Begin if BuffLen>=SizeOf(Integer) then Begin Integer(data):=GetOrdProp(self,propinfo); BuffLen:=SizeOf(Integer); end; break; end; tkChar: begin if BuffLen>=SizeOf(char) then Begin PChar(data)^:=Char ( GetOrdProp(self,propinfo) ); BuffLen:=SizeOf(Char); end; break; end; tkEnumeration, tkSet, tkWChar: Begin if PropInfo^.PropType^ = TypeInfo(boolean) then Begin if BuffLen>=SizeOf(Boolean) then begin PBoolean(Data)^:=Boolean(GetOrdProp(self,propinfo)); BuffLen:=SizeOf(Boolean); break; end; end; if BuffLen>=SizeOf(longword) then Begin PLongword(data)^:=GetOrdProp(self,propinfo); BuffLen:=SizeOf(Longword); end; break; end; tkFloat: Begin if BuffLen>=SizeOf(Double) then Begin PDouble(data)^:=GetOrdProp(self,propinfo); BuffLen:=SizeOf(Double); end; break; end; tkString, tkLString, tkUString: begin mText:=GetStrProp(self,propinfo); mLen:=length(mText) * SizeOf(Char); if BuffLen>=mLen then Begin move(mText[1],data^,mLen); BuffLen:=mLen; end; break; end; tkInt64: Begin if BuffLen>=SizeOf(Char) * Length(mText) then Begin PInt64(data)^:=GetInt64Prop(self,propinfo); BuffLen:=SizeOf(Int64); end; break; end; tkVariant: begin if BuffLen>=SizeOf(variant) then Begin PVariant(Data)^:=getVariantProp(self,PropInfo); BuffLen:=SizeOf(Variant); end; break; end; (* tkInterface: begin break; end; tkMethod: Begin break; end; *) end; end; end; result:=(BuffLen>0); end; finally FreeMem(props); end; end; end; function TQTXObject.queryPropertyInfo (var list:TQTXObjectPropertyInfoList):Boolean; var numProps, I : Integer; props: PPropList; PropInfo: PPropInfo; mInfo: TQTXObjectPropertyInfo; Begin list:=NIL; result:=False; numProps := GetPropList(self, props); try if numProps>0 then begin list:=TQTXObjectPropertyInfoList.Create(self); for i:=0 to numProps-1 do begin PropInfo := props^[i]; if not (PropInfo^.PropType^.Kind in [tkClass,tkArray,tkRecord,tkDynArray]) then Begin mInfo:=TQTXObjectPropertyInfo.Create(list); mInfo.PropertyName:=propInfo^.Name; mInfo.PropertyType:=PropInfo^.PropType^.Kind; list.Add(mInfo); end; end; if list.Count<1 then freeAndNIL(list); result:=list<>NIL; end; finally FreeMem(props); end; end; procedure TQTXObject.CloneProperties(aSource,aTarget:TQTXObject; Recursive:Boolean=False); var numProps, I : Integer; props: PPropList; PropInfo: PPropInfo; src: TObject; dst: TObject; Begin numProps := GetPropList(aSource, props ); Try For I := 0 To numProps - 1 Do Begin PropInfo := props^[I]; Case PropInfo^.PropType^.Kind Of tkInteger, tkChar, tkEnumeration, tkSet, tkWChar: SetOrdProp(aTarget,propinfo,GetOrdProp(aSource,propinfo)); tkFloat: SetFloatProp(aTarget,propinfo,GetFloatProp(aSource,propinfo)); tkString, tkLString, tkUString: SetStrProp( aTarget, propinfo,GetStrProp( aSource, propinfo)); tkWString: SetWideStrProp(aTarget,propinfo,GetWideStrProp(aSource,propinfo)); tkMethod: SetMethodProp(aTarget,propinfo,GetMethodProp(aSource,propinfo)); tkInt64: SetInt64Prop(aTarget,propinfo,GetInt64Prop(aSource,propinfo)); tkVariant: SetVariantProp(aTarget,propinfo,GetVariantProp(aSource,propinfo)); tkInterface: SetInterfaceProp(aTarget,propinfo,GetInterfaceProp(aSource,propinfo)); tkClass: Begin if Recursive then Begin src := GetObjectProp( aSource, propinfo ); If Assigned( src ) Then Begin If src Is TComponent Then SetObjectProp( aTarget, propinfo, src ) else If src Is TPersistent Then Begin if src<>self then begin dst := GetObjectProp( aTarget, propinfo, TPersistent); if dst<>self then begin If Assigned( dst ) Then TPersistent( dst ).Assign( TPersistent(src)); end; end; End; End; end; End; tkArray, tkRecord, tkDynArray: begin end end; end; Finally FreeMem( props ); End; end; function TQTXObject.CloneMemberWise(var aClone):Boolean; var mClass: TClass; begin NativeInt(aClone):=0; result:=False; mClass:=getType; if mClass<>NIl then Begin TQTXObject(pointer(aClone)):=TQTXObject(mClass.Create); (* Do a recursive "deep-copy" of the object properties *) try cloneProperties(self,TQTXObject(pointer(aClone)),false); except on e: exception do begin freeAndNIL(result); Raise EQTXObjectCloneFailed.CreateFmt ('Failed to clone %s, method %s threw exception %s with message %s', [self.ClassType.ClassName,'CloneMemberWise',e.ClassName,e.Message]); end; end; //cloneProperties(self,TQTXObject(pointer(aClone))); result:=NativeInt(aClone)<>0; end; end; end.
You must be logged in to post a comment.