Windows NT Systems Programming: Spring 2000

[ Home | Syllabus | Course Notes | Assignments | Search]


Distributed Objects


Different Models of Distribution

c7f2.gif (7959 bytes)


Issues


CORBA

Common Object Request Broker Architecture (specification)

 


Java Distributed Objects


COM   


Historical Perspective


OLE 1.0


OLE 2.0


OLE Controls (OCXs)


32 bit OLE/COM/ActiveX


COM basics

 


IUnknown

HRESULT QueryInterface(REFIID iid, void** ppvObject);
ULONG AddRef(void);
ULONG Release(void);

Identifiers


Using COM


COM Servers

dcom.gif (32122 bytes)


Some Definitions

interface:
a set of semantically related methods (function calls). Can be used to provide access to the public member functions of an object. A COM interface is implemented as a C++ V-table (in C++ programs) However the COM interface is language independent.
virtual function:
a function that can be redefined in a derived class and which can be dynamically bound to any object in the inheritance hierarchy. Thus a pointer to the base class could point to any object of a derived class and any function referenced by that pointer is dynamically bound to the function of the correct derived class. This ability of a function to be dynamically bound permits polymorphism.
pure virtual function:
A virtual function is undefined in the base class and must be defined in any derived class. This allows a abstract base class to place requirements on any inherited object class.
polymorphism:
The ability of a function in a program to work with any object in an inheritance chain without recompilation. This implies that the run-time system must be able to find the address of the function based on the type of the object at the time the function is invoked (dynamic or late binding).
v-table:
a table containing the address of virtual functions. A v-table is associated with each class.
component:
set of (possibly) related COM classes. Housed either in a DLL (Dynamically Linked Library) or an executable file.
idl (interface definition language):
langauge independent/ platform independent means of specifiying a function's prototype. Adapted from Open Software Foundation (OSF) RPC standard.
 

Let's develop a simple COM class, exploring the problems and solutions to them.

An Example: Chapter 2.

Project: write a simple COM object with one function which takes as input two integers and returns their sum (this very simple object has no state).
We want this object to be language independent and location independent (distributed).

PROBLEM: how to specify a language independent header file.
SOLUTION: Use IDL. The IDL file is compiled into language dependent code by MIDL (Microsoft's IDL compiler)

rainbow.gif (2243 bytes)

// component.idl
import "unknwn.idl";

[ object, uuid(10000001-0000-0000-0000-000000000001) ]
interface ISum : IUnknown
{
	HRESULT Sum([in] int x, [in] int y, [out, retval] int* retval);
};
rainbow.gif (2243 bytes)

 


Compiling the IDL will the language dependent files:

rainbow.gif (2243 bytes)

/* this ALWAYS GENERATED file contains the definitions for the interfaces */


/* File created by MIDL compiler version 3.01.75 */
/* at Sun Jan 17 11:56:28 1999
 */
/* Compiler settings for ..\component.idl:
    Os (OptLev=s), W1, Zp8, env=Win32, ms_ext, c_ext
    error checks: none
*/
//@@MIDL_FILE_HEADING(  )
#include "rpc.h"
#include "rpcndr.h"
#ifndef COM_NO_WINDOWS_H
#include "windows.h"
#include "ole2.h"
#endif /*COM_NO_WINDOWS_H*/

#ifndef __component_h__
#define __component_h__

#ifdef __cplusplus
extern "C"{
#endif 

/* Forward Declarations */ 

#ifndef __ISum_FWD_DEFINED__
#define __ISum_FWD_DEFINED__
typedef interface ISum ISum;
#endif 	/* __ISum_FWD_DEFINED__ */


/* header files for imported files */
#include "unknwn.h"

void __RPC_FAR * __RPC_USER MIDL_user_allocate(size_t);
void __RPC_USER MIDL_user_free( void __RPC_FAR * ); 

#ifndef __ISum_INTERFACE_DEFINED__
#define __ISum_INTERFACE_DEFINED__

/****************************************
 * Generated header for interface: ISum
 * at Sun Jan 17 11:56:28 1999
 * using MIDL 3.01.75
 ****************************************/
/* [uuid][object] */ 



EXTERN_C const IID IID_ISum;

#if defined(__cplusplus) && !defined(CINTERFACE)
    
    interface DECLSPEC_UUID("10000001-0000-0000-0000-000000000001")
    ISum : public IUnknown
    {
    public:
        virtual HRESULT STDMETHODCALLTYPE Sum( 
            /* [in] */ int x,
            /* [in] */ int y,
            /* [retval][out] */ int __RPC_FAR *retval) = 0;
        
    };
    
#else 	/* C style interface */

    typedef struct ISumVtbl
    {
        BEGIN_INTERFACE
        
        HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )( 
            ISum __RPC_FAR * This,
            /* [in] */ REFIID riid,
            /* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject);
        
        ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )( 
            ISum __RPC_FAR * This);
        
        ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )( 
            ISum __RPC_FAR * This);
        
        HRESULT ( STDMETHODCALLTYPE __RPC_FAR *Sum )( 
            ISum __RPC_FAR * This,
            /* [in] */ int x,
            /* [in] */ int y,
            /* [retval][out] */ int __RPC_FAR *retval);
        
        END_INTERFACE
    } ISumVtbl;

    interface ISum
    {
        CONST_VTBL struct ISumVtbl __RPC_FAR *lpVtbl;
    };

    

#ifdef COBJMACROS


#define ISum_QueryInterface(This,riid,ppvObject)	\
    (This)->lpVtbl -> QueryInterface(This,riid,ppvObject)

#define ISum_AddRef(This)	\
    (This)->lpVtbl -> AddRef(This)

#define ISum_Release(This)	\
    (This)->lpVtbl -> Release(This)


#define ISum_Sum(This,x,y,retval)	\
    (This)->lpVtbl -> Sum(This,x,y,retval)

#endif /* COBJMACROS */


#endif 	/* C style interface */



HRESULT STDMETHODCALLTYPE ISum_Sum_Proxy( 
    ISum __RPC_FAR * This,
    /* [in] */ int x,
    /* [in] */ int y,
    /* [retval][out] */ int __RPC_FAR *retval);


void __RPC_STUB ISum_Sum_Stub(
    IRpcStubBuffer *This,
    IRpcChannelBuffer *_pRpcChannelBuffer,
    PRPC_MESSAGE _pRpcMessage,
    DWORD *_pdwStubPhase);



#endif 	/* __ISum_INTERFACE_DEFINED__ */


/* Additional Prototypes for ALL interfaces */

/* end of Additional Prototypes */

#ifdef __cplusplus
}
#endif

