pass array to ActiveX Control

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
12 messages Options
Reply | Threaded
Open this post in threaded view
|

pass array to ActiveX Control

Jochen Riekhof
have most of my ActiveX control features running now, but I cannot figure
out how to pass an Array of numbers.
The workspace code is:

array := (DOUBLEArray withAll: #( 1 2 3 4)) .
myOb addArray: array size yArray: array xArray: array.

It crashes the image with "Undefined Object does not understand *". It seems
that during a copy operation of the DOUBLEArray one of them is invalid and
gives nil as size.

I am not shure if I need a DOUBLEArray here, a normal array fails exactly
with the same behaviour.

here is the condensed VB code sample:

Dim MyXArray(4) As Double
Dim MyYArray(4) As Double
myOb.AddArray UBound(MyYArray), MyYArray(), MyXArray()

Ciao

...Jochen


P.S. playing with ActiveX is quite a "crashy" experience :-)


Reply | Threaded
Open this post in threaded view
|

Re: pass array to ActiveX Control

Christopher J. Demers
"Jochen Riekhof" <[hidden email]> wrote in message
news:[hidden email]...
> have most of my ActiveX control features running now, but I cannot figure
> out how to pass an Array of numbers.
> The workspace code is:
>
> array := (DOUBLEArray withAll: #( 1 2 3 4)) .
> myOb addArray: array size yArray: array xArray: array.
>
> It crashes the image with "Undefined Object does not understand *". It
seems
...
> here is the condensed VB code sample:
>
> Dim MyXArray(4) As Double
> Dim MyYArray(4) As Double
> myOb.AddArray UBound(MyYArray), MyYArray(), MyXArray()

I have had my own "fun" trying to pass arrays around recently, try this
perhaps:
array := SAFEARRAY withAll: #( 1 2 3 4) elementClass: DOUBLE

You may also want to try sending two different arrays rather than the same
one twice.  Also see Blair's recent response to my post "Help needed passing
an array of float values by refference." for more info.

> P.S. playing with ActiveX is quite a "crashy" experience :-)

I have been throwing some bad stuff at the ActiveX subsystem in Dolphin, but
I have to say it has not once crashed Dolphin for me lately.  I am running
Windows XP,  I am sure 9x versions of Windows may not fare as well.

Chris


Reply | Threaded
Open this post in threaded view
|

Re: pass array to ActiveX Control

Jochen Riekhof
Christopher...

Thanks you for the hints. Doesn't work, though. I now get FACILITY_NULL in
the title and hresultError/invalidCall in the walkback. SAFEARRAY are safer
however as they do not crash my Dolphin anymore, though.

>I have been throwing some bad stuff at the ActiveX subsystem in Dolphin,
>but I have to say it has not once crashed Dolphin for me lately.

I use XP pro. Anyway, contrary to the usual experience with doing plain
smalltalk stuff in Dolphin (rock solid IMO), some forms of ActiveX access
(e.g arrays) crash reliably when something is done wrong.

> I am running Windows XP,  I am sure 9x versions of Windows may not fare as
well.

I shurely can believe that :-).


Ciao

...Jochen


Reply | Threaded
Open this post in threaded view
|

Re: pass array to ActiveX Control

Blair McGlashan
"Jochen Riekhof" <[hidden email]> wrote in message
news:[hidden email]...
> Christopher...
>
> Thanks you for the hints. Doesn't work, though. I now get FACILITY_NULL in
> the title and hresultError/invalidCall in the walkback. SAFEARRAY are
safer
> however as they do not crash my Dolphin anymore, though.
>
> >I have been throwing some bad stuff at the ActiveX subsystem in Dolphin,
> >but I have to say it has not once crashed Dolphin for me lately.
>
> I use XP pro. Anyway, contrary to the usual experience with doing plain
> smalltalk stuff in Dolphin (rock solid IMO), some forms of ActiveX access
> (e.g arrays) crash reliably when something is done wrong.

