1 // Written by Christopher E. Miller 2 // See the included license.txt for copyright and license details. 3 4 module dfl.internal.com; 5 6 import core.sys.windows.windows; 7 import core.sys.windows.com; 8 import core.sys.windows.objidl; // IStream 9 10 // FIX: import dfl.internal.winapi; 11 // FIX: import dfl.internal.wincom; 12 import dfl.internal.dlib; 13 14 // Importing dfl.application here causes the compiler to crash. 15 //import dfl.application; 16 private extern(C) { 17 size_t C_refCountInc(void* p); 18 size_t C_refCountDec(void* p); 19 } 20 21 22 // Won't be killed by GC if not referenced in D and the refcount is > 0. 23 class DflComObject: ComObject { 24 extern(Windows) { 25 override ULONG AddRef() { 26 //cprintf("AddRef `%.*s`\n", cast(int)toString().length, toString().ptr); 27 return C_refCountInc(cast(void*)this); 28 } 29 30 override ULONG Release() { 31 //cprintf("Release `%.*s`\n", cast(int)toString().length, toString().ptr); 32 return C_refCountDec(cast(void*)this); 33 } 34 } 35 } 36 37 class DStreamToIStream: DflComObject, IStream { 38 this(DStream sourceDStream) { 39 this.stm = sourceDStream; 40 } 41 42 43 extern(Windows): 44 override HRESULT QueryInterface(IID* riid, void** ppv) { 45 if(*riid == IID_IStream) { 46 *ppv = cast(void*)cast(IStream)this; 47 AddRef(); 48 return S_OK; 49 } else if(*riid == IID_ISequentialStream) { 50 *ppv = cast(void*)cast(ISequentialStream)this; 51 AddRef(); 52 return S_OK; 53 } else if(*riid == IID_IUnknown) { 54 *ppv = cast(void*)cast(IUnknown)this; 55 AddRef(); 56 return S_OK; 57 } else { 58 *ppv = null; 59 return E_NOINTERFACE; 60 } 61 } 62 63 64 HRESULT Read(void* pv, ULONG cb, ULONG* pcbRead) { 65 ULONG read; 66 HRESULT result = S_OK; 67 68 try { 69 read = stm.readBlock(pv, cb); 70 } catch(DStreamException e) { 71 result = S_FALSE; // ? 72 } 73 74 if(pcbRead) { 75 *pcbRead = read; 76 } 77 //if(!read) 78 // result = S_FALSE; 79 return result; 80 } 81 82 83 HRESULT Write(void* pv, ULONG cb, ULONG* pcbWritten) { 84 ULONG written; 85 HRESULT result = S_OK; 86 87 try { 88 if(!stm.writeable) { 89 return E_NOTIMPL; 90 } 91 written = stm.writeBlock(pv, cb); 92 } catch(DStreamException e) { 93 result = S_FALSE; // ? 94 } 95 96 if(pcbWritten) { 97 *pcbWritten = written; 98 } 99 //if(!written) 100 // result = S_FALSE; 101 return result; 102 } 103 104 105 version(DFL_TANGO_NO_SEEK_COMPAT) { 106 } else { 107 long _fakepos = 0; 108 } 109 110 111 HRESULT Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) { 112 HRESULT result = S_OK; 113 114 //cprintf("seek move=%u, origin=0x%x\n", cast(uint)dlibMove.QuadPart, dwOrigin); 115 116 try { 117 if(!stm.seekable) { 118 //return S_FALSE; // ? 119 return E_NOTIMPL; // ? 120 } 121 122 ulong pos; 123 switch (dwOrigin) with (STREAM_SEEK) { 124 case STREAM_SEEK_SET: 125 pos = stm.seekSet(dlibMove.QuadPart); 126 if(plibNewPosition) { 127 plibNewPosition.QuadPart = pos; 128 } 129 break; 130 131 case STREAM_SEEK_CUR: 132 pos = stm.seekCur(dlibMove.QuadPart); 133 if(plibNewPosition) { 134 plibNewPosition.QuadPart = pos; 135 } 136 break; 137 138 case STREAM_SEEK_END: 139 pos = stm.seekEnd(dlibMove.QuadPart); 140 if(plibNewPosition) { 141 plibNewPosition.QuadPart = pos; 142 } 143 break; 144 145 default: 146 result = STG_E_INVALIDFUNCTION; 147 } 148 } catch(DStreamException e) { 149 result = S_FALSE; // ? 150 } 151 152 return result; 153 } 154 155 156 HRESULT SetSize(ULARGE_INTEGER libNewSize) { 157 return E_NOTIMPL; 158 } 159 160 161 HRESULT CopyTo(IStream pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) { 162 // TODO: implement. 163 return E_NOTIMPL; 164 } 165 166 167 HRESULT Commit(DWORD grfCommitFlags) { 168 // Ignore -grfCommitFlags- and just flush the stream.. 169 //stm.flush(); 170 stm.flush(); 171 return S_OK; // ? 172 } 173 174 175 HRESULT Revert() { 176 return E_NOTIMPL; // ? S_FALSE ? 177 } 178 179 180 HRESULT LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { 181 return E_NOTIMPL; 182 } 183 184 185 HRESULT UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { 186 return E_NOTIMPL; 187 } 188 189 190 HRESULT Stat(STATSTG* pstatstg, DWORD grfStatFlag) { 191 return E_NOTIMPL; // ? 192 } 193 194 195 HRESULT Clone(IStream* ppstm) { 196 // Cloned stream needs its own seek position. 197 return E_NOTIMPL; // ? 198 } 199 200 201 extern(D): 202 private DStream stm; 203 } 204 205 class MemoryIStream: DflComObject, IStream { 206 this(void[] memory) { 207 this.mem = memory; 208 } 209 210 211 extern(Windows): 212 213 override HRESULT QueryInterface(IID* riid, void** ppv) { 214 if(*riid == IID_IStream) { 215 *ppv = cast(void*)cast(IStream)this; 216 AddRef(); 217 return S_OK; 218 } else if(*riid == IID_ISequentialStream) { 219 *ppv = cast(void*)cast(ISequentialStream)this; 220 AddRef(); 221 return S_OK; 222 } else if(*riid == IID_IUnknown) { 223 *ppv = cast(void*)cast(IUnknown)this; 224 AddRef(); 225 return S_OK; 226 } else { 227 *ppv = null; 228 return E_NOINTERFACE; 229 } 230 } 231 232 233 HRESULT Read(void* pv, ULONG cb, ULONG* pcbRead) { 234 // Shouldn't happen unless the mem changes, which doesn't happen yet. 235 if(seekpos > mem.length) { 236 return S_FALSE; // ? 237 } 238 239 size_t count = mem.length - seekpos; 240 if(count > cb) { 241 count = cb; 242 } 243 244 pv[0 .. count] = mem[seekpos .. seekpos + count]; 245 seekpos += count; 246 247 if(pcbRead) { 248 *pcbRead = count; 249 } 250 return S_OK; 251 } 252 253 254 HRESULT Write(void* pv, ULONG cb, ULONG* pcbWritten) { 255 //return STG_E_ACCESSDENIED; 256 return E_NOTIMPL; 257 } 258 259 260 HRESULT Seek(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER* plibNewPosition) { 261 //cprintf("seek move=%u, origin=0x%x\n", cast(uint)dlibMove.QuadPart, dwOrigin); 262 263 auto toPos = cast(long)dlibMove.QuadPart; 264 switch (dwOrigin) with (STREAM_SEEK) { 265 case STREAM_SEEK_SET: 266 break; 267 268 case STREAM_SEEK_CUR: 269 toPos = cast(long)seekpos + toPos; 270 break; 271 272 case STREAM_SEEK_END: 273 toPos = cast(long)mem.length - toPos; 274 break; 275 276 default: 277 return STG_E_INVALIDFUNCTION; 278 } 279 280 if(withinbounds(toPos)) { 281 seekpos = cast(size_t)toPos; 282 if(plibNewPosition) { 283 plibNewPosition.QuadPart = seekpos; 284 } 285 return S_OK; 286 } else { 287 return 0x80030005; //STG_E_ACCESSDENIED; // Seeking past end needs write access. 288 } 289 } 290 291 292 HRESULT SetSize(ULARGE_INTEGER libNewSize) { 293 return E_NOTIMPL; 294 } 295 296 297 HRESULT CopyTo(IStream pstm, ULARGE_INTEGER cb, ULARGE_INTEGER* pcbRead, ULARGE_INTEGER* pcbWritten) { 298 // TODO: implement. 299 return E_NOTIMPL; 300 } 301 302 303 HRESULT Commit(DWORD grfCommitFlags) { 304 return S_OK; // ? 305 } 306 307 308 HRESULT Revert() { 309 return E_NOTIMPL; // ? S_FALSE ? 310 } 311 312 313 HRESULT LockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { 314 return E_NOTIMPL; 315 } 316 317 318 HRESULT UnlockRegion(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType) { 319 return E_NOTIMPL; 320 } 321 322 323 HRESULT Stat(STATSTG* pstatstg, DWORD grfStatFlag) { 324 return E_NOTIMPL; // ? 325 } 326 327 328 HRESULT Clone(IStream* ppstm) { 329 // Cloned stream needs its own seek position. 330 return E_NOTIMPL; // ? 331 } 332 333 334 extern(D) { 335 private void[] mem; 336 private size_t seekpos = 0; 337 338 339 private bool withinbounds(long pos) { 340 if(pos < seekpos.min || pos > seekpos.max) { 341 return false; 342 } 343 // Note: it IS within bounds if it's AT the end, it just can't read there. 344 return cast(size_t)pos <= mem.length; 345 } 346 } 347 } 348