Note that there are some explanatory texts on larger screens.

plurals
  1. POC++/COM/Proxy Dlls: method override/method forwarding (COM implementation inheritance)
    primarykey
    data
    text
    <p>Hello and good day to you.</p> <p><strong>Situation:</strong><br> For some reason, from time to time I run into situation when I need to override one or two methods of a COM interface (that is being used for some older application without source code), which is normally Direct3D/DirectInput related (i.e. it is created by calling a DLL method, not by CoCreateInstance). Normally I deal with situation by writing a proxy DLL that overrides a method that creates interface I need to "modify", and replace original interface with my own. Normally this is required to make some older application work properly without crashing/artifacts.</p> <p><strong>Compiler:</strong><br> I use Visual Studio express 2008 on windows machine, so there are no C++0x features. The system has msysgit, msys, python, perl, gnu utilities (awk/sed/wc/bash/etc), gnu make and qmake (Qt-4.7.1) installed (and available within PATH).</p> <p><strong>Problem:</strong><br> Overriding one method of a COM interface is a pain (especially if original interface has a hundred of methods or so), because I need to forward many calls to original interface, and currently I see no way to simplify or automate the process. For example, override of IDirect3D9 looks like this: </p> <pre><code>class MyD3D9: public IDirect3D9{ protected: volatile LONG refCount; IDirect3D9 *orig; public: STDMETHOD(QueryInterface)(THIS_ REFIID riid, LPVOID * ppvObj){ if (!ppvObj) return E_INVALIDARG; *ppvObj = NULL; if (riid == IID_IUnknown || riid == IID_IDirect3D9){ *ppvObj = (LPVOID)this; AddRef(); return NOERROR; } return E_NOINTERFACE; } STDMETHOD_(ULONG,AddRef)(THIS){ InterlockedIncrement(&amp;refCount); return refCount; } STDMETHOD_(ULONG,Release)(THIS){ ULONG ref = InterlockedDecrement(&amp;refCount); if (refCount == 0) delete this; return ref; } /*** IDirect3D9 methods ***/ STDMETHOD(RegisterSoftwareDevice)(THIS_ void* pInitializeFunction){ if (!orig) return E_FAIL; return orig-&gt;RegisterSoftwareDevice(pInitializeFunction); } STDMETHOD_(UINT, GetAdapterCount)(THIS){ if (!orig) return 0; return orig-&gt;GetAdapterCount(); } STDMETHOD(GetAdapterIdentifier)(THIS_ UINT Adapter,DWORD Flags, D3DADAPTER_IDENTIFIER9* pIdentifier){ if (!orig) return E_FAIL; return orig-&gt;GetAdapterIdentifier(Adapter, Flags, pIdentifier); } STDMETHOD_(UINT, GetAdapterModeCount)(THIS_ UINT Adapter,D3DFORMAT Format){ if (!orig) return 0; return orig-&gt;GetAdapterModeCount(Adapter, Format); } /* some code skipped*/ MyD3D9(IDirect3D9* origD3D9) :refCount(1), orig(origD3D9){ } ~MyD3D9(){ if (orig){ orig-&gt;Release(); orig = 0; } } }; </code></pre> <p>As you can see, this is very inefficient, error-prone and requires a lot of copy-pasting.</p> <p><strong>Question:</strong><br> How can I simplify overriding of a single method of a COM interface in this situation? I would like to specify only method I change, but I currently see no way to do so. I also don't see a way to elegantly shorten "forwarded" methods with macros or templates or macros, because they have variable number of arguments. Another approach I saw is to use directly patch method table returned by another method (modify access right using VirtualProtect, then write into method table), which I don't exactly like.</p> <p><strong>Limitations:</strong><br> I would prefer to solve in C++ source code (macros/templates) and without code generators (unless code generator usage is extremely simple/elegant - i.e. writing code generator is not ok, using already available code generator I can set up in minutes and solve the whole thing in one line of code is ok). Boost is okay only if it doesn't add extra DLL dependency. MS-specific compiler directives and language extensions are also ok.</p> <p>Ideas? Thanks in advance.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload