Category Archives: C/C++

Form layout manager for C++ Builder 6

You have a C++ builder application, with some complex forms, and you’d like them to properly react to window resizing.
You heavily used anchors and alignment, but reached the limits of these features. For example, as soon as you have 3 controls in a row and that your form is resized, you can’t get them to grow proportionaly. If some controls must sometimes be hidden, you can’t get their neighbours to automatically shift to fill the holes.
Dealing with these situations manually is painful and costly, you miss Java layouts.

There’s no builtin features solving these problems in older versions of C+ Builder (<= 6), but you might find helpful my GitHub CppBuilderFormLayoutDemo project, which contains a couple of classes inspired from Java Layout Managers, along with a C++ Builder 6 demo project.

demo-layout
Continue reading

Using WM_SETREDRAW to prevent window flickering

Flickering is a common issue with Windows applications. Different techniques exist to solve it, but they are more or less intrusive, and more or less efficient. Double-buffering for example is probably the best solution, but hard to put in place in a legacy code (even impossible sometimes). Using the WM_SETREDRAWmessage can be a light and efficient solution. Continue reading

When C++ Builder 6 fails to properly import COM Objects

In Borland C++ Builder 6, the code generated to import COM objects slightly differs from the one generated by previous versions of C++ Builder.
Specifically, the VARIANT date type is used instead of TVariant. Giving up its TVariant “smart wrapper” was a good move from Borland, but it broke backward compatibility with output parameters of some COM methods, which don’t receive a value anymore.

For example, below is the code generated by C++ Builer 4 for the FarPoint TfpSpread COM object (from file FPSpreadADO_TLB.h) :
[code lang=cpp]
VARIANT_BOOL __fastcall GetText(long Col, long Row, TVariant* Var)
{
_TDispID _dispid(/* GetText */ DISPID(252));
TAutoArgs<3> _args;
_args[1] = Col /*[VT_I4:0]*/;
_args[2] = Row /*[VT_I4:0]*/;
_args[3] = Var /*[VT_VARIANT:1]*/;
OleFunction(_dispid, _args);
return _args.GetRetVariant();
}
[/code]

When generated using C++ Builder 6, the code becomes :
[code lang=cpp]
VARIANT_BOOL __fastcall GetText(long Col, long Row, VARIANT* Var)
{
_TDispID _dispid(/* GetText */ DISPID(252));
TAutoArgs<3> _args;
_args[1] = Col /*[VT_I4:0]*/;
_args[2] = Row /*[VT_I4:0]*/;
_args[3] = Var /*[VT_VARIANT:1]*/;
OleFunction(_dispid, _args);
return _args.GetRetVariant();
}
[/code]

Notice the Var parameter, whose type was changed from TVariant* to VARIANT* : that’s the source of the problem.

The issue comes from the TAutoArgs class, more specifically from its array of Variant.
The Variant assignment operator (=) behaves differently depending if its RHS is a TVariant* or a VARIANT* :

  1. Variant = TVariant* : The Variant is initialized with a reference to the TVariant* object (vt = VT_BYREF|VT_VARIANT, and pvarVal receives a pointer to the TVariant*
  2. Variant = VARIANT* : the Variant ‘=’ operator assumes the VARIANT* is a VT_BOOL. Changes to the Variant are not reflected on the VARIANT*

To fix the problem, one must explicitly set the Variant as a reference to the VARIANT*. For example, the previous example must be changed to :
[code lang=cpp]
VARIANT_BOOL __fastcall GetText(long Col, long Row, VARIANT* Var)
{
_TDispID _dispid(/* GetText */ DISPID(252));
TAutoArgs<3> _args;
_args[1] = Col /*[VT_I4:0]*/;
_args[2] = Row /*[VT_I4:0]*/;
_args[3].vt = VT_BYREF|VT_VARIANT /*[VT_VARIANT:1]*/;
_args[3].pvarVal = Var;
OleFunction(_dispid, _args);
return _args.GetRetVariant();
}
[/code]

How to compare C++ builder/Delphi DFM binary files with Tortoise SVN ?


With antique versions of Delphi or C++ builder (<= 4), the DFM files – which define the structure of the application forms – are stored as binary files.
Binary files are a hassle because they prevent any batch processing, search, etc… But only with version control do they become a real pain in the ass. Versions can’t be compared, which makes conflict solving almost impossible. And conflicts happen often because Delphi and C++ builder modifiy DFM files for any reason (ex : moving a form around).

If you use Tortoise SVN and strugle with DFM conflicts, here is a solution to automate DFM comparison : Continue reading