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:
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:
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).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).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).IString
interface is beyond me, but they didn't.class MyClass : COM::Object<IThis, IThat> {...
)If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With