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)
Related
I'm designing (brainstorming) a C++ plugin framework for an extensible architecture.
Each plugin registers an interface, which is implemented by the plugin itself.
Such framework may be running on relatively capable embedded devices (e.g. Atom/ARM) so I can use STL and Boost.
At the moment I've managed to write a similar framework, in which interfaces are known in advance and plugins (loaded from dynamic libraries) register the objects implementing them. Those objects are instantiated as needed by their factory methods, and methods are called correctly.
Now I want to make it more flexible, having plugins register new interfaces (not just implementing the existing ones) thus extending the API available to the framework users.
I thought of using a std::map<std::string, FunctionPtr>, which is also mentioned by several articles and stackoverflow replies I've read. Unfortunately it doesn't seem to capture the case of different method interfaces.
I feel it might have something to do with template metaprogramming, or traits perhaps, but I can't figure out how it should work exactly. Can anyone help?
Try looking at XPCOM which solves these problems for you - by sortof re-implementing COM.
You have the issue of not knowing what interface the plugin provides to your application, so you need a way for the developer to access it, without the compiler knowing what it is (though, if you supply a header file, then suddenly you do know what it is and you can compile it without any need for plugin unknown-interface fanciness)
so, you're going to have to rely on runtime determinism of the interface, that roughly requires you to define the interface in some way so that the framework can call arbitrary methods on it, and I think the only realistic way you can do that is to define each interface as a set of function pointers that are loaded individually and then stored in data for the user to call. And that pretty much means a map of function pointers to names. It also means you can only user compiler niceties (such as overloading) by making the function names unique. The compiler does this for you by 'mangling' all functions to unique, coded names.
Type Traits will help you wrap your imported functions in your framework, so you can inspect them and create classes that work with any imported type, but it isn't going to solve the main problem of importing arbitrary functions.
Possibly one approach that you'll want to read is Metaclasses and Reflection by Vollmann. This was referenced by the C++ standard body, though I don't know if it will become part of a future spec. Alternatively you can look at Boost.Extension
Maybe the first thing you need check is COM.
Anything that can be done with templates, can be done without, though perhaps in a much less convenient way, by writing "template instances" by hand.
If your framework was compiled without seeing a declaration of class MyNewShinyInterface, it cannot store pointers of type MyNewShinyInterface *, and cannot return them to the framework users. No amount of template wizardry can change that. The framework can only store an pass around pointers to some base class. The users will have to do a dynamic_cast to retrieve the correctly typed pointer.
The same is true about function pointers, only functions have no base classes and one will have to do the error-prone reinterpret_cast to retrieve the right type. (This is just another reason to prefer proper objects over function pointers.)
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.
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
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.
I am quite new to COM so the question may seem naive.
Q1. About Windows DLL
Based on my understanding, a Windows DLL can export functions, types(classes) and global variables. Is this understanding all right?
Q2. About COM
My naive understanding is that: a COM DLL seems to be just a new logical way to organize the functions and types exported by a standard Windows DLL. A COM DLL exports both functions such as DllRegisterServer() and DllGetClassObject(), and also the Classes which implements the IUnknown interface. Is this understanding all right?
Q3. *.def & *.idl
*.def is used to define the functions exported by a Windows DLL in the traditional way, such as DllGetClassObject().
*.idl is used to define the interface implemented by a COM coclass.
Thanks in advance.
Think of COM as a binary compatible way to share interfaces across DLL boundaries. C++ classes can't easily be exported from DLLs because of the non-standard name mangling done between various compiler versions. COM allows code in one DLL or executable, to create an implementation of an interface from another DLL or EXE as long as that implementation follows a defined interface and calling convention. This is what allows a COM class to be written in C# and invoked from C++, Python, and many other COM-aware languages.
COM interfaces are just standard C++ classes containing all pure virtual functions and derived from IUnknown. IUnknown is a pre-defined interface that all compliant COM interfaces must derive from that provides common facilities like reference counting and the ability to query whether an object implements a particular interface.
DLLs that wish to advertise the fact they can create implementations of COM interfaces do so by exporting 4 functions:
DllGetClassObject => Return a class factory of a requested interface
DllCanUnloadNow => Whether all instances handed out have since been released
DllRegisterServer => Register the types this DLL supplies in the registry
DllUnregisterServer => Unregister this DLL and its types from the registry
So to answer your questions:
Q1. About Windows DLL Based on my understanding, a Windows DLL can export functions,
types(classes) and global variables. Is this understanding all right?
DLLs can export functions and classes (not sure about global variables, but you don't want to be exporting them DLLs even if you can! :-) ) However, exported classes will be name mangled and hence only usable by other DLLs or EXEs that happen to have the same name mangling (not a good way to do business). Functions with C-style calling convention are not name mangled and hence can be exported and called from elsewhere without problems.
Q2. A COM DLL exports both functions such as DllRegisterServer() and DllGetClassObject(),
and also the Classes which implements the IUnknown interface. Is this understanding all
right?
Halfway, there are 4 functions to export to be a full COM compliant DLL (shown above). You can search MSDN for any of those names to see the full signatures fro them. Your implementation for DllGetClassObject is going to be the main one which outside parties will use. They can use that to get an IClassFactory to an interface your DLL provides, and then use that to create an instance.
COM is a large and complicated beast, but its foundations are fairly straightforward. You can also check out this link COM Intro for some more info. Good luck!
To add on to cpalmer's nice answer, there's no particular reason why you need to use the registry and the four recommended functions to export COM from your DLL.
You could use a registry-free COM, or COM-lite approach, where you simply export factory methods, such as
__declspec(dllexport) void MyDllCreateFoo(IFoo ** ppFoo);
DLL users would call your factory to create your class CMyFoo which implements IFoo. What DllRegisterServer et. al. do is allow CMyFoo and other classes to be looked up in the registry, among other things.
Q3: You are correct in fact, if not in spirit. .def files and .idl files are pretty different beasts. .def files are used by the linker only, and aren't even necessary - you can export all the functions you want using
__declspec(dllexport) void foo() {
}
inside your C++ code.
.idl files are used to generate C++ headers (.h files) which are included both by the DLL as well as its clients. It generates the interfaces plus some glue code that does things like parameter mashalling.
Again, you don't techincally need to use IDL to use COM, but it can make things more convenient.
The reason I'm breaking it down like this is to illustrate that COM is not a big monolithic thing, but rather a really small thing with a bunch of stuff built up around it that you could opt to use, or not, to taste.
You have it all exactly right so far. The only bit I would clarify is "the Classes which implements the IUnknown interface." A class is represented by an object that implements the IClassFactory interface. You can get such a class factory by calling DllGetClassObject in a DLL, and then you can ask the class factory to make an object of the class. This is similar to many other object-oriented systems: there is a variety of objects that represent classes and which can be used to manufacture instances.
Other useful facts about COM:
There is a small but complicated library of helper functions, mostly named with the prefix Co. It is these which actually load the DLLs, locate the exported functions and call them. Client code would not normally call the DLL exports directly (although it is a fairly straightforward matter to write your own hosting system for simple in-process COM objects).
There is an important interface IDispatch which adds another layer of abstraction such that it is possible to dynamically identify methods to call on the object, using a string to find the method and passing an array of argument values. This allows scripting languages to call COM objects safely (i.e. in a way that tolerates mistakes by the programmer instead of crashing).
There is a more complex "marshalling" system for allowing objects to be called from other threads, other processes or even other computers; in its remote (and security-aware) for form it was called DCOM. It did not succeed on anything like the scale that other COM usages did.
The cross-process support was the basis of OLE2, a gimmick that every application rushed to support in the early 1990s, most of them implementing the (very complicated) interfaces wrongly and so crashing all over the place.
Far more successful were OLE Controls, which were technically a lot simpler (not using the marshalling) and which offered a way to extend Visual Basic.
There is at least one widely distributed COM-inspired system that is not compatible with COM but shares exactly the same concepts (at least the simple stuff), which is called XPCOM and is the basis of the Mozilla Firefox Web browser.
If you use COM pervasively, you will have a great way to integrate with the .NET framework, as it includes superb interoperability with COM. But you must follow the rules of COM precisely: AddRef/Release must work exactly as defined, so an object must never be destroyed while its reference count is greater than zero, it must be possible to use QueryInterface to find IUnknown from any interface, and from there to get back to the original interface, the IUnknown obtained from any interface must always have the same memory address for the lifetime of the object (so it can be used for identity comparison). So for example: don't create COM objects on the stack, and don't return separate objects from QueryInterface (that is, objects that have their own QueryInterface that returns different interfaces).
A major gotcha with COM is that it has at least two standard ways of representing strings. Neither uses reference counting. Why they never defined an IString interface is beyond me, but they didn't.
You'll go insane if you try to write COM code without smart pointers to hold references, or without a base class to help you implement interfaces, e.g. class MyClass : COM::Object<IThis, IThat> {...)