Board index » cppbuilder » Workaround for BCB6 bug

Workaround for BCB6 bug


2003-11-06 10:25:23 AM
cppbuilder75
I found a bug in BCB6 when attempting to derive a component from TDBComboBox
and overriding TDBComboBox's ComboWndProc virtual function. When one does
this, the linker gives an unresolved external error for
TDBComboBox::ComboWndProc, in other words this member function appears never
have been put into a library, or to have been put into a library with a
different mangled name signature.
So I thought I would take the dbctrls.pas file, where TDBComboBox, and its
ComboWndProc, is implemented, and add that to my component. When I attempt
to add this to my project, a whole host of VCL source file components are
compiled and errors ensue in the compiler and linker stages.
Does anyone know of some magic setting which will let me just compile the
dbctrls.pas file without regenerating a whole host of other .pas source
files ? I don't understand the pascal compiler and its need to recompiler
many other .pas files when I only need to compile dbctrls.pas into my
project.
 
 

Re:Workaround for BCB6 bug

Hi,
Quote
and overriding TDBComboBox's ComboWndProc virtual function. When one does
Does anyone know of some magic setting which will let me just compile the
dbctrls.pas file without regenerating a whole host of other .pas source
files ? I don't understand the pascal compiler and its need to recompiler
many other .pas files when I only need to compile dbctrls.pas into my
project.
The pascal compiler needs to find the things that are in the
uses list of dbctrls.pas and is apparently finding the .pas
before finding the .dcu which might happen if your edited
dbctrls.pas file is still in the vcl source directory.
The .dcu's that it should be finding are in ..\lib\objs so
I think moving the modified dbctrls.pas out of source should
avoid the recompilation, but if it doesn't then PFLAGS line in
the makefile might have to be edited to make sure the .dcu's are
found first. Of course, if you compile once to get a modified
dbctrls.obj, then you can remove the .pas from your project and
add in it's place the dbctrls.obj and never have to worry about
unintended recompilation again. If you pursue creating the needed
.obj outside of your project all you should need would be something
like dcc32.exe -JPHN to compile via to .OBJ. BTW, the only reason
dcu's exist in ..\lib\obj is to make BCB projects that use
.pas source happy. For the more typical .cpp usage the files that
are necessary are the dcc32-generated .obj and .hpp files.
As an alternate approach, there is a workaround for the mangled name
problem described below. Copy and paste of the alias below should
avoid the linker error:
Resolving problems with name-mangled names when functions contain
HWND or HDC params.
There are two potential resolutions:
[these examples resolve the error for a TDBComboBox derivative]
1) Edit the ancestor's header file, e.g.
virtual void __fastcall ComboWndProc(Messages::TMessage &Message,
/*HWND*/unsigned ComboWnd, void * ComboProc);
2)
a)Tdump both sides of the unresolved external problem
tdump -m DBComboBox1.obj DBComboBox1.dmp
tdump -m C:\Windows\System32\VCL60.BPL VCL60.dmp
b)Find the name-mangled names
grep ComboWndProc *.dmp>manglednames.txt
c)Paste the names into an alias in the .cpp source
#pragma alias
"@Dbctrls@TDBComboBox@ComboWndProc$qqrr17Messages@TMessagepvt2"="@Stdctrls@TCustomCombo@ComboWndProc$qqrr17Messages@TMessageuipv"
Method 1) has the problem that you will have to distribute
an edited VCL header with your component. Approach 2) is similar
to what VCL itself does in VCLExx.LIB (VCL Emulation, that
provides similar 'thunks'). Note when using method 2)
that editing an alias while the linker has the image
open in memory can have instability side affects on the
linker but a direct one-time paste per build should work fine.
 

Re:Workaround for BCB6 bug

Craig Farrell wrote:
Quote
Hi,

>and overriding TDBComboBox's ComboWndProc virtual function. When one
>does

>Does anyone know of some magic setting which will let me just
>compile the dbctrls.pas file without regenerating a whole host of
>other .pas source files ? I don't understand the pascal compiler and
>its need to recompiler many other .pas files when I only need to
>compile dbctrls.pas into my project.

Thanks very much for your answer, and all its explanations.
Quote
Snipped... If you pursue creating the needed
.obj outside of your project all you should need would be something
like dcc32.exe -JPHN to compile via to .OBJ. BTW, the only reason
dcu's exist in ..\lib\obj is to make BCB projects that use
.pas source happy. For the more typical .cpp usage the files that
are necessary are the dcc32-generated .obj and .hpp files.
This does not work since I still get the same unresolved external after
generating a dbctrls.obj file and adding it to my project.
Quote

As an alternate approach, there is a workaround for the mangled name
problem described below. Copy and paste of the alias below should
avoid the linker error:

Resolving problems with name-mangled names when functions contain
HWND or HDC params.
There are two potential resolutions:

[these examples resolve the error for a TDBComboBox derivative]
1) Edit the ancestor's header file, e.g.
virtual void __fastcall ComboWndProc(Messages::TMessage &Message,
/*HWND*/unsigned ComboWnd, void * ComboProc);
I didn't try this, although it should work, because I don't want to
distribute a corrected header file.
Quote
2)
a)Tdump both sides of the unresolved external problem
tdump -m DBComboBox1.obj DBComboBox1.dmp
tdump -m C:\Windows\System32\VCL60.BPL VCL60.dmp
b)Find the name-mangled names
grep ComboWndProc *.dmp>manglednames.txt
c)Paste the names into an alias in the .cpp source
#pragma alias

dbctrls@TDBComboBox@ComboWndProc$qqrr17Messages@TMessagepvt2"="@Stdctrls@TC
ustomCombo@ComboWndProc$qqrr17Messages@TMessageuipv"
First of all, there is no documentation for #pragma alias. I will try it
nonetheless. It is so typical of Borland not to document something like
this.
But I don't think using tdump on vcl60.bpl is correct, since dbctrls is in
vcldb60.bpl:
0CF2C 345 00D3 @Dbctrls@TDBComboBox@ComboWndProc$qqrr17Messages@TMessageuipv
and this in my own .obj file:
594: '@Dbctrls@TDBComboBox@ComboWndProc$qqrr17Messages@TMessagepvt2' Type: 0
I then used your #pragma alias in my source file, via:
#pragma alias
"@Dbctrls@TDBComboBox@ComboWndProc$qqrr17Messages@TMessagepvt2" =
"@Dbctrls@TDBComboBox@ComboWndProc$qqrr17Messages@TMessageuipv"
and it worked !!! Bravo !
Quote

Method 1) has the problem that you will have to distribute
an edited VCL header with your component. Approach 2) is similar
to what VCL itself does in VCLExx.LIB (VCL Emulation, that
provides similar 'thunks'). Note when using method 2)
that editing an alias while the linker has the image
open in memory can have instability side affects on the
linker but a direct one-time paste per build should work fine.
Yes, I used 2) since I did not want to have to redistribute the VCL header
file, which is a maintenance PITA. I decided to put the #pragma alias in my
source file, since nobody deriving a component from my component can ever
call down to TDBComboBox::ComboWndProc but they have to call
MyComponent::ComboWndProc instead.
Thanks again for your help in resolving this. I had given up this problem as
lost and had already decided against pursuing my derived component until
your answer came and now I am back in business <g>.
 

{smallsort}