|
Thanks CPallini,
I have did more study and I want to share my points here. Could you help to
review whether my points are correct please?
1. If a component implements IDispatch directly, we can only invoke its
member methods through IDispatch.Invoke -- only one way, so it is not dual
interface;
2. If a component implements IUnknown directly, we can only use
AddRef/Release/QueryInterface, it is useless since we can only use the 3
methods;
3. If a component implements a customized interface, then the customized
interface implements IUnknown, then we could invoke the component's member
methods through QueryInterface to get the customized interface, and using the
vtable in the customized interface to invoke member methods. But still one
way, so it is not dual interface;
4. If a component implements a customized interface, then the customized
interface implements IDispatch, then we could invoke the component's member
methods through QueryInterface to get the customized interface, and using the
vtable in the customized interface to invoke member methods, and also we
could invoke through IDispatch.Invoke. Two ways to invoke it, so called dual
interface.
All of my understandings are correct? Anything missing?
regards,
George
|
|
|
|
|
IMHO your understandings are correct.
Point (2), as it stands, IMHO is misleading: since IUnknown implementation is mandatory, I will say: if a component implements only IDispatch ...
But such a point is obvious.
Also, as you know well, IDispatch , like any other COM interface must provide IUnknown , then saying: "implementing only IDispatch" it is equivalent to say: "implementing a IUnknown whose QueryInterface method may return only IDispatch ".
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
|
When you say a component implements IDispatch or IUnknown im assuming that you have an interface IX that is derived from either of those interfaces (IDispatch or IUnknown)and you are implementing those intrefaces in a coclass.
1. Any COM interface has to be derived from IUnknown. So when you implement IDispatch you also have to implement IUnknown, because IDispatch is also derived from IUnknown.
Any interface,say IX, that is derived from IDispatch is a dual interface. Because IX methods can be invoked through IDispatch methods as well as vtable.
2. You can also derive your interface IX from IUnknown and invoke its methods through vtable.
3,4. Don't know what you mean by customized interface.
May i suggest that you go through "Inside COM" by Dale Rogerson. It is a very good book it will help you in understanding COM much better.
|
|
|
|
|
Thanks sw@thi,
1.
You mentioned twice about "invoke its methods through vtable". My confusion is what exactly mean "through vtable". I think you mean QueryInterface for interface IX for the coclass object, and invoke the exposed methods in IX is through vtable of coclass object for interface IX. Correct?
2.
sw@thi wrote: 3,4. Don't know what you mean by customized interface.
Customized interface I mean any C++ eligible interface which is not IDispatch and IUnknown, and in 3 the customized interface inherits IUnknown and in 4 the customized interface inherits IDispatch. From my description, do you think my points for 3 and 4 are both correct?
regards,
George
|
|
|
|
|
Hi CPallini,
I am not sure that we require an extra Interface. Check this Link Dual Interfaces[^]
I could not find some good sample for this do you have one which will explain step by step procedure.. I am asking for this because i have never implemented this ..
CPallini wrote: Sandip I don't remember the technical details and, as usual: "this in going on my arrogant assumptions..."
Smile
Regards,
Sandip.
modified on Friday, September 12, 2008 4:31 AM
|
|
|
|
|
I think you're right, since you may simply do something like:
class IMyDualInterface : public IDispatch
with a VTABLE arranged the following way:
- QueryInterface methods
- IDispatch methods
- 'Add' method here.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
Thanks CPallini,
I am a little losing the context and my English is not very good.
Do you guys mean in order to implement a dual interface,
- we need an additional customized interface, which implements IDispatch?
- or we need implement both an additional customized interface (and the customized interface inherits from IUnknown) and also implement IDispatch?
- or both the above two ways are fine?
regards,
George
|
|
|
|
|
We need a customized interface that implements (also) IDispatch (Usually it inherits from IDispatch , that in turn, inherits from IUnknown ).
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
Hi CPallini,
I didn't find any simple article or example to do this on CP, which will explain steps.
Do you know any?
If not i think George can write one side by side as he implements Dual Interface
Regards,
Sandip.
|
|
|
|
|
I am also asking for this, about various ways to implement dual interface.
regards,
George
|
|
|
|
|
SandipG wrote: Do you know any?
Unfortunately, no.
SandipG wrote: If not i think George can write one side by side as he implements Dual Interface
Oh, he's writing the George's COM Bible!
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
modified on Friday, September 12, 2008 5:39 AM
|
|
|
|
|
Thanks CPallini,
I have one more comment, at first I agree with what you mean above. I think there is another way to implement dual interface, which is we need implement both an additional customized interface (and the customized interface inherits from IUnknown) and also implement IDispatch (in IDispatch's Invoke implementation we can call the methods from the customized interface methods' implementation)? Is that also dual interface?
regards,
George
|
|
|
|
|
I think the standard way is just inheriting from IDispatch (since IDispatch in turn inherits from IUnknown ) this way does not prevent IDispatch::Invoke to call the methods of the customized interface.
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
I agree, but my implementation above is wrong and not dual interface, CPallini?
regards,
George
|
|
|
|
|
Well, it depends on how do you implement the IDispatch interface (for instance, if your customized interface inherits both from IUnknown and IDispatch the you've a undesirable diamond inehritance path).
If the Lord God Almighty had consulted me before embarking upon the Creation, I would have recommended something simpler.
-- Alfonso the Wise, 13th Century King of Castile.
This is going on my arrogant assumptions. You may have a superb reason why I'm completely wrong.
-- Iain Clarke
[My articles]
|
|
|
|
|
Thanks CPallini,
I agree the solution you mentioned -- making my component implement a customized interface, and making the IDispatch interface should be the optimum solution.
regards,
George
|
|
|
|
|
Actually, "dual interface" refers to a COM class's ability to have its methods bound at compile time OR at run-time.
Generally, all COM classes implement "custom" interfaces - after all, they do things that are specific to defined set of requirements, and are thus "custom".
The COM class's methods are bound at compile time into a virtual function table, or VTABLE. For a program (client) to invoke the COM class's methods, it must have "knowledge" of the methods exported by the COM component at the time the client program itself is compiled into executable form. For applications where the COM object (server) and the client program are designed and built together, the client can easily have such "knowledge". I often develop COM servers and clients simultaneously, and my client programs have "intimate" knowledge of the names of the methods exported by the COM server.
But what about client programs that want to use a COM server's methods at RUN TIME, but do not necessarily know the names and other properties of the methods exported by the COM server? This situation arises very often for scripting languages where the executable code is built "on the fly".
The process whereby a client program "discovers" and uses the methods exported by a COM server is called "Run-time" binding, also known as "late" binding. This process allows scripting languages to identify what interfaces (methods) a COM class supports at run time, long AFTER the COM class has been compiled into executable code. This is done through QueryInterface and the IDispatch method. Thus, a COM class must support the IDispatch interface if it wants to allow client programs to bind to its methods at run-time.
A COM class that supports IDispatch is thus said to be "dual interface" - a client program with "intimate" knowledge of its method's names and parameters can bind to it a compile time, OR the client can bind to its methods at run time via QueryInterface and IDispatch.
Incidentally, "IDispatch" is aptly named because it is a method that "dispatches" a function call to the proper method within the COM server.
|
|
|
|
|
Thanks Scott,
I like your long and comprehensive post. Two more comments,
1.
To implement dual interface is easy, i.e. making the component implement a customized interface, and making the customized interface inherits IDispatch. So, I think since it is easy, every COM component should implement it and be a dual interface. Why implementing dual interface is not mandatory -- i.e. for some other reasons, developer will not implement dual interface?
2.
For the compile time binding as you mentioned -- just clarify one point, I think COM consumer should not create and component and call its implementation method directly (call the component other than call the interface) -- but should use QueryInterface to get the interface which the COM component implements, then call the methods (using vtable) through the interface. Correct?
regards,
George
|
|
|
|
|
On point 1: I rarely implement dual interfaces because I develop COM servers and COM clients as part of a package application, and my client components always have "up front" knowledge of what the server can do. So, I typically do not implement the IDispatch interface. This results in a little less complexity in my application and improved performance.
My belief is that you should only implement IDispatch if a) you are developing a COM component that you are going to make publicly available to other developers so that they might use it in their applications, or b) your COM component needs to be used by a scripting language, for example VBScript within a web page, in which case you must implement IDispatch so that the VBScript can bind to your COM component at run time (late binding).
The application that I support is all written in C++ (no scripting languages) and contains no components that are intended to be available for use by other developers outside my company.
On point 2: You are correct, the client should always call "QueryInterface" to get a pointer to the desired interface exported by a server, then call the methods of that interface via the pointer. Since the methods of the interface are all defined as virtual functions in C++, you are implicitly invoking the methods through the virtual function table. (Of course, virtual functions are intrinsic to the C++ language and existed long before COM was created.)
|
|
|
|
|
Thanks Scott,
1.
Why "you are developing a COM component that you are going to make publicly available to other developers" as you mentioned, I must expose IDisaptch? I could expose vtable only and let them use C++.
Any comments or any important points which I missed in my above statements?
2.
I further question. If we want to support IDispatch, all types in methods' parameter/return value must be auomtation compatible? If yes, why?
regards,
George
|
|
|
|
|
Yes, on point number 1...You ONLY have to support IDispatch if you want scripting languages or other languages that use late binding to be able to use to your COM server component. Of course, this is very often the case these days with so many COM components being written to plug into web sites and be called from VB script, Java script, etc. I'm sorry I should have made this more clear. So, you CAN have a COM component publicly available that does NOT support IDispatch, but it will need to be linked with the client program at compile (build) time.
On point 2: YES, all parameter/return values MUST be automation compatible. Basically, this means that everything must be VARIANT, BSTR, long integer, etc. Why? Because COM is a defined standard that all programming languages that wish to be COM compliant must adhere to if they wish to interface with each other, and IDispatch is a defined interface within the standard. If you wish to use much of the automation linkage already put into place by Microsoft, and the COM subsystem (also implemented by Microsoft via Windows), you'll have to adhere to the standards of the subsystem components. For example, of you try to pass a "C-style" string from a C++ program to a VB program through a COM interface, the VB program will probably crash because it doesn't "understand" the structure of a C-style string.
Incidentally, I had to read two or three books on COM and diligently work the examples before I got it figured out. I tried using ATL and the Visual Studio wizards to create my COM components, but quickly gave up on this because it was very inflexible when I wanted to make additions or changes to my COM classes. I ended up hand-building, from scratch, all of my COM components, but now I have a library of components for use in my applications.
Scott
|
|
|
|
|
Thanks Scott,
Your answer is really great! Just want to clarify two things.
1.
No matter who (I mean COM consumer) will use IDispatch interface, like C++/VB such advanced client or script client, all the parameter types and return value types we use IDispatch.Invoke to pass in/out should be VARIANT, correct?
2.
My current confusion is, in IDL I have defined some customized data type (some struct) and in some methods I use such customized data type as input parameter or return value. If I want to support IDispatch.Invoke to consume the methods, could I use such customized data type either as input parameter or return value, even for advanced client C++/VB?
regards,
George
|
|
|
|
|
1) Well, not necessarily: for example, automation directly supports BSTR (b-strings) and 4-byte integer values (known as long integers in C++), BUT...to keep things more simple, I would recommend just using VARIANT for all of your parameters, as you suggest. If you study the VARIANT data type closely, you'll see that the VARIANT structure itself actually can hold many other data types. Its up to you to figure out what a VARIANT contains by looking at the '.vt' member of the structure.
Also, if you're writing in VB, VB can automatically convert from VARIANT to other data types for you. I believe C# can do this also, although I haven't really dabbled in C# yet. If you're writing in C++, you can use the _variant_t class which provides many conversion operators (I use _variant_t all the time in my C++ code).
2) I wouldn't necessarily recommend using a custom data type through the IDispatch interface unless your ready to write "custom marshalling" routines. "Marshaling" is the process of packaging up your function calls and parameters, then passing them across process boundaries, and possibly even across machine boundaries if you are going to have a client on one machine invoke a COM server on another machine (which is another really cool thing to do with COM). Microsoft provides COM components that can performing the marshalling for you based on the information you have in your IDL.
Is there a way you can take your custom data type and make it "look" like a standard type? For example, could your custom data type be type cast as a long integer (vt = VT_I4) and placed into a VARIANT for the function call? And then when the server gets the parameter value, it can type cast it again into whatever you need it to be?
Scott
|
|
|
|
|
Thanks Scott,
I am always confused about two concepts. Automation compatible data type and VARIANT. Are they the same thing -- means if a data type could be represented by VARIANT, it is automation compatible?
I did some study, and find seems VARIANT is not ole automation type? So, I am even confused. It is appreciated if you could clarify the relationship between ole automation data type and VARIANT.
http://msdn.microsoft.com/en-us/library/aa367129%28VS.85%29.aspx[^]
regards,
George
|
|
|
|
|