/////////////////////////////////////////////////////////
//
// IFoo.h - interface definition
//
#ifndef _IFOO_H
#ifndef _IFOO_H
class IFoo : public IUnknown {
public:
STDMETHOD(Argument)(short arg1) PURE;
STDMETHOD(Agreement)(short *parg1) PURE;
STDMETHOD(Articulate)(short arg1) PURE;
STDMETHOD(Announcement)(short arg1) PURE;
};
DEFINE_GUID(IID_IFoo,0xBABACACAL,0xDADA,0xEAEA,0xFA,0xFA,0x00,0x00,0x00,0x00,0x00,0x0B);
#endif
/////////////////////////////////////////////////////////
//
// CoFoo.cpp - an implementation of IFoo
//
#include <windows.h>
#include "IFoo.h"
class CoFoo : public IFoo {
ULONG m_cRef;
public:
// ctor/dtor
CoFoo() : m_cRef(0) {}
virtual ~CoFoo() {}
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID riid, void** ppv) {
if (riid = = IID_IFoo || riid = = IID_IUnknown)
*ppv = (IFoo*)this;
else
*ppv = 0;
if (*ppv)
AddRef();
return *ppv ? S_OK : E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) AddRef() {
return ++m_cRef;
}
STDMETHODIMP_(ULONG) Release() {
ULONG result = --m_cRef;
if (!result)
delete this;
return result;
}
// IFoo methods
STDMETHODIMP Argument(short arg1) {
return (arg1 = = 0) ? S_OK : S_FALSE;
}
STDMETHODIMP Agreement(short *parg1) {
*parg1 = 0;
return NOERROR;
}
STDMETHODIMP Articulate(short arg1) {
return (arg1 = = 0) ? S_OK : S_FALSE;
}
STDMETHODIMP Announcement(short arg1) {
return (arg1 = = 0) ? S_OK : S_FALSE;
}
};
/////////////////////////////////////////////////////////
//
// Client1.cpp - client code to access IFoo
//
#include <windows.h>
#include "IFoo.h"
void UseFoo(IUnknown *punk)
{
IFoo *pfoo = 0;
if (SUCCEEDED(punk->QueryInterface(IID_IFoo, (void**)&pfoo))) {
short s = 0;
if (pfoo->Agreement(&s) = = S_OK)
pfoo->Argument(s);
pfoo->Release();
}
}
|
Standard Marshaling Upon initial connection to the object, the system creates and connects the standard proxy manager on the client side to the stub manager on the object side. The particular proxy and stub implementations for the interface being marshaled are then created and connected as well. Both the client and the object are oblivious to the entire infrastructure. Custom Marshaling Upon initial connection to the object, the system asks the object to build a marshaling packet that is transmitted to the client. Once transmitted, an object-specified handler is created in the client's address space to read the packet and act as a delegate. The client is oblivious to this. The object and handler, however, must explicitly support the IMarshal interface to enable custom marshaling. Standard Interface A Microsoft-defined interface that is part of the standard OLE distribution. A large number of standard interfaces support standard marshaling via proxy/stub implementations provided by the system DLLs. Custom Interface An interface defined by an independent software vendor. All custom interfaces require an ISV-supplied proxy/stub DLL to participate in standard marshaling. |
IFOO.IDL
[uuid(BABACACA-DADA-EAEA-FAFA-00000000000B), object]
interface IFoo : IUnknown
{
import "unknwn.idl";
HRESULT Argument([in] short arg1);
HRESULT Agreement([out] short *parg1);
HRESULT Articulate([in] short arg1);
HRESULT Announcement([in] short arg1);
}
IFOOPS.DEF
LIBRARY IFOOPS
EXPORTS
DllGetClassObject
DllCanUnloadNow
GetProxyDllInfo
IFOOPS.MAK
!include <ntwin32.mak>
!ifndef MIDL
MIDL = midl
!endif
MIDLFLAGS = /ms_ext /c_ext /cpp_cmd $(CC)
.cxx.obj:
$(CC) $(cdebug) $(CFLAGS) $(cvars) /c $<
.c.obj:
$(CC) $(cdebug) $(CFLAGS) $(cvars) /c $<
all: IFooPS.dll
IFoo_i.obj : IFoo_i.c
IFoo_p.obj : IFoo_p.c IFoo.h
dlldata.obj : dlldata.c
DLLOBJS= IFoo_p.obj IFoo_i.obj dlldata.obj
idirps.dll: $(DLLOBJS) IFooPS.def
$(link) $(linkdebug) -DLL -OUT:IFooPS.dll -DEF:IFooPS.def \
$(DLLOBJS) rpcrt4.lib $(ole2libs)
IFoo.h dlldata.c IFoo_p.c IFoo_i.c : IFoo.idl
$(MIDL) $(MIDLFLAGS) -Oi IFoo.idl
interface IDispatch : public IUnknown {
HRESULT GetTypeInfoCount(UINT *pctinfo);
HRESULT GetTypeInfo(UINT itinfo,
LCID lcid,
ITypeInfo **pptinfo);
HRESULT GetIDsOfNames(REFIID riid,
LPOLESTR *rgszNames,
UINT cNames,
LCID lcid,
DISPID *rgdispid);
HRESULT Invoke( DISPID dispidMember,
REFIID riid,
LCID lcid,
WORD wFlags,
DISPPARAMS *pdispparams,
VARIANT *pvarResult,
EXCEPINFO *pexcepinfo,
UINT *puArgErr);
};
COQUUX.ODL
[ uuid(BABACACA-DADA-EAEA-FAFA-00000000000A),
version(1.0),
lcid(9),
helpstring("The Quux Type Library")
]
library Quux
{
importlib("stdole32.tlb");
// the logical interface
[ uuid(00000001-0000-0000-FFFF-112233445566), odl]
interface IQuuxLogical : IUnknown {
[id(1)] void Chatter([in] short arg1);
[id(2)] short Commentary();
[id(3)] void Criticism([in] long arg1);
[id(4)] void ChitChat([in] long arg1);
}
// the physical interface
[ uuid(00000002-0000-0000-FFFF-112233445566)]
dispinterface DQuuxPhysical {
interface IQuuxLogical;
}
// the instantiable implementation class
[ uuid(00000003-0000-0000-FFFF-112233445566)]
coclass CoQuux {
[default] dispinterface DQuuxPhysical;
}
}
COQUUX.CPP
/////////////////////////////////////////////
//
// CoQuux.cpp - an implementation of a dispatch-interface
//
#include <windows.h>
// bring in ODL generated header
#include "CoQuux.h"
LPCOLESTR szTypeLibName = OLESTR("CoQuux.tlb");
class CoQuux : public IQuuxLogical, // ->IUnknown
public DQuuxPhysical // ->IDispatch->IUnknown
{
ULONG m_cRef;
short m_sum;
static ITypeInfo *s_pTypeInfo;
public:
// ctor/dtor
CoQuux()
: m_cRef(0), m_sum(0)
{
if (s_pTypeInfo != 0)
return;
// load the type info to implement IDispatch members
ITypeLib *ptl;
if (SUCCEEDED(LoadTypeLib(szTypeLibName, &ptl))) {
ptl->GetTypeInfoOfGuid(IID_IQuuxLogical, &s_pTypeInfo);
ptl->Release();
}
}
virtual ~CoQuux() { }
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppv) {
if (riid = = IID_IUnknown || riid = = IID_IQuuxLogical)
*ppv = (IQuuxLogical *)this;
else if (riid = = IID_IDispatch || riid = = DIID_DQuuxPhysical)
*ppv = (DQuuxPhysical *)this;
else
*ppv = 0;
if (*ppv)
AddRef();
return *ppv ? S_OK : E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) AddRef() {
return ++m_cRef;
}
STDMETHODIMP_(ULONG) Release() {
ULONG result = --m_cRef;
if (!result)
delete this;
return result;
}
// IDispatch methods
STDMETHODIMP GetTypeInfoCount(UINT FAR* pctinfo) {
*pctinfo = s_pTypeInfo ? 1 : 0;
return NOERROR;
}
STDMETHODIMP GetTypeInfo( UINT itinfo, LCID lcid,
ITypeInfo FAR* FAR* pptinfo) {
*pptinfo = 0;
if (itinfo != 0)
return E_INVALIDARG;
else if (s_pTypeInfo = = 0)
return E_NOTIMPL;
(*pptinfo = s_pTypeInfo)->AddRef();
return NOERROR;
}
STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR * * rgszNames,
UINT cNames, LCID lcid,
DISPID * rgdispid) {
if (s_pTypeInfo = = 0)
return E_NOTIMPL;
return s_pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
}
// forward invoke to the type info object, providing an implementation
// of the logical interface as the first parameter
STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid,
WORD wFlags, DISPPARAMS FAR* pdispparams,
VARIANT FAR* pvarResult,
EXCEPINFO FAR* pexcepinfo, UINT FAR* puArgErr) {
if (s_pTypeInfo = = 0)
return E_NOTIMPL;
return s_pTypeInfo->Invoke((IQuuxLogical*)this, dispidMember, wFlags,
pdispparams, pvarResult,
pexcepinfo, puArgErr);
}
// IQuuxLogical methods
STDMETHODIMP_(void) Chatter(short arg1) {
m_sum += arg1;
}
STDMETHODIMP_(short) Commentary() {
return m_sum;
}
STDMETHODIMP_(void) Criticism(short arg1) {
m_sum *= arg1;
}
STDMETHODIMP_(void) ChitChat(short arg1) {
m_sum -= arg1;
}
};
// give the type info pointer linkage
ITypeInfo *CoQuux::s_pTypeInfo;
| Invocations per Second by Argument Type | |||
| Scalars | Unicode Text | ANSI Text | |
| In-process | |||
| Custom Interface | 3,822,265 | 73,421 | 120,337 |
| IDispatch::Invoke | 14,333 | 11,494 | 7,500 |
| GetIDsOfNames + Invoke | 5,826 | 4,910 | 3,891 |
| Out-of-process | |||
| Custom Interface | 675 | 591 | 640 |
| IDispatch::Invoke | 555 | 447 | 468 |
| GetIDsOfNames + Invoke | 274 | 252 | 258 |
| All figures based on a 90MHz Pentium running Windows NT 3.5 | |||
/////////////////////////////////////////////
//
// CoQuux2.cpp - an implementation of a dual-interface
//
#include <windows.h>
// bring in ODL generated header
#include "CoQuux2.h"
LPCOLESTR szTypeLibName = OLESTR("CoQuux2.tlb");
class CoQuux2 : public DIQuux // ->IDispatch->IUnknown
{
ULONG m_cRef;
short m_sum;
static ITypeInfo *s_pTypeInfo;
public:
// ctor/dtor
CoQuux2()
: m_cRef(0), m_sum(0)
{
if (s_pTypeInfo != 0)
return;
// load the type info to implement IDispatch members
ITypeLib *ptl;
if (SUCCEEDED(LoadTypeLib(szTypeLibName, &ptl))) {
ptl->GetTypeInfoOfGuid(IID_IQuuxLogical, &s_pTypeInfo);
ptl->Release();
}
}
virtual ~CoQuux2() { }
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID riid, LPVOID FAR* ppv) {
if (riid= =IID_IUnknown || riid==IID_IDispatch || riid= =IID_DIQuux)
*ppv = (DIQuux *)this;
else
*ppv = 0;
if (*ppv)
AddRef();
return *ppv ? S_OK : E_NOINTERFACE;
}
STDMETHODIMP_(ULONG) AddRef() {
return ++m_cRef;
}
STDMETHODIMP_(ULONG) Release() {
ULONG result = --m_cRef;
if (!result)
delete this;
return result;
}
// IDispatch methods
STDMETHODIMP GetTypeInfoCount(UINT FAR* pctinfo) {
*pctinfo = s_pTypeInfo ? 1 : 0;
return NOERROR;
}
STDMETHODIMP GetTypeInfo( UINT itinfo, LCID lcid,
ITypeInfo FAR* FAR* pptinfo) {
*pptinfo = 0;
if (itinfo != 0)
return E_INVALIDARG;
else if (s_pTypeInfo = = 0)
return E_NOTIMPL;
(*pptinfo = s_pTypeInfo)->AddRef();
return NOERROR;
}
STDMETHODIMP GetIDsOfNames(REFIID riid, OLECHAR * * rgszNames,
UINT cNames, LCID lcid,
DISPID * rgdispid) {
if (s_pTypeInfo = = 0)
return E_NOTIMPL;
return s_pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgdispid);
}
// forward invoke to the type info object, providing an implementation
// of the logical interface as the first parameter
STDMETHODIMP Invoke(DISPID dispidMember, REFIID riid, LCID lcid,
WORD wFlags, DISPPARAMS FAR* pdispparams,
VARIANT FAR* pvarResult,
EXCEPINFO FAR* pexcepinfo, UINT FAR* puArgErr) {
if (s_pTypeInfo = = 0)
return E_NOTIMPL;
return s_pTypeInfo->Invoke((DIQuux*)this, dispidMember, wFlags,
pdispparams, pvarResult,
pexcepinfo, puArgErr);
}
// DIQuux methods
STDMETHODIMP Dialog(short arg1) {
m_sum += arg1;
return NOERROR;
}
STDMETHODIMP Dissension(short *pResult) {
*pResult = m_sum;
return NOERROR;
}
STDMETHODIMP Debate(short arg1) {
m_sum *= arg1;
return NOERROR;
}
STDMETHODIMP Diatribe(short arg1) {
m_sum -= arg1;
return NOERROR;
}
};
// give the type info pointer linkage
ITypeInfo *CoQuux::s_pTypeInfo;
| Invocations per Second by Argument Type | |||
| Scalars | Unicode Text | ANSI Text | |
| In-process | |||
| Custom Interface | 3,822,265 | 73,421 | 120,337 |
| Dual Interface | 3,822,265 | 60,698 | 19,503 |
| IDispatch::Invoke | 14,333 | 11,494 | 7,500 |
| GetIDsOfNames + Invoke | 5,826 | 4,910 | 3,891 |
| Out-of-process | |||
| Custom Interface | 675 | 591 | 640 |
| Dual Interface | 613 | 549 | 549 |
| IDispatch::Invoke | 555 | 447 | 468 |
| GetIDsOfNames + Invoke | 274 | 252 | 258 |
| All figures based on a 90MHz Pentium running Windows NT 3.51 | |||
| Dispatch | Dispatch with DISPID resolved at run time | Dual | Custom | |
| Standard marshaling support | Built-in | Built-in | User-supplied | |
| Physical parameter data types | VARIANTARG | VARIANTARG | 13 VARTYPES | Unlimited |
| Logical parameter data types | 13 VARTYPES | 13 VARTYPES | 13 VARTYPES | Unlimited |
| Physical result type | VARIANT | VARIANT | HRESULT | HRESULT |
| Logical result type | 13 VARTYPES | 13 VARTYPES | 13 VARTYPES | HRESULT |
| Inproc performance penalty (integral types) | 275 | 700 | None | None |
| Inproc performance penalty (Unicode text) | 7 | 15 | 1.25 | None |
| Inproc performance penalty (ANSI text) | 17 | 32 | 6.75 | None |
| OutOfProc performance penalty (integral types) | 7,300 | 14,500 | 6,600 | 6,000 |
| OutOfProc performance penalty (Unicode text) | 170 | 300 | 140 | 128 |
| OutOfProc performance penalty (ANSI text) | 275 | 500 | 240 | 200 |
| Primary clients | Visual Basic 3.0 and 4.0, C++ | Visual Basic 3.0 and 4.0, C++ | Visual Basic 3.0 and 4.0, C++ | C++ |
| MFC support | Good | Good | None | Minimal |
| All penalties are relative to the performance of an inproc custom interface. For example, a performance penalty of 275 means that call took 275 times as long to complete than an inproc custom interface call. | ||||