From C++
#define IID_PPV_ARGS(ppType) __uuidof(**(ppType)), IID_PPV_ARGS_Helper(ppType)

//ComPtr version
ComPtr<ID3D12Debug> debugController;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
{
        // do stuff
}

//Raw Pointer Version
ID3D12Debug* debugController;
if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&debugController))))
{
        // do stuff
}

IID_PPV_ARGS expands into two arguments of types (const IID &, void**).

The first arg expansion uses a compiler intrinsic to look up the GUID of the type.

The second arg expansion uses an IID_PPV_ARGS_Helper, a templated function that return a void**. This either forwards the address of the pointer passed in, or the result of ReleaseAndGetAddressOf() from the com object within the ComPtr.



Now in D!
Here is my attempt so far, pared down to just enough to compile "IID_PPV_ARGS(debugController).expand".

// ----- uuidtemplate.d -----
module uuidtemplate;
import core.sys.windows.com;

mixin( uuid!(IUnknown, "00000000-0000-0000-C000-000000000046"));
mixin( uuid!(IClassFactory,"00000001-0000-0000-C000-000000000046"));

template uuid(T, const char[] g) {
        const char [] uuid =
"const IID IID_"~T.stringof~"={ 0x" ~ g[0..8] ~ ",0x" ~ g[9..13] ~ ",0x" ~ g[14..18] ~ ",[0x" ~ g[19..21] ~ ",0x" ~ g[21..23] ~ ",0x" ~ g[24..26] ~ ",0x" ~ g[26..28] ~ ",0x" ~ g[28..30] ~ ",0x" ~ g[30..32] ~ ",0x" ~ g[32..34] ~ ",0x" ~ g[34..36] ~ "]};"~
                "template uuidof(T:"~T.stringof~"){"~
" const IID uuidof ={ 0x" ~ g[0..8] ~ ",0x" ~ g[9..13] ~ ",0x" ~ g[14..18] ~ ",[0x" ~ g[19..21] ~ ",0x" ~ g[21..23] ~ ",0x" ~ g[24..26] ~ ",0x" ~ g[26..28] ~ ",0x" ~ g[28..30] ~ ",0x" ~ g[30..32] ~ ",0x" ~ g[32..34] ~ ",0x" ~ g[34..36] ~ "]};"~
                "}";
}

//  ----- debuginterface.d -----
module debuginterface;

import core.sys.windows.com;
import uuidtemplate : uuid; // uuidof

mixin(uuid!(ID3D12Debug, "344488b7-6846-474b-b989-f027448245e0"));
interface ID3D12Debug : IUnknown {
        void EnableDebugLayer();
}

//  ----- comptr.d -----
module comptr;
public import std.typecons;
import core.sys.windows.com;
import uuidtemplate : uuid; // uuidof

mixin template IID_PPV_ARGS()
{
        auto IID_PPV_ARGS(T : ComPtr!U, U)(ref T arg)
        {
                return tuple(&uuidof!(U), arg.ptrRef());
        }

        auto IID_PPV_ARGS(T)(ref T arg)
        {
                return tuple(&uuidof!(T), &arg);
        }
}

template ComPtr(T)
{
        struct ComPtr
        {
        protected:
                T _ptr = null;

        public:
                this(ref T inVar)
                {
                        _ptr = inVar;
                }

                @property T ptr() { return _ptr; }
                @property T* ptrRef() { return &_ptr; }
                
                alias ptr this;
        }
}


//  ----- app.d -----
module app;

import core.sys.windows.com;
import comptr;
import debuginterface;
import std.stdio;

// Necessary to mixin since the declaration in comptr.d
// cannot see the uuidof declared by debuginterface.
// When removing the mixin, it always returns the GUID for IUnknown.
mixin IID_PPV_ARGS;

bool D3D12GetDebugInterface(const (GUID)* riid, ID3D12Debug* ppvDebug)
{
printf("Guid = {%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}",
        riid.Data1, riid.Data2, riid.Data3,
        riid.Data4[0], riid.Data4[1], riid.Data4[2], riid.Data4[3],
        riid.Data4[4], riid.Data4[5], riid.Data4[6], riid.Data4[7]);

        // output should be: "344488b7-6846-474b-b989-f027448245e0"

        return true;
}

void main()
{
        ComPtr!ID3D12Debug debugController;

        // I want to get rid of the .expand syntax here
        if (D3D12GetDebugInterface(IID_PPV_ARGS(debugController).expand))
        {
                writefln("success!");
        }
}

/// end code

So my goal here is to get the syntax for IID_PPV_ARGS down to looking just like a function call.

I'd like to get rid of the .expand call. I haven't figured out a better way to express converting the ComPtr input into two outputs used as separate arguments into the outer function.

Any ideas?

Reply via email to