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
25 #include "wine/debug.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(storage
);
34 BOOL delete_on_release
;
37 static void handle_addref(struct handle_wrapper
*handle
)
39 InterlockedIncrement(&handle
->ref
);
42 static void handle_release(struct handle_wrapper
*handle
)
44 ULONG ref
= InterlockedDecrement(&handle
->ref
);
48 if (handle
->delete_on_release
) GlobalFree(handle
->hglobal
);
53 static struct handle_wrapper
*handle_create(HGLOBAL hglobal
, BOOL delete_on_release
)
55 struct handle_wrapper
*handle
;
57 handle
= malloc(sizeof(*handle
));
58 if (!handle
) return NULL
;
60 /* allocate a handle if one is not supplied */
61 if (!hglobal
) hglobal
= GlobalAlloc(GMEM_MOVEABLE
| GMEM_NODISCARD
| GMEM_SHARE
, 0);
68 handle
->hglobal
= hglobal
;
69 handle
->size
= GlobalSize(hglobal
);
70 handle
->delete_on_release
= delete_on_release
;
77 IStream IStream_iface
;
80 struct handle_wrapper
*handle
;
81 ULARGE_INTEGER position
;
84 static inline struct hglobal_stream
*impl_from_IStream(IStream
*iface
)
86 return CONTAINING_RECORD(iface
, struct hglobal_stream
, IStream_iface
);
89 static const IStreamVtbl hglobalstreamvtbl
;
91 static struct hglobal_stream
*hglobalstream_construct(void)
93 struct hglobal_stream
*object
= calloc(1, sizeof(*object
));
97 object
->IStream_iface
.lpVtbl
= &hglobalstreamvtbl
;
103 static HRESULT WINAPI
stream_QueryInterface(IStream
*iface
, REFIID riid
, void **obj
)
108 if (IsEqualIID(&IID_IUnknown
, riid
) ||
109 IsEqualIID(&IID_ISequentialStream
, riid
) ||
110 IsEqualIID(&IID_IStream
, riid
))
113 IStream_AddRef(iface
);
118 return E_NOINTERFACE
;
121 static ULONG WINAPI
stream_AddRef(IStream
*iface
)
123 struct hglobal_stream
*stream
= impl_from_IStream(iface
);
124 return InterlockedIncrement(&stream
->ref
);
127 static ULONG WINAPI
stream_Release(IStream
*iface
)
129 struct hglobal_stream
*stream
= impl_from_IStream(iface
);
130 ULONG ref
= InterlockedDecrement(&stream
->ref
);
134 handle_release(stream
->handle
);
141 static HRESULT WINAPI
stream_Read(IStream
*iface
, void *pv
, ULONG cb
, ULONG
*read_len
)
143 struct hglobal_stream
*stream
= impl_from_IStream(iface
);
147 TRACE("%p, %p, %ld, %p\n", iface
, pv
, cb
, read_len
);
152 if (stream
->handle
->size
>= stream
->position
.LowPart
)
153 len
= min(stream
->handle
->size
- stream
->position
.LowPart
, cb
);
157 buffer
= GlobalLock(stream
->handle
->hglobal
);
160 WARN("Failed to lock hglobal %p\n", stream
->handle
->hglobal
);
165 memcpy(pv
, buffer
+ stream
->position
.LowPart
, len
);
166 stream
->position
.LowPart
+= len
;
170 GlobalUnlock(stream
->handle
->hglobal
);
175 static HRESULT WINAPI
stream_Write(IStream
*iface
, const void *pv
, ULONG cb
, ULONG
*written
)
177 struct hglobal_stream
*stream
= impl_from_IStream(iface
);
182 TRACE("%p, %p, %ld, %p\n", iface
, pv
, cb
, written
);
193 size
.LowPart
= stream
->position
.LowPart
+ cb
;
195 if (size
.LowPart
> stream
->handle
->size
)
198 HRESULT hr
= IStream_SetSize(iface
, size
);
201 ERR("IStream_SetSize failed with error %#lx\n", hr
);
206 buffer
= GlobalLock(stream
->handle
->hglobal
);
209 WARN("write to invalid hglobal %p\n", stream
->handle
->hglobal
);
213 memcpy(buffer
+ stream
->position
.LowPart
, pv
, cb
);
214 stream
->position
.LowPart
+= cb
;
216 GlobalUnlock(stream
->handle
->hglobal
);
224 static HRESULT WINAPI
stream_Seek(IStream
*iface
, LARGE_INTEGER move
, DWORD origin
,
227 struct hglobal_stream
*stream
= impl_from_IStream(iface
);
228 ULARGE_INTEGER position
= stream
->position
;
231 TRACE("%p, %s, %ld, %p\n", iface
, wine_dbgstr_longlong(move
.QuadPart
), origin
, pos
);
235 case STREAM_SEEK_SET
:
236 position
.QuadPart
= 0;
238 case STREAM_SEEK_CUR
:
240 case STREAM_SEEK_END
:
241 position
.QuadPart
= stream
->handle
->size
;
244 hr
= STG_E_SEEKERROR
;
248 position
.HighPart
= 0;
249 position
.LowPart
+= move
.QuadPart
;
251 if (move
.LowPart
>= 0x80000000 && position
.LowPart
>= move
.LowPart
)
253 /* We tried to seek backwards and went past the start. */
254 hr
= STG_E_SEEKERROR
;
258 stream
->position
= position
;
261 if (pos
) *pos
= stream
->position
;
266 static HRESULT WINAPI
stream_SetSize(IStream
*iface
, ULARGE_INTEGER size
)
268 struct hglobal_stream
*stream
= impl_from_IStream(iface
);
271 TRACE("%p, %s\n", iface
, wine_dbgstr_longlong(size
.QuadPart
));
273 if (stream
->handle
->size
== size
.LowPart
)
276 hglobal
= GlobalReAlloc(stream
->handle
->hglobal
, size
.LowPart
, GMEM_MOVEABLE
);
278 return E_OUTOFMEMORY
;
280 stream
->handle
->hglobal
= hglobal
;
281 stream
->handle
->size
= size
.LowPart
;
286 static HRESULT WINAPI
stream_CopyTo(IStream
*iface
, IStream
*dest
, ULARGE_INTEGER cb
,
287 ULARGE_INTEGER
*read_len
, ULARGE_INTEGER
*written
)
289 ULARGE_INTEGER total_read
, total_written
;
293 TRACE("%p, %p, %ld, %p, %p\n", iface
, dest
, cb
.LowPart
, read_len
, written
);
296 return STG_E_INVALIDPOINTER
;
298 total_read
.QuadPart
= 0;
299 total_written
.QuadPart
= 0;
301 while (cb
.QuadPart
> 0)
303 ULONG chunk_size
= cb
.QuadPart
>= sizeof(buffer
) ? sizeof(buffer
) : cb
.LowPart
;
304 ULONG chunk_read
, chunk_written
;
306 hr
= IStream_Read(iface
, buffer
, chunk_size
, &chunk_read
);
310 total_read
.QuadPart
+= chunk_read
;
314 hr
= IStream_Write(dest
, buffer
, chunk_read
, &chunk_written
);
318 total_written
.QuadPart
+= chunk_written
;
321 if (chunk_read
!= chunk_size
)
324 cb
.QuadPart
-= chunk_read
;
328 read_len
->QuadPart
= total_read
.QuadPart
;
330 written
->QuadPart
= total_written
.QuadPart
;
335 static HRESULT WINAPI
stream_Commit(IStream
*iface
, DWORD flags
)
340 static HRESULT WINAPI
stream_Revert(IStream
*iface
)
345 static HRESULT WINAPI
stream_LockRegion(IStream
*iface
, ULARGE_INTEGER offset
,
346 ULARGE_INTEGER len
, DWORD lock_type
)
348 return STG_E_INVALIDFUNCTION
;
351 static HRESULT WINAPI
stream_UnlockRegion(IStream
*iface
, ULARGE_INTEGER offset
,
352 ULARGE_INTEGER len
, DWORD lock_type
)
357 static HRESULT WINAPI
stream_Stat(IStream
*iface
, STATSTG
*pstatstg
, DWORD flags
)
359 struct hglobal_stream
*stream
= impl_from_IStream(iface
);
361 memset(pstatstg
, 0, sizeof(STATSTG
));
363 pstatstg
->pwcsName
= NULL
;
364 pstatstg
->type
= STGTY_STREAM
;
365 pstatstg
->cbSize
.QuadPart
= stream
->handle
->size
;
370 static HRESULT WINAPI
stream_Clone(IStream
*iface
, IStream
**ppstm
)
372 struct hglobal_stream
*stream
= impl_from_IStream(iface
), *clone
;
373 ULARGE_INTEGER dummy
;
374 LARGE_INTEGER offset
;
376 TRACE("%p, %p\n", iface
, ppstm
);
380 clone
= hglobalstream_construct();
381 if (!clone
) return E_OUTOFMEMORY
;
383 *ppstm
= &clone
->IStream_iface
;
384 handle_addref(stream
->handle
);
385 clone
->handle
= stream
->handle
;
387 offset
.QuadPart
= (LONGLONG
)stream
->position
.QuadPart
;
388 IStream_Seek(*ppstm
, offset
, STREAM_SEEK_SET
, &dummy
);
392 static const IStreamVtbl hglobalstreamvtbl
=
394 stream_QueryInterface
,
410 /***********************************************************************
411 * CreateStreamOnHGlobal (combase.@)
413 HRESULT WINAPI
CreateStreamOnHGlobal(HGLOBAL hGlobal
, BOOL delete_on_release
, IStream
**stream
)
415 struct hglobal_stream
*object
;
420 object
= hglobalstream_construct();
421 if (!object
) return E_OUTOFMEMORY
;
423 object
->handle
= handle_create(hGlobal
, delete_on_release
);
427 return E_OUTOFMEMORY
;
430 *stream
= &object
->IStream_iface
;
435 /***********************************************************************
436 * GetHGlobalFromStream (combase.@)
438 HRESULT WINAPI
GetHGlobalFromStream(IStream
*stream
, HGLOBAL
*phglobal
)
440 struct hglobal_stream
*object
;
442 if (!stream
|| !phglobal
)
445 object
= impl_from_IStream(stream
);
447 if (object
->IStream_iface
.lpVtbl
== &hglobalstreamvtbl
)
448 *phglobal
= object
->handle
->hglobal
;