1 module speech.windows.comref; 2 3 import core.sys.windows.com; 4 import core.sys.windows.windows; 5 import std.windows.syserror; 6 7 class COMException : Exception 8 { 9 immutable HRESULT error; 10 11 this(HRESULT hr, string fn = __FILE__, size_t ln = __LINE__) 12 { 13 import std.string : format; 14 error = hr; 15 super(format("error occured during COM call (0x%X)", hr), fn, ln); 16 } 17 } 18 19 void coEnforce(HRESULT result, string fn = __FILE__, size_t ln = __LINE__) 20 { 21 if(result != S_OK) 22 throw new COMException(result, fn, ln); 23 } 24 25 // Note: relies on being TLS. 26 // CoUninitialize must not be called 27 // if CoInitializeEx returned 28 // RPC_E_CHANGED_MODE. 29 version(speech4d_autocominit) private bool shouldUninitialize = true; 30 31 struct CoReference(T : IUnknown) 32 { 33 private: 34 T CoReference_object = null; 35 36 public: 37 T CoReference_get() @property 38 { 39 return CoReference_object; 40 } 41 42 alias CoReference_get this; 43 44 // @disable this(); 45 46 this(CLSID* clsid, IID* iid) 47 { 48 version(speech4d_autocom) 49 { 50 HRESULT hr = CoInitializeEx(null, COINIT_MULTITHREADED); 51 if(hr < 0 && hr != RPC_E_CHANGED_MODE) 52 throw new COMException(hr); 53 54 shouldUninitialize = hr != RPC_E_CHANGED_MODE; 55 } 56 57 coEnforce(CoCreateInstance(clsid, null, CLSCTX_ALL, iid, cast(void**)&CoReference_object)); 58 } 59 60 this(T object) 61 { 62 CoReference_object = object; 63 } 64 65 this(this) 66 { 67 if(CoReference_object !is null) 68 { 69 AddRef(); 70 } 71 } 72 73 void opAssign(typeof(this) rhs) 74 { 75 import std.algorithm.mutation : swap; 76 swap(CoReference_object, rhs.CoReference_object); 77 } 78 79 ~this() 80 { 81 if(CoReference_object !is null && Release() == 0) 82 { 83 CoReference_object = null; 84 version(speech4d_autocom) if(shouldUninitialize) 85 { 86 CoUninitialize(); 87 } 88 } 89 } 90 }