Please help with ActiveX component instantiation.

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

Please help with ActiveX component instantiation.

Costas Menico-2
I have created a COM server which works properly when I use

srv:=IDispatch createObject: 'Myserver.server'.
srv invoke: 'func' with: param.

However I feel this may be slowing it down for certain functions and I
tried using the Active X wizard.

I am not sure if I am doing this right,. After the wizard generates
the MyserverIserver class under IDispatch I am not sure which is the
best way to go about intantiating it and invoking functions.

I did the following but I have problems:

srv:=MyserverIserver on: 'Myserver.server'.
srv invoke: 'func' with: param.

On the #invoke line I get a does not understand message:

GetIDsOfNames:rgszNames:cNames:lcid:rgdispid: arguments: #(a
REFGUID{00000000-0000-0000-0000-000000000000} a LPVOID(an
ExternalAddress(16r8226754)) 1 1024 a SDWORD(0))

Ami I instantiating this correctly? ShouldI be using invoke? What am I
missing?

Thanks

Costas Menico


Reply | Threaded
Open this post in threaded view
|

Re: Please help with ActiveX component instantiation.

Bill Schwab-2
Costas,

I think you still want to use #createObject: to get your IDispatch
subinstance.  The benefit of the ActiveX Wizard will be to use the generated
methods as opposed to #invoke:with:.  Your code would look more like

   srv:=IDispatch createObject: 'Myserver.server'.
   srv func:param.

Does that help?

Bill

--
Wilhelm K. Schwab, Ph.D.
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: Please help with ActiveX component instantiation.

Costas Menico-2
"Bill Schwab" <[hidden email]> wrote:

>Costas,
>
>I think you still want to use #createObject: to get your IDispatch
>subinstance.  The benefit of the ActiveX Wizard will be to use the generated
>methods as opposed to #invoke:with:.  Your code would look more like
>
>   srv:=IDispatch createObject: 'Myserver.server'.
>   srv func:param.
>
>Does that help?

You bet it helps! Thanks so much

Costas


Reply | Threaded
Open this post in threaded view
|

Re: Please help with ActiveX component instantiation.

Blair McGlashan
In reply to this post by Costas Menico-2
Costas

"Costas Menico" <[hidden email]> wrote in message
news:[hidden email]...
> I have created a COM server which works properly when I use
>
> srv:=IDispatch createObject: 'Myserver.server'.
> srv invoke: 'func' with: param.
>
> However I feel this may be slowing it down for certain functions and I
> tried using the Active X wizard. I'm not sure if I am doing this right,.
After the wizard generates
> the MyserverIserver class under IDispatch I am not sure which is the
> best way to go about intantiating it and invoking functions.

Going through IDispatch will indeed be significantly slower (probably two
orders of magnitude) than invocation through a generated interface. Once
generated you can treat it as a normal Smalltalk object since the wizard
generated "high-level" wrapper methods that hide most of the argument/return
value marshalling. Take a look at the generated class - it also includes a
lot of "documentation", generated from the type library, which makes it much
easier to discover how use an Active-X component by expirementation.

> I did the following but I have problems:
>
> srv:=MyserverIserver on: 'Myserver.server'.
> srv invoke: 'func' with: param.
>

If the interface is defined as the default for the Active-X component, then
you can probably just do:

    srv := MyserverIserver new.

Try it anyway, you'll get a "#clsid is the responsibility of the subclass"
error if not, in which case:

    srv := MyserverIserver createObject: 'Myserver.server'

will work. You can then invoke the methods and property accessors as normal
Smalltalk message sends, e.g.

    srv func.

You can also add further "helper" methods to the interface class which make
it easier to use, or whatever.

Regards

Blair


Reply | Threaded
Open this post in threaded view
|

Re: Please help with ActiveX component instantiation.

Costas Menico-2
"Blair McGlashan" <[hidden email]> wrote:


>>
>> srv:=MyserverIserver on: 'Myserver.server'.
>> srv invoke: 'func' with: param.
>>
>
>If the interface is defined as the default for the Active-X component, then
>you can probably just do:
>
>    srv := MyserverIserver new.
>
>Try it anyway, you'll get a "#clsid is the responsibility of the subclass"
>error if not, in which case:
>
>    srv := MyserverIserver createObject: 'Myserver.server'
>
>will work. You can then invoke the methods and property accessors as normal
>Smalltalk message sends, e.g.
>
>    srv func.
>

Blair,

Just wanted to report back to you what works and what doesn't work and
see if there is anything else I should check or test.

Assume the method to invoke is func: param

This always works:
===============

        srv := IDispatch createObject: 'Myserver.server'.
        srv invoke: 'func' with param.

This partially works
===============
        srv := IDispatch createObject: 'Myserver.server'.
        srv func: param.

The func executes correctly but always returns nil. I get the answer
by having a method inside the OLE that reads it as such:

        srv getLastResult.

In effect I have to do this:

        srv func: param; getLastRes.

It seems to me that methods with no parameters answer correctly. Its
only if you have a parameter that it does not work properly.

This does not work.
===============

        MyserverIserver createObject: 'Myserver.server'  
        ----> No such interface. 16r4002

        MyserverIserver new.
        ----> No such interface. 16r4002

Any ideas or things to check would be appreciated...

Costas


Reply | Threaded
Open this post in threaded view
|

Re: Please help with ActiveX component instantiation.

Blair McGlashan
Costas

You wrote in message news:[hidden email]...

> ...
> Just wanted to report back to you what works and what doesn't work and
> see if there is anything else I should check or test.
>
> Assume the method to invoke is func: param
>
> This always works:
> ===============
>
> srv := IDispatch createObject: 'Myserver.server'.
> srv invoke: 'func' with param.

That is the preferred way to invoke via IDispatch, though I would only use
IDispatch where it is the only thing available, or where the object model
being used is very large and one only wants to use part of it. Actually I
think the latter is pretty dubious too, since Dolphin Pro's image stripper
will do a good job of removing most of the stuff that isn't used, so the
cost is mainly a larger (perhaps much larger if the object model is for the
HTML DOM) development image.

>
> This partially works
> ===============
> srv := IDispatch createObject: 'Myserver.server'.
> srv func: param.
>
> The func executes correctly but always returns nil. I get the answer
> by having a method inside the OLE that reads it as such:

This goes through DNU (#doesNotUnderstand:) processing of IDispatch. It
doesn't use any type information other than a look up of the name (taken to
be the primary keyword of the selector that accompanies the message which
was not understood), i.e. a call to IDispatch>>GetIdsOfNames(). It is
frankly unreliable, partly because in Smalltalk we can't distinguish a
property access from a method invocation, and partly because the approach is
simple. A better job could be done by dynamically looking up type
information in the object's type library (if available), but as I don't
really believe this is the correct approach for anything but scripting
languages (for one it is dog slow), I am not terribly keen to encourage its
use.

> srv getLastResult.
>
> In effect I have to do this:
>
> srv func: param; getLastRes.

I think that is most unsatisfactory. Generally speaking DNU access will
work, but it depends on the automation server. I can't say why in particular
it is failing in this case.

> It seems to me that methods with no parameters answer correctly. Its
> only if you have a parameter that it does not work properly.

That gives a clue. As I mentioned above, Dolphin is unable to distinguish
between a property access and a method invocation. Therefore if there are no
arguments it assumes that the call is either a property read (propget) or
method invocation, and passes both flags to the

This always works because VB isn't able to distinguish this case either,
e..g:

X = Obj.PropOrMethod    ' Am I a method invocation with a return value, or a
property read, VB doesn't know

Hence one is specifically allowed to pass both DISPATCH_PROPERTYGET and
DISPATCH_METHOD together in a call to IDispatch::Invoke(). It is up to the
server to work out whether a property access or method invocation is being
attempted

However, VB _is_ able to distinguish between a property write (propput) and
a method invocation

Obj.Prop = 2        ' Assignment allows VB to know this is a property write
Obj.Method(2)

Note that in the case of the latter VB still doesn't know if this is an read
of an indexed property or a method with one argument (I can't remember
whether the brackets are needed or not in this case; VB syntax is so
inconsistent.

In Smalltalk we can't distinguish this case, because we can only assign to
Smalltalk variables, not properties of objects. An invocation of a simple
instance variable setter method in Smalltalk, for example, looks exactly
like a one argument keyword message send, because that is what it is. Thus
the DNU handler for IDispatch has no completely reliable way of knowing
whether to pass DISPATCH_PROPERTYPUT, DISPATCH_PROPERTYPUTREF,
DISPATCH_METHOD, or even DISPATCH_PROPERTYGET (since the argument might be
the subscript accompanying an indexed propget). Passing combinations of
these flags seems to work for some cases with some servers, but it is not
specifically permitted in the spec. Dolphin passes both DISPATCH_METHOD and
DISPATCH_PROPERTYPUT, which some automation servers don't like.

Another issue is with the handling of the return value. A method in an
interface may pass its return value through an output argument rather than
through the return value holder specifically provided for this purpose.
Dolphin's type library analyzer (used by the AX Component Wizard to generate
interface wrapper classses) can spot this and do the necessary to generate a
suitable wrapper method, but it will be more difficult to call the methods
successfully through IDispatch.

