blob: 75930f403d25c3cbaf010bd8c48dddd2875be92f [file] [log] [blame]
Francis Beaudet4f8b5a81999-04-24 12:00:31 +00001/*
2 * HGLOBAL Stream implementation
3 *
4 * This file contains the implementation of the stream interface
Alexandre Julliard81ee21d1999-12-27 05:26:00 +00005 * for streams contained supported by an HGLOBAL pointer.
Francis Beaudet4f8b5a81999-04-24 12:00:31 +00006 *
7 * Copyright 1999 Francis Beaudet
Alexandre Julliard0799c1a2002-03-09 23:29:33 +00008 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Francis Beaudet4f8b5a81999-04-24 12:00:31 +000022 */
Patrik Stridvallbc38d6b2001-07-20 18:00:00 +000023
24#include "config.h"
25
Francis Beaudet4f8b5a81999-04-24 12:00:31 +000026#include <assert.h>
27#include <stdlib.h>
28#include <stdio.h>
29#include <string.h>
30
Dimitrie O. Paun297f3d82003-01-07 20:36:20 +000031#define NONAMELESSUNION
32#define NONAMELESSSTRUCT
Patrik Stridvallbc38d6b2001-07-20 18:00:00 +000033#include "windef.h"
34#include "objbase.h"
35#include "ole2.h"
Francis Beaudet4f8b5a81999-04-24 12:00:31 +000036#include "winbase.h"
37#include "winerror.h"
Patrik Stridvall9c1de6d2002-09-12 22:07:02 +000038#include "winternl.h"
Francis Beaudet4f8b5a81999-04-24 12:00:31 +000039
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000040#include "wine/debug.h"
Francis Beaudet4f8b5a81999-04-24 12:00:31 +000041
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000042WINE_DEFAULT_DEBUG_CHANNEL(storage);
Francis Beaudet4f8b5a81999-04-24 12:00:31 +000043
44/****************************************************************************
45 * HGLOBALStreamImpl definition.
46 *
47 * This class imlements the IStream inteface and represents a stream
48 * supported by an HGLOBAL pointer.
49 */
50struct HGLOBALStreamImpl
51{
Francois Gouget01c9ac41999-10-31 01:59:23 +000052 ICOM_VFIELD(IStream); /* Needs to be the first item in the stuct
53 * since we want to cast this in a IStream pointer */
Vincent Béron9a624912002-05-31 23:06:46 +000054
Francis Beaudet4f8b5a81999-04-24 12:00:31 +000055 /*
56 * Reference count
57 */
58 ULONG ref;
59
60 /*
61 * Support for the stream
62 */
63 HGLOBAL supportHandle;
64
65 /*
66 * This flag is TRUE if the HGLOBAL is destroyed when the stream
67 * is finally released.
68 */
69 BOOL deleteOnRelease;
70
71 /*
72 * Helper variable that contains the size of the stream
73 */
74 ULARGE_INTEGER streamSize;
75
76 /*
77 * This is the current position of the cursor in the stream
78 */
79 ULARGE_INTEGER currentPosition;
80};
81
82typedef struct HGLOBALStreamImpl HGLOBALStreamImpl;
83
84/*
85 * Method definition for the StgStreamImpl class.
86 */
87HGLOBALStreamImpl* HGLOBALStreamImpl_Construct(
88 HGLOBAL hGlobal,
89 BOOL fDeleteOnRelease);
90
91void HGLOBALStreamImpl_Destroy(
92 HGLOBALStreamImpl* This);
93
94void HGLOBALStreamImpl_OpenBlockChain(
95 HGLOBALStreamImpl* This);
96
97HRESULT WINAPI HGLOBALStreamImpl_QueryInterface(
98 IStream* iface,
Vincent Béron9a624912002-05-31 23:06:46 +000099 REFIID riid, /* [in] */
100 void** ppvObject); /* [iid_is][out] */
101
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000102ULONG WINAPI HGLOBALStreamImpl_AddRef(
103 IStream* iface);
Vincent Béron9a624912002-05-31 23:06:46 +0000104
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000105ULONG WINAPI HGLOBALStreamImpl_Release(
106 IStream* iface);
Vincent Béron9a624912002-05-31 23:06:46 +0000107
108HRESULT WINAPI HGLOBALStreamImpl_Read(
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000109 IStream* iface,
110 void* pv, /* [length_is][size_is][out] */
Vincent Béron9a624912002-05-31 23:06:46 +0000111 ULONG cb, /* [in] */
112 ULONG* pcbRead); /* [out] */
113
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000114HRESULT WINAPI HGLOBALStreamImpl_Write(
115 IStream* iface,
Vincent Béron9a624912002-05-31 23:06:46 +0000116 const void* pv, /* [size_is][in] */
117 ULONG cb, /* [in] */
118 ULONG* pcbWritten); /* [out] */
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000119
Vincent Béron9a624912002-05-31 23:06:46 +0000120HRESULT WINAPI HGLOBALStreamImpl_Seek(
121 IStream* iface,
122 LARGE_INTEGER dlibMove, /* [in] */
123 DWORD dwOrigin, /* [in] */
124 ULARGE_INTEGER* plibNewPosition); /* [out] */
125
126HRESULT WINAPI HGLOBALStreamImpl_SetSize(
127 IStream* iface,
128 ULARGE_INTEGER libNewSize); /* [in] */
129
130HRESULT WINAPI HGLOBALStreamImpl_CopyTo(
131 IStream* iface,
132 IStream* pstm, /* [unique][in] */
133 ULARGE_INTEGER cb, /* [in] */
134 ULARGE_INTEGER* pcbRead, /* [out] */
135 ULARGE_INTEGER* pcbWritten); /* [out] */
136
137HRESULT WINAPI HGLOBALStreamImpl_Commit(
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000138 IStream* iface,
Vincent Béron9a624912002-05-31 23:06:46 +0000139 DWORD grfCommitFlags); /* [in] */
140
141HRESULT WINAPI HGLOBALStreamImpl_Revert(
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000142 IStream* iface);
Vincent Béron9a624912002-05-31 23:06:46 +0000143
144HRESULT WINAPI HGLOBALStreamImpl_LockRegion(
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000145 IStream* iface,
Vincent Béron9a624912002-05-31 23:06:46 +0000146 ULARGE_INTEGER libOffset, /* [in] */
147 ULARGE_INTEGER cb, /* [in] */
148 DWORD dwLockType); /* [in] */
149
150HRESULT WINAPI HGLOBALStreamImpl_UnlockRegion(
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000151 IStream* iface,
Vincent Béron9a624912002-05-31 23:06:46 +0000152 ULARGE_INTEGER libOffset, /* [in] */
153 ULARGE_INTEGER cb, /* [in] */
154 DWORD dwLockType); /* [in] */
155
156HRESULT WINAPI HGLOBALStreamImpl_Stat(
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000157 IStream* iface,
158 STATSTG* pstatstg, /* [out] */
Vincent Béron9a624912002-05-31 23:06:46 +0000159 DWORD grfStatFlag); /* [in] */
160
161HRESULT WINAPI HGLOBALStreamImpl_Clone(
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000162 IStream* iface,
Vincent Béron9a624912002-05-31 23:06:46 +0000163 IStream** ppstm); /* [out] */
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000164
165
166/*
167 * Virtual function table for the HGLOBALStreamImpl class.
168 */
169static ICOM_VTABLE(IStream) HGLOBALStreamImpl_Vtbl =
170{
Paul Quinn2305f3c1999-05-22 11:41:38 +0000171 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000172 HGLOBALStreamImpl_QueryInterface,
173 HGLOBALStreamImpl_AddRef,
174 HGLOBALStreamImpl_Release,
175 HGLOBALStreamImpl_Read,
176 HGLOBALStreamImpl_Write,
177 HGLOBALStreamImpl_Seek,
178 HGLOBALStreamImpl_SetSize,
179 HGLOBALStreamImpl_CopyTo,
180 HGLOBALStreamImpl_Commit,
181 HGLOBALStreamImpl_Revert,
182 HGLOBALStreamImpl_LockRegion,
183 HGLOBALStreamImpl_UnlockRegion,
184 HGLOBALStreamImpl_Stat,
185 HGLOBALStreamImpl_Clone
186};
187
188/***********************************************************************
189 * CreateStreamOnHGlobal [OLE32.61]
190 */
191HRESULT WINAPI CreateStreamOnHGlobal(
Vincent Béron9a624912002-05-31 23:06:46 +0000192 HGLOBAL hGlobal,
193 BOOL fDeleteOnRelease,
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000194 LPSTREAM* ppstm)
195{
196 HGLOBALStreamImpl* newStream;
197
198 newStream = HGLOBALStreamImpl_Construct(hGlobal,
199 fDeleteOnRelease);
200
201 if (newStream!=NULL)
202 {
Vincent Béron9a624912002-05-31 23:06:46 +0000203 return IUnknown_QueryInterface((IUnknown*)newStream,
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000204 &IID_IStream,
205 (void**)ppstm);
206 }
207
208 return E_OUTOFMEMORY;
209}
210
Thuy Nguyen115d8cc1999-05-08 10:48:44 +0000211/***********************************************************************
212 * GetHGlobalFromStream [OLE32.71]
213 */
214HRESULT WINAPI GetHGlobalFromStream(IStream* pstm, HGLOBAL* phglobal)
215{
216 HGLOBALStreamImpl* pStream;
217
218 if (pstm == NULL)
219 return E_INVALIDARG;
220
221 pStream = (HGLOBALStreamImpl*) pstm;
222
223 /*
224 * Verify that the stream object was created with CreateStreamOnHGlobal.
225 */
Alexandre Julliardc2ebe1f2003-04-10 18:17:34 +0000226 if (pStream->lpVtbl == &HGLOBALStreamImpl_Vtbl)
Thuy Nguyen115d8cc1999-05-08 10:48:44 +0000227 *phglobal = pStream->supportHandle;
228 else
229 {
230 *phglobal = 0;
231 return E_INVALIDARG;
232 }
233
234 return S_OK;
235}
236
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000237/******************************************************************************
238** HGLOBALStreamImpl implementation
239*/
240
241/***
242 * This is the constructor for the HGLOBALStreamImpl class.
243 *
244 * Params:
245 * hGlobal - Handle that will support the stream. can be NULL.
Vincent Béron9a624912002-05-31 23:06:46 +0000246 * fDeleteOnRelease - Flag set to TRUE if the HGLOBAL will be released
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000247 * when the IStream object is destroyed.
248 */
249HGLOBALStreamImpl* HGLOBALStreamImpl_Construct(
250 HGLOBAL hGlobal,
251 BOOL fDeleteOnRelease)
252{
253 HGLOBALStreamImpl* newStream;
254
255 newStream = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALStreamImpl));
Vincent Béron9a624912002-05-31 23:06:46 +0000256
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000257 if (newStream!=0)
258 {
259 /*
260 * Set-up the virtual function table and reference count.
261 */
Alexandre Julliardc2ebe1f2003-04-10 18:17:34 +0000262 newStream->lpVtbl = &HGLOBALStreamImpl_Vtbl;
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000263 newStream->ref = 0;
Vincent Béron9a624912002-05-31 23:06:46 +0000264
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000265 /*
266 * Initialize the support.
267 */
268 newStream->supportHandle = hGlobal;
269 newStream->deleteOnRelease = fDeleteOnRelease;
270
271 /*
272 * This method will allocate a handle if one is not supplied.
273 */
Alexandre Julliardbd14f662000-11-25 01:40:34 +0000274 if (!newStream->supportHandle)
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000275 {
Huw D M Davies9bc79122000-07-08 11:46:16 +0000276 newStream->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD |
277 GMEM_SHARE, 0);
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000278 }
Vincent Béron9a624912002-05-31 23:06:46 +0000279
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000280 /*
Francois Gouget3bb9a362001-10-22 19:04:32 +0000281 * Start the stream at the beginning.
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000282 */
Patrik Stridvall311e4561999-09-19 14:20:33 +0000283 newStream->currentPosition.s.HighPart = 0;
284 newStream->currentPosition.s.LowPart = 0;
Vincent Béron9a624912002-05-31 23:06:46 +0000285
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000286 /*
287 * Initialize the size of the stream to the size of the handle.
288 */
Patrik Stridvall311e4561999-09-19 14:20:33 +0000289 newStream->streamSize.s.HighPart = 0;
290 newStream->streamSize.s.LowPart = GlobalSize(newStream->supportHandle);
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000291 }
Vincent Béron9a624912002-05-31 23:06:46 +0000292
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000293 return newStream;
294}
295
296/***
297 * This is the destructor of the HGLOBALStreamImpl class.
298 *
Vincent Béron9a624912002-05-31 23:06:46 +0000299 * This method will clean-up all the resources used-up by the given HGLOBALStreamImpl
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000300 * class. The pointer passed-in to this function will be freed and will not
301 * be valid anymore.
302 */
303void HGLOBALStreamImpl_Destroy(HGLOBALStreamImpl* This)
304{
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000305 TRACE("(%p)\n", This);
Francis Beaudetec2edc71999-05-02 11:41:10 +0000306
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000307 /*
308 * Release the HGlobal if the constructor asked for that.
309 */
310 if (This->deleteOnRelease)
311 {
312 GlobalFree(This->supportHandle);
313 This->supportHandle=0;
314 }
315
316 /*
317 * Finally, free the memory used-up by the class.
318 */
Vincent Béron9a624912002-05-31 23:06:46 +0000319 HeapFree(GetProcessHeap(), 0, This);
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000320}
321
322/***
323 * This implements the IUnknown method QueryInterface for this
324 * class
325 */
326HRESULT WINAPI HGLOBALStreamImpl_QueryInterface(
327 IStream* iface,
Vincent Béron9a624912002-05-31 23:06:46 +0000328 REFIID riid, /* [in] */
329 void** ppvObject) /* [iid_is][out] */
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000330{
331 HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
332
333 /*
334 * Perform a sanity check on the parameters.
335 */
336 if (ppvObject==0)
337 return E_INVALIDARG;
Vincent Béron9a624912002-05-31 23:06:46 +0000338
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000339 /*
340 * Initialize the return parameter.
341 */
342 *ppvObject = 0;
Vincent Béron9a624912002-05-31 23:06:46 +0000343
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000344 /*
345 * Compare the riid with the interface IDs implemented by this object.
346 */
Vincent Béron9a624912002-05-31 23:06:46 +0000347 if (memcmp(&IID_IUnknown, riid, sizeof(IID_IUnknown)) == 0)
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000348 {
349 *ppvObject = (IStream*)This;
350 }
Vincent Béron9a624912002-05-31 23:06:46 +0000351 else if (memcmp(&IID_IStream, riid, sizeof(IID_IStream)) == 0)
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000352 {
353 *ppvObject = (IStream*)This;
354 }
Vincent Béron9a624912002-05-31 23:06:46 +0000355
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000356 /*
357 * Check that we obtained an interface.
358 */
359 if ((*ppvObject)==0)
360 return E_NOINTERFACE;
Vincent Béron9a624912002-05-31 23:06:46 +0000361
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000362 /*
363 * Query Interface always increases the reference count by one when it is
364 * successful
365 */
366 HGLOBALStreamImpl_AddRef(iface);
Vincent Béron9a624912002-05-31 23:06:46 +0000367
368 return S_OK;
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000369}
370
371/***
372 * This implements the IUnknown method AddRef for this
373 * class
374 */
375ULONG WINAPI HGLOBALStreamImpl_AddRef(
376 IStream* iface)
377{
378 HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
379
380 This->ref++;
Vincent Béron9a624912002-05-31 23:06:46 +0000381
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000382 return This->ref;
383}
384
385/***
386 * This implements the IUnknown method Release for this
387 * class
388 */
389ULONG WINAPI HGLOBALStreamImpl_Release(
390 IStream* iface)
391{
392 HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
393
394 ULONG newRef;
Vincent Béron9a624912002-05-31 23:06:46 +0000395
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000396 This->ref--;
Vincent Béron9a624912002-05-31 23:06:46 +0000397
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000398 newRef = This->ref;
Vincent Béron9a624912002-05-31 23:06:46 +0000399
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000400 /*
401 * If the reference count goes down to 0, perform suicide.
402 */
403 if (newRef==0)
404 {
405 HGLOBALStreamImpl_Destroy(This);
406 }
Vincent Béron9a624912002-05-31 23:06:46 +0000407
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000408 return newRef;
409}
410
411/***
412 * This method is part of the ISequentialStream interface.
413 *
414 * If reads a block of information from the stream at the current
415 * position. It then moves the current position at the end of the
416 * read block
417 *
418 * See the documentation of ISequentialStream for more info.
419 */
Vincent Béron9a624912002-05-31 23:06:46 +0000420HRESULT WINAPI HGLOBALStreamImpl_Read(
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000421 IStream* iface,
422 void* pv, /* [length_is][size_is][out] */
Vincent Béron9a624912002-05-31 23:06:46 +0000423 ULONG cb, /* [in] */
424 ULONG* pcbRead) /* [out] */
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000425{
426 HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
427
428 void* supportBuffer;
429 ULONG bytesReadBuffer;
430 ULONG bytesToReadFromBuffer;
Francis Beaudetec2edc71999-05-02 11:41:10 +0000431
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000432 TRACE("(%p, %p, %ld, %p)\n", iface,
Francis Beaudetec2edc71999-05-02 11:41:10 +0000433 pv, cb, pcbRead);
Vincent Béron9a624912002-05-31 23:06:46 +0000434
435 /*
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000436 * If the caller is not interested in the nubmer of bytes read,
437 * we use another buffer to avoid "if" statements in the code.
438 */
439 if (pcbRead==0)
440 pcbRead = &bytesReadBuffer;
Vincent Béron9a624912002-05-31 23:06:46 +0000441
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000442 /*
443 * Using the known size of the stream, calculate the number of bytes
444 * to read from the block chain
445 */
Francois Gouget6d77d3a2000-03-25 21:44:35 +0000446 bytesToReadFromBuffer = min( This->streamSize.s.LowPart - This->currentPosition.s.LowPart, cb);
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000447
448 /*
449 * Lock the buffer in position and copy the data.
450 */
451 supportBuffer = GlobalLock(This->supportHandle);
452
Patrik Stridvall311e4561999-09-19 14:20:33 +0000453 memcpy(pv, (char *) supportBuffer+This->currentPosition.s.LowPart, bytesToReadFromBuffer);
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000454
455 /*
456 * Move the current position to the new position
457 */
Patrik Stridvall311e4561999-09-19 14:20:33 +0000458 This->currentPosition.s.LowPart+=bytesToReadFromBuffer;
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000459
460 /*
461 * Return the number of bytes read.
462 */
463 *pcbRead = bytesToReadFromBuffer;
464
465 /*
466 * Cleanup
467 */
468 GlobalUnlock(This->supportHandle);
Vincent Béron9a624912002-05-31 23:06:46 +0000469
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000470 /*
471 * The function returns S_OK if the buffer was filled completely
472 * it returns S_FALSE if the end of the stream is reached before the
473 * buffer is filled
474 */
475 if(*pcbRead == cb)
476 return S_OK;
Vincent Béron9a624912002-05-31 23:06:46 +0000477
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000478 return S_FALSE;
479}
Vincent Béron9a624912002-05-31 23:06:46 +0000480
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000481/***
482 * This method is part of the ISequentialStream interface.
483 *
484 * It writes a block of information to the stream at the current
485 * position. It then moves the current position at the end of the
486 * written block. If the stream is too small to fit the block,
487 * the stream is grown to fit.
488 *
489 * See the documentation of ISequentialStream for more info.
490 */
491HRESULT WINAPI HGLOBALStreamImpl_Write(
492 IStream* iface,
Vincent Béron9a624912002-05-31 23:06:46 +0000493 const void* pv, /* [size_is][in] */
494 ULONG cb, /* [in] */
495 ULONG* pcbWritten) /* [out] */
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000496{
497 HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
498
499 void* supportBuffer;
500 ULARGE_INTEGER newSize;
501 ULONG bytesWritten = 0;
Francis Beaudetec2edc71999-05-02 11:41:10 +0000502
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000503 TRACE("(%p, %p, %ld, %p)\n", iface,
Francis Beaudetec2edc71999-05-02 11:41:10 +0000504 pv, cb, pcbWritten);
Vincent Béron9a624912002-05-31 23:06:46 +0000505
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000506 /*
507 * If the caller is not interested in the number of bytes written,
508 * we use another buffer to avoid "if" statements in the code.
509 */
510 if (pcbWritten == 0)
511 pcbWritten = &bytesWritten;
Vincent Béron9a624912002-05-31 23:06:46 +0000512
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000513 if (cb == 0)
514 {
515 return S_OK;
516 }
517 else
518 {
Patrik Stridvall311e4561999-09-19 14:20:33 +0000519 newSize.s.HighPart = 0;
520 newSize.s.LowPart = This->currentPosition.s.LowPart + cb;
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000521 }
Vincent Béron9a624912002-05-31 23:06:46 +0000522
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000523 /*
524 * Verify if we need to grow the stream
525 */
Patrik Stridvall311e4561999-09-19 14:20:33 +0000526 if (newSize.s.LowPart > This->streamSize.s.LowPart)
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000527 {
528 /* grow stream */
Francis Beaudetec2edc71999-05-02 11:41:10 +0000529 IStream_SetSize(iface, newSize);
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000530 }
Vincent Béron9a624912002-05-31 23:06:46 +0000531
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000532 /*
533 * Lock the buffer in position and copy the data.
534 */
535 supportBuffer = GlobalLock(This->supportHandle);
536
Vincent Béron9a624912002-05-31 23:06:46 +0000537 memcpy((char *) supportBuffer+This->currentPosition.s.LowPart, pv, cb);
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000538
539 /*
540 * Move the current position to the new position
541 */
Patrik Stridvall311e4561999-09-19 14:20:33 +0000542 This->currentPosition.s.LowPart+=cb;
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000543
544 /*
545 * Return the number of bytes read.
546 */
547 *pcbWritten = cb;
548
549 /*
550 * Cleanup
551 */
552 GlobalUnlock(This->supportHandle);
Vincent Béron9a624912002-05-31 23:06:46 +0000553
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000554 return S_OK;
555}
556
557/***
558 * This method is part of the IStream interface.
559 *
560 * It will move the current stream pointer according to the parameters
561 * given.
562 *
563 * See the documentation of IStream for more info.
Vincent Béron9a624912002-05-31 23:06:46 +0000564 */
565HRESULT WINAPI HGLOBALStreamImpl_Seek(
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000566 IStream* iface,
Vincent Béron9a624912002-05-31 23:06:46 +0000567 LARGE_INTEGER dlibMove, /* [in] */
568 DWORD dwOrigin, /* [in] */
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000569 ULARGE_INTEGER* plibNewPosition) /* [out] */
570{
571 HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
572
573 ULARGE_INTEGER newPosition;
574
Alexandre Julliard359f497e1999-07-04 16:02:24 +0000575 TRACE("(%p, %ld, %ld, %p)\n", iface,
Patrik Stridvall311e4561999-09-19 14:20:33 +0000576 dlibMove.s.LowPart, dwOrigin, plibNewPosition);
Francis Beaudetec2edc71999-05-02 11:41:10 +0000577
Vincent Béron9a624912002-05-31 23:06:46 +0000578 /*
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000579 * The file pointer is moved depending on the given "function"
580 * parameter.
581 */
582 switch (dwOrigin)
583 {
584 case STREAM_SEEK_SET:
Juergen Schmied33817372002-07-01 18:10:34 +0000585 newPosition.s.HighPart = 0;
586 newPosition.s.LowPart = 0;
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000587 break;
588 case STREAM_SEEK_CUR:
Juergen Schmied33817372002-07-01 18:10:34 +0000589 newPosition = This->currentPosition;
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000590 break;
591 case STREAM_SEEK_END:
Juergen Schmied33817372002-07-01 18:10:34 +0000592 newPosition = This->streamSize;
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000593 break;
594 default:
595 return STG_E_INVALIDFUNCTION;
596 }
597
598 /*
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000599 * Move the actual file pointer
600 * If the file pointer ends-up after the end of the stream, the next Write operation will
601 * make the file larger. This is how it is documented.
602 */
Juergen Schmied33817372002-07-01 18:10:34 +0000603 newPosition.QuadPart = RtlLargeIntegerAdd(newPosition.QuadPart, dlibMove.QuadPart);
604 if (newPosition.QuadPart < 0) return STG_E_INVALIDFUNCTION;
605
606 if (plibNewPosition) *plibNewPosition = newPosition;
607 This->currentPosition = newPosition;
Vincent Béron9a624912002-05-31 23:06:46 +0000608
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000609 return S_OK;
610}
611
612/***
613 * This method is part of the IStream interface.
614 *
615 * It will change the size of a stream.
616 *
617 * TODO: Switch from small blocks to big blocks and vice versa.
618 *
619 * See the documentation of IStream for more info.
620 */
Vincent Béron9a624912002-05-31 23:06:46 +0000621HRESULT WINAPI HGLOBALStreamImpl_SetSize(
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000622 IStream* iface,
Vincent Béron9a624912002-05-31 23:06:46 +0000623 ULARGE_INTEGER libNewSize) /* [in] */
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000624{
625 HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
626
Patrik Stridvall311e4561999-09-19 14:20:33 +0000627 TRACE("(%p, %ld)\n", iface, libNewSize.s.LowPart);
Francis Beaudetec2edc71999-05-02 11:41:10 +0000628
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000629 /*
630 * As documented.
631 */
Patrik Stridvall311e4561999-09-19 14:20:33 +0000632 if (libNewSize.s.HighPart != 0)
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000633 return STG_E_INVALIDFUNCTION;
Vincent Béron9a624912002-05-31 23:06:46 +0000634
Patrik Stridvall311e4561999-09-19 14:20:33 +0000635 if (This->streamSize.s.LowPart == libNewSize.s.LowPart)
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000636 return S_OK;
637
638 /*
639 * Re allocate the HGlobal to fit the new size of the stream.
640 */
Vincent Béron9a624912002-05-31 23:06:46 +0000641 This->supportHandle = GlobalReAlloc(This->supportHandle,
Patrik Stridvall311e4561999-09-19 14:20:33 +0000642 libNewSize.s.LowPart,
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000643 0);
644
Patrik Stridvall311e4561999-09-19 14:20:33 +0000645 This->streamSize.s.LowPart = libNewSize.s.LowPart;
Vincent Béron9a624912002-05-31 23:06:46 +0000646
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000647 return S_OK;
648}
Vincent Béron9a624912002-05-31 23:06:46 +0000649
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000650/***
651 * This method is part of the IStream interface.
652 *
653 * It will copy the 'cb' Bytes to 'pstm' IStream.
654 *
655 * See the documentation of IStream for more info.
656 */
Vincent Béron9a624912002-05-31 23:06:46 +0000657HRESULT WINAPI HGLOBALStreamImpl_CopyTo(
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000658 IStream* iface,
Vincent Béron9a624912002-05-31 23:06:46 +0000659 IStream* pstm, /* [unique][in] */
660 ULARGE_INTEGER cb, /* [in] */
661 ULARGE_INTEGER* pcbRead, /* [out] */
662 ULARGE_INTEGER* pcbWritten) /* [out] */
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000663{
664 HRESULT hr = S_OK;
665 BYTE tmpBuffer[128];
666 ULONG bytesRead, bytesWritten, copySize;
667 ULARGE_INTEGER totalBytesRead;
668 ULARGE_INTEGER totalBytesWritten;
669
Vincent Béron9a624912002-05-31 23:06:46 +0000670 TRACE("(%p, %p, %ld, %p, %p)\n", iface, pstm,
Patrik Stridvall311e4561999-09-19 14:20:33 +0000671 cb.s.LowPart, pcbRead, pcbWritten);
Francis Beaudetec2edc71999-05-02 11:41:10 +0000672
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000673 /*
674 * Sanity check
675 */
676 if ( pstm == 0 )
677 return STG_E_INVALIDPOINTER;
678
Patrik Stridvall311e4561999-09-19 14:20:33 +0000679 totalBytesRead.s.LowPart = totalBytesRead.s.HighPart = 0;
680 totalBytesWritten.s.LowPart = totalBytesWritten.s.HighPart = 0;
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000681
682 /*
683 * use stack to store data temporarly
684 * there is surely more performant way of doing it, for now this basic
685 * implementation will do the job
686 */
Patrik Stridvall311e4561999-09-19 14:20:33 +0000687 while ( cb.s.LowPart > 0 )
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000688 {
Patrik Stridvall311e4561999-09-19 14:20:33 +0000689 if ( cb.s.LowPart >= 128 )
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000690 copySize = 128;
691 else
Patrik Stridvall311e4561999-09-19 14:20:33 +0000692 copySize = cb.s.LowPart;
Vincent Béron9a624912002-05-31 23:06:46 +0000693
Francis Beaudetec2edc71999-05-02 11:41:10 +0000694 IStream_Read(iface, tmpBuffer, copySize, &bytesRead);
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000695
Patrik Stridvall311e4561999-09-19 14:20:33 +0000696 totalBytesRead.s.LowPart += bytesRead;
Vincent Béron9a624912002-05-31 23:06:46 +0000697
Francis Beaudetec2edc71999-05-02 11:41:10 +0000698 IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten);
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000699
Patrik Stridvall311e4561999-09-19 14:20:33 +0000700 totalBytesWritten.s.LowPart += bytesWritten;
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000701
702 /*
703 * Check that read & write operations were succesfull
704 */
Francis Beaudetec2edc71999-05-02 11:41:10 +0000705 if (bytesRead != bytesWritten)
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000706 {
707 hr = STG_E_MEDIUMFULL;
708 break;
709 }
Vincent Béron9a624912002-05-31 23:06:46 +0000710
Francis Beaudetec2edc71999-05-02 11:41:10 +0000711 if (bytesRead!=copySize)
Patrik Stridvall311e4561999-09-19 14:20:33 +0000712 cb.s.LowPart = 0;
Francis Beaudetec2edc71999-05-02 11:41:10 +0000713 else
Patrik Stridvall311e4561999-09-19 14:20:33 +0000714 cb.s.LowPart -= bytesRead;
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000715 }
716
717 /*
718 * Update number of bytes read and written
719 */
720 if (pcbRead)
721 {
Patrik Stridvall311e4561999-09-19 14:20:33 +0000722 pcbRead->s.LowPart = totalBytesRead.s.LowPart;
723 pcbRead->s.HighPart = totalBytesRead.s.HighPart;
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000724 }
725
726 if (pcbWritten)
727 {
Patrik Stridvall311e4561999-09-19 14:20:33 +0000728 pcbWritten->s.LowPart = totalBytesWritten.s.LowPart;
729 pcbWritten->s.HighPart = totalBytesWritten.s.HighPart;
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000730 }
731 return hr;
732}
733
734/***
735 * This method is part of the IStream interface.
736 *
Vincent Béron9a624912002-05-31 23:06:46 +0000737 * For streams supported by HGLOBALS, this function does nothing.
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000738 * This is what the documentation tells us.
739 *
740 * See the documentation of IStream for more info.
Vincent Béron9a624912002-05-31 23:06:46 +0000741 */
742HRESULT WINAPI HGLOBALStreamImpl_Commit(
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000743 IStream* iface,
Vincent Béron9a624912002-05-31 23:06:46 +0000744 DWORD grfCommitFlags) /* [in] */
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000745{
746 return S_OK;
747}
748
749/***
750 * This method is part of the IStream interface.
751 *
Vincent Béron9a624912002-05-31 23:06:46 +0000752 * For streams supported by HGLOBALS, this function does nothing.
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000753 * This is what the documentation tells us.
754 *
755 * See the documentation of IStream for more info.
Vincent Béron9a624912002-05-31 23:06:46 +0000756 */
757HRESULT WINAPI HGLOBALStreamImpl_Revert(
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000758 IStream* iface)
759{
760 return S_OK;
761}
762
763/***
764 * This method is part of the IStream interface.
765 *
Vincent Béron9a624912002-05-31 23:06:46 +0000766 * For streams supported by HGLOBALS, this function does nothing.
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000767 * This is what the documentation tells us.
768 *
769 * See the documentation of IStream for more info.
Vincent Béron9a624912002-05-31 23:06:46 +0000770 */
771HRESULT WINAPI HGLOBALStreamImpl_LockRegion(
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000772 IStream* iface,
Vincent Béron9a624912002-05-31 23:06:46 +0000773 ULARGE_INTEGER libOffset, /* [in] */
774 ULARGE_INTEGER cb, /* [in] */
775 DWORD dwLockType) /* [in] */
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000776{
777 return S_OK;
778}
779
780/*
781 * This method is part of the IStream interface.
782 *
Vincent Béron9a624912002-05-31 23:06:46 +0000783 * For streams supported by HGLOBALS, this function does nothing.
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000784 * This is what the documentation tells us.
785 *
786 * See the documentation of IStream for more info.
Vincent Béron9a624912002-05-31 23:06:46 +0000787 */
788HRESULT WINAPI HGLOBALStreamImpl_UnlockRegion(
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000789 IStream* iface,
Vincent Béron9a624912002-05-31 23:06:46 +0000790 ULARGE_INTEGER libOffset, /* [in] */
791 ULARGE_INTEGER cb, /* [in] */
792 DWORD dwLockType) /* [in] */
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000793{
794 return S_OK;
795}
796
797/***
798 * This method is part of the IStream interface.
799 *
800 * This method returns information about the current
801 * stream.
802 *
803 * See the documentation of IStream for more info.
Vincent Béron9a624912002-05-31 23:06:46 +0000804 */
805HRESULT WINAPI HGLOBALStreamImpl_Stat(
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000806 IStream* iface,
807 STATSTG* pstatstg, /* [out] */
Vincent Béron9a624912002-05-31 23:06:46 +0000808 DWORD grfStatFlag) /* [in] */
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000809{
810 HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
811
812 memset(pstatstg, 0, sizeof(STATSTG));
813
814 pstatstg->pwcsName = NULL;
815 pstatstg->type = STGTY_STREAM;
816 pstatstg->cbSize = This->streamSize;
817
818 return S_OK;
819}
Vincent Béron9a624912002-05-31 23:06:46 +0000820
821HRESULT WINAPI HGLOBALStreamImpl_Clone(
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000822 IStream* iface,
Vincent Béron9a624912002-05-31 23:06:46 +0000823 IStream** ppstm) /* [out] */
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000824{
Alberto Massari544efc82002-11-12 02:13:49 +0000825 ULARGE_INTEGER dummy;
826 LARGE_INTEGER offset;
827 HRESULT hr;
828 HGLOBALStreamImpl* const This=(HGLOBALStreamImpl*)iface;
829 TRACE(" Cloning %p (deleteOnRelease=%d seek position=%ld)\n",iface,This->deleteOnRelease,(long)This->currentPosition.QuadPart);
830 hr=CreateStreamOnHGlobal(This->supportHandle, FALSE, ppstm);
831 if(FAILED(hr))
832 return hr;
833 offset.QuadPart=(LONGLONG)This->currentPosition.QuadPart;
834 HGLOBALStreamImpl_Seek(*ppstm,offset,STREAM_SEEK_SET,&dummy);
835 return S_OK;
Francis Beaudet4f8b5a81999-04-24 12:00:31 +0000836}