Last active
June 13, 2016 16:50
-
-
Save thedeemon/3c2989b76004fafe9aa0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module comptr; | |
import std.stdio, core.sys.windows.com, core.sys.windows.windows, std.exception, std.meta, std.traits; | |
//version = comptrtalk; | |
GUID Guid(string str)() { | |
static assert(str.length==36, "Guid string must be 36 chars long"); | |
enum GUIDstring = "GUID(0x" ~ str[0..8] ~ ", 0x" ~ str[9..13] ~ ", 0x" ~ str[14..18] ~ | |
", [0x" ~ str[19..21] ~ ", 0x" ~ str[21..23] ~ ", 0x" ~ str[24..26] ~ ", 0x" ~ str[26..28] | |
~ ", 0x" ~ str[28..30] ~ ", 0x" ~ str[30..32] ~ ", 0x" ~ str[32..34] ~ ", 0x" ~ str[34..36] ~ "])"; | |
return mixin(GUIDstring); | |
} | |
struct ComPtr(Interface) //taken from VisualD, then modified | |
{ | |
protected Interface ptr; | |
protected string name; | |
this(Interface i, bool doref = true) { | |
version(comptrtalk) writeln("ComPtr this (Interface)"); | |
ptr = i; | |
if(ptr && doref) | |
ptr.AddRef(); | |
} | |
static if (!is(Interface==IUnknown)) { | |
this(IUnknown i) { | |
version(comptrtalk) writeln("ComPtr this(IUnknown), doing qi_cast"); | |
ptr = qi_cast!(Interface)(i); | |
} | |
this(T)(ComPtr!T p) { | |
version(comptrtalk) writeln("ComPtr this(IUnknown), doing qi_cast"); | |
ptr = qi_cast!(Interface)(p.raw); | |
} | |
this(ref CLSID clsid, string name_ = "") { | |
name = name_; | |
version(comptrtalk) writeln("ComPtr this (CLSID) ", name); | |
auto hr = CoCreateInstance(&clsid, null, CLSCTX_ALL, &Interface.iid, cast(void**)&ptr); | |
version(comptrtalk) writefln("ComPtr create instance: %X", hr); | |
} | |
} | |
this(this) { | |
version(comptrtalk) writeln("this(this) ", name); | |
if (ptr) ptr.AddRef(); | |
} | |
~this() { | |
version(comptrtalk) writeln("ComPtr ~this ", name); | |
if(ptr) | |
ptr.Release(); | |
} | |
Interface detach() { | |
Interface p = ptr; | |
ptr = null; | |
return p; | |
} | |
void opAssign(Interface i) { | |
version(comptrtalk) writeln("ComPtr opAssign = Interface"); | |
if(ptr) | |
ptr.Release(); | |
ptr = i; | |
if(ptr) | |
ptr.AddRef(); | |
} | |
void opAssign(IUnknown i) { | |
version(comptrtalk) writeln("ComPtr opAssign = IUnknown"); | |
if(ptr) | |
ptr.Release(); | |
ptr = qi_cast!(Interface)(i); | |
} | |
Interface opCast(T:Interface)() { return ptr; } | |
Interface raw() { return ptr; } | |
bool opCast(T:bool)() { return ptr !is null; } | |
auto opDispatch(string fn, Ts...)(Ts vs) { | |
import std.format; | |
enum vss = unwrapPtrs!Ts; | |
alias RetType = ReturnType!(mixin("ptr."~fn)); | |
static if (is(RetType == HRESULT)) { | |
HRESULT hr = mixin("ptr." ~ fn ~ "(" ~ vss ~ ")"); | |
if (hr < 0) { | |
string msg = format("%s%s::%s returned %X", | |
name.length > 0 ? name ~ " calling " : "", | |
Interface.stringof, fn, hr); | |
throw new COMException(hr, msg); | |
} | |
return hr; | |
} else | |
return mixin("ptr." ~ fn ~ "(" ~ vss ~ ")"); | |
} | |
} | |
enum isComPtr(T) = is(T == ComPtr!A, A); | |
string unwrapPtrs(Ts...)() { | |
import std.string : format; | |
import std.array : join; | |
string[] res; | |
res.length = Ts.length; | |
foreach(n, T; Ts) { | |
static if (isComPtr!T) res[n] = format("vs[%d].raw", n); | |
else res[n] = format("vs[%d]", n); | |
} | |
return res.join(", "); | |
} | |
I qi_cast(I)(IUnknown obj) | |
{ | |
I iobj; | |
if (obj is null) return null; | |
static if (!is(I == IUnknown)) { | |
if(obj.QueryInterface(&I.iid, cast(void**)&iobj) == S_OK) | |
return iobj; | |
} else { | |
obj.AddRef(); | |
return obj; | |
} | |
return null; | |
} | |
class COMException : Exception { | |
HRESULT hr; | |
this(int hrcode, string msg="hr is no good") { super(msg); hr = hrcode; } | |
this(string msg, string file, size_t line) { super(msg, file, line); hr = E_POINTER; } | |
} | |
HRESULT checkHR(HRESULT hr, string msg = "hr is no good") { | |
if (hr < 0) throw new COMException(hr, msg); | |
return hr; | |
} | |
auto doing(lazy HRESULT smth, string desc) { | |
try { | |
return smth; | |
} catch(COMException ex) { | |
throw new COMException(ex.hr, desc ~ ": " ~ ex.msg); | |
} | |
} | |
auto require(T)(ComPtr!T x) { | |
enforce!COMException(x); | |
return x; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment