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