Windows Systems Programming: Spring 2002

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


Automation


IDispatch

IDispatch is a universal COM interface that can be used to call other Automation compliant COM interfaces.
It contains the following methods:


Variants

UNION: (a structure that can contain one a several types over time – but only one of these types at a time)

 

        struct  __tagVARIANT

            {

            VARTYPE vt; // enumeration variable telling which type in the union is active

            union

                {

                LONG lVal;

                BYTE bVal;

                SHORT iVal;

                FLOAT fltVal;

                DOUBLE dblVal;

                VARIANT_BOOL boolVal;

                _VARIANT_BOOL bool;

                SCODE scode;

                CY cyVal;

                DATE date;

                BSTR bstrVal; // important – basic String

                IUnknown __RPC_FAR *punkVal;

                IDispatch __RPC_FAR *pdispVal;

                SAFEARRAY __RPC_FAR *parray; // an array that knows its limitations

                BYTE __RPC_FAR *pbVal;

                SHORT __RPC_FAR *piVal;

                LONG __RPC_FAR *plVal;

                FLOAT __RPC_FAR *pfltVal;

                DOUBLE __RPC_FAR *pdblVal;

                VARIANT_BOOL __RPC_FAR *pboolVal;

                _VARIANT_BOOL __RPC_FAR *pbool;

                SCODE __RPC_FAR *pscode;

                CY __RPC_FAR *pcyVal;

                DATE __RPC_FAR *pdate;

                BSTR __RPC_FAR *pbstrVal;

                IUnknown __RPC_FAR *__RPC_FAR *ppunkVal;

                IDispatch __RPC_FAR *__RPC_FAR *ppdispVal;

                SAFEARRAY __RPC_FAR *__RPC_FAR *pparray;

                VARIANT __RPC_FAR *pvarVal;

                PVOID byref;

                CHAR cVal;

                USHORT uiVal;

                ULONG ulVal;

                INT intVal;

                UINT uintVal;

                DECIMAL __RPC_FAR *pdecVal;

                CHAR __RPC_FAR *pcVal;

                USHORT __RPC_FAR *puiVal;

                ULONG __RPC_FAR *pulVal;

                INT __RPC_FAR *pintVal;

                UINT __RPC_FAR *puintVal;

                struct  __tagBRECORD

                    {

                    PVOID pvRecord;

                    IRecordInfo __RPC_FAR *pRecInfo;

                    }  __VARIANT_NAME_4;

                }      __VARIANT_NAME_3;

            };

 

Strings

Basic String (BSTR) uses 16 bit “wide” Characters, has string length at the beginning and can have multiple NULLs

 

MFC has COleVariant and Cstring is compatible with BSTR

            CloeVariant var(“some string”);

 

ATL has CcomVariant and CcomBstr

 

Native support includes class “_variant_t” and “_bstr_t”

 

 

Dual Interfaces

Supports both Automation (language independent) and v-table (efficient)

Default with C++ wizards

 

Early-binding to objects uses the V-table interface (checking at compile-time)

Late-binding to objects uses the Idispatch interface (checking at run-time)

 

In Visual Basic

 

‘ Late Bound

Private mLateBound As Object

Set mLateBound = CreateObject("Financialcomponent.TimeValue")

txtLoanAmount.Text = mLateBound.loanAmount(CInt(txtNumMonths.Text), CDbl(txtPayment.Text))

 

‘ Early Bound

‘ import type library from server

Private mEarlyBound As TimeValue

Set mEarlyBound = New TimeValue

txtLoanAmount.Text = mEarlyBound.loanAmount(CInt(txtNumMonths.Text), CDbl(txtPayment.Text))

 

In Visual C++

 

Three choices

  1. MFC can generate a ColeDispatchDriver wrapper class
  2. Use Native Com support in visual C++ and the import keyword
  3. Call the IDispatch interface directly (Complex and rarely used)

 

 

Dual Interface COM Server (ATL)

// financialcomponent.idl : IDL source for financialcomponent.dll

//

 

// This file will be processed by the MIDL tool to

// produce the type library (financialcomponent.tlb) and marshalling code.

 

import "oaidl.idl";

import "ocidl.idl";

            [

                        object,

                        uuid(EB47FA0D-22EE-11D3-998A-E0EC08C10000),

                        dual,

                        helpstring("ITimeValue Interface"),

                        pointer_default(unique)

            ]

            interface ITimeValue : IDispatch

            {

                        [propget, id(1), helpstring("property InterestRate")] HRESULT InterestRate([out, retval] double *pVal);

                        [propput, id(1), helpstring("property InterestRate")] HRESULT InterestRate([in] double newVal);

                        [id(2), helpstring("method MonthlyPayment")] HRESULT MonthlyPayment([in] short numMonths,[in] double loanAmount, [out,retval] double *result);

                        [id(3), helpstring("method LoanAmount")] HRESULT LoanAmount([in] short numMonths,[in] double monthlyPayment,[out,retval] double * loanAmount);

            };

 

            [

                        object,

                        uuid(1C208680-22F2-11d3-998A-E0EC08C10000),

                        dual,

                        helpstring("ITaxCalculator Interface"),

                        pointer_default(unique)

            ]

            interface ITaxCalculator : IDispatch

            {

                        [id(1), helpstring("method CalculateTax")] HRESULT CalculateTax([in] double earnings,[out,retval] double *tax);

            };

 

