2 * HGLOBAL Stream implementation
4 * Copyright 1999 Francis Beaudet
5 * Copyright 2016 Dmitry Timoshkov
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 #define NONAMELESSUNION
27 #include "wine/debug.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(storage
);
36 BOOL delete_on_release
;
39 static void handle_addref(struct handle_wrapper
*handle
)
41 InterlockedIncrement(&handle
->ref
);
44 static void handle_release(struct handle_wrapper
*handle
)
46 ULONG ref
= InterlockedDecrement(&handle
->ref
);
50 if (handle
->delete_on_release
) GlobalFree(handle
->hglobal
);
51 HeapFree(GetProcessHeap(), 0, handle
);
55 static struct handle_wrapper
*handle_create(HGLOBAL hglobal
, BOOL delete_on_release
)
57 struct handle_wrapper
*handle
;
59 handle
= HeapAlloc(GetProcessHeap(), 0, sizeof(*handle
));
60 if (!handle
) return NULL
;
62 /* allocate a handle if one is not supplied */
63 if (!hglobal
) hglobal
= GlobalAlloc(GMEM_MOVEABLE
| GMEM_NODISCARD
| GMEM_SHARE
, 0);
66 HeapFree(GetProcessHeap(), 0, handle
);
70 handle
->hglobal
= hglobal
;
71 handle
->size
= GlobalSize(hglobal
);
72 handle
->delete_on_release
= delete_on_release
;
79 IStream IStream_iface
;
82 struct handle_wrapper
*handle
;
83 ULARGE_INTEGER position
;
86 static inline struct hglobal_stream
*impl_from_IStream(IStream
*iface
)
88 return CONTAINING_RECORD(iface
, struct hglobal_stream
, IStream_iface
);
91 static const IStreamVtbl hglobalstreamvtbl
;
93 static struct hglobal_stream
*hglobalstream_construct(void)
95 struct hglobal_stream
*object
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(*object
));
99 object
->IStream_iface
.lpVtbl
= &hglobalstreamvtbl
;
105 static HRESULT WINAPI
stream_QueryInterface(IStream
*iface
, REFIID riid
, void **obj
)
110 if (IsEqualIID(&IID_IUnknown
, riid
) ||
111 IsEqualIID(&IID_ISequentialStream
, riid
) ||
112 IsEqualIID(&IID_IStream
, riid
))
115 IStream_AddRef(iface
);
120 return E_NOINTERFACE
;
123 static ULONG WINAPI
stream_AddRef(IStream
*iface
)
125 struct hglobal_stream
*stream
= impl_from_IStream(iface
);
126 return InterlockedIncrement(&stream
->ref
);
129 static ULONG WINAPI
stream_Release(IStream
*iface
)
131 struct hglobal_stream
*stream
= impl_from_IStream(iface
);
132 ULONG ref
= InterlockedDecrement(&stream
->ref
);
136 handle_release(stream
->handle
);
137 HeapFree(GetProcessHeap(), 0, stream
);
143 static HRESULT WINAPI
stream_Read(IStream
*iface
, void *pv
, ULONG cb
, ULONG
*read_len
)
145 struct hglobal_stream
*stream
= impl_from_IStream(iface
);
149 TRACE("%p, %p, %d, %p\n", iface
, pv
, cb
, read_len
);
154 len
= min(stream
->handle
->size
- stream
->position
.u
.LowPart
, cb
);
156 buffer
= GlobalLock(stream
->handle
->hglobal
);
159 WARN("Failed to lock hglobal %p\n", stream
->handle
->hglobal
);
164 memcpy(pv
, buffer
+ stream
->position
.u
.LowPart
, len
);
165 stream
->position
.u
.LowPart
+= len
;
169 GlobalUnlock(stream
->handle
->hglobal
);
174 static HRESULT WINAPI
stream_Write(IStream
*iface
, const void *pv
, ULONG cb
, ULONG
*written
)
176 struct hglobal_stream
*stream
= impl_from_IStream(iface
);
181 TRACE("%p, %p, %d, %p\n", iface
, pv
, cb
, written
);
192 size
.u
.LowPart
= stream
->position
.u
.LowPart
+ cb
;
194 if (size
.u
.LowPart
> stream
->handle
->size
)
197 HRESULT hr
= IStream_SetSize(iface
, size
);
200 ERR("IStream_SetSize failed with error 0x%08x\n", hr
);
205 buffer
= GlobalLock(stream
->handle
->hglobal
);
208 WARN("write to invalid hglobal %p\n", stream
->handle
->hglobal
);
212 memcpy(buffer
+ stream
->position
.u
.LowPart
, pv
, cb
);
213 stream
->position
.u
.LowPart
+= cb
;
215 GlobalUnlock(stream
->handle
->hglobal
);
223 static HRESULT WINAPI
stream_Seek(IStream
*iface
, LARGE_INTEGER move
, DWORD origin
,
226 struct hglobal_stream
*stream
= impl_from_IStream(iface
);
227 ULARGE_INTEGER position
= stream
->position
;
230 TRACE("%p, %s, %d, %p\n", iface
, wine_dbgstr_longlong(move
.QuadPart
), origin
, pos
);
234 case STREAM_SEEK_SET
:
235 position
.QuadPart
= 0;
237 case STREAM_SEEK_CUR
:
239 case STREAM_SEEK_END
:
240 position
.QuadPart
= stream
->handle
->size
;
243 hr
= STG_E_SEEKERROR
;
247 position
.u
.HighPart
= 0;
248 position
.u
.LowPart
+= move
.QuadPart
;
250 if (move
.u
.LowPart
>= 0x80000000 && position
.u
.LowPart
>= move
.u
.LowPart
)
252 /* We tried to seek backwards and went past the start. */
253 hr
= STG_E_SEEKERROR
;
257 stream
->position
= position
;
260 if (pos
) *pos
= stream
->position
;
265 static HRESULT WINAPI
stream_SetSize(IStream
*iface
, ULARGE_INTEGER size
)
267 struct hglobal_stream
*stream
= impl_from_IStream(iface
);
270 TRACE("%p, %s\n", iface
, wine_dbgstr_longlong(size
.QuadPart
));
272 if (stream
->handle
->size
== size
.u
.LowPart
)
275 hglobal
= GlobalReAlloc(stream
->handle
->hglobal
, size
.u
.LowPart
, GMEM_MOVEABLE
);
277 return E_OUTOFMEMORY
;
279 stream
->handle
->hglobal
= hglobal
;
280 stream
->handle
->size
= size
.u
.LowPart
;
285 static HRESULT WINAPI
stream_CopyTo(IStream
*iface
, IStream
*dest
, ULARGE_INTEGER cb
,
286 ULARGE_INTEGER
*read_len
, ULARGE_INTEGER
*written
)
288 ULARGE_INTEGER total_read
, total_written
;
292 TRACE("%p, %p, %d, %p, %p\n", iface
, dest
, cb
.u
.LowPart
, read_len
, written
);
295 return STG_E_INVALIDPOINTER
;
297 total_read
.QuadPart
= 0;
298 total_written
.QuadPart
= 0;
300 while (cb
.QuadPart
> 0)
302 ULONG chunk_size
= cb
.QuadPart
>= sizeof(buffer
) ? sizeof(buffer
) : cb
.u
.LowPart
;
303 ULONG chunk_read
, chunk_written
;
305 hr
= IStream_Read(iface
, buffer
, chunk_size
, &chunk_read
);
309 total_read
.QuadPart
+= chunk_read
;
313 hr
= IStream_Write(dest
, buffer
, chunk_read
, &chunk_written
);
317 total_written
.QuadPart
+= chunk_written
;
320 if (chunk_read
!= chunk_size
)
323 cb
.QuadPart
-= chunk_read
;
327 read_len
->QuadPart
= total_read
.QuadPart
;
329 written
->QuadPart
= total_written
.QuadPart
;
334 static HRESULT WINAPI
stream_Commit(IStream
*iface
, DWORD flags
)
339 static HRESULT WINAPI
stream_Revert(IStream
*iface
)
344 static HRESULT WINAPI
stream_LockRegion(IStream
*iface
, ULARGE_INTEGER offset
,
345 ULARGE_INTEGER len
, DWORD lock_type
)
347 return STG_E_INVALIDFUNCTION
;
350 static HRESULT WINAPI
stream_UnlockRegion(IStream
*iface
, ULARGE_INTEGER offset
,
351 ULARGE_INTEGER len
, DWORD lock_type
)
356 static HRESULT WINAPI
stream_Stat(IStream
*iface
, STATSTG
*pstatstg
, DWORD flags
)
358 struct hglobal_stream
*stream
= impl_from_IStream(iface
);
360 memset(pstatstg
, 0, sizeof(STATSTG
));
362 pstatstg
->pwcsName
= NULL
;
363 pstatstg
->type
= STGTY_STREAM
;
364 pstatstg
->cbSize
.QuadPart
= stream
->handle
->size
;
369 static HRESULT WINAPI
stream_Clone(IStream
*iface
, IStream
**ppstm
)
371 struct hglobal_stream
*stream
= impl_from_IStream(iface
), *clone
;
372 ULARGE_INTEGER dummy
;
373 LARGE_INTEGER offset
;
375 TRACE("%p, %p\n", iface
, ppstm
);
379 clone
= hglobalstream_construct();
380 if (!clone
) return E_OUTOFMEMORY
;
382 *ppstm
= &clone
->IStream_iface
;
383 handle_addref(stream
->handle
);
384 clone
->handle
= stream
->handle
;
386 offset
.QuadPart
= (LONGLONG
)stream
->position
.QuadPart
;
387 IStream_Seek(*ppstm
, offset
, STREAM_SEEK_SET
, &dummy
);
391 static const IStreamVtbl hglobalstreamvtbl
=
393 stream_QueryInterface
,
409 /***********************************************************************
410 * CreateStreamOnHGlobal (combase.@)
412 HRESULT WINAPI
CreateStreamOnHGlobal(HGLOBAL hGlobal
, BOOL delete_on_release
, IStream
**stream
)
414 struct hglobal_stream
*object
;
419 object
= hglobalstream_construct();
420 if (!object
) return E_OUTOFMEMORY
;
422 object
->handle
= handle_create(hGlobal
, delete_on_release
);
425 HeapFree(GetProcessHeap(), 0, object
);
426 return E_OUTOFMEMORY
;
429 *stream
= &object
->IStream_iface
;
434 /***********************************************************************
435 * GetHGlobalFromStream (combase.@)
437 HRESULT WINAPI
GetHGlobalFromStream(IStream
*stream
, HGLOBAL
*phglobal
)
439 struct hglobal_stream
*object
;
441 if (!stream
|| !phglobal
)
444 object
= impl_from_IStream(stream
);
446 if (object
->IStream_iface
.lpVtbl
== &hglobalstreamvtbl
)
447 *phglobal
= object
->handle
->hglobal
;