Wednesday, October 8, 2008

Delphi Packages not appearing in C++ Builder personality

One of the new features in CodeGear RAD Studio 2007 (actually Borland Developer Studio which is the 2006 version of RAD Studio) is the ability to get the Delphi compiler / linker to generate all the files required by C++ Builder (.hpp, .obj, .lib etc.) for a Delphi package, without having to create the equivalent C++ Builder package.

Unfortunately, there's one ugly bug that has plagued this feature - you may find that the components in the package that you've installed does not come up in the designer's Tool Palette. This bug was first reported by yours truly against BDS 2006 and it appears that it hasn't been and won't be fixed even for RAD Studio 2009. That's more than 3 years since I've reported it in QC! Wow!

If you have left all settings to the default when you create a package in Delphi (which you most likely will), you will find that the components you've registered in the package won't appear in a C++ Builder project. That is simply because you have not specifically told the linker to "Generate all C++Builder files". So you would go back to the Delphi package and select that option in the Linker output and recompile / reinstall. This time, however, you would expect the installed components to appear in the Tool Palette when you try to use it in C++ Builder... Surprise surprise, it's not there!

It's as though once the IDE has decided that it is a Delphi-only package, it will remain a Delphi-only package forever. Note that if you uninstall and recreate and then reinstall the entire package, it will still be invisible to C++ Builder - that is, until you've renamed the package. That's because the IDE remembers the package name!

The other cleaner workaround would be to go to your registry via Regedit.exe and remove all the following entries to your package (say, MyPackage.bpl).

HKEY_CURRENT_USER\Software\Borland\BDS\5.0\Known Packages\
Look for the entry with [path]\MyPackage.bpl and remove it

HKEY_CURRENT_USER\Software\Borland\BDS\5.0\Package Cache\
Look for the key called MyPackage.bpl and remove the entire sub-key

Look for the key called MyPackage.bpl and remove the entire sub-key

Remember to first shut down CodeGear RAD Studio before changing the registry keys. Once you have removed the entries, restart RAD Studio and this time, remember to select "Generate all C++Builder files" for all build configurations (e.g. Debug and Release) before you install the Delphi package.

And in the future, keep in mind to always set the linker to "Generate all C++Builder files" or set that as your default for all build configurations.

ps. Yup, they haven't rebranded it to CodeGear in the registry - it's still Borland as we know it! :)


Remy Lebeau said...

The "feature" of the compiler to produce C++ support files (hpp, obj, lib, etc) is not new to BDS. The command-line Pascal compiler that has shipped with every version of C++Builder since the beginning has always had that feature. The only thing that is new in BDS is that the feature has finally been added to the IDE's GUI as user-configurable options, that's all.

Jon said...

The problem is still present in RAD Studio 2009 - and the same fix still applies, only now they have renamed it from Borland to CodeGear in the registry.

SoCo said...

I stumbled across this post because I had the same problem in RAD Studio 2010. Unfortunately I installed a 3rd party component, kbmMW 3.40.1, and part of it, the kbmMemTable part only shows in the Delphi tool palette. Oddly the kbmMW part that I don't need does show in in both Delphi and CB. This component was automatically installed with an installer, which is likely to blame. Time to try to install the package from source with the option you mentioned.

Anonymous said...

Yep, same problem today with RAD Studio 2010. I changed the linker options which was not succcessful. Then I renamed the package. That was as mentioned the solution.
Thanks for that hint! Wasted a lot of time during the last years...

SlavaC said...

I have this problem in RAD 2007 with dbExpress. In Delphi personality I see all the installed components, but in C++ I see only TSimpleDataSet. Any ideas how to solve this?

Anonymous said...

I can confirm that this bug still exists in XE4.

Anonymous said...

This Bug persists in XE5. Incredible

Max Kielland said...

Still having no luck to register my components in C++ Builder Berlin.

Anonymous said...

...however, Berlin is at least a nice name! This product suffers strongly from Featuritis. Installed XE7 yesterday on another machine, you still need a third party tool to let the compiler use all processor cores.

Max Kielland said...

After a lot of searching I found out why it won't register (in my case).
C++ Builder is very pedantic when it comes to naming.

The function registering the component must be like this:

#define PACKAGE_PAGE L"My component page"

namespace Tdevicemanager {
void __fastcall PACKAGE Register()
TComponentClass classes[1] = {__classid(TDeviceManager)};
RegisterComponents(PACKAGE_PAGE, classes, 0);

The critical here is the namespace. It MUST be exactly the same name as the filename where the class is defined. Not the class name itself!
It also has to be all lowercase, optional with the first letter in capital.

The defined PACKAGE_PAGE is my own construct so I don't have to repeat the page name for each registration.

By default, the Register() function is added to each one of your component units. I found it more efficient to move all Register() function to the package project .cpp file instead, right after the _libmain(). Since they are all in their own namespace you can collect them all without name collisions.

If you have more than one component class in the same module (.cpp) you just add them to the component array:

namespace Tcssdevice {
void __fastcall PACKAGE Register()
TComponentClass classes[2] = {
RegisterComponents(PACKAGE_PAGE, classes, 1);

Here are the components TCSSDevice and TCSSUnknownDevice declared in the same unit; TCSSDevice.cpp

The array classes[] must of course be adjusted to accommodate all your __classid() and the RegisterComponent's last parameter should be the last array index (0-based).

To define the images for each component is an entirely different chapter!
You need to manually add a resource script, but you can't add it to your project as a .rc file, it will refuse! No, instead it wants a .dcr file, which you can't create nor add to the project in an easy manner.

1. Create a normal text (.txt)
2. Edit the file and add the images you want to use:

TDeviceManager BITMAP "TDeviceManager.bmp"
TCSSDevice BITMAP "TCSSDevice.bmp"
TCSSUnknownDevice BITMAP "TCSSUnknownDevice.bmp"

The identifiers here has to be the exactly same name as the class they should represent.
The bitmap must be in the old style with all transparent pixels colored in Fusia (the good old days mask color). The size of the images should be 24x24 pixels to look good on the form. They will be scaled down to the palette.

3. Save and rename the file to .rc (I named mine to "ComponentImages.rc")
4. Go into to the package "Options->Build Events"
5. Manually add the resource compiler to the "Pre-build events".

brcc32 -fo"ComponentImages.dcr" "ComponentImages.rc"

6. Do a build and then you would have a .dcr file.
7. Add this .dcr file to your project. You have to change the filter mask to *.dcr because it's not an option in the list but will be accepted by the project.

8. Build/link again and the images will now be registered together with the components. Due to cache issues it might take a while before they show up in the palette, but you can always verify them in "Component->Install Packages...". Select your package in the list and click "Components". Here you can see that the images has been registered with the components.

Thank you Embarcadero for making component creation so easy...

Zach Saw said...

LoL!! I can't believe that they still haven't fixed this... Very surprised they're still around to be honest!