[

            uuid(EB47FA01-22EE-11D3-998A-E0EC08C10000),

            version(1.0),

            helpstring("financialcomponent 1.0 Type Library")

]

library FINANCIALCOMPONENTLib

{

            importlib("stdole32.tlb");

            importlib("stdole2.tlb");

 

            [

                        uuid(EB47FA0E-22EE-11D3-998A-E0EC08C10000),

                        helpstring("TimeValue Class")

            ]

            coclass TimeValue // two interface

            {

                        [default] interface ITimeValue;

                        interface ITaxCalculator;

            };

};

 

// TimeValue.h : Declaration of the CTimeValue

 

#ifndef __TIMEVALUE_H_

#define __TIMEVALUE_H_

 

#include "resource.h"       // main symbols

 

/////////////////////////////////////////////////////////////////////////////

// CTimeValue

class ATL_NO_VTABLE CTimeValue :

            public CComObjectRootEx<CComSingleThreadModel>,

            public CComCoClass<CTimeValue, &CLSID_TimeValue>,

            public ISupportErrorInfo,

            public IDispatchImpl<ITimeValue, &IID_ITimeValue, &LIBID_FINANCIALCOMPONENTLib>,

            public IDispatchImpl<ITaxCalculator, &IID_ITaxCalculator, &LIBID_FINANCIALCOMPONENTLib>

{

public:

            CTimeValue()

            {

                        mInterestRate=8.0;

            }

 

DECLARE_REGISTRY_RESOURCEID(IDR_TIMEVALUE)

 

DECLARE_PROTECT_FINAL_CONSTRUCT()

 

BEGIN_COM_MAP(CTimeValue)

            COM_INTERFACE_ENTRY(ITimeValue)

//DEL   COM_INTERFACE_ENTRY(IDispatch)

            COM_INTERFACE_ENTRY(ISupportErrorInfo)

            COM_INTERFACE_ENTRY2(IDispatch, ITimeValue)

            COM_INTERFACE_ENTRY(ITaxCalculator)

END_COM_MAP()

 

// ISupportsErrorInfo

            STDMETHOD(InterfaceSupportsErrorInfo)(REFIID riid);

 

// ITimeValue

public:

            STDMETHOD(CalculateTax)(/*[in]*/ double earnings,/*[out,retval]*/ double *tax);

            STDMETHOD(LoanAmount)(/*[in]*/ short numMonths,/*[in]*/ double monthlyPayment,/*[out,retval]*/ double * loanAmount);

            STDMETHOD(MonthlyPayment)(/*[in]*/ short numMonths,/*[in]*/ double loanAmount, /*[out,retval]*/ double *result);

            STDMETHOD(get_InterestRate)(/*[out, retval]*/ double *pVal);

            STDMETHOD(put_InterestRate)(/*[in]*/ double newVal);

// ITaxCalculator

private:

            double mInterestRate;

};

 

#endif //__TIMEVALUE_H_

 

 

Visual Basic Client

 

Option Explicit

Private Declare Function GetTickCount& Lib “Kernel32” ()

Private mLateBound As Object

Private mEarlyBound As TimeValue

Private mElapsedTime As Long

 

Private Sub cmdCalculateLoanAmount_Click()

    On Error GoTo errHandler

    Dim lngSavedTime As Long

    Dim intTimesToCall As Integer

    Dim I As Integer

   

    MEarlyBound.InterestRate = CDbl(txtInterestRate.Text) ‘ instead of calling put-method

    lngSavedTime = GetTickCount()

' Call the method multiple times so you can see the difference between

' early and late bound calls

    For i = 1 To CInt(txtTimesToCall)

        txtLoanAmount.Text = mEarlyBound.loanAmount(CInt(txtNumMonths.Text), CDbl(txtPayment.Text))

    Next

    lblEarlyElapsedTime.Caption = GetTickCount() - lngSavedTime

   

    mLateBound.InterestRate = CDbl(txtInterestRate.Text)

    lngSavedTime = GetTickCount()

    For i = 1 To CInt(txtTimesToCall)

        txtLoanAmount.Text = mLateBound.loanAmount(CInt(txtNumMonths.Text), CDbl(txtPayment.Text))

    Next

    lblLateElapsedTime.Caption = GetTickCount() - lngSavedTime

    Exit Sub

errHandler:

    If Err.Number = 13 Then

        MsgBox ("You must enter a valid payment amount, # of months, and APR")

    Else

        MsgBox (Err.Description)

    End If

End Sub

 

 

Private Sub Form_Load()

    On Error GoTo errHandler

    txtTimesToCall = 1000

    txtInterestRate = 8#

    txtNumMonths = 60

    Set mLateBound = CreateObject("Financialcomponent.TimeValue") ‘ create instance of COM object

    Set mEarlyBound = New TimeValue

    Exit Sub

errHandler:

    MsgBox (Err.Description)

End Sub

 

Private Sub Form_Terminate()

    Set mEarlyBound = Nothing ‘ release COM object

    Set mLateBound = Nothing

End Sub

 

 

 

 




Copyright chris wild 1999-2002.
For problems or questions regarding this web contact [Dr. Wild].
Last updated: March 27, 2002.