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