BTW: I would recommend looking at the IDL which Dolphin can reverse engineer
from a type library (The ''Browse IDL' command on the main context menu of
the . You may see that components built exclusively with VB, etc, tend to
treat a lot method arguments as in-out parameters. These are most awkward to
wrap successfully because one must assume the argument has to be passed by
reference, and forms an output from the method too. It is often necessary to
hand code a suitable wrapper method for such interface methods. Try and
avoid implicit or explicit By-Ref parameters to COM objects. in-out
parameters are usually a bad idea, but that is another topic.

> This does not work.
> ===============
>
> MyserverIserver createObject: 'Myserver.server'
> ----> No such interface. 16r4002
>
> MyserverIserver new.
> ----> No such interface. 16r4002
>
> Any ideas or things to check would be appreciated...
>

Take the error report literally; the server is telling you it does not
support the interface requested, a decision it makes on the basis of the IID
(the GUID that uniquely identifies the COM interface). That is almost
certainly because you have rebuilt the automation server since you generated
MyserverIserver using the AX Component Wizard. VB, for example, changes the
IID every time one rebuilds a server, at least by default. I imagine other
Microsoft tools may be similar. It is necessary to turn on 'Binary
Compatibiliy', or some similar option, to prevent this happenning, or
alternatively to regenerate the interface in Dolphin every time the server
is rebuilt. One other approach is to construct the IDL separately, run it
through MIDL, import (reference) the resulting typelib into VB, and then
declare the COM objects as implementing interfaces from that type lib. This
allows much more control over the definitions of the methods, and also
provides useful documentation (the IDL).

Regenerating an interface from the current type library information is is
pretty easy in Dolphin:

    MyserverIserver typeInfo generate

Regards

Blair


Reply | Threaded
Open this post in threaded view
|

Re: Please help with ActiveX component instantiation.

Costas Menico-2
"Blair McGlashan" <[hidden email]> wrote:

>> This does not work.
>> ===============
>>
>> MyserverIserver createObject: 'Myserver.server'
>> ----> No such interface. 16r4002
>>
>> MyserverIserver new.
>> ----> No such interface. 16r4002
>>
>> Any ideas or things to check would be appreciated...
>>
>
>Take the error report literally; the server is telling you it does not
>support the interface requested, a decision it makes on the basis of the IID
>(the GUID that uniquely identifies the COM interface). That is almost
>certainly because you have rebuilt the automation server since you generated
>MyserverIserver using the AX Component Wizard. VB, for example, changes the
>IID every time one rebuilds a server, at least by default. I imagine other
>Microsoft tools may be similar.
>...............

In an effort to figure out the problem, I used another COM which
worked fine by sending it message new. However I discovered something
interesting in the process. This COM's _guid and clsid were the same.
My COM's _guid and CLSID are NOT the same. I am not sure if this is
significant.

I then tested both COMs using VB. I defined it as a COM Reference (and
declared it accordingly. It executed fine. (This is the equivalent of
what Dolphin does with the wizrd)

        Dim srv As new Myserver.server
        srv.func("whatever")

(In VB you can also use: set srv = createObject("Myserver.server")
which is the equivalent of #createObject: in Dolphin )

I then edited the registry and deleted any keys refering to myserver.
I recompiled and marked the "Generate new CLSID/GUID" in Visual Foxpro
(My COM object is VFP).

I then used a fresh image of Dolphin4.0 and created the
Myserver.server class using the Dolphin Wizard.

Then I debugged it:

        self halt. MyserverIserver new.

The failure of my COM is exactly at the point where the CreateInstance
method is called:

        COMInterface class>> onCLSID: aCLSID outerIUnknown: pUnkOuter
hostName:hostNameString licenseKey: licenseString
...<snipcode>...
           hr := pFactory CreateInstance: pUnkOuter riid: self iid
ppvObject: pUnk.

So here (self iid) uses the GUID from the list below. Since I can't
trace any further I  can't tell why it fails if the CLSID is not equal
to GUID.

Here are the ids I located for MyServer in the registry.

'{FEC38E94-3EBB-4E2B-ABF8-083C79D7E0B9}' guid/interface
'{E817962D-F94B-4EF1-AF5C-ECAA32AEBE57}' clsid/clsid
'{31270B36-F532-46DA-80E2-FA4764375175}' typelib/interface
'{00020424-0000-0000-C000-000000000046}' Proxy for typelib

I believe I am doing everything correctly. Could it be that
#CreateInstance: riid:ppvObject: is assuming that the iids must be
equal?

Also you were going to tell me how I can look at an IDL file but
somehow you never finished the sentence.  You said: " (The ''Browse
IDL' command on the main context menu of
the . )". I looked for a Browse IDL everywhere. I could not find it.

Sorry if I am persistent because this COM I made works with other
languages and I would like to make sure its not some issue with
Dolphin.


Regards,

Costas


Reply | Threaded
Open this post in threaded view
|

Re: Please help with ActiveX component instantiation.

Costas Menico-2
Blair,

I forgot one more important point. The COM server that works is very
similar to my server (itsalso  VFP made).  When instantiated with
#new, all the methods work properly within Dolphin, including methods
with parameters that return variant values [in, out].

Costas


Reply | Threaded
Open this post in threaded view
|

Re: Please help with ActiveX component instantiation.

Mikael Svane
In reply to this post by Costas Menico-2
Costas,

Sorry that I can't help you with the problem you are having, but at least I
know where you can find the 'Browse IDL' command. Open the ActiveX control
browser on the control that you are interested in. Then choose Help\Show IDL
from the menu.

Sincerely,

Mikael Svane
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: Please help with ActiveX component instantiation.

Costas Menico-2
"Mikael Svane" <[hidden email]> wrote:

>Sorry that I can't help you with the problem you are having, but at least I
>know where you can find the 'Browse IDL' command. Open the ActiveX control
>browser on the control that you are interested in. Then choose Help\Show IDL
>from the menu.

Mikael (and Blair),

Thanks... As a matter of fact the Dolphin IDL Browser does not work
right on this component either. It does not produce any of the
interface methods. I downloaded the Microsoft IDL viewer from
http://www.microsoft.com/com/resources/oleview.asp and tried it.
Microsoft's works fine and shows all the interface methods.

Blair, I hope you are reading this because in my programmer's paranoia
I tested my component, on the same machine,  with Dolphin 3.0 and it
works like a charm. Even the answers come back correctly (except D3
replies an Array with the original parameter at: 1 and the answer at:
2). And I get a speed increase of 400%.

I hope you agree with me that this may be an issue witht Dolphin 4.0.
(I feel like an idiot for not testing with D3.0 from the start and
saved myself all this debugging effort. But I did learn a lot<g>).

Regards,

Costas


Reply | Threaded
Open this post in threaded view
|

Re: Please help with ActiveX component instantiation.

Blair McGlashan
Costas

If you send me a copy of the component then I will investigate.

Regards

Blair

"Costas Menico" <[hidden email]> wrote in message
news:[hidden email]...
> "Mikael Svane" <[hidden email]> wrote:
>
> >Sorry that I can't help you with the problem you are having, but at least
I
> >know where you can find the 'Browse IDL' command. Open the ActiveX
control
> >browser on the control that you are interested in. Then choose Help\Show
IDL

> >from the menu.
>
> Mikael (and Blair),
>
> Thanks... As a matter of fact the Dolphin IDL Browser does not work
> right on this component either. It does not produce any of the
> interface methods. I downloaded the Microsoft IDL viewer from
> http://www.microsoft.com/com/resources/oleview.asp and tried it.
> Microsoft's works fine and shows all the interface methods.
>
> Blair, I hope you are reading this because in my programmer's paranoia
> I tested my component, on the same machine,  with Dolphin 3.0 and it
> works like a charm. Even the answers come back correctly (except D3
> replies an Array with the original parameter at: 1 and the answer at:
> 2). And I get a speed increase of 400%.
>
> I hope you agree with me that this may be an issue witht Dolphin 4.0.
> (I feel like an idiot for not testing with D3.0 from the start and
> saved myself all this debugging effort. But I did learn a lot<g>).
>
> Regards,
>
> Costas