Well if you can let us know what they are, then we can see whether anything
can be done about them. However you must bear in mind that if you are
passing the wrong type (or size) of object so something external, then it is
quite possible that an unrecoverable memory fault will occur, and this is
really outside our control.

In this case you are probably passing a C-style array (DOUBLEArray
corresponding to a C array of doubles), where a SAFEARRAY is expected.
SAFEARRAYs are the VB form of ARRAYs, and have a completely different format
than C style arrays. SAFEARRAYs are almost always used in COM, and
exclusively in Automation.

If you are having difficulty calling COM methods, then its a good idea to
post the IDL, as from that one can usually deduce the form of arguments
expected.

Regards

Blair


Reply | Threaded
Open this post in threaded view
|

Re: pass array to ActiveX Control

Jochen Riekhof
Hi Blair...

> However you must bear in mind that if you are
> passing the wrong type (or size) of object so something external, then it
is
> quite possible that an unrecoverable memory fault will occur, and this is
> really outside our control.

Yes, I did not mean to blame you for anything, it is just as you say :-).


> In this case you are probably passing a C-style array (DOUBLEArray
> corresponding to a C array of doubles), where a SAFEARRAY is expected.
> SAFEARRAYs are the VB form of ARRAYs, and have a completely different
format
> than C style arrays. SAFEARRAYs are almost always used in COM, and
> exclusively in Automation.

Makes perfect sense to me.

> If you are having difficulty calling COM methods, then its a good idea to
> post the IDL, as from that one can usually deduce the form of arguments
> expected.

