This document describes the do's and don'ts of component writing
when you want your Delphi component to work with C++Builder. Many of
these issues were discovered while creating and testing the JVCL
packages with C++ Builder. We are trying to test as much as we can, but
there might still be other issues. If you know of such issues or even
any other issues that might help us and other Delphi developers, please
contact the JVCL team through the newsgroups on talkto.net:
news://forums.talkto.net/jedi.vcl
You must add 'uses Variant' in the implementation section of the
incriminated pas file even if it was already in the interface section.
Doing so would break Delphi compilation, so you must enclose it with
conditional compilation directives, {$IFDEF BCB6}uses Variant;{$ENDIF}
This error occurs because the pascal compiler (yes, pascal, not c++)
couldn't find the indicated dcu file. If the dcu file is available
directly, then add the path to where it is in the include path for the
package. By doing so, please use the $(BCB) constant and not the
absolute path to your installation.
But in most cases, the dcu file is not available in the distribution.
If you have the VCL source, you may find the associated .pas file.
However, DO NOT compile this file, you would break your installation.
The dcu file IS AVAILABLE but not directly, it is included in a .dcp
file and this file must be indicated to the pascal compiler.
Unfortunately, there is no easy way to do that in the IDE, so you will
have to close the package from BCB and reopen it with a text editor.
This is an XML file and the node you're looking for is called PFLAGS.
This contains the flags passed to the pascal compiler. At the end, just
before the closing quote, add the recommended flag (preceded by a
space)
as indicated in the table below:
Missing
file |
BCB5
flag |
BCB6
flag |
AccCtrl.dcu |
-LUvcl50 |
|
FiltEdit.dcu* |
-LUdclstd50 |
-LUdclstd |
DesignIntf.dcu* |
-LUdsnide50 |
-LUDesignIde |
Some files in the JVCL were imported from libraries that had partial
support for BCB prior to version 5. As these versions did not support
sets, they were replaced by other constructs, most often strings. But
because JVCL doesn't support anything below BCB5, all conditional
compilation directives defining Delphi sets as string must be removed
to
only leave Delphi style sets definitions and as such remove this error.
Usually an error that has to do with record constructs being used to
perform automatic casting. This a language feature to avoid as it is
not
supported by BCB.
Missing
file |
Missing
bpi file |
|
BCB5,
D5 |
Others |
|
CHECKLST.OBJ |
vclx50.bpi |
vclx.bpi |
SYSTEM.OBJ |
vcl50.bpi |
rtl.bpi |
CONTROLS.OBJ |
vcl50.bpi |
vcl.bpi |
FILECTRL.OBJ |
vclx50.bpi |
vclx.bpi |
SPIN.OBJ |
vclsmp50.bpi |
vclsmp.bpi |
You must add CJCL60.bpi to the requires list of your package. The
directory to both CJCL60.bpi and CJCL60.bpl MUST be in the PATH
environment variable. If you don't have these files, you need to
compile
the JCL first, with the BCB6 specific packages. Remember that you must
use JCL version 1.9 or newer in order to compile the JVCL 3.
See "Do not use WEAKPACKAGEUNIT" above. These errors should have
been all removed from the JVCL following the discovery of a useless
WEAKPACKAGEUNIT directive in the file JclResources.pas from the
JCL. Their team has been informed and the file has been updated
in version 1.9 and newer.
Before discovering this error, we found that changing the order of the
bpi files in the FILELIST node sometimes solved this crash. It is not
clear what is the best order, but you may want to try shuffling around
the order of CJCL60.bpi, JvCoreC6R.bpi and JvCoreC6D.bpi
This problem may arise from other files and because it actually is the result of the linker crashing, it is very hard to track down. Borland has been told about this problem, we are yet to receive any answer from them.
Please note that sometimes, the linker decides to crash on its own,
giving you two linker errors. If this happens, close BCB and reopen it.
Finally, it seems that Update 4 for BCB6 corrected most errors in
the linker and as a result we won't support any BCB installation that
doesn't use Update 4.
This one is coupled with an E2344 error. This problems comes from
the fact that C++ Builder puts all the inherited functions in the
declaration of a class in a header file and the VCL may already define
a method with the same name and the same parameters. If your method is
not a constructor, the easiest solution is to rename it so that it is
different from the inherited one. However, if the error occurs on a
constructor (TJvClass::TJvClass), you must follow the guidelines
hereafter. This problem comes from the fact that in C++, constructors
are named after the class name and
there is no way to change that. So to avoid confusion, avoid calling
your constructors anything else than Create. If you need additionnal
parameters, use the overload directive and adapt your code to take this
into account. The disctinction between the different constructors is
made upon the order and the types of their parameters.
But in the end, this may not be enough as Borland's VCL already
contains a number of constructors. As a result, the types you chose to
use for your own constructor may conflict with an existing constructor.
In such a case, you should follow Borland's guidelines from their help
files: Add a dummy parameter at the end, giving it a default value.
Usually, an Integer parameter is enough, like this:
From the C++ code, to be sure to call the correct constructor, you must give a value for this dummy parameter even if it won't be used.
This is because of bad casing on an inherited property. The usual
example is having a property named PopUpMenu where it should be
PopupMenu. BCB is case sensitive so you must respect casing in your pas
files, at least in the interface section.
This generally happens on a constant declaration and is because one or more pas files declare a value for a constant that already exists in the header files bundled with BCB. You must tell the hpp generator not to include this constant by adding a $EXTERNALSYM compilation directive in the pas file, just after your pascal constant. For instance, you must do this for S_OK
const S_OK : Integer = 0;
{$EXTERNALSYM S_OK}
This is because you placed Windows after Types in the uses for your
unit. If you don't have Types in the uses for your unit, either add it
(simplest), or find all instances of TPoint and replace them by
Types.TPoint. This has no impact on your code as the Windows.pas unit
defines its TPoint type to be Types.TPoint. However, it does not end up
in the Windows.hpp file for C++ Builder because of a NODEFINE directive.
Note that the Types unit is not available in version 5 of the VCL,
which means that this problem does not affect Delphi 5 or C++ Builder 5.
(or something similar, usually provokes 3 errors on the same line,
the second being the interesting one). This is because the parameter
name you chose for your function is a constant under BCB. The only
solution is to change the name of the incriminated parameter. This was
found with a parameter called SwitchChars in the GetCmdLineArg function
in JvJCLUtils.pas
This is generally because the component doesn't uses Integer as its
index type for an indexed property getter or setter. You can always
avoid using indexed property setters, so please don't use them.
This is because the type SOMETYPE is a global type (in windows.h,
generally) and is also defined in the SomeDomain file. To lift this
ambiguity, you must add a line at the beginning of the pas file that
does that: "{$HPPEMIT '#define SOMETYPE SomeDomain::SOMETYPE'}". But if
SOMETYPE is a JVCL type (starts with TJv) then this is because
SomeDomain.pas contains a bogus declaration and should be fixed. Please
notify us if that problem occurs.
ATTENTION: If the second type is a function like in
"JclWin32::WORD(const unsigned int)" you MUST not add this HPPEMIT
directive. The problem in this case comes from the fact that a function
defined in the .pas file is named exactly as a macro in the windows
header an gets replaced by its value. For instance in the given
example,
LANGFROMLCID was replaced by its value which is WORD and that lead to
the declaration of LANGFROMLCID(const unsigned int) from the pascal
code
to be replaced by WORD(const unsigned int).
However, if this error is generated in an hpp file not from the JVCL
(filename not starting with Jv), such as Controls.hpp, you can't change
this file, you must reorder the units in your uses clause so that the
conflict goes away. For instance, in the case of Controls.hpp, the
solution was to put Controls before Windows in the uses clause.
This is because SomeType has a public function (or getter/setter for
a public property) that is named GetMessage while GetMessage is also a
function from the Win32 API. As this function is implemented as Ansi
and Unicode versions, there is a typedef that tells the compiler this:
whenever you see GetMessage, replace it by GetMessageA.
So the compiler always uses GetMessageA and is happy about it. But when
the linker comes in, it looks for GetMessageA in the SomeType class and
of course does not find it.
The ONLY solution to this is to rename the function to a name that is
not the name of an API function, and as such must be mentionned to the
JVCL developpers.
GetMessage is not the only function name that can trigger this error,
any function from the Win32 API that is implemented as Ansi and Unicode
is not to be used for a public method of a class.