When building Hydra hosts and plugin modules with Delphi, both the host and plugins must be compiled with runtime packages. The host and plugin modules must be compiled against the packages that contain the classes that are used in both the host and the modules. Usually this means, at the least, compiling against rtlXXX.bpl, vclXXX.bpl, and Hydra_Core_DXX.bpl. This also means you must deploy these BPL’s, with their naming conventions and version information. At some point you may wish to create your own RTL, VCL, and RemObjects packages against which you can build your Hydra hosts and plugin modules. This means you can name the packages as you like, tailor the included units, and version the packages as you see fit.
The steps and ideas we will cover in this article aren’t specific to Hydra. The steps outlined below will work any time you wish to create custom packages for a set of units, be they CodeGear components or 3rd party controls.
- Create RTL, VCL, and RO packages
- Discuss how to handle the prompts for implicitly imported units
- Cover easy ways to add units using macro recording and playback in Delphi
- Create a Hydra host that uses our custom packages
Creating the RTL Package
First, start up the Delphi IDE. In this article we’ll be using Delphi 2007. While the unit names may differ for other versions of Delphi, the principles should apply to any version of the Delphi IDE.
Click File > New > Package. Right click Package1.bpl in the Project Manager and click Options. On the Description screen, select Explicit rebuild. Change to the Directories/Conditionals screen and set both the Output directory and DCP output directory to “.\”. This will ensure our designtime and runtime packages are placed in the project folder rather than the default BPL output directory found in the Delphi preferences (found in Tools > Options > Environment Options > Delphi Options > Library – Win32). The BPL files are the runtime packages. These are what must be distributed with the application. The DCP files are designtime packages. These are what must be present at designtime to link against when compiling our other packages, plugin modules, and host.
After setting the output directories, click OK.
Right click Package1.bpl and click View Source. Remove the requires section, including the reference to rtl. We don’t want our packages to require any Delphi or RemObjects packages – they should be self sufficient. Click File > Save Project As, and save the project as rtl.dproj in the C:\Packages directory.
Add a contains section where the removed requires section was, and add the first few RTL units that come to mind after the contains keyword. This is not an exact science and these units will probably differ from one version of Delphi to another. The important part is the concept of how to create the packages, set the output directories, search paths, and handle implicitly imported units. We’ll start with Classes, SysUtils, and Variants:
contains Classes, SysUtils, Variants;
Right click rtl.bpl in the Project Manager and click Compile, clicking OK on the compiler progress after the package has compiled.
At this point there should be several lines of warnings in the messages pane in Delphi, indicating units were implicitly imported into the package. Go ahead and add these units to your contains section (if you are using Delphi 2007 and following these steps, you should have been warned about, and need to add, ActiveX, Types, RTLConsts, and SysConst). Right click rtl.bpl and compile again. At this point the package should successfully compile, but if you get more implicit unit warnings in the messages pane, add those units as well (and recompile).
Our RTL package now compiles without warnings, but we are not done. We will leave the package for now and move on, but will need to revisit it to add more units as you will see.
Creating the VCL Package
Now that our RTL package compiles, we’ll move on to our VCL package. Right click ProjectGroup1 in the Delphi Project Manager and click Add New Project. Click Delphi Projects, then Packages, and click OK.
Right click Package1.bpl and click Options. As before, on the Description screen, select Explicit rebuild. On the Directories/Conditionals tab, set the Output directory, DCP output directory, and the Search path to “.\”. The search path must be set to the same place where our DCP’s are being generated, as these must be found at designtime for linking. Click OK. Click File and then Save All. Save the package as vcl.dproj and the project group as Hydra Packages.grouproj in the C:\Packages directory.
Right click vcl.bpl and click View Source. Add a contains section and add the first few VCL units you can think of. We’ll start with Forms, Controls, and StdCtrls.
requires rtl; contains Forms, Controls, StdCtrls;
Right click vcl.bpl in the Project Manager and click Compile. Click OK on compiler progress. At this point you will be greeted with a prompt that should be familiar if you’ve created custom packages before, but is probably one of the bigger stumbling blocks for those creating their first custom packages.
What this means is that the Delphi IDE knows that units that are going to be implicitly imported into vcl.bpl already exist in its own rtlXXX.bpl package. The IDE is prompting us to build against its rtlXXX.bpl package instead. This may make sense in some scenarios, but we don’t want our packages to depend on any CodeGear or RemObjects package. What we want to do in this case is add those units to our rtl.bpl contains section. Copy the unit names out of the dialog and click Cancel, followed by OK.
Now we’ll revisit our rtl.bpl package and add the missing units. Right click rtl.bpl and click View Source. Add the units copied out of the dialog to the contains section. Right click rtl.bpl in the Delphi Project Manager and click Compile All From Here. As before, add any implicitly imported units shown as warnings in the messages pane to the contains section of our vcl.bpl project (in this case in Delphi 2007 we would need to add StdActns, ImgList, Clipbrd, etc).
Finally, right click vcl.bpl and click Compile. At this point the package should successfully compile. If you get more implicit unit warnings in the messages pane, add those as well, compiling again afterward.
Creating the RO Package
Now we will create our RemObjects package, which should include (for simplicity of deployment, but that’s up to you the developer) the necessary units from RemObjects, Hydra, and (if used) Data Abstract.
Right click Hydra Packages and click Add New Project. Select Delphi Projects, then Package, and click OK. Right click Package1.bpl and apply the same settings as above, namely setting Explicit rebuild on the Description screen and the Output directory, DCP output directory, and Search path on the Directories/Conditionals screen. Click OK.
Click File > Save All. Save the package as ro.dproj in the C:\Packages folder. Right click ro.bpl and click View Source. Add vcl to the requires section. As before, add the first few RemObjects and Hydra (and, if used in your project, Data Abstract) units that come to mind. We’ll start with uROCOMInit, uROWinInetHttpChannel, uHYVisualPlugin, and DataAbstractService_Impl:
requires rtl, vcl; contains uROCOMInit, uROWinInetHttpChannel, uHYVisualPlugin, DataAbstractService_Impl;
In the Delphi Project Manager, right click ro.bpl and click Compile. At this point, depending on Delphi version, you will probably either receive the dialog prompting you to change ro.bpl or the warnings in the message pane about implicitly imported units. If you are using Delphi 2007 and have been following the steps above, you will be greeted with the following dialog:
Again, what prompts and warnings you will receive will vary depending on the version of Delphi, the packages you are creating, the units you are adding, etc. The important part is knowing how to deal with these prompts in warnings. In this case, the above dialog is letting us know that there are several units that need to be added to our RTL, VCL, and RemObjects packages:
RTL – msxml, XMLConst, WideStrings, MaskUtils
VCL – OleServer, StdVcl, OleConst, ListActns, ComCtrls
RemObjects – uHY*, uRO*, uDA*
Revisit our rtl.bpl and vcl.bpl packages, adding the units found in the dialog. Right click rtl.bpl and click Compile All From Here.
At this point, you will probably receive a large number of warnings in the Delphi message pane about more implicitly imported units. There is a simple way to add all of these units without entering them manually. Select all of the warnings in the message pane and copy them using either CTRL+C or the context menu.
Paste the text into the ro.bpl source after your existing units in the contains section. Now, we’ll use the macro recording and playback in Delphi to fix these up. Start with your cursor on the line above the first pasted warning. Click CTRL+SHIFT+R to begin recording your macro. Use the keyboard to arrow down one line to the first warning. Use the keyboard (not mouse) to edit the line in a way that can be played against subsequent lines. You’ll want to use CTRL+Arrows, CTRL+SHIFT+Arrows, the END key, etc, to edit the line to match the units in your contains section.
Once the line is edited, hit CTRL+SHIFT+R to stop recording. Now, if you created the macro properly, you should be able to hit CTRL+SHIFT+P repeatedly to play the macro and fix the rest of the lines.
Finally, in the Project Manager, right click rtl.bpl and click Compile All From Here again.
At this point, all of the packages should compile without warnings.
One thing of note is that the RemObjects packages are well divided by channel (WinInet, Indy, Synapse), so the IDE may not prompt you about implicitly imported units for these channels and servers. Ensure you add the units for the channels and servers you use, such as uROWinMessageChannel, uROWinMessageServer, uRODLLChannel, uRODLLServer, uRONamedPipeChannel, uRONamedPipeServer, etc.
Creating a Hydra Host
Our final step will be to create a Hydra host application that uses our custom packages rather than the stock CodeGear and RemObjects packages. Click File > New > Other. Select RemObjects Hydra, then Host Application, and click OK.
Follow the wizard, specifying C:\Hydra Host as the directory and CustomPackagesHost as the project name. Click Next, followed by Finish.
When the Project Package Settings dialog is displayed, select Custom Package List and specify rtl;vcl;ro as shown below.
Right click CustomPackagesHost.exe in the Delphi Project Manager and click Options. On the Directories/Conditionals screen, specify C:\Packages as the Search path. This ensures that, at designtime, the Delphi IDE will find and use our custom DCP files when linking the application. Click OK.
Right click CustomPackagesHost.exe and click Compile. The program should compile without errors or warnings. However, there is one last problem. If you try to run the host application you will receive an error. This is because the host EXE cannot find the custom BPL’s. The BPL’s, at runtime, need to either be in the same folder as the EXE or somewhere on the system PATH environment variable. This is the same with the stock CodeGear and RemObjects packages – they are simply already on your system PATH thanks to their respective installers.
Copy your BPL’s to the C:\Hydra Host folder and run your host application CustomPackagesHost.exe. The program should run without issue, using your custom packages at runtime.
If you are having trouble, some common mistakes include:
- Not setting the Output directory, DCP output directory, or Search path on your packages
- Not setting the Search path on your application
- Not having the location of your BPL’s in the system PATH environment variable or in the same folder as your application
When doing plugin work with Delphi, it’s almost unavoidable that you’ll need to compile your host and plugins with runtime packages, whether you are using Hydra or not. Deploying the stock rtlXXX.bpl, vclXXX.bpl, and Hydra_Core_DXX.bpl packages may not be a problem for many. However, some developers may wish to have more control over the package names, the units included in the packages, the version information for the packages, etc. The techniques described above should allow you to create your own custom packages for your Delphi projects, fitting your own needs. While we created three separate RTL, VCL, and RemObjects packages, you could just as easily create a single package containing all of these units, or, at the other end of the spectrum, break up the single RemObjects package into separate packages for RemObjects SDK, Hydra, and Data Abstract.