What exactly is a com object, and how do I use it?
The essence of COM is a language-neutral way of implementing objects that can be used in environments different from the one in which they were created, even across machine boundaries. For well-authored components, COM allows reuse of objects with no knowledge of their internal implementation, as it forces component implementers to provide well-defined interfaces that are separate from the implementation
More details you can check out on WIKI
Related
Creating an ATL project in MSVC seems to create not one but two projects; the latter named the same as the former but with PS appended to its name. What is the purpose of this second project and how can I tell whether I need it?
COM supports making interface method calls across two different threads, two different processes or two different machines. This is called marshaling. Two different threads is the most common case, a COM server is often not thread-safe. COM implements thread-safety for such single-threaded coclasses by marshaling the call from the 'wrong' thread to the thread that created the server. Marshaling between processes occurs when you write an out-of-process server. Between different machines across a network is called DCOM.
This is implemented by creating an instance of the interface that looks exactly like the original. But all the methods of the interface are actually substitutes that do the job of the marshaling the call. This is the proxy. On the other end of the wire there's a substitute that looks exactly like the interface but does the opposite job. This is the stub. The proxy and stub work together to create the illusion that you're making a simple method call in your program.
The primary job of the proxy is to serialize the arguments of the method call into a memory buffer or network packet. This can be pretty untrivial, especially when you use pointers to variable-sized structures. COM needs help to get that right and that's the job of your FooPS project. When you run midl.exe on your .idl file, midl auto-generates code from the interface definitions to implement the proxy and the stub. This is quite often good enough but you may need to implement your own if the built-in keywords in IDL are not sufficient to describe your data.
Last but not least, Windows provides a standard marshaller that can marshal simple interfaces. Designed to support the sub-set of COM that's defined by COM Automation. In other words, interfaces that derive from IDispatch and only use Automation compatible types. You only need to get the registry entries right to enable it and don't otherwise need the proxy/stub generated by midl. And of course, if you only make simple in-process calls on one thread then you won't need it either. This is pretty common.
As #ebutusov said, *PS project contains implementations for Proxy and Stub. They are not standard, instead they are generated by MIDL for interfaces exported from your ATL server. These interfaces are declared in the *.IDL file. The ouput of the project is DLL. You may read this article to get more details.
You may remove PS project from the solution in case if you do not define any custom interfaces in you *.IDL file or if you define only interfaces which have dual and oleautomation modifiers. In that case a standard typelib marshaller will be used.
In order to be able to make use of the standard typelib marshaller, one has to register a typelibrary (which is done automatically since you are using ATL)
It's proxy/stub code, which contains non-standard data marshallers needed to transfer data between different apartments (threading related). It's used when application, which calls your COM object, uses different COM threading model. There was an option in ATL/COM wizard to merge this code into main library. In many common scenarios you don't have to worry about it (i.e. when your COM dll runs in the client context), unless you want to write a custom marshaller.
Given an instance of an ActiveX control, how do I enumerate it's interfaces? (I'd like to get the names of the interfaces).
Like others have mentioned, the only way is to QueryInterface for all possible interfaces. And this is exactly what the Microsoft tool OleView does for you.
Unfortunately, that's not something COM is designed for. At the basic COM level, you can merely ask an object whether it supports a specific UUID-identified interface, one at a time. Since there are a lot of potential UUID's, getting an exhaustive list that way would take quite a bit of time! While most object implementations would track the list of supported interfaces internally, there is no standard COM way of accessing those lists from the outside. And even if there were, you could only get a programmatic name of the interface by looking their UUID's up in the registry, which isn't always reliable.
ActiveX objects (a tricky term!) tend to support automation through IDispatch. If the objects are well behaved, you will able to get some information on the methods they support through GetTypeInfo(). This won't include the names of the interfaces (if any) the methods belong to.
To summarize, COM is rather poor at object metadata.
No way. The idea behind COM interfaces is that you ask the object - "please give me interface XYZ if you support it) and the object decides how to respond - provide the reference to itself or expose the interface of some internal object etc. So you can't know what interfaces the object "supports" without asking the object as described above. This was the design decision of COM designers.
..for an out-of-process-server, or can I call a dispatch interface without registering a proxy/stub?
The interface in question is very high level, so performance is a non-issue, and I could make the whole thing registration-free, which is a big plus
I'm pretty sure you don't need to provide a custom proxy/stub dll if you limit your interface(s) to automation-compatible types. In that case, the system can use the automation marshaler and doesn't need any additional help. I believe the automation-compatible types are the types that can fit into a VARIANT, e.g. simple POD types, BSTRs, and the like.
I found this KB article which has some discussion of the automation marshaler, although it's not specifically targeted at your question. It does list the compatible types, at the very least. It also mentions that you need to specifically identify the automation marshaler in the registration for your component, but in my experience this isn't necessary - your mileage may vary.
Lastly, you may need to implement IProvideClassInfo as well; I usually use the implementation provided by ATL.
You only need a proxy/stub dll if your interface needs to be marshalled. This means if your COM server is in process, and the interface is not passed between apartments, and you aren't going to be calling it from .Net or any other situation that would require it to be marshalled, then you do not need a proxy/stub dll.
Assume that you work only in the C++ world (cross-language interop is not required). What advantages/inconvenients do you see in using COM instead of a plain basic DLL? Do you think using COM is worth the trouble if you are not going to use the interface from different languages?
Everybody is mentioning things that are in COM's plus column. I'll mention a couple of detractions.
When you implement your system using COM, you need to register the COM 'servers' (be they in-proc or out-of-proc) at setup and unregister them at uninstall. This could increase the complexity of your setup system slightly and tends to require a reboot unless the user carefully tears down running processes first.
COM is slow compared to other standard ways of doing the same thing. This comment will probably generate a lot of hate and maybe some downvotes, but the fact of the matter is that at some point you will need to marshall data, and that is expensive.
According to the Rules of COM, once an interface has been published it can never be changed. That in itself is not a negative, and you might even argue that it forces you to do thorough design before shipping the interface. But the truth is there's no such thing as never, and in production code interfaces change. You will undoubtedly need to either add methods or change the signatures of existing methods. In order to accomplish this you have to either break the rules of COM -- which has bad effects -- or follow the rules of COM which are more complicated than just adding a parameter to a function like you would with a astraight DLL.
COM can be useful in plain old C++ for:
Interprocess communication
Plugin architectures
Late binding scenarios
"Much, much, more..." (tm)
That said, if you don't need it, don't use it.
With DLL you can get much closer coupling, while COM limits interactions very precisely. This is the root of both the advantages and the disadvantages!
You get more power and flexibility (e.g. inherit from classes defined in the DLL, not feasible in COM) but the dependency is thereby much stronger (need to rebuild the user for certain changes to the DLL, etc).
Often especially galling is that all DLLs and the EXE must use the same kind of runtime library and options (e.g. all dynamically linked to the non-debug multithreaded version of msvcrt* for example -- can't rebuild just one to use the debug version without incurring very likely errors!).
The looser coupling of COM is therefore often preferable, unless you really need the closer-coupling kinds of interactions in a specific case (e.g., a framework, which definitely requires user-code to inherit from its classes, should be a DLL).
If you can avoid don't use it. In my last project COM brought pretty much limitations into C++ interfaces being used. Just imagine, that you can't simply pass a std::string but have to use an array of characters. In that case you build the string, an then copy it to an array which can be handled by COM.
You also can only use very limited set of fundamental types, have casts and proprietary memory management. You can't use new/delete, but have to use COM own functions.
You also can't simply throw an exception, but have to initialize some COM interface IErrorInfo, which will be rethrown at the other end.
So if you don't need, don't use it. It will definitely screw your design. And if you need it, try to evaluate other interop possibilities: boost::interprocess, zeroc ice...
Regards,
Ovanes
Registration and discovery
Out-of-process
Remote invocation
are the few extra features that you would have got. Even transactional support can flow without the need for COM support these days.
The IUnknown interface is a good base level to support anyway -- gets you a way to add features without breaking old clients (QueryInterface) and pervasive reference counting. You can implement this without buying into everything in COM.
Then, whenever you are adding a feature to a class, if you use the COM interface for it, you at least get an interface that is known -- for example IDispatch if you want reflection features.
Your only delta away from being able to be called by another language would then be the registration and the class factory.
Because interfaces are independent of any particular DLL, at its simplest level, a COM like approach at the very least frees you to change the dll serving an interface under the hood, without having to recompile your app against the new dll name.
Using Full COM with MIDL defined interfaces and proxy stub dlls means that you can use COM to manage thread safety in-process, interprocess comms on the same PC, or even connect to the COM server object on a remote PC.
I've seen with Microsoft COM and XPCOM, at least from what I've read and gathered so far, that the implementations of interfaces in a component have to essentially be in the single class that derives all the virtual interfaces. Is this correct? What am I missing?
Is there a way to have multiple objects (possibly in separate DLL's) each provide their functionality and still be able to freely transition between them using QueryIterface?
What I'm looking for is to have a component with some functionality, but still allow external client code to create new extensions of the component with (possibly) new interfaces. Ideally this should happen without divulging the current source of the component and its implementation.
This should be possible, although probably not supported by the standard high-level wrappers. Most of the wrappers (ATL, MFC, etc.) only support mapping a COM object to a single class. However, QueryInterface is allowed to return a different pointer and calls COM object code, so the first COM object could load a different DLL, instantiate a different object, and return a pointer to it's interface (vtable).
It's all possible as far as I know, you'll just likely be writing a lot of the low-level glue code yourself.
Yes, ATL supports tear-off interfaces
This allows to imlement the interface in another class that is instantiated only when the interface is requested. Since it passes only an interface, I guess it can be put into a separate DLL, too.
(can also be cached after being requested once)