digitalmars.D.learn - Quirks of 'alias foo this'
- Sean Cavanaugh (108/108) Apr 25 2011 So my research into making a nice friendly to use COM interface wrapper
- Andrej Mitrovic (9/9) Apr 25 2011 I have a similar problem. :)
- Andrej Mitrovic (3/3) Apr 25 2011 Well I've tried it with a COM object and it seems to work. So I'll
So my research into making a nice friendly to use COM interface wrapper for D has had a few odd turns and I am wondering if there is an answer to making the implementation nicer. I discovered the 'alias foo this' syntax to let structs nearly seamlessly impersonate a member variable. This has turned out to solve most of my original need to wrap the functions, but it is imperfect. The main problem with 'alias foo this' is that I am having is that I can't find a way to catch code reading the aliased variable, in cases of assignment or implicit conversion to foo type. I can catch writes just fine with opAssign, but finding a way to overload the reads have me stumped. I did some experiments with wraping the methods with some mixin templates, but using 'alias foo this' is about 100% more useful, intuitive and 99.9% less code to write :) Examples (The fully ComPtr code is down further): // initializes to null by default ComPtr!(ID3D11Device) device; ComPtr!(ID3D11Device) otherdevice; // The 'device' argument to D3D11CreateDevice is implemented as // 'out ID3D11Device', and uses the 'alias p this' feature to // auto-magically write directly into device.p; Ideally // I could hook this and either call SafeRelease here or assert // that the p variable is null before being written to. // This also represents the a case that you can write to the // struct without detecting it. HRESULT rslt = D3D11CreateDevice( null, D3D11_DRIVER_TYPE.HARDWARE, null, 0 | D3D11_CREATE_DEVICE.DEBUG, null, 0, D3D11_SDK_VERSION, device, &featureLevel, null); // post-blit case, works otherdevice = device; // gives me a copy of 'p' due to 'alias p this' ID3D11Device rawdevice = device; // assignment back the other direction is caught by opAssign // this is also the code path used if there are multiple COM // interfaces in the hierarchy (IUnknown->ID3D11Resource->ID3D11Texture) // and post-blit isn't used because the types are different. device = rawdevice; My current version of ComPtr: struct ComPtr(T) { public: static assert(is(T : std.c.windows.com.IUnknown) || is(T : win32.unknwn.IUnknown)); T p; alias p this; private: this(T inPtr) { p = inPtr; } public: this(this) { if (p !is null) { p.AddRef(); } } ~this() { SafeRelease(); } // Attach and Detach set/unset the pointer without messing with the refcount (unlike opAssign assignment) void Attach(T other) { SafeRelease(); p = other; } T Detach() { T rval = p; p = null; return rval; } const bool HasData() { return (p !is null); } void opAssign(T other) { if (other !is null) { other.AddRef(); SafeRelease(); p = other; } else { SafeRelease(); } } void SafeRelease() { if (p !is null) { p.Release(); p = null; } } }
Apr 25 2011
I have a similar problem. :) I'd like to catch a call to a COM object to check if it was properly initialized first. Here's one way to do it with regular classes: http://codepad.org/lHsQf4UG You can read about whitehole here: http://www.digitalmars.com/d/2.0/phobos/std_typecons.html#WhiteHole I think the above example could be used with COM objects but I haven't tried yet.
Apr 25 2011
Well I've tried it with a COM object and it seems to work. So I'll definitely use this technique now. I do wish whitehole gave me the option to throw a custom error message.
Apr 25 2011