ThreadingModel="Both", , , : STA . , , . , , . , ( , , STA). , , . , ORPC- , , .
, , . , ORPC- , . , ORPC, . . . - CoMarshalInterface / CoUnmarshalInterface. , . , , , . , , , MSHCTX_INPROC.
, IMarshal, , . (FreeThreaded Marshaler - FTM) API- CoCreateFreeThreadedMarshaler:
HRESULT CoCreateFreeThreadedMarshaler( [in] IUnknown *pUnkOuter, [out] IUnknown **ppUnkInner);
, FTM, , QueryInterface IMarshal. FTM .
class Point : public IPoint { LONG m_cRef; IUnknown *m_pUnkFTM; long m_x; long m_y; Point(void) : m_cRef(0), m_x(0), m_y(0) { HRESULT hr = CoCreateFreeThreadedMarshaler(this,&m_pUnkFTM); assert(SUCCEEDED(hr)) ; } virtual ~Point(void) { m_pUnkFTM->Release(); } };
QueryInterface IMarshal FTM:
STDMETHODIMP Point::QueryInterface(REFIID riid, void **ppv) { if (riid == IID_IUnknown || riid == IID_IPoint) *ppv = static_cast<IPoint*>(this); else if (riid == IID_IMarshal) return m_pUnkFTM->QueryInterface(riid, ppv); else return (*ppv = 0), E_NOINTERFACE; ((IUnknown* )*ppv)->AddRef(); return S_OK; }
FTM, , Point. CoMarshalInterface / CoUnmarshalInterface, , Point , Point.
FTM 16 . , FTM . , . FTM (lazy-aggregated) QueryInterface IMarshal. , :
class LazyPoint : public IPoint { LONG m_cRef; IUnknown *m_pUnkFTM; long m_x; long m_y; LazyPoint (void) : m_cRef (0) .m_pUnkFTM(0),m_x(0), m_y(0) {} virtual ~LazyPoint(void) { if (m_pUnkFTM) m_pUnkFTM->Release(); } void Lock(void); // acquire object-specific lock // , void Unlock(void); // release object-specific lock // , : : : };
, QueryInterface FTM :
STDMETHODIMP Point::QueryInterface(REFIID riid, void **ppv) { if (riid == IID_IUnknown || riid == IID_IPoint) *ppv = static_cast<IPoint*>(this); else if (riid == IID_IMarshal) { this->Lock(); HRESULT hr = E_NOINTERFACE; *ppv = 0; if (m_pUnkFTM == 0) // acquire FTM first time through // FTM CoCreateFreeThreadedMarshaler(this, &m_pUnkFTM); if (m_pUnkFTM != 0) // by here, FTM is acquired // FTM hr = m_pUnkFTM->QueryInterface(riid, ppv); this->Unlock(); return hr; } else return (*ppv = 0), E_NOINTERFACE; ((IUnknown *)*ppv)->AddRef(); return S_OK; }
, QueryInterface IMarshal ( ); , IMarshal , .
, FTM, , FTM . , , , FTM, , . , , FTM. , - :
class Rect : public IRect { LONG m_cRef; IPoint *m_pPtTopLeft; IPoint *m_pPtBottomRight; Rect(void) : m_cRef(0) { HRESULT hr = CoCreateInstance(CLSID_Point, 0, CLSCTX_INPROC, IID_Ipoint, (void**) &m_pPtTopLeft); assert(SUCCEEDED (hr)); hr = CoCreateInstance(CLSID_Point, 0, CLSCTX_INPROC, IID_Ipoint, (void**)&m_pPtBottomRight); assert (SUCCEEDED(hr)); } ; ; ; }
Rect ThreadingModel = "Both". Rect- , CoCreateInstance (CLSID_Rect). , CoCreateInstance (CLSID_Point) . , m_pPtTopLeft m_pPtBottomRight , CoCreateInstance.
, Rect :
STDMETHODIMP Rect::get_Area(long *pn) { long top, left, bottom, right; HRESULT hr = m_pPtTopLeft->GetCoords(&left, &top); assert(SUCCEEDED(hr)); hr = m_pPtBottomRight->GetCoords(&right, &bottom); assert (SUCCEEDED (hr)); *pn = (right - left) * (bottom - top); return S_OK; }
Rect FTM, , , CoCreateInstance. , get_Area , . Point FTM, . , ( , Rect), . , Point FTM - ThreadingModel, Rect . , RPC_E_WRONG_THREAD , .
Rect . FTM , Rect , Rect ORPC. , , . - , . (Global Interface Table - GIT). Rect , " " (cookies) DWORD:
class SafeRect : public IRect { LONG m_cRef; // reference count // IUnknown *m_pUnkFTM; // cache for FTM lazy aggregate // FTM DWORD m_dwTopLeft; // GIT cookie for top/left // GIT / DWORD m_dwBottomR1ght; // GIT cookie for bottom/right // GIT /
- Point, GIT:
SafeRect::SafeRect(void) : m_cRef(0), m_pUnkFTM(0) { // assume ptr to GIT is initialized elsewhere // , GIT // - extern IGIobalInterfaceTable *g_pGIT; assert(g_pGIT != 0); IPoint *pPoint = 0; // create instance of class Point // Point HRESULT hr = CoCreateInstance(CLSID_Point, 0, CLSCTX_INPROC, IID_Ipoint, (void**)&pPoint); assert (SUCCEEDED (hr)); // register interface pointer in GIT // GIT hr = g_pGIT->RegisterInterfaceInGlobal(pPoint, IID_Ipoint, &m_dwTopLeft); assert(SUCCEEDED(hr)); pPoint->Release(); // reference is now held in GIT // GIT // create instance of class Point // Point hr = CoCreateInstance(CLSID_Point, 0, CLSCTX_INPROC, IID_Ipoint, (void**)&pPoint); assert(SUCCEEDED(hr)); // register interface pointer in GIT // GIT hr = g_pGIT->RegisterInterfaceInGlobal(pPoint, IID_Ipoint, &m_dwBottomRight); assert(SUCCEEDED(hr)); pPoint->Release(); // reference is now held in GIT // GIT }
, , GIT, .
GIT , , :
STDMETHODIMP SafeRect::get_Area(long *pn) { extern IGlobalInterfaceTable *g_pGIT; assert(g_pGIT != 0); // unmarshal the two interface pointers from the GIT // GIT IPoint *ptl = 0, *pbr = 0; HRESULT hr = g_pGIT->GetInterfaceFromGlobal(m_dwPtTopLeft, IID_Ipoint, (void**)&ptl); assert (SUCCEEDED(hr)); hr = g_pGIT->GetInterfaceFromGlobal(m_dwPtBottomRight, IID_Ipoint, (void**)&pbr); // use temp ptrs to implement method // long top, left, bottom, right; hr = ptl->GetCoords(&left, &top); assert (SUCCEEDED(hr)); hr = pbr->GetCoords(&right, &bottom); assert (SUCCEEDED (hr)); *pn = (right - left) * (bottom - top); // release temp ptrs. // ptl->Release(); pbr->Release(); return S_OK; }
SafeRect FTM, , , .
GIT , GIT. , SafeRect GIT :
SafeRect::~SafeRect(void) { extern IGlobalInterfaceTable *g_pGIT; assert(g_pGIT != 0); HRESULT hr = g_pGIT->RevokeInterfaceFromGlobal(m_dwTopLeft); assert(SUCCEEDED(hr)); hr = g_pGIT->RevokeInterfaceFromGlobal(m_dwBottomRight); assert(SUCCEEDED(hr)); }
GIT .
, GIT FTM GIT, , . GIT , . C++ " " GIT , :
template <class Itf, const IID* piid> class GlobalInterfacePointer { DWORD m_dwCookie; // the GIT cookie // " " GIT // prevent misuse // GlobalInterfacePointer(const GlobalInterfacePointer&); void operator =(const GlobalInterfacePointer&); public: // start as invalid cookie // " " GlobalInterfacePointer(void) : m_dwCookie(0) { } // start with auto-globalized local pointer // GlobalInterfacePointer(Itf *pItf, HRESULT& hr) : m_dwCookie(0) { hr = Globalize(pItf); } // auto-unglobalize // ~GlobalInterfacePointer(void) { if(m_dw ki ) Unglobalize() ; } // register an interface pointer in GIT // GIT HRESULT Globalize(Itf *pItf) { assert (g_pGIT != 0 && m_dwCookie == 0); return g_pGIT->RegisterInterfaceInGlobal(pItf, * piid, &m_dwCookie); } // revoke an interface pointer in GIT // GIT HRESULT Unglobalize(void) { assert(g_pGIT != 0 && m_dwCookie != 0); HRESULT hr = g_pGIT->RevokeInterfaceFromGlobal(m_dwCookie); m_dwCookie = 0; return hr; } // get local interface pointer from GIT // GIT HRESULT Localize(Itf **ppItf) const { assert(g_pGIT != 0 && m_dwCookie != 0); return g_pGIT->GetInte faceFromGlobal(m_dwCookie, *piid, (void**)ppItf); } // convenience methods // bool IsOK(void) const { return m_dwCookie != 0; } DWORD GetCookie(void) const { return m_dwCookie; } }; #define GIP(Itf) GlobalInterfacePointer<Itf, &IID_##Itf>
, SafeRect DWORD GlobalInterfacePointers:
class SafeRect : public IRect { LONG m_cRef: // M reference count // IUnknown *m_pUnkFTM; // cache for FTM lazy aggregate // FTM GIP(IPoint) m_gipTopLeft; // GIT cookie - top/left // " " GIT / GIP(IPoint) m_gipBottomRight; // GIT cookie - bottom/right // " " GIT / : : : }
GlobalInterfacePointer ( ) , Globalize GlobalInterfacePointer:
SafeRect::SafeRect(void) : m_cRef (0), m_pUnkFTM(0) { IPoint *pPoint = 0; // create instance of class Point // Point HRESULT hr = CoCreateInstance(CLSID_Point, 0, CLSCTX_INPROC, IID_Ipoint, (void**)&pPoint); assert (SUCCEEDED(hr)); // register interface pointer in GIT // GIT hr = m_gipTopLeft.Globalize(pPoint); assert (SUCCEEDED(hr)); pPoint->Release(); // reference is now held in GIT // GIT // create instance of class Point // Point hr = CoCreateInstance(CLSID_Point, 0, CLSCTX_INPROC, IID_I int, (void**) & int); assert(SUCCEEDED(hr)); // register interface pointer in GIT // GIT hr = m_gipBottomRight.Globalize(pPoint); assert (SUCCEEDED (hr)); pPoint->Release(); // reference is now held in GIT // GIT }
, , Localize GlobalInterfa ePointer:
STDMETHODIMP SafeRect::get_Top(long *pVal) { IPoint *pPoint = 0; // local imported pointer // HRESULT hr = m_gipTopLeft.Localize(&pPoint); if (SUCCEEDED(hr)){ long x; hr = pPoint->get_Coords(&x, pVal); pPoint->Release(); } return hr; }
, (FreeThreaded Marshaler) , , .
. GlobalInterfacePointer , , (smart pointer):
template <class Itf, const IID* piid> class LocalInterfacePointer { Itf *m_pItf; // temp imported pointer // // prevent misuse // LocalInterfacePointer(const LocalInterfacePointer&); operator = (const LocalInterfacePointer&); public: LocalInterfacePointer(const GlobalInterfacePointer<Itf, piid>& rhs, HRESULT& hr) { hr = rhs.Loca1ize(&m_pItf) ; } LocalInterfacePointer(DWORD dwCookie, HRESULT& hr) { assert(g_pGIT != 0); hr = g_pGIT->GetInterfaceFromGlobal(dwCookie, *piid, (void**)&m_pItf); } ~LocalInterfacePointer(void) { if (m_pItf) m_pItf->Release(); } class SafeItf : public Itf { STDMETHOD_(ULONG, AddRef) (void) = 0; // hide // STDMETHOD_(ULONG, Release)(void) = 0; // hide // }; SafeItf *GetInterface(void) const { return (SafeItf*) m_pItf; } SafeItf *operator ->(void) const { assert(m_pItf != 0); return GetInterface(); } }; #def1ne LIP(Itf) LocalInterfacePointer<Itf, &IID_##Itf>
C++ :
STDMETHODIMP SafeRect::get_Area(long *pn) { long top, left, bottom, right; HRESULT hr, hr2; // import pointers // LIP(IPoint) lipTopLeft(m_gipTopLeft, hr); LIP(IPoint) lipBottomRight(m_gipBottomRight, hr2); assert(SUCCEEDED(hr) && SUCCEEDED(hr2)); // use temp tocal pointers // hr = lipTopLeft->GetCoords(&left, &top); hr2 = lipBottomRight->GetCoords(&right, &bottom); assert(SUCCEEDED(hr) && SUCCEEDED(hr2)); *pn = (right - left) * (bottom - top); return S_OK; // LocalInterfacePointer auto-releases temp ptrs. // LocalInterfacePointer // }
GIP LIP GIT FTM . GIT FTM , , .