from
http://progtutorials.tripod.com/COM.htm
- Service Control Manager (SCM)
- Interface IUnknown
- Global Unique ID (GUID)
- OLE/COM Object Viewer
- System Registry
- DLL server's entries in System Registry
- EXE server's entries in System Registry
1 Service Control Manager (SCM)
A Windows program called Service Control Manager (SCM) does most of the job in COM server invoking. It finds the server through System Registry, runs it, has it create the COM object, sets up local/remote transparency, and returns an interface pointer to the client.
Then the client can directly invoke methods of the COM object through the pointer, and there is no middleware involved unless it is a remote server, in which case only RPC is involved.
2 Interface IUnknown
All COM interfaces should inherit interface IUnknown:
interface IUnknown
{
HRESULT QueryInterface(REFIID iid, void** ppvObject);
ULONG AddRef();
ULONG Release();
} One COM object may be used by multiple clients. The COM server maintains a reference count for each interface of the object. When one client asks to create an instance of the interface with CoCreateInstance or CoCreateInstanceEx, the COM server will call that interface¡¯s method AddRef to increment the reference count.
When one client is finished with an interface, it should call its Release method to decrement the reference count. When the count reaches zero, the COM server should destroy the COM object.
In Visual Basic, a local COM object is automatically destroyed when leaving scope. To manually delete an object, say
Set objAccount = Nothing
3 Global Unique ID (GUID)
Each coclass and interface has its guid, which is a 128-bit number. For easy use by the programmer, an easy-remember manifest constant is defined for each guid. In Visual C++ these constants are defined in a header file e.g. ¡°Bank_i.c¡±, and some entries look like:
const IID IID_IGreet = {0x7A5E6E81,0x3DF8,0x11D3,{0x90,0x3D,0x00,0x10,0x5A,0xA4,0x5B,0xDC}};
const IID LIBID_BANKLib = {0x0FFBDAA1,0xFCA7,0x11D2,{0x8F,0xF4,0x00,0x10,0x5A,0xA4,0x5B,0xDC}};
const CLSID CLSID_Account = {0x0FFBDAAE,0xFCA7,0x11D2,{0x8F,0xF4,0x00,0x10,0x5A,0xA4,0x5B,0xDC}}; GUID constants such as IID_IGreet and CLSID_Account are not globally unique, but it does not matter because they live only in the scope of one application program. The compiler will read the interface definition file to convert the constant to the corresponding guid.
GUIDs for classes are of type CLSID, and all variables start with ¡°CLSID_¡± followed by the class name, such as ¡°CLSID_Account¡±. GUIDs for interfaces are of type IID, and all start with ¡°IID_¡± followed by the interface name such as ¡°IID_IAccount¡±.
To convert between CLSID and unicode array:
CLSID clsid;
...
WCHAR * ostr;
HRESULT hr = StringFromCLSID(clsid, &ostr);
Program ¡°Microsoft Visual Studio\Common\Tools\Guidgen.exe¡± is used to generate a guid. Choose the format of the guid and press button ¡°Copy¡±. The generated guid will be in the clipboard.
You can also add it to the ¡°Tools¡± menu with menu ¡°Tools | Customize | Tools¡±.
4 OLE/COM Object Viewer
OLE/COM Object Viewer goes through System Registry and collects all info about each coclass and their interfaces, and put them under one entry as their ¡°user names¡±, which is the help string in the IDL file. You can find this entry under ¡°All Objects¡± entry.
The ¡°user name¡± entry stores the info about the coclass itself. Under it there are entries for all the interfaces of this class. Each entry stores the info about a specific interface.
OLD/COM Object Viewer can be started both from the ¡°Start¡± menu and from Visual C++ menu ¡°Tools¡±.
5 System Registry
System Registry contains information about the computer. Under its ¡°HKEY_CLASSES_ROOT¡± entry, all information about a coclass is stored. Under this entry, all coclasses are listed by their ProgIDs. Among the countless ProgID entries, there are two other entries: one named CLSID, under which all coclasses are listed by their guids; the other named Interface, under which all interfaces are listed by their guids.
ProgIDs are not guaranteed to be unique. They are used by some languages that can not directly refer to guids such as VBScript. VB can directly refer to guids, and can also optionally use ProgIDs. COM library provides to functions which can go through the System Registry and convert a ProgID to a CLSID or vice versa:
CLSID clsid;
CLSIDFromProgID(L"Cars.Jeep.1", &clsid);
LPOLESTR progid;
ProgIDFromCLSID(clsid, &progid);
We also need an entry to store some attributes about the whole server. For each server we can assign an AppID, under which we store all those atttributes such as AccessPermission, AuthenticationLevel, DllSurogate, LunchPermissions, RemoteServerName, etc. Then under each coclass entry under HKCR\CLSID, we add an AppID entry containing the AppID of the server.
When a coclass in invoked, the SCM reads the CLSID entry under HKCR\CLSID. If it finds an AppID entry, it will go further to find the AppID entry under HKCR\AppID. There it reads more about the server and knows how to deal with the server. For example, if SCM finds RemoteServerName entry there containing the name of another computer, it knows that the server is located oin another computer and it should contact the SCM of that computer.
When you call COM library functions such as CoCreateInstance passing a guid constant such as "CLSID_CoCar" or "IID_IRegistration", the compiler converts the guid contstant to the real guid by looking up the guid definition file *_i.c. At run time the real guid is sent to the API function.
5.1 DLL server's entries in System Registry
A DLL server should have the following basic entries in the System Registry:
HKEY_CLASSES_ROOT\<ProgID>\CLSID = <clsid>
HKEY_CLASSES_ROOT\CLSID\<clsid> = <ProgID>
HKEY_CLASSES_ROOT\CLSID\<clsid>\InprocServer32 = <server full path>
You do not have to register your type library, for VC can directly #import from any directory, and VB and J++ can browse to find a *.tlb file. However, if you want to do it, you should add the following type library entries:
HKEY_CLASSES_ROOT\CLSID\<clsid>\TypeLib = <libid>
HKEY_CLASSES_ROOT\TypeLib\<libid> = <type library help string>
HKEY_CLASSES_ROOT\TypeLib\<libid>\1.0\0\Win32 = <type library full path>
HKEY_CLASSES_ROOT\TypeLib\<libid>\1.0\FLAGS = 0
HKEY_CLASSES_ROOT\TypeLib\<libid>\1.0\HELPDIR
When client calls CoCreateInstance with a CLSID and a IID, the COM run time will:
- go to the HKCR\CLSID\<guid>\InProcServer32 entry to find the location of the DLL server.
- load the DLL into process, call its exported DllGetClassObject function passing the coclass guid to get an IClassFactory pointer of the corresponding class factory;
- call the IClassFactory's CreateInstance method passing the IID of the interface to get a pointer of the interface.
You can see in the above process that the guids of the interfaces are only used inside the class factory. There is no need to store an entry for an interface in the System Registry.
5.2 EXE server's entries in System Registry
A EXE server should have similar basic entries as a DLL server except it is LocalServer32:
HKEY_CLASSES_ROOT\<ProgID>\CLSID = <clsid>
HKEY_CLASSES_ROOT\CLSID\<clsid> = <ProgID>
HKEY_CLASSES_ROOT\CLSID\<clsid>\LocalServer32 = <server full path>
Besides these, it should have the following entries for each interface:
HKEY_CLASSES_ROOT\Interface\<iid>
HKEY_CLASSES_ROOT\Interface\ProxyStubClsid = <proxy/stub dll clsid>
HKEY_CLASSES_ROOT\Interface\ProxyStubClsid32 = <proxy/stub dll clsid>
If you use universal marshaller oleaut32.dll, which reads the registered type library and creates proxy/stub classes on the fly, you should put the CLSID of oleaut32.dll under ProxyStubClsid32, add the following interface entry, plus all the type library entries:
HKEY_CLASSES_ROOT\Interface\TypeLib = <type library libid>
For each interface you invoke, one proxy/stub object is instantiated. Therefore, you must set up a correspondence between an interface and its proxy/stub DLL server, so that when client invoke an interface, the SCM can find the corresponding proxy/stub DLL and create the corresponding proxy/stub object from it.
For this purpose, the System Registry stores the guids of the all interfaces of an EXE server under entry HKCR\Interface. Under each interface guid entry there is a ProxyStubClsid32 entry, which stores the CLSID of the custom proxy/stub DLL server which contains the proxy/stub coclass for that interface, or the universal marshaller oleaut32.dll.
Therefore, if you use the type library marshalling, you must register the type library under HKCR\TypeLib entry and each interface entry.
System Registry editor can be started at command line by typing ¡°regedit¡±, or from OLE/COM Object Viewer in Visual C++.
SeriousMoin v1 (koMoinMoin 1.0a4 Modified)