Jump to content
Software FX Community

Delphi6 and ChartFx98


User (Legacy)

Recommended Posts

Hi,

Below is a post that goes into detail of the problem and suggests a

workaround.

What are the chances that the control would be fixed in the near future?

--

Mikhail Khilkov

Senior Software Engineer

NEC Integrated Applications Division

mkhilkov@necam.com

>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

"Stefan Hoffmeister" <no@email.here> wrote in message

I got myself their latest and greatest trial version and see the problem

with the following steps:

* Component | Import ActiveX Control

* Select "ChartFX Client Server Control (Version 4.0)"

* Click "Install..." button

* Do everything to get the control installed onto the component palette

// control appears as "ChartFX" on ActiveX tab

* File | New Application

* Drop ChartFX control from ActiveX tab onto form designer

//exp: control appears on form designer

//act: does not appear; instead exception "Invalid variant operatioN"

Ok, so that's the "reproducable" part. On to something easier to play

with:

The code will also produce the problem, making debugging the problem

more enjoyable:

***************

uses

ChartfxLib_TLB;

procedure TForm1.Button1Click(Sender: TObject);

var

c: TChartFX;

begin

c := TChartFX.Create(Self);

c.Parent := Self;

c.Visible := True;

end;

***************

Running this code will trigger then on the VarInvalidOp in the

VarClearDeep

procedure VarClearDeep(var V: TVarData);

var

LHandler: TCustomVariantType;

begin

...

// ok, finally is it a custom variant type?

else if FindCustomVariantType(V.VType, LHandler) then

LHandler.Clear(V)

else

VarInvalidOp;

end;

as you correctly observed. Note that this is not a new feature of the

beta code but is also present in D6 SP2.

Now lets try to pass the Variant onwards to OLEAUT32.DLL; this will

emulate the behaviour that D5 had. In contrast to D5, we will not throw

away the return value of the API call, but check it:

procedure VarClearDeep(var V: TVarData);

var

LHandler: TCustomVariantType;

begin

...

else if FindCustomVariantType(V.VType, LHandler) then

LHandler.Clear(V)

else

- VarInvalidOp;

+ VarResultCheck(VariantClear(V));

end;

Run the code from above and get

EVariantBadVarTypeError: 'Invalid variant type'

from the call to

VarResultCheck(VariantClear(V));

which is not all that surprising, given that

(VType:33876; Reserved1:4097; Reserved2:36808; Reserved3:4101;

VSmallInt:1; VInteger:1; ...)

A VType = 33876 = $8454 =

VT_RESERVED = $8000

or ??? = $0454

(see wtypes.h and wtypes.idl for VT_RESERVED) which is not really

documented except for a search hit via Google (and no MS docs) that says

that this is flag is reserved for future Microsoft use.

On the other hand VT_HARDTYPE = VT_RESERVED in oleauto.h:

<quote oleauto.h with reformatting>

VT_HARDTYPE tells the compare routine that the argument is a

literal or otherwise declared of that specific type.

It causes comparison rules to change. For example, if a hard-type

string is compared to a variant (not hard-type) number, the number

is converted to string. If a hard-type number is compared to a

variant string, the string is converted to number. If they're

both variant, then number < string.

</quote>

but apart from that there is no documentation in MSDN or found by

Google.

Given that OLEAUTO32.DLL throws a fit when presented with a

Variant.VType = $8454, I'd tend to point my finger into the direction of

SoftwareFX - I *suspect* that they pass uninitialized data to an

IDispatch::Invoke interface; the real source of the problem is in

function TOleControl.Invoke(DispID: Integer; const IID: TGUID;

LocaleID: Integer; Flags: Word; var Params;

VarResult, ExcepInfo, ArgErr: Pointer): HResult;

var

F: TFont;

begin

if (Flags and DISPATCH_PROPERTYGET <> 0) and (VarResult <> nil) then

begin

Result := S_OK;

case DispID of

...

DISPID_AMBIENT_USERMODE:

PVariant(VarResult)^ := not (csDesigning in ComponentState);

where the pointer to the variant result, "VarResult", comes from the

ChartFX control.

*PLEASE* complain to SoftwareFX support and tell them where their

problem is.

Solving the problem you (and others) have with Delphi, the following

"sort of" hack should be relatively clean and works well in my ad hoc

testing:

************************************

uses

ActiveX, VarUtils,

ChartfxLib_TLB;

type

TChartFX_work_around_chartfx_bug = class(TChartFX, IDispatch)

function Invoke(DispID: Integer; const IID: TGUID;

LocaleID: Integer; Flags: Word; var Params;

VarResult, ExcepInfo, ArgErr: Pointer): HResult; stdcall;

end;

function TChartFX_work_around_chartfx_bug.Invoke

(DispID: Integer; const IID: TGUID;

LocaleID: Integer; Flags: Word; var Params;

VarResult, ExcepInfo, ArgErr: Pointer): HResult;

begin

if (Flags and DISPATCH_PROPERTYGET <> 0) and (VarResult <> nil) then

begin

if VariantClear(PVarData(VarResult)^) <> S_OK then

PVarData(VarResult)^.VType := varEmpty;

end;

Result := inherited Invoke(DispID, IID, LocaleID, Flags, Params,

VarResult, ExcepInfo, ArgErr);

end;

procedure TForm1.Button1Click(Sender: TObject);

var

c: TChartFX;

begin

c := TChartFX_work_around_chartfx_bug.Create(Self);

c.Parent := Self;

c.Visible := True;

end;

************************************

IOW, create a new class TChartFX_work_around_chartfx_bug that descends

from TChartFX and publishes IDispatch. The implementation then "cleanly"

clears the passed in variants data; if invalid data is passed in (as is

the case with the ChartFX control), radically zap the variant and

overwrite its content to mark is as an empty (varEmpty / VT_EMPTY)

variant.

If you need / want to have the control on the component palette, simply

register TChartFX_work_around_chartfx_bug as a component.

I'll have a look at why D5 works in that area; I'd suspect that the only

reason it works is that in D5 the return value of the call to the

OLEAUTO32.DLL API function VariantClear() was not checked.

I hope everybody realizes now that providing information on how to

reproduce a problem will gets problems solved really quickly - many

thanks to you, Mikhail, for providing the necessary details.

Again, *PLEASE* complain to SoftwareFX support and tell them where their

problem is.

Link to comment
Share on other sites

GREAT !!!!

Finally somebody from Borland explains what they changed !

Was it a BUG in Chart FX, I guess you can say yes to that but when you

release a new version of a product, you change something and controls start

to break isn't your responsibility to maintain compatibility with previous

versions ? I mean how are we supposed to know what Borland changes from one

version to the next ??

Anyway, the good thing is that the problem is now solved. I will be posting

a SP in our support site this week.

--

FP

Software FX, Inc.

Link to comment
Share on other sites

Aaaaaaaaaaah!. I installed the latest version(5.0.4.0) and I'm still getting

the same error. I installed the control on the machine where Delphi6 did

not have ANY previously installed version of ChartFx, so there is no chance

that it's old code running from somewhere. What's going on??

--

Mikhail Khilkov

Senior Software Engineer

NEC Integrated Applications Division

mkhilkov@necam.com

"SoftwareFX Support" <support@softwarefx.com> wrote in message

news:SsER2ZQ$BHA.1088@webserver1.softwarefx.com...

> A service pack for Chart FX is now Available.

>

> --

> FP

> Software FX, Inc.

>

>

Link to comment
Share on other sites

Well, I downloaded the SP 2 hours after it was announced in this group...

Anyway, thanks for fixing it( finally :-) )

Regards,

Mikhail.

"SoftwareFX Support" <support@softwarefx.com> wrote in message

news:mOydTBb$BHA.580@webserver1.softwarefx.com...

> The latest version is 5.0.5.0. You must have downloaded it too soon.

>

> --

> FP

> Software FX, Inc.

>

>

Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...