{"id":986,"date":"2026-03-08T11:46:24","date_gmt":"2026-03-08T19:46:24","guid":{"rendered":"https:\/\/www.installaware.com\/blog\/?p=986"},"modified":"2026-10-28T20:46:06","modified_gmt":"2026-10-29T04:46:06","slug":"a-case-study-in-porting-from-delphi-to-lazarus-arm64-diskzips-shell-extensions","status":"publish","type":"post","link":"https:\/\/www.installaware.com\/blog\/?p=986","title":{"rendered":"A Case Study in Porting from Delphi to Lazarus ARM64: DiskZIP&#8217;s Shell Extensions"},"content":{"rendered":"\n<p>Having waited for almost ten years for Delphi&#8217;s <strong>ARM64 <\/strong>Windows compiler, we threw in the towel and sponsored <strong>Lazarus<\/strong>&#8216;s <strong>ARM64 <\/strong>compiler:<\/p>\n\n\n\n<p><a href=\"https:\/\/www.installaware.com\/lazarus-arm64.msi\">www.installaware.com\/lazarus-arm64.msi<\/a> (or download <a href=\"https:\/\/www.installaware.com\/lazarus-arm64.exe\">www.installaware.com\/lazarus-arm64.exe<\/a> should you fancy a direct executable instead of a network deployable MSI file)<\/p>\n\n\n\n<p>For several years now, <strong>Free Pascal<\/strong>&#8216;s <strong>ARM64 <\/strong>support had almost worked, with only a few outlier issues that resisted resolution. Install<strong>Aware<\/strong> kept prodding and prodding, and the community delivered! That&#8217;s the power of open source. You can read about my initial reactions here:<\/p>\n\n\n\n<p><a href=\"https:\/\/forum.lazarus.freepascal.org\/index.php\/topic,66952.msg577034.html#msg577034\">Lazarus for Windows on aarch64 (ARM64) &#8211; Native Compiler<\/a><\/p>\n\n\n\n<p>TLDR; this post describes some of the problems we came across while porting our product from Delphi to <strong>Lazarus<\/strong>, specifically with a view towards how we resolved them. If you, like us, need true <strong>ARM64 <\/strong>support from Delphi and are tired of waiting &#8211; read on! This guide is intended for an audience that is totally new to <strong>Lazarus<\/strong>, and we hope to ease your pain with all we&#8217;ve learned.<\/p>\n\n\n\n<p><strong>ARM64 is NOT ARM64EC<\/strong><\/p>\n\n\n\n<p>Sadly, I must stress that ARM64EC is absolutely useless for anyone who actually needs a true <strong>ARM64 <\/strong>compiler. Even if ARM64EC code is comprised of &#8220;pure&#8221; ARM instructions, the binary format results in ARM EXEs that can load x64 DLLs, or ARM DLLs that can be loaded from x64 EXEs. Sure, the code that runs may be &#8220;pure&#8221; ARM, but it&#8217;s useless for all scenarios that actually require a true <strong>ARM64 <\/strong>compiler &#8211; of which we had one in our hands: <strong>Shell Extensions<\/strong>.<\/p>\n\n\n\n<p><strong>Shell Extensions<\/strong> are DLLs loaded by Windows File Explorer. Explorer is a true <strong>ARM64 <\/strong>process &#8211; it&#8217;s not an ARM64EC or x64 or x86 process. This means if you try to load an ARM64EC DLL into Explorer, that&#8217;s absolutely no different than trying to load an x64 DLL, or an x86 DLL into Explorer. It just won&#8217;t work. <em>And you might think &#8211; like I did &#8211; that it defeats the purpose of having an ARM compiler at all!<\/em><\/p>\n\n\n\n<p><strong>Why We Needed True ARM64 for DiskZIP&#8217;s Shell Extensions<\/strong><\/p>\n\n\n\n<p>You&#8217;re already familiar with <strong>Shell Extensions<\/strong>, even if you don&#8217;t think you are.<\/p>\n\n\n\n<p><strong>Context Menus<\/strong><\/p>\n\n\n\n<p>You work with these, literally every day. Any time you right-click in Windows File Explorer, you&#8217;re basically working with <strong>Context Menu <\/strong>Extensions:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"661\" height=\"516\" src=\"https:\/\/www.installaware.com\/blog\/wp-content\/uploads\/2026\/03\/context-menu-extension.png\" alt=\"Context Menu Shell Extension\" class=\"wp-image-990\"\/><\/figure>\n\n\n\n<figure class=\"wp-block-pullquote\"><blockquote><p>A real quick, brief sidebar here: While we certainly did port DiskZIP&#8217;s <strong>Context Menu<\/strong>&#8216;s to <strong>ARM64<\/strong>, this was perhaps the most useless part of the exercise. <strong>Context Menu<\/strong> Extensions, as you already know, are so prevalent and ubiquitous! Windows actually supports loading x86 and x64 extensions inside the <strong>ARM64 <\/strong>version of File Explorer through various compatibility shims. This means the process isn&#8217;t perfect, but here is where a true <strong>ARM64 <\/strong>compiler does add the least value to the equation.<br><br>You might also be familiar with how most <strong>Context Menus<\/strong> are nowadays hidden inside Windows 11&#8217;s higher level menus:<br><br><img decoding=\"async\" src=\"https:\/\/www.installaware.com\/blog\/wp-content\/uploads\/2026\/03\/context-menu-sidebar.png\" alt=\"Windows 11 Right Click Menu\"><br><br>We can&#8217;t take credit for this implementation, either. That was handled by the Install<strong>Aware<\/strong> team, and their truly magical <strong>Context Menu Bridge:<\/strong><br><br><a href=\"https:\/\/www.installaware.com\/context-menu-bridge.htm\">InstallAware Context Menu Bridge &#8211; InstallAware<\/a><br><br>To get your stuff showing inside this top-most level Windows 11-only menu, you actually have to do three things:<br><br>1) Write a different type of Shell Extension that&#8217;s NOT a <strong>Context Menu<\/strong> Extension<br>2) Build a <strong>Sparse MSIX<\/strong> package for it, and get it code signed (or Windows refuses to load it)<br>3) Automate the <strong>installation and removal<\/strong> of this <strong>Sparse MSIX<\/strong> package<br><br>Just to get on the new Windows 11-exclusive menu. Yes, it&#8217;s torture. That&#8217;s why Install<strong>Aware<\/strong>&#8216;s <strong>Context Menu Bridge<\/strong> is a lifesaver, but that&#8217;s a topic for another post.<\/p><cite>from <a href=\"https:\/\/www.installaware.com\/context-menu-bridge.htm\">InstallAware Context Menu Bridge &#8211; InstallAware<\/a><\/cite><\/blockquote><\/figure>\n\n\n\n<p><strong>Copy Hooks<\/strong><\/p>\n\n\n\n<p>So you&#8217;re already familiar with right-clicking to create archives on Windows, who isn&#8217;t? But did you know that with DiskZIP, you can create new archives out of existing folders by just adding an archive extension to your desired folder?<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"193\" height=\"173\" src=\"https:\/\/www.installaware.com\/blog\/wp-content\/uploads\/2026\/03\/copy-hook-extension.png\" alt=\"Copy Hook Shell Extension\" class=\"wp-image-991\"\/><\/figure>\n\n\n\n<p>Isn&#8217;t that fun? The technical name for the type of shell extension that makes this possible is a <strong>Copy Hook Extension<\/strong>. It triggers when some file &#8211; or folder &#8211; is being copied, moved, or renamed &#8211; our extension fires on renames when it detects you&#8217;re using an archive file extension that is supported by one of its installed plug-ins: It blocks the rename, and compresses the chosen folder instead (leaving its original contents intact, of course).<\/p>\n\n\n\n<p>And of course, all shell extensions we describe from here onwards, including the <strong>Copy Hook Extension<\/strong>, require true <strong>ARM64 <\/strong>compiler outputs. ARM64EC won&#8217;t work (so sadly, the upcoming Delphi won&#8217;t cut it). <strong>ARM64 <\/strong>Windows won&#8217;t emulate x86 or x64 shell extensions for <strong>Copy Hooks<\/strong> or anything else I&#8217;ve written about below.<\/p>\n\n\n\n<p><strong>Tool Tip Handlers<\/strong><\/p>\n\n\n\n<p>Here&#8217;s another fun one. Just hover your mouse over a file type, and get a customized textual preview of its contents &#8211; all dished up by the custom code running in your shell extension:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"270\" height=\"205\" src=\"https:\/\/www.installaware.com\/blog\/wp-content\/uploads\/2026\/03\/tooltipextension.png\" alt=\"Tool Tip Shell Extension\" class=\"wp-image-995\"\/><\/figure>\n\n\n\n<p><strong>Property Sheet Handlers<\/strong><\/p>\n\n\n\n<p>Did you know you can actually tap into the File Properties window shown by Windows File Explorer? Yup, that&#8217;s just another type of shell extension:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"433\" height=\"555\" src=\"https:\/\/www.installaware.com\/blog\/wp-content\/uploads\/2026\/03\/propertysheet.png\" alt=\"Property Sheet Shell Extension\" class=\"wp-image-993\"\/><\/figure>\n\n\n\n<p><strong>Drag and Drop Handlers<\/strong><\/p>\n\n\n\n<p>You know, like when you drag files on top of an existing archive &#8211; and it adds the files into the archive.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"157\" height=\"152\" src=\"https:\/\/www.installaware.com\/blog\/wp-content\/uploads\/2026\/03\/dragdrop.png\" alt=\"Drag Drop Shell Extension\" class=\"wp-image-992\"\/><\/figure>\n\n\n\n<p><strong>Shell Namespace Extensions<\/strong><\/p>\n\n\n\n<p>The name&#8217;s a mouthful for sure, but this is the best we saved for last:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img loading=\"lazy\" decoding=\"async\" width=\"877\" height=\"637\" src=\"https:\/\/www.installaware.com\/blog\/wp-content\/uploads\/2026\/03\/shell-namespace-extension.png\" alt=\"Shell Namespace Extension\" class=\"wp-image-994\"\/><\/figure>\n\n\n\n<p>You&#8217;re basically tapping into File Explorer&#8217;s tree, your code injecting virtual folders inside a given file type (such as an archive). You&#8217;re also injecting your own <strong>Lazarus <\/strong>(formerly Delphi) window directly inside File Explorer&#8217;s right pane, the contents of which you control exclusively. It&#8217;s a bit of rocket science to get it working right, honestly!<\/p>\n\n\n\n<p>And yes, for all these things &#8211; you need true <strong>ARM64 <\/strong>&#8211; or File Explorer just won&#8217;t play ball, at all.<\/p>\n\n\n\n<p><strong>Porting Challenges<\/strong><\/p>\n\n\n\n<p>So<strong> Lazarus ARM64<\/strong> definitely proves itself by being able to port a full-blown shell namespace extension from Delphi, and run it successfully under Windows File Explorer. But how did we get there, how hard was the journey?<\/p>\n\n\n\n<p>It&#8217;s a lot easier than you think, actually. Here&#8217;s our findings, with shoutouts included for the best practices!<\/p>\n\n\n\n<p><strong>Start With Lazarus&#8217;s Own Import Process<\/strong><\/p>\n\n\n\n<p>You&#8217;re not the first one looking to bring over code and projects from Delphi, and it shows. Click <strong>Tools | Delphi Conversion<\/strong> on the main <strong>Lazarus <\/strong>menu. Choose <strong>Convert Delphi Project to Lazarus Project<\/strong> for the most comprehensive solution. Sometimes it helps to move over units (and forms) individually, for which you&#8217;d go with the<strong> Convert Delphi Unit to Lazarus Unit<\/strong> menu item.<\/p>\n\n\n\n<p><em><strong>Best practice:<\/strong> Always do the conversion on a copy of your projects folder, instead of the original project folder.<\/em><\/p>\n\n\n\n<p>You can generally accept the defaults for the conversion. <strong>Lazarus<\/strong>&#8216;s default conversion process takes care of most of the grunt work in getting started for you &#8211; such as adding in a vital <strong>Lazarus<\/strong>-only units that you may not already know about, which comes in especially handy when this is your first time using <strong>Lazarus<\/strong>.<\/p>\n\n\n\n<p><strong>Activate ARM64<\/strong><\/p>\n\n\n\n<p><strong><em><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-amber-color\">Edit:<\/mark> The steps below are required <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-amber-color\">only<\/mark> when you&#8217;re using the 32-bit Lazarus IDE.<\/em><\/strong><\/p>\n\n\n\n<p><strong><em>After the original publishing of this article, the Lazarus team built a <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-amber-color\">native ARM64 IDE<\/mark>, along with a <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-amber-color\">native ARM64 debugger<\/mark><\/em>.<\/strong> <strong><em>This IDE cannot run on AMD\/Intel platforms, so we updated our installer to seamlessly install the original <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-amber-color\">32-bit IDE on AMD\/Intel<\/mark>, and to install the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-amber-color\">native ARM64 IDE on Snapdragon\/nVIDIA AI PC\/&#8221;Apple Silicon&#8221;<\/mark>.<\/em><\/strong><\/p>\n\n\n\n<p><strong><em>This way, even if you don&#8217;t own an ARM64 device, you can still develop for ARM64 by doing what&#8217;s called <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-amber-color\">cross-compilation<\/mark><\/em><\/strong><strong><em>. The steps below activate this convenient cross-compilation option, which was all we had when this article was first published:<\/em><\/strong><\/p>\n\n\n\n<p>Follow these steps to enable the <strong>ARM64 <\/strong>compiler sponsored by Install<strong>Aware<\/strong>:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>On the main <strong>Lazarus <\/strong>menu, click<strong> Project | Project Options<\/strong>. Then choose <strong>Compiler Options | Config and Target<\/strong>.<\/li>\n\n\n\n<li>In the <strong>Target platform<\/strong> box, inside the <strong>Target OS<\/strong> field, choose <strong>Win64<\/strong>.<\/li>\n\n\n\n<li>Inside the <strong>Target CPU<\/strong> family field, choose <strong>aarch64<\/strong>.<\/li>\n<\/ol>\n\n\n\n<p>If your project is a <strong>DLL<\/strong>, <strong>Lazarus <\/strong>will now place it inside the <strong>lib\\aarch64-win64<\/strong> folder of your main project folder.<\/p>\n\n\n\n<p>For executables, the outputs are found inside your main project folder.<\/p>\n\n\n\n<p>Now the real fun begins \ud83d\ude00<\/p>\n\n\n\n<p><strong>When Projects Fail to Convert<\/strong><\/p>\n\n\n\n<p>It&#8217;s not a bad idea to create them from scratch. Simply start with an empty <strong>Lazarus <\/strong>project:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>On the main <strong>Lazarus <\/strong>menu, click <strong>File | New<\/strong>. Then choose <strong>Project | Application<\/strong> to start with a new GUI app.<\/li>\n\n\n\n<li>On the main <strong>Lazarus <\/strong>menu, click <strong>Project | Project Inspector<\/strong>. Right click &#8220;<strong>unit1.pas<\/strong>&#8221; and choose <strong>Remove<\/strong>.<\/li>\n\n\n\n<li>Manually convert all your units one by one using the <strong>Convert Delphi Unit to Lazarus Unit<\/strong> option.<\/li>\n\n\n\n<li>Add them in to your new <strong>Lazarus <\/strong>project using the<strong> Project Inspector<\/strong>.<\/li>\n\n\n\n<li>If you have any custom code in your <strong>DPR <\/strong>project file, paste it into its <strong>Lazarus <\/strong>equivalent in the <strong>LPR <\/strong>file.<\/li>\n\n\n\n<li>If you have any custom defines in your <strong>Delphi <\/strong>project settings, add them in to your <strong>Lazarus <\/strong>project:<br>a. On the main <strong>Lazarus <\/strong>menu, click <strong>Project | Project Options<\/strong>. Then choose <strong>Compiler Options | Custom Options<\/strong>.<br>b. In the <strong>Custom <\/strong>options box, type each define you have in your <strong>Delphi <\/strong>project using the form &#8220;<strong>-dDEFINE<\/strong>&#8220;, separating them with a space.<\/li>\n\n\n\n<li>If your project references units in source paths, add them in with these steps:<br>a. On the main <strong>Lazarus <\/strong>menu, click <strong>Project | Project Options<\/strong>. Then choose <strong>Compiler Options | Paths<\/strong>.<br>b. Add each path to the <strong>Other unit files<\/strong> and <strong>Include files<\/strong> fields, separating paths using a semicolon &#8220;<strong>;<\/strong>&#8220;.<\/li>\n<\/ol>\n\n\n\n<p>This approach works really well with projects that don&#8217;t convert over well for whatever reason.<\/p>\n\n\n\n<p><strong>When Forms Fail to Convert<\/strong><\/p>\n\n\n\n<p>In our real world experience, forms that had multiple nested controls didn&#8217;t port over too well. Also problematic was image data, which was sometimes encoded differently by Delphi. Re-creating complex form layouts can be a pain, so don&#8217;t despair and give these suggestions a try instead &#8211; pre-processing misbehaving forms using Delphi, before you feed things over to <strong>Lazarus<\/strong>.<\/p>\n\n\n\n<p><em><strong>Best practice:<\/strong> Delete all image data, saving all image content to temporary files first. You can always load them right back into your <strong>Lazarus <\/strong>form after the initial conversion.<\/em><\/p>\n\n\n\n<p><em><strong>Best practice:<\/strong> Delete all controls that you don&#8217;t already have installed on the <strong>Lazarus <\/strong>component palette. Alternately, you can take to AI (Claude seems to work well enough) to port over the components over to <strong>Lazarus <\/strong>first, which is also an effective strategy.<\/em><\/p>\n\n\n\n<p><em><strong>Best practice:<\/strong> Feed your forms directly to AI (again, Claude was what we used), asking it to convert from Delphi to <strong>Lazarus<\/strong>. Sometimes when there&#8217;s no obvious cause for failure, this gets you over the conversion hurdle.<\/em><\/p>\n\n\n\n<p><strong>Touching Up Converted Units<\/strong><\/p>\n\n\n\n<p>So you&#8217;ve got your project file (<strong>LPR<\/strong>) and your forms (<strong>LFM<\/strong>) converted over &#8211; congrats! Now it&#8217;s time to touch up the units themselves.<\/p>\n\n\n\n<p><em><strong>Best practice:<\/strong> Always add in <strong>Windows <\/strong>to your <span style=\"text-decoration: underline;\">uses<\/span> clause. Chances are it was already there, but removed by <strong>Lazarus <\/strong>during conversion.<\/em><\/p>\n\n\n\n<p><em><strong>Best practice:<\/strong> If you&#8217;re working with GUI projects, also add in the <strong>Interfaces <\/strong>unit to the first line of your project file <em>(<strong>LPR<\/strong>)<\/em>&#8216;s <span style=\"text-decoration: underline;\">uses<\/span> clause, assuming it wasn&#8217;t there already<\/em>.<\/p>\n\n\n\n<p><em><strong>Best practice:<\/strong> Again for GUI projects, be sure to add in the <strong>LCLIntf<\/strong>, <strong>LCLType<\/strong>, and <strong>LMessages<\/strong> units to the <span style=\"text-decoration: underline;\">uses<\/span><strong> <\/strong>clauses of your form unit files (<strong>PAS<\/strong>) &#8211; chances are they&#8217;re there already, but we&#8217;ve seen them go missing every now and then.<\/em><\/p>\n\n\n\n<p><em><strong>Best practice:<\/strong> Add the define<strong> {$mode delphiunicode} <\/strong>immediately after your unit name declaration, especially if you&#8217;re wanting <span style=\"text-decoration: underline;\">Unicode<\/span> support in <strong>Lazarus<\/strong>. This define is the closest to what we get with Unicode Delphi.<\/em><\/p>\n\n\n\n<p><em><strong>Best practice:<\/strong> Manually replace all ANSI Windows API references with <span style=\"text-decoration: underline;\">Unicode<\/span> Windows API references. This is necessary because <strong>Lazarus <\/strong>defaults to ANSI versions of the Windows API. For example, replace CopyFile with CopyFile<strong>W<\/strong>, MoveFile with MoveFile<strong>W<\/strong>, etc. Most of the time, simply adding <strong>W <\/strong>to the end of the Windows API being rejected by the compiler because of string type mismatches works fine.<\/em><\/p>\n\n\n\n<p><em><strong>Best practice:<\/strong> The above applies to not just function names, but also to record names. For example, not only would you need to rename the ShellExecuteEx function to ShellExecuteEx<strong>W<\/strong>, but also the record it uses from SHELLEXECUTEINFO to SHELLEXECUTEINFO<strong>W<\/strong> &#8211; the former just resolves to SHELLEXECUTEINFOA in <strong>Lazarus<\/strong>, which will get you stuck in ANSI-land.<\/em><\/p>\n\n\n\n<p><em><strong>Best practice:<\/strong> For undeclared APIs, structures, constants, etc. ask your favorite AI for <strong>Lazarus <\/strong>declarations designed to work with the <strong>{$mode delphiunicode}<\/strong>, or just copy them over from the Delphi &#8220;headers&#8221; for the Windows API:<\/em><\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>In your Delphi IDE, right-click the declaration and choose &#8220;<strong>Find Declaration<\/strong>&#8221; in the popup menu.<\/li>\n\n\n\n<li>Copy the constants\/records right on over.<\/li>\n\n\n\n<li>Where record fields involve string types, make sure to explicitly convert them to <span style=\"text-decoration: underline;\">Unicode<\/span> strings for <strong>Lazarus<\/strong>. For example, a record field which reads LPCSTR would have to become LPC<strong>W<\/strong>STR in <strong>Lazarus <\/strong>for proper <span style=\"text-decoration: underline;\">Unicode<\/span> support.<\/li>\n\n\n\n<li>Where declarations involve functions, you may need to also press <strong>Ctrl + Shift + Down Arrow<\/strong> to navigate to the portion of the unit which declares the external DLL it is imported from &#8211; you&#8217;ll want to copy over both the function prototype and its external DLL reference to your <strong>Lazarus <\/strong>unit.<\/li>\n\n\n\n<li>We worked a lot with COM interfaces, this being a <strong>Shell Extension<\/strong> undertaking; and found that interfaces were sometimes defined differently as compared to Delphi: <strong>Lazarus <\/strong>would complain that interfaces which we already implemented were somehow missing. In these cases, it was easiest to:<br>a. Right-click the interface, for example <em>IContextMenu<\/em>, and choose &#8220;<strong>Find Declaration of IContextMenu<\/strong>&#8220;. Note that you do this in the <strong>Lazarus <\/strong>IDE (and not in Delphi), seeing as you need to access how <strong>Lazarus<\/strong> defines the interface.<br>b. Copy over all the function prototypes into your own COM Object&#8217;s interface declaration, and of course also update the function signatures in your implementations of those functions to the <strong>Lazarus <\/strong>way of declaring things.<br>c. While you&#8217;re at it, make sure you&#8217;re using the right interface &#8211; adding a <strong>W <\/strong>where necessary to the interface name.<\/li>\n\n\n\n<li>When parameter types change in function declarations, it is simply a matter of fixing code that calls those functions. For instance, where <strong>Lazarus <\/strong>expects the address of a variable, instead of the variable itself; just adding an &#8220;<strong>@<\/strong>&#8221; in front of the variable name pleases the compiler. The underlying APIs and function calls are all the same, it&#8217;s just about formatting the code to suit how it&#8217;s all ben declared, as it were.<\/li>\n\n\n\n<li>Last but not least, it is worth mentioning that some declarations may reside inside different units in <strong>Lazarus<\/strong>. You can always ask your favorite AI to see if it knows (if it&#8217;s hallucinating about the unit, chances are you&#8217;ll have to declare things yourself). I&#8217;ve also seen where ANSI functions\/records are declared in <strong>Lazarus<\/strong>, but their <span style=\"text-decoration: underline;\">Unicode<\/span> counterparts are not &#8211; so it&#8217;s up to you again.<\/li>\n<\/ol>\n\n\n\n<p>This is literally the entire gamut of the grunt work that <strong>Lazarus <\/strong>could not automate for us. We didn&#8217;t use AI for it, although you could certainly try and see how much you can get away with it?<\/p>\n\n\n\n<p><strong>Odds and Ends<\/strong><\/p>\n\n\n\n<p>So since we&#8217;re building shell extensions, our projects never had a predefined <em>TApplication<\/em> object. In Delphi, you can create a form without having an owner <em>TApplication<\/em>, but if you try this in <strong>Lazarus<\/strong>, it&#8217;ll crash everything swiftly. The cure is mind numbingly simple. Just make sure you use this code before creating any stand-alone forms you may have in your DLLs (admittedly, this may not apply to you):<\/p>\n\n\n\n<p><em>MyApp := TApplication.Create(nil);<br>MyApp.Initialize;<\/em><\/p>\n\n\n\n<p>Certain function names may also conflict between <strong>Lazarus <\/strong>class libraries and Windows &#8211; for us, <em>TRTLCriticalSection<\/em> and its associated function calls was one of these. Simply prefixing &#8220;<strong>Windows.<\/strong>&#8221; to all mismatched references (in both functions and data types) sorts this problem in no time at all, without having to rewrite your code to use <strong>Lazarus<\/strong>&#8216;s library functions instead.<\/p>\n\n\n\n<p><strong>Touching Up Project Settings<\/strong><\/p>\n\n\n\n<p>So you&#8217;ve imported your project, forms, and units &#8211; and even gotten them to compile &#8211; great job!<\/p>\n\n\n\n<p>One of the best surprises of <strong>Lazarus <\/strong>is after you manage to get things to compile, everything just works, exactly as it used to \ud83d\ude42<\/p>\n\n\n\n<p>After all, you&#8217;re literally porting to a dialect of the same language &#8211; and almost the same class library &#8211; we deserve this break, don&#8217;t we?<\/p>\n\n\n\n<p><strong>Debugging<\/strong><\/p>\n\n\n\n<p>Chances are by the time you&#8217;re reading this, <strong>Lazarus <\/strong>will already have a debugger for <strong>ARM64 <\/strong>&#8211; but as the earliest of the early adopters here, we weren&#8217;t as fortune.<\/p>\n\n\n\n<p><strong><em><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-amber-color\">Edit:<\/mark> Indeed, now we have an invaluable, <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-amber-color\">native ARM64 debugger!<\/mark><\/em><\/strong> <strong><em>The steps below would be required only if you&#8217;re running the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-amber-color\">32-bit Lazarus IDE on an AMD or Intel device<\/mark>.<\/em><\/strong> <strong><em>Debugging automatically works on the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-amber-color\">ARM64 Lazarus IDE<\/mark>, even including support for <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-luminous-vivid-amber-color\">attaching to external processes<\/mark> for DLL debugging (which comes in very handy when you&#8217;re debugging shell extensions, and need to attach to explorer.exe).<\/em><\/strong><\/p>\n\n\n\n<p>For those edge cases which must absolutely have troubleshooting help with a debugger, it helps to revert your project settings back to defaults, so you can step through your code line by line:<\/p>\n\n\n\n<ol class=\"wp-block-list\">\n<li>On the main <strong>Lazarus <\/strong>menu, click <strong>Project | Project Options<\/strong>. Then choose <strong>Compiler Options | Config and Target<\/strong>.<\/li>\n\n\n\n<li>In the <strong>Target platform<\/strong> box, inside the <strong>Target OS<\/strong> field, choose <strong>(Default)<\/strong>.<\/li>\n\n\n\n<li>Inside the <strong>Target CPU<\/strong> family field, choose <strong>(Default)<\/strong>.<\/li>\n<\/ol>\n\n\n\n<p>Now you can debug easily in the <strong>Lazarus <\/strong>IDE!<\/p>\n\n\n\n<p>Of course, when you&#8217;re done testing, be sure to change your settings back to <strong>ARM64<\/strong>.<\/p>\n\n\n\n<p>Also, keep in mind that some issues might only surface with an <strong>ARM64 <\/strong>target.<\/p>\n\n\n\n<p>Don&#8217;t be shy to ask AI if you&#8217;re ever stuck and need further help!<\/p>\n\n\n\n<p><strong>Build and Enjoy<\/strong><\/p>\n\n\n\n<p>You&#8217;ve done it!<\/p>\n\n\n\n<p>That wasn&#8217;t too bad, was it? We got everything done &#8211; for our extremely complicated shell namespace extension code &#8211; in just about a week&#8217;s time! I&#8217;m betting most of your projects would be done in an hour, or a day tops \ud83d\ude42<\/p>\n\n\n\n<p>You can take a look at our own work by installing DiskZIP from <a href=\"https:\/\/www.installaware.com\/diskzip.exe\">www.installaware.com\/diskzip.exe<\/a> &#8211; thanks to its intelligent Install<strong>Aware<\/strong> setup, it&#8217;ll seamlessly install the <strong>ARM64 <\/strong>components when you run it on an <strong>ARM64 <\/strong>device (such as native <strong>ARM <\/strong><em>Microsoft Surface<\/em> hardware, or virtualized Windows 11 running on <em>Parallels <\/em>on your Apple Silicon device), while installing x86 or x64 components when you run it on other kinds of (virtualized) hardware &#8211; all from a single installation binary.<\/p>\n\n\n\n<p>Now that your code is compiling under <strong>Lazarus<\/strong>, you&#8217;re basically one step away from compiling it natively for macOS and Linux, too! That&#8217;s exactly what we did some time ago, bringing Install<strong>Aware<\/strong> to Macintosh and GNU\/Linux worldwide.<\/p>\n\n\n\n<p>But that&#8217;s a topic for another blog post \ud83d\ude09<\/p>\n\n\n\n<p><em>John Gaver<br>for Install<strong>Aware<\/strong> Skunkworks<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Having waited for almost ten years for Delphi&#8217;s ARM64 Windows compiler, we threw in the towel and sponsored Lazarus&#8216;s ARM64 compiler: www.installaware.com\/lazarus-arm64.msi (or download www.installaware.com\/lazarus-arm64.exe should you fancy a direct executable instead of a network deployable MSI file) For several years now, Free Pascal&#8216;s ARM64 support had almost worked, with only a few outlier issues &hellip; <\/p>\n<p class=\"link-more\"><a href=\"https:\/\/www.installaware.com\/blog\/?p=986\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;A Case Study in Porting from Delphi to Lazarus ARM64: DiskZIP&#8217;s Shell Extensions&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-986","post","type-post","status-publish","format-standard","hentry","category-news"],"_links":{"self":[{"href":"https:\/\/www.installaware.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/986","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.installaware.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.installaware.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.installaware.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.installaware.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=986"}],"version-history":[{"count":23,"href":"https:\/\/www.installaware.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/986\/revisions"}],"predecessor-version":[{"id":1044,"href":"https:\/\/www.installaware.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/986\/revisions\/1044"}],"wp:attachment":[{"href":"https:\/\/www.installaware.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=986"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.installaware.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=986"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.installaware.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=986"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}