[ Home | Syllabus | Course Notes | Assignments | Search]
Consider information in the type library can be read to construct a table of function calls on that COM object.
Each function in that table can be assigned an "id" that can be used to call that function
Since the type library also contains the parameter list, you could set up the function calling stack with the required parameters.
Accessing a data member (property) is a call to a get/set function for that data member
IDispatch is a universal COM interface that can be used to
call other Automation compliant COM interfaces.
It contains the following methods:
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;
};
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”
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)
‘ 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))
Three choices
// 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_
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