1 module nulib.system.com.com; 2 import nulib.system.com.objbase; 3 import nulib.system.com.uuid; 4 import numem.core.atomic : nu_atomic_add_32, nu_atomic_sub_32; 5 import numem; 6 7 public import nulib.system.com.hresult; 8 public import nulib.system.com.unk; 9 import nulib.system.com.objbase; 10 11 /** 12 Class Context for COM Object Instantiation. 13 */ 14 enum ComClassContext : CLSCTX { 15 16 /** 17 Class Context that covers everything. 18 */ 19 all = CLSCTX.CLSCTX_INPROC_SERVER|CLSCTX.CLSCTX_INPROC_HANDLER|CLSCTX.CLSCTX_LOCAL_SERVER, 20 21 /** 22 Class Context that covers in-process COM. 23 */ 24 inProcess = CLSCTX.CLSCTX_INPROC_SERVER|CLSCTX.CLSCTX_INPROC_HANDLER, 25 26 /** 27 Class Context that covers remote/serverside COM. 28 */ 29 server = CLSCTX.CLSCTX_INPROC_SERVER|CLSCTX.CLSCTX_LOCAL_SERVER|CLSCTX.CLSCTX_REMOTE_SERVER, 30 } 31 32 /** 33 Determines the concurrency model used for incoming calls to 34 objects created by this thread. 35 36 This concurrency model can be either apartment-threaded or multithreaded. 37 */ 38 enum ComInitFlags : uint { 39 40 /** 41 Initializes the thread for (single) apartment-threaded object concurrency. 42 */ 43 appartmentThreaded = 0x2, 44 45 /** 46 Initializes the thread for multithreaded object concurrency. 47 */ 48 multithreaded = 0x0, 49 50 /** 51 Disables DDE for OLE1 support. 52 */ 53 disableOLE1DDE = 0x4, 54 55 /** 56 Increase memory usage in an attempt to increase performance. 57 */ 58 speedOverMemory = 0x8, 59 } 60 alias COINIT = ComInitFlags; /// ditto 61 62 /** 63 Initializes the COM Framework. 64 65 Returns: 66 $(D true) if the COM framework was initialized, 67 $(D false) otherwise. 68 */ 69 extern(C) 70 bool nu_com_init(ComInitFlags flags = ComInitFlags.appartmentThreaded) { 71 return CoInitializeEx(flags, null) == S_OK; 72 } 73 74 /** 75 Closes the COM Framework. 76 */ 77 extern(C) 78 void nu_com_quit() { 79 CoUninitialize(); 80 } 81 82 /** 83 Gets the current COM Thread ID. 84 */ 85 extern(C) 86 uint nu_com_gettid() { 87 return CoGetCurrentProcess(); 88 } 89 90 /** 91 Frees specified library or unused libraries if $(D lib) is $(D null) 92 93 Params: 94 lib = the library to free, or $(D null) to free unused. 95 */ 96 extern(C) 97 void nu_com_freelibrary(void* lib) { 98 if (lib) 99 CoFreeLibrary(lib); 100 else 101 CoFreeUnusedLibraries(); 102 } 103 104 /** 105 Base COM Class for D extensions to the COM API. 106 */ 107 @nu_autoreleasewith!((ref obj) { obj.Release(); }) 108 class ComObject : IUnknown { 109 extern(Windows) @nogc: 110 private: 111 uint refcount; 112 113 public: 114 115 /** 116 Creates and default-initializes a single object of the class specified. 117 118 Params: 119 target = The target interface to put the class instance into. 120 context = The context in which the class will be instantiated. 121 outer = The outer class instance that this instance should be instantiated 122 within, or $(D null) if it's not an aggregate COM Object. 123 124 Returns: 125 $(D HRESULT) describing whether the operation succeeded. 126 Check against $(D S_OK). 127 */ 128 extern(D) 129 static HRESULT createInstance(T, I = IUnknown)(ref I target, CLSCTX context = CLSCTX_INPROC, IUnknown outer = null) 130 if (is(T == class) && is(I == interface) && is(T : IUnknown) && is(I : IUnknown)) { 131 const(Guid) clsid = __uuidof!T; 132 const(Guid) riid = __uuidof!I; 133 return CoCreateInstance(&clsid, outer, context, &riid, cast(void**)&target); 134 } 135 136 /** 137 Params: 138 progID = ProgID of the class to instantiate in any encoding. 139 The encoding is automatically converted to the correct format. 140 target = The target instance to create 141 context = The class context 142 outer = The outer class 143 */ 144 extern(D) 145 static HRESULT createInstance(T, I = IUnknown)(inout(T)[] progID, ref I target, ComClassContext context = ComClassContext.inProcess, IUnknown outer = null) 146 if (is(I == interface) && is(I : IUnknown)) { 147 import nulib.string : nwstring; 148 149 nwstring clsname = progID; 150 const(Guid) riid = __uuidof!I; 151 const(Guid) clsid; 152 153 CLSIDFromProgID(clsname.ptr, &clsid); 154 return CoCreateInstance(&clsid, outer, context, &riid, cast(void**)&target); 155 } 156 157 /** 158 Queries a COM object for a pointer to one of its interface. 159 160 Note: 161 Because you pass the address of an interface pointer, 162 the method can overwrite that address with the pointer to the interface being queried for. 163 Upon successful return, $(D *ppvObject) (the dereferenced address) contains a pointer to 164 the requested interface. 165 If the object doesn't support the interface, the method sets $(D *ppvObject) 166 (the dereferenced address) to $(D null). 167 168 Params: 169 riid = Pointer to the Guid of the interface being queried for. 170 ppvObject = Pointer to pointer to store result of operation. 171 172 Returns: 173 $(D S_OK) if supported, $(D E_NOINTERFACE) otherwise. 174 If ppvObject is $(D null), returns $(D E_POINTER). 175 */ 176 HRESULT QueryInterface(const(IID)* riid, out void* ppvObject) { // @suppress(dscanner.style.phobos_naming_convention) 177 if (*riid == IUnknown.iid) { 178 ppvObject = cast(void*)cast(IUnknown)this; 179 AddRef(); 180 return S_OK; 181 } 182 183 ppvObject = null; 184 return E_NOINTERFACE; 185 } 186 187 /** 188 Increments the reference count for an interface pointer to a COM object. 189 190 You should call this method whenever you make a copy of an interface pointer. 191 192 Returns: 193 The new reference count, should only be used for debugging. 194 */ 195 uint AddRef() { // @suppress(dscanner.style.phobos_naming_convention) 196 return nu_atomic_add_32(refcount, 1); 197 } 198 199 /** 200 Decrements the reference count for an interface on a COM object. 201 202 Returns: 203 The new reference count, should only be used for debugging. 204 */ 205 uint Release() { // @suppress(dscanner.style.phobos_naming_convention) 206 int lref = nu_atomic_sub_32(refcount, 1); 207 if (lref == 0) { 208 ComObject self = this; 209 nogc_delete(self); 210 } 211 return cast(uint)lref; 212 } 213 }