Mimicking IID_PPV_ARGS

Cody Duncan dlang at codyduncan.net
Wed Aug 29 09:51:41 UTC 2018


 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?


More information about the Digitalmars-d-learn mailing list