visual c++ - Self modifying virtual table entries to point to concrete implementation -


short version:

can com class modify own virtual table entries @ runtime? (disregarding thread issues)

full version:

i'm providing number of c++ classes implement interface. com interface defined in third-party framework.

(edited: vtable of com interface standard on windows platform; relationship between c++ vtable , com vtable isn't clear me.)

in order inject implementations correctly framework, needs use two-step initialization: first create object no parameters, call initialize method parameters. moment when 1 of implementations can chosen.

to make happen, added "resolver" class (or wrapper class), sole responsibility choose implementation in initialize method. after that, every call com methods forwarded actual implementation.

the resolver class injected framework. gets around framework limitation.

now, seeing resolver class doesn't have use after initialization, i'm wondering if there way rid of virtual method indirection cost? idea copy each com vtable entry concrete implementation vtable of resolver class.

will work?

example:

// (fyi) #define hresult unsigned long  struct iinterface {     // ... usual addref, release , qi omitted       virtual hresult initialize(variant v) = 0;  // initialize method, implementation gets chosen     virtual hresult dowork() = 0;               // can call after initialization. };  class myresolver : public iinterface {     // ... usual addref, release , qi omitted  public:     virtual hresult initialize(variant v)      {         if ( /* conditions based on v */ )             return implem_one.create((void**) &m_pimpl);         else             return implem_two.create((void**) &m_pimpl);          "here, can copy vtable entries m_pimpl vtable of myresolver (*this) ?";         (int k = 0; k < num_virtual_methods; ++k)             this->vtbl[k] = m_pimpl->vtbl[k];     }     virtual hresult dowork()     {         if (!m_pimpl) return error_not_initialized;         m_pimpl->dowork();     } public:     // creation method injected framework     static hresult create(void**) { /* create instance of class , return */ } private:     myresolver() : m_pimpl(null) {}     virtual ~myresolver() { if (m_pimpl) m_pimpl->release(); }     iinterface* m_pimpl; }; 

you can't safely copy vtable entries; since this pointer still refer proxy class, real implementation won't find private data.

if base classes support com aggregation, can use avoid overhead however. when constructing base object, you'd pass outer class's iunknown outer aggregation iunknown. means queryinterface/addref/release on derived interfaces of base object delegate outer object, making part of outer object.

now can have queryinterface return original object (with proxying methods) prior initialization, or base object's interface directly when initialization complete. example:

class myproxy : public iinterface {   long refct;   iunknown *punkinner;   iinterface *pifaceinner;    ~myproxy() {     addref(); // punkinner may take references in destruction; prevent reentrancy per aggregating object rules     if (punkinner) {       punkinner->release();     }   } public:   myproxy() : refct(1), punkinner(null), pifaceinner(null) { }    stdmethodimp queryinterface(refiid riid, void **ppvobject)   {     if (!ppvobject) return e_pointer;      if (riid == iid_iunknown) {       addref();       *ppvobject = (void *)static_cast<iunknown *>(this);       return s_ok;     } else if (riid == iid_iinterface && punkinner) {       // increments refcount of _outer_ object       return punkinner->queryinterface(riid, ppvobject);     } else if (riid == iid_iinterface) {       addref();       *ppvobject = (void *)static_cast<iinterface *>(this);       return s_ok;     } else {       return e_nointerface;     }   }    stdmethodimp_(dword) addref(void)   { return interlockedincrement(&refct); }   stdmethodimp_(dword) release(void)   { if (!interlockeddecrement(&refct)) delete this; }    hresult initialize(variant v) {     // can use protocol create object long supports aggregation     hresult res = cocreateinstance(clsid_innerclass, this, clsctx_inproc_server, iid_iunknown, (lpvoid *)&punkinner);     if (failed(res)) return res;      res = punkinner->queryinterface(iid_iinterface, (void **)&pifaceinner);     if (failed(res)) {       punkinner->release();       punkinner = null;       return res;     }      release(); // above queryinterface incremented _outer_ refcount, don't want that.      return s_ok;   }    hresult dowork() {     if (!pifaceinner) return error_not_initialized;      return pifaceinner->dowork();   } }; 

although initial iinterface pointer client gets has double-call overhead, once initialization complete, can re-queryinterface more direct pointer. what's more, if can move initialization different interface, can force client re-queryinterface, ensuring direct pointer.

that said, it's vitally important aggregated objects support aggregation protocol; otherwise you'll end inconsistent reference counts , other badness. read msdn documentation before implementing aggregation.


Comments

Popular posts from this blog

linux - Using a Cron Job to check if my mod_wsgi / apache server is running and restart -

actionscript 3 - TweenLite does not work with object -

jQuery Ajax Render Fragments OR Whole Page -