Hum, it is just an OCX. Can you tell me how to get an IDL from this. I have
appended what dolphin produced on typelib generation for now. The closest I
could imagine is now:
array1 := (SAFEARRAY withAll: #( 1 2 3 4) elementClass: DOUBLE) .
array2 := (SAFEARRAY withAll: #( 1 2 3 4) elementClass: DOUBLE) .
series addArray: array1 size yArray: array1 asVariant xArray: array2
asVariant.

but it does not work, either?!?

This remembers me of some errrors I had during generation, can you make any
sense of them?
Error: TC5ISeries>>CalcXSizeValue:Value: at line 9: undeclared 'Value'
Error: TC5ISeries>>calcXSizeValue: at line 5: undeclared 'Value'
Error: TC5ISeries>>CalcYSizeValue:Value: at line 9: undeclared 'Value'
Error: TC5ISeries>>calcYSizeValue: at line 5: undeclared 'Value'
Error: TC5ISeries>>XValueToText:Value: at line 9: undeclared 'Value'
Error: TC5ISeries>>xValueToText: at line 5: undeclared 'Value'
Error: TC5ISeries>>YValueToText:Value: at line 9: undeclared 'Value'
Error: TC5ISeries>>yValueToText: at line 5: undeclared 'Value'
Error: TC5IValueList>>Locate:Value: at line 9: undeclared 'Value'
Error: TC5IValueList>>locate: at line 5: undeclared 'Value'
Error: TC5TeeRect class>>defineFields at line 5: undeclared 'Defines'

(While AddArray:... is in the TC5ISeries interface, these convert errors
seem to be unrelated to the array problem I have, or what do you think?)

Ciao

...Jochen

------------------------------------------------------------
AddArray: arraySize YArray: yArray XArray: xArray
"Private - Invoke the AddArray() method of the COM object.
Helpstring: 'Adds an array of data directly to the Series.'
HRESULT __stdcall AddArray(
[in] long ArraySize,
[in] VARIANT YArray,
[in, optional] VARIANT XArray);"
<virtual stdcall: hresult 111 sdword variant variant>
^self invalidCall


Reply | Threaded
Open this post in threaded view
|

Re: pass array to ActiveX Control

Jochen Riekhof
In reply to this post by Blair McGlashan
ah yes, and here's the stack trace:
16:29:08, Freitag, 7. Februar 2003: 'HRESULT Error: Schwerwiegender Fehler
(FACILITY_NULL)'
TC5ISeries(IDispatch)>>hresultError:
TC5ISeries(ExternalStructure)>>invalidCall
TC5ISeries>>AddArray:YArray:XArray:
TC5ISeries>>addArray:yArray:xArray:
UndefinedObject>>{unbound}doIt
CompiledExpression>>value:
SmalltalkWorkspace>>evaluateRange:ifFail:debug:
...


Reply | Threaded
Open this post in threaded view
|

Re: pass array to ActiveX Control

Jochen Riekhof
In reply to this post by Blair McGlashan
Ah weekend, time to do real work :-).

Finally I had time to fire up VC++ and look into the typelib of the ocx.
Here is the IDL of the offending method:
        HRESULT AddArray(
                        [in] long ArraySize,
                        [in] VARIANT YArray,
                        [in, optional] VARIANT XArray);

Looks like dolphin did a good job converting so far. Maybe you experts see
more...

Ciao

...Jochen


Reply | Threaded
Open this post in threaded view
|

Re: pass array to ActiveX Control

Blair McGlashan
In reply to this post by Jochen Riekhof
"Jochen Riekhof" <[hidden email]> wrote in message
news:3e4397d5$[hidden email]...
>  [Blair McGlashan wrote]
> > If you are having difficulty calling COM methods, then its a good idea
to
> > post the IDL, as from that one can usually deduce the form of arguments
> > expected.
>
> Hum, it is just an OCX. Can you tell me how to get an IDL from this.

Well you can use various tools (e.g. OleView from MS) or Dolphin itself. In
the Active-X Component Wizard right click on a type library or interface and
choose 'Browse IDL'. Dolphin will reverse engineer IDL from the type
library. Be warned, however, that the IDL generated by any tool may not
match the original IDL because the type library format is "lossy" and so
does not necessarily contain all the original information, though this is
rarely an issue.

>...I have
> appended what dolphin produced on typelib generation for now. The closest
I
> could imagine is now:
> array1 := (SAFEARRAY withAll: #( 1 2 3 4) elementClass: DOUBLE) .
> array2 := (SAFEARRAY withAll: #( 1 2 3 4) elementClass: DOUBLE) .
> series addArray: array1 size yArray: array1 asVariant xArray: array2
> asVariant.
>
> but it does not work, either?!?

You might like to read my most recent posting in the thread entitled "Help
needed passing an array of float values by refference." It is possible your
control is expecting the arrays to be passed by reference, and so they need
to be wrapped up into the variant slightly differently than Dolphin's
default conversion.

>
> This remembers me of some errrors I had during generation, can you make
any
> sense of them?
> Error: TC5ISeries>>CalcXSizeValue:Value: at line 9: undeclared 'Value'
> Error: TC5ISeries>>calcXSizeValue: at line 5: undeclared 'Value'
>[...snip...]
> (While AddArray:... is in the TC5ISeries interface, these convert errors
> seem to be unrelated to the array problem I have, or what do you think?)

These suggest a bug in the type library analyzer - it shouldn't generate
methods that cannot be compiled. Is the OCX in question available for me to
investigate it?

Regards

Blair


Reply | Threaded
Open this post in threaded view
|

Re: pass array to ActiveX Control

Jochen Riekhof-3
Hi Blair...

> Well you can use various tools (e.g. OleView from MS) or Dolphin itself.
In
> the Active-X Component Wizard right click on a type library or interface
and
> choose 'Browse IDL'. Dolphin will reverse engineer IDL from the type
> library. Be warned, however, that the IDL generated by any tool may not
> match the original IDL because the type library format is "lossy" and so
> does not necessarily contain all the original information, though this is
> rarely an issue.

I posted IDL generated from OCX with VC++6 in another post to the same
ancestor message, but it shows the same code that dolphin wrote in the
comment of the corresponding generated method.

> You might like to read my most recent posting in the thread entitled "Help
> needed passing an array of float values by refference." It is possible
your
> control is expecting the arrays to be passed by reference, and so they
need
> to be wrapped up into the variant slightly differently than Dolphin's
> default conversion.

Of course, I have immediately tried that out, but it did not work, either.
I used
array1 := VARIANT new.
array2 := VARIANT new.
array1 arrayRef: (SAFEARRAY withAll: #(1 2 3 4) elementClass: FLOAT).
array2 arrayRef: (SAFEARRAY withAll: #(1 2 3 4) elementClass: FLOAT).
series addArray: 4 yArray: array1 xArray: array2.


> These suggest a bug in the type library analyzer - it shouldn't generate
> methods that cannot be compiled. Is the OCX in question available for me
to
> investigate it?

That would be really cool!

I believe so. It is a very popular charting component: TeeChart 5 ActiveX.
You can get a free evaluation version from
http://www.teechart.com/download/Downloadindex.htm#TeeAXTrialver. Be shure
to get the ActiveX version.
It is probably a great test ocx for the interface generator, as it contains
a lot of interfaces and methods. I can send you a piece of workspace code to
set up a chart if you like, so that you do not need to dig through all the
complex docs.


Also, I recognized that while a chart set up in the workspace gives back the
correct interface type calling controlDispatch, this is not true for an
AXControlSite loaded from a resource? Here, I had to change the code back to
MyInterface queryOn: ax controlDispatch. However, it works this way, so I
don't bother much.

Ciao and thank you for support!

...Jochen


Reply | Threaded
Open this post in threaded view
|

Re: pass array to ActiveX Control

Blair McGlashan
"Jochen Riekhof" <[hidden email]> wrote in message
news:[hidden email]...

[ re: Compilation error on transcript running Active-X component wizard]

> > These suggest a bug in the type library analyzer - it shouldn't generate
> > methods that cannot be compiled. Is the OCX in question available for me
> to
> > investigate it?
>
> That would be really cool!
>
> I believe so. It is a very popular charting component: TeeChart 5 ActiveX.
> You can get a free evaluation version from
> http://www.teechart.com/download/Downloadindex.htm#TeeAXTrialver. Be shure
> to get the ActiveX version.
> It is probably a great test ocx for the interface generator, as it
contains
> a lot of interfaces and methods. I can send you a piece of workspace code
to
> set up a chart if you like, so that you do not need to dig through all the
> complex docs.
>

The code generation/compilation errors are caused by the helpstrings in the
IDL. D5.01 is copying these directly into the method comment, but as they
can contain double quotes (which some of these do), the syntax of the
generated method can be incorrect. This bug (#1118) has been fixed in the
latest version of PL2, which is now available via Live Update.

When running with PL2 installed, I didn't get any errors generating from
this library.

By all means send me the workspace, I'd like to see it.

>
> Also, I recognized that while a chart set up in the workspace gives back
the
> correct interface type calling controlDispatch, this is not true for an
> AXControlSite loaded from a resource? Here, I had to change the code back
to
> MyInterface queryOn: ax controlDispatch. However, it works this way, so I
> don't bother much.

Hmm, thanks for that. This is caused by an oversight in the control
recreation that occurs when the progId is changed. The site attempts to
reuse the existing interface object so that clients can hold on to it.
However when the progId is changed in the view composer, the old interface
pointer object should be discarded completely. The patch below fixes this.
In order to get it to take for any existing resource, you'll have to go into
the view composer and evaluate an expression like this.

    self controlDispatch become: self controlDispatch asImplType

Alternatively if you don't mind losing the control configuration, just
change the progId to some other control, and then switch it back.

Regards

Blair

---------------------
"#1144"!
!AXControlSite methodsFor!

createControl
 "Private - Create the embedded control in its initalized state."

 self free.
 "We must discard the old controls interface pointer, as it is probably of
the wrong type"
 dispControl := nil.
 self safeCreateControlFromStream: nil! !
!AXControlSite categoriesFor: #createControl!public!realizing/unrealizing! !


Reply | Threaded
Open this post in threaded view
|

Re: pass array to ActiveX Control

Blair McGlashan
In reply to this post by Jochen Riekhof-3
"Jochen Riekhof" <[hidden email]> wrote in message
news:[hidden email]...
> ....
> Of course, I have immediately tried that out, but it did not work, either.
> I used
> array1 := VARIANT new.
> array2 := VARIANT new.
> array1 arrayRef: (SAFEARRAY withAll: #(1 2 3 4) elementClass: FLOAT).
> array2 arrayRef: (SAFEARRAY withAll: #(1 2 3 4) elementClass: FLOAT).
> series addArray: 4 yArray: array1 xArray: array2.

It occurred to me that the problem might be that the TeeChart control is
expecting the arrays to have a lower bound of zero. SAFEARRAYs support an
arbitrary lower bound, and for no particular reason, other than conceptual
compatibility with Smalltalk arrays, we chose to use a lower bound of 1. For
the most part this does not matter, as users of SAFEARRAYs are supposed to
check the bounds and adjust indexing calculations to suit, however in this
case it would appear to be the root of the problem. If you modify the
SAFEARRAY class>>createVector:vt:extra: method to pass 0 as the lLbound:
parameter ot the SafeArrayCreateVectorEx() API call, then you should find
that you can successfully evaluate (for example):

    n := 10.
    series addArray: n yArray: ((1 to: n) collect: [:each | each squared])
xArray: (1 to: n)

It seems that the control is only choosy about the lower bound being zero,
and despite the fact that the SAFEARRAYs passed as a result of Dolphin's
automatic coercion of (1 to: 4) will be safe arrays of variants holding
integers, that still works as it should.

The default lower bound in VB is almost certainly zero, so it probably makes
sense to change Dolphin to use that as well. I don't believe that changing
it to zero will cause any problems in Dolphin itself, since the SAFEARRAY
wrapper class is independent of the lower bound - it has to be able to
support the arbitrary bounds it may get back from the various sources that
might create SAFEARRAYs. Certainly it runs our (limited) SAFEARRAY tests
fine after the change. Also this doesn't affect the use of the array from
within Smalltalk, as the #at: method offsets off the lower bound correctly
so it always one-based inside Dolphin.

Regards

Blair
------------------
!SAFEARRAY class methodsFor!

createVector: lenInteger vt: vtInteger extra: pvExtra
 "Private - Answer a pointer to a new vector (single dimensioned)
 SAFEARRAY of the specified size and element type, allocated
 by the OLE Automation Library. The lower bound is defaulted to
 zero for compatibility with VB."

 | answer |
 answer := OLEAutLibrary default
    safeArrayCreateVectorEx: vtInteger
    lLbound: 0
    cElements: lenInteger
    pvExtra: pvExtra.
 answer isNull
  ifTrue:
   ["Unfortunately we don't know why it failed, because the call does not
return an HRESULT,
    and doesn't SetLastError() either"

   ^self error: 'Failed to create vector'].
 answer beFinalizable.
 ^answer! !
!SAFEARRAY class categoriesFor: #createVector:vt:extra:!helpers!private! !


Reply | Threaded
Open this post in threaded view
|

Re: pass array to ActiveX Control

Jochen Riekhof
Blair...

> It occurred to me that the problem might be that the TeeChart control is
> expecting the arrays to have a lower bound of zero. SAFEARRAYs support an
> arbitrary lower bound, and for no particular reason, other than conceptual
> compatibility with Smalltalk arrays, we chose to use a lower bound of 1.
For
> the most part this does not matter, as users of SAFEARRAYs are supposed to
> check the bounds and adjust indexing calculations to suit, however in this
> case it would appear to be the root of the problem.

Yep, this helps! With the SAFEARRAYS internally starting from 0 the array
passing works perfectly!
It is probably a very good idea to use zero-based as default, as it is
almost always used in practise (it's VB default as well).  As some
environments, e.g. VB-Script, can only handle zero-based arrays, Dolphin is
also compatible here in this case. (and maybe sometimes a creation method
that allows specification of lower bounds is useful).

Thanks a lot!

Ciao

...Jochen