#endif

rainbow.gif (2243 bytes)


Now let's see how a client can access this  COM object:

PROBLEM: Creating an object in a language independent manner
SOLUTION: CoCreateInstance

PROBLEM: Returning an interface to the COM Object (like attaching a v-table)
SOLUTION: QueryInterface Method

PROBLEM: managing a shared interface's lifetime
SOLUTION: AddRef and Release Methods

rainbow.gif (2243 bytes)

// client.cpp
#include <iostream.h>
#include "Component with Registration\component.h" // Generated by MIDL

// {10000002-0000-0000-0000-000000000001}
const CLSID CLSID_InsideDCOM = {0x10000002,0x0000,0x0000,{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01}};

void main()
{
	cout << "Client: Calling CoInitialize()" << endl;
	HRESULT hr = CoInitialize(NULL);
	if(FAILED(hr))
		cout << "CoInitialize failed" << endl;
	
	IUnknown* pUnknown;
	ISum* pSum;

	cout << "Client: Calling CoCreateInstance()" << endl;
	hr = CoCreateInstance(CLSID_InsideDCOM, NULL, CLSCTX_INPROC_SERVER, IID_IUnknown, (void**)&pUnknown);
	if(FAILED(hr))
		cout << "CoCreateInstance failed" << endl;

	cout << "Client: Calling QueryInterface() for ISum on " << pUnknown << endl;
	hr = pUnknown->QueryInterface(IID_ISum, (void**)&pSum); 
           // missing reference operator could crash the appliation
	if(FAILED(hr))
		cout << "IID_ISum not supported" << endl;

	hr = pUnknown->Release();
	cout << "Client: Calling pUnknown->Release() reference count = " << hr << endl;

	int sum;
	hr = pSum->Sum(2, 3, &sum);
	if(SUCCEEDED(hr))
		cout << "Client: Calling Sum(2, 3) = " << sum << endl;

	hr = pSum->Release();
	cout << "Client: Calling pSum->Release() reference count = " << hr << endl;

	cout << "Client: Calling CoUninitialize()" << endl;
	CoUninitialize();
}

 

rainbow.gif (2243 bytes)


 


Copyright chris wild 1999/2000.
For problems or questions regarding this web contact [Dr. Wild].
Last updated: March 14, 2000.