This article provides a fully-usedC ++Implemented in-process DLL) COM server, do not provide any support by ATL or MFC. Writing COM objects in this way can give you a deep insight into the methods used by COM to process servers in the process and how COM creates a class factory. Using the simple framework provided in this article, you can implement basic COM components, such as Shell extension Shell Extensions.
The following are the steps to compile your own COM object in the method described in this article:
Step 1: Write a header file that contains the following content:
1. include the file comdef. h: # include <comdef. h>.
2. Define the GUID of the COM server.
- _declspec(selectany) GUID CLSID_Mine = { 0xdc186800,
- 0x657f,
- 0x11d4,
- {0xb0, 0xb5, 0x0, 0x50, 0xba, 0xbf, 0xc9, 0x4}
- };
3. Provide the IID of the interface and the method definition to be implemented for this interface. Then the client will use the IID and method of this interface.
- interface __declspec(uuid("F614FB00-6702-11d4-B0B7-0050BABFC904")) ImyInterface : public IUnknown
- {
- STDMETHOD(Square)(long *pVal)PURE;
- STDMETHOD(Cube)(long *pVal)PURE;
- };
The client uses this interface:
- HRESULT hr;
- ImyInterface * pmine = (0 );
- Hr = CoCreateInstance (CLSID_Mine, // CLSID of the COM Server
- NULL, // does not support Aggregation
- CLSCTX_INPROC_SERVER, // is a DLL
- _ Uuidof (ImyInterface), // The IID OF THE INTERFACE
- (Void **) & pmine
- );
Another way is to obtain the CLSID of the COM object from the registry, that is, call the CLSIDFromProgId () function, but you must pass the ProgId of the component to this function.
Step 2: You must provide implementation for the defined interface. The method used in this article is to create a new class inherited from the interface:
- // This class implements a single interface ImyInterface...
- //
- //
- Class CmyInterface: public CComBase <>,
- Public InterfaceImpl <ImyInterface>
- {
- Public:
- CmyInterface ();
- Virtual ~ CmyInterface ();
- // We must write code for QueryInterface
- STDMETHOD (QueryInterface) (REFIID riid, LPVOID * GMM );
- // ImyInterface Interface Method
- STDMETHOD (Square) (long * pVal );
- STDMETHOD (Cube) (long * pVal );
- };
The template class InterfaceImpl <> provides the implementation of interface reference count. Here we can use multi-interface inheritance to implement multiple interfaces in a COM component.
Step 3: before completing this object, we also need to write Queryinterface and two interface methods:
- STDMETHODIMP CmyInterface: QueryInterface (REFIID riid, LPVOID * bp)
- {
- * GMM = NULL;
- If (IsEqualIID (riid, IID_IUnknown) | IsEqualIID (riid ,__ uuidof (ImyInterface )))
- {
- // Force type conversion is required because we inherit from ImyInterface
- * GMM = (ImyInterface *) this;
-
- _ AddRef (); // This method is inherited from a base class.
- Return S_ OK;
- }
- Return E_NOINTERFACE;
- }
-
- STDMETHODIMP CmyInterface: Square (long * pVal)
- {
- Long value = * pVal;
- * PVal = value * value;
- Return S_ OK;
- }
-
- STDMETHODIMP CmyInterface: Cube (long * pVal)
- {
- Long value = * pVal;
- * PVal = value * value;
- Return S_ OK;
- }
Note that _ uuidof (ImyInterface) is used to obtain the IID of the interface, because we have associated this interface with a uuid in the first step.
Last step: the DLLs of the COM component must output a function called DllGetClassObject. This function creates a class factory for CmyInterface and returns a reference to it. Then we call CoCreateInstance to create a class factory for COM in the process, and then call DllGetClassObject. A method of this class factory is CreateInstance, which creates an object and returns a reference to it.
- STDAPI DllGetClassObject (REFCLSID rclsid, REFIID riid, LPVOID * ppvOut)
- {
- * PpvOut = NULL;
- If (IsEqualIID (rclsid, CLSID_Mine ))
- {
- // Declare a factory for the CmyInterface class
- CClassFactory <CmyInterface>
- * Pcf = new CClassFactory <CmyInterface>;
- Return pcf-> QueryInterface (riid, ppvOut );
- }
- Return CLASS_E_CLASSNOTAVAILABLE;
- }
Check whether the requested CLSID is CLSID_Mine. If not, an error code is returned.
You may ask where to create the actual CmyInterface class object. In fact, this is handled by the template instance of CClassFactory <CmyInterface>. The following is the implementation of CClassFatory:
- // CSingleCreator is used for a single instance class factory. This class returns the same object pointer for multiple CreateObject requests ..
- Template <class comObj>
- Class CSingleCreator
- {
- Protected:
- CSingleCreator (): m_pObj (0 ){};
- ComObj * CreateObject ()
- {
- If (! M_pObj)
- {
- M_pObj = new comObj;
- }
- Return m_pObj;
- }
- ComObj * m_pObj;
- };
- // CMultiCreator is used in common class factories. This class returns a new object pointer for each CreateObject request ..
- Template <class comObj>
- Class CMultiCreator
- {
- Protected:
- CMultiCreator (): m_pObj (0 ){};
- ComObj * CreateObject ()
- {
- Return new comObj;
- }
- ComObj * m_pObj;
- };
- // ClassFactory class implementation
- // MultiCreator is the default class factory creator.
- // This class implements the interface IclasFactory ......
-
- Class CClassFactory: public CComBase <>,
- Public InterfaceImpl <IClassFactory>,
- Public creatorClass
- {
- Public:
- CClassFactory (){};
- Virtual ~ CClassFactory (){};
-
- STDMETHOD (QueryInterface) (REFIID riid, LPVOID * GMM)
- {
- * GMM = NULL;
- If (IsEqualIID (riid, IID_IUnknown) | IsEqualIID (riid, IID_IClassFactory ))
- {
- * GMM = (IClassFactory *) this;
- _ AddRef ();
- Return S_ OK;
- }
- Return E_NOINTERFACE;
- }
-
- STDMETHODIMP CreateInstance (LPUNKNOWN pUnkOuter, REFIID riid, LPVOID * ppvObj)
- {
- * PpvObj = NULL;
- If (pUnkOuter)
- Return CLASS_E_NOAGGREGATION;
- M_pObj = CreateObject (); // m_pObj is defined in creatorClass
- If (! M_pObj)
- Return E_OUTOFMEMORY;
- HRESULT hr = m_pObj-> QueryInterface (riid, ppvObj );
- If (hr! = S_ OK)
- {
- Delete m_pObj;
- }
- Return hr;
- }
- STDMETHODIMP LockServer (BOOL) {return S_ OK;} // not implemented
- };
COM calls CreateInstance to create the requested object. The riid parameter refers to the requested interface IID. If this object supports this interface, it will increase its reference count and return its reference to itself.
Code: the method proposed in this article is to use pure C ++ to compile a big concept of COM components. Many details are omitted. From the text and code in this article, we can see what needs to be done to write COM components in pure C ++. If you want to write COM components in this way, these codes can only be used as a reference, the specific implementation can be further implemented on this basis.