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 }