Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/dlls/coml2/memlockbytes.c
4389 views
1
/******************************************************************************
2
*
3
* Global memory implementation of ILockBytes.
4
*
5
* Copyright 1999 Thuy Nguyen
6
*
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.
11
*
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.
16
*
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
20
*/
21
22
#include <assert.h>
23
#include <stdarg.h>
24
#include <string.h>
25
26
#define COBJMACROS
27
#include "windef.h"
28
#include "winbase.h"
29
#include "winuser.h"
30
#include "objbase.h"
31
#include "ole2.h"
32
#include "winerror.h"
33
34
#include "wine/debug.h"
35
36
WINE_DEFAULT_DEBUG_CHANNEL(ole);
37
38
/******************************************************************************
39
* HGLOBALLockBytesImpl definition.
40
*
41
* This class implements the ILockBytes interface and represents a byte array
42
* object supported by an HGLOBAL pointer.
43
*/
44
struct HGLOBALLockBytesImpl
45
{
46
ILockBytes ILockBytes_iface;
47
LONG ref;
48
49
/*
50
* Support for the LockBytes object
51
*/
52
HGLOBAL supportHandle;
53
54
/*
55
* This flag is TRUE if the HGLOBAL is destroyed when the object
56
* is finally released.
57
*/
58
BOOL deleteOnRelease;
59
60
/*
61
* Helper variable that contains the size of the byte array
62
*/
63
ULARGE_INTEGER byteArraySize;
64
};
65
66
typedef struct HGLOBALLockBytesImpl HGLOBALLockBytesImpl;
67
68
static inline HGLOBALLockBytesImpl *impl_from_ILockBytes( ILockBytes *iface )
69
{
70
return CONTAINING_RECORD(iface, HGLOBALLockBytesImpl, ILockBytes_iface);
71
}
72
73
static const ILockBytesVtbl HGLOBALLockBytesImpl_Vtbl;
74
75
/******************************************************************************
76
* CreateILockBytesOnHGlobal [OLE32.@]
77
*
78
* Create a byte array object which is intended to be the compound file foundation.
79
* This object supports a COM implementation of the ILockBytes interface.
80
*
81
* PARAMS
82
* global [ I] Global memory handle
83
* delete_on_release [ I] Whether the handle should be freed when the object is released.
84
* ret [ O] Address of ILockBytes pointer that receives
85
* the interface pointer to the new byte array object.
86
*
87
* RETURNS
88
* Success: S_OK
89
*
90
* NOTES
91
* The supplied ILockBytes pointer can be used by the StgCreateDocfileOnILockBytes
92
* function to build a compound file on top of this byte array object.
93
* The ILockBytes interface instance calls the GlobalReAlloc function to grow
94
* the memory block as required.
95
*/
96
HRESULT WINAPI CreateILockBytesOnHGlobal(HGLOBAL global, BOOL delete_on_release, ILockBytes **ret)
97
{
98
HGLOBALLockBytesImpl* lockbytes;
99
100
lockbytes = HeapAlloc(GetProcessHeap(), 0, sizeof(HGLOBALLockBytesImpl));
101
if (!lockbytes) return E_OUTOFMEMORY;
102
103
lockbytes->ILockBytes_iface.lpVtbl = &HGLOBALLockBytesImpl_Vtbl;
104
lockbytes->ref = 1;
105
106
/*
107
* Initialize the support.
108
*/
109
lockbytes->supportHandle = global;
110
lockbytes->deleteOnRelease = delete_on_release;
111
112
/*
113
* This method will allocate a handle if one is not supplied.
114
*/
115
if (lockbytes->supportHandle == 0)
116
lockbytes->supportHandle = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD, 0);
117
118
/*
119
* Initialize the size of the array to the size of the handle.
120
*/
121
lockbytes->byteArraySize.HighPart = 0;
122
lockbytes->byteArraySize.LowPart = GlobalSize(lockbytes->supportHandle);
123
124
*ret = &lockbytes->ILockBytes_iface;
125
126
return S_OK;
127
}
128
129
/******************************************************************************
130
* GetHGlobalFromILockBytes [OLE32.@]
131
*
132
* Retrieve a global memory handle to a byte array object created
133
* using the CreateILockBytesOnHGlobal function.
134
*
135
* PARAMS
136
* plkbyt [ I] Pointer to the ILockBytes interface on byte array object
137
* phglobal [ O] Address to store a global memory handle
138
* RETURNS
139
* S_OK if *phglobal has a correct value
140
* E_INVALIDARG if any parameters are invalid
141
*
142
*/
143
HRESULT WINAPI GetHGlobalFromILockBytes(ILockBytes* iface, HGLOBAL* phglobal)
144
{
145
HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
146
STATSTG stbuf;
147
HRESULT hres;
148
ULARGE_INTEGER start;
149
ULONG xread;
150
151
*phglobal = 0;
152
if (This->ILockBytes_iface.lpVtbl == &HGLOBALLockBytesImpl_Vtbl) {
153
*phglobal = This->supportHandle;
154
if (*phglobal == 0)
155
return E_INVALIDARG;
156
return S_OK;
157
}
158
/* It is not our lockbytes implementation, so use a more generic way */
159
hres = ILockBytes_Stat(iface,&stbuf,STATFLAG_NONAME);
160
if (hres != S_OK) {
161
ERR("Cannot ILockBytes_Stat, %lx\n",hres);
162
return hres;
163
}
164
TRACE("cbSize is %s\n", wine_dbgstr_longlong(stbuf.cbSize.QuadPart));
165
*phglobal = GlobalAlloc( GMEM_MOVEABLE|GMEM_SHARE, stbuf.cbSize.LowPart);
166
if (!*phglobal)
167
return E_INVALIDARG;
168
memset(&start,0,sizeof(start));
169
hres = ILockBytes_ReadAt(iface, start, GlobalLock(*phglobal), stbuf.cbSize.LowPart, &xread);
170
GlobalUnlock(*phglobal);
171
if (hres != S_OK) {
172
FIXME("%p->ReadAt failed with %lx\n",iface,hres);
173
return hres;
174
}
175
if (stbuf.cbSize.LowPart != xread) {
176
FIXME("Read size is not requested size %ld vs %ld?\n",stbuf.cbSize.LowPart, xread);
177
}
178
return S_OK;
179
}
180
181
/******************************************************************************
182
*
183
* HGLOBALLockBytesImpl implementation
184
*
185
*/
186
187
/******************************************************************************
188
* This implements the IUnknown method QueryInterface for this
189
* class
190
*/
191
static HRESULT WINAPI HGLOBALLockBytesImpl_QueryInterface(
192
ILockBytes* iface,
193
REFIID riid, /* [in] */
194
void** ppvObject) /* [iid_is][out] */
195
{
196
HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
197
198
if (ppvObject==0)
199
return E_INVALIDARG;
200
201
*ppvObject = 0;
202
203
if (IsEqualIID(riid, &IID_IUnknown) ||
204
IsEqualIID(riid, &IID_ILockBytes))
205
{
206
*ppvObject = &This->ILockBytes_iface;
207
}
208
else
209
return E_NOINTERFACE;
210
211
ILockBytes_AddRef(iface);
212
213
return S_OK;
214
}
215
216
/******************************************************************************
217
* This implements the IUnknown method AddRef for this
218
* class
219
*/
220
static ULONG WINAPI HGLOBALLockBytesImpl_AddRef(ILockBytes* iface)
221
{
222
HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
223
return InterlockedIncrement(&This->ref);
224
}
225
226
/******************************************************************************
227
* This implements the IUnknown method Release for this
228
* class
229
*/
230
static ULONG WINAPI HGLOBALLockBytesImpl_Release(ILockBytes* iface)
231
{
232
HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
233
ULONG ref;
234
235
ref = InterlockedDecrement(&This->ref);
236
if (!ref)
237
{
238
if (This->deleteOnRelease)
239
{
240
GlobalFree(This->supportHandle);
241
This->supportHandle = 0;
242
}
243
HeapFree(GetProcessHeap(), 0, This);
244
}
245
246
return ref;
247
}
248
249
/******************************************************************************
250
* This method is part of the ILockBytes interface.
251
*
252
* It reads a block of information from the byte array at the specified
253
* offset.
254
*
255
* See the documentation of ILockBytes for more info.
256
*/
257
static HRESULT WINAPI HGLOBALLockBytesImpl_ReadAt(
258
ILockBytes* iface,
259
ULARGE_INTEGER ulOffset, /* [in] */
260
void* pv, /* [length_is][size_is][out] */
261
ULONG cb, /* [in] */
262
ULONG* pcbRead) /* [out] */
263
{
264
HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
265
266
void* supportBuffer;
267
ULONG bytesReadBuffer = 0;
268
ULONG bytesToReadFromBuffer;
269
270
/*
271
* If the caller is not interested in the number of bytes read,
272
* we use another buffer to avoid "if" statements in the code.
273
*/
274
if (pcbRead == 0)
275
pcbRead = &bytesReadBuffer;
276
277
/*
278
* Make sure the offset is valid.
279
*/
280
if (ulOffset.LowPart > This->byteArraySize.LowPart)
281
return E_FAIL;
282
283
/*
284
* Using the known size of the array, calculate the number of bytes
285
* to read.
286
*/
287
bytesToReadFromBuffer = min(This->byteArraySize.LowPart - ulOffset.LowPart, cb);
288
289
/*
290
* Lock the buffer in position and copy the data.
291
*/
292
supportBuffer = GlobalLock(This->supportHandle);
293
294
memcpy(pv,
295
(char *) supportBuffer + ulOffset.LowPart,
296
bytesToReadFromBuffer);
297
298
/*
299
* Return the number of bytes read.
300
*/
301
*pcbRead = bytesToReadFromBuffer;
302
303
/*
304
* Cleanup
305
*/
306
GlobalUnlock(This->supportHandle);
307
308
/*
309
* The function returns S_OK if the specified number of bytes were read
310
* or the end of the array was reached.
311
* It returns STG_E_READFAULT if the number of bytes to read does not equal
312
* the number of bytes actually read.
313
*/
314
if(*pcbRead == cb)
315
return S_OK;
316
317
return STG_E_READFAULT;
318
}
319
320
/******************************************************************************
321
* This method is part of the ILockBytes interface.
322
*
323
* It writes the specified bytes at the specified offset.
324
* position. If the array is too small, it will be resized.
325
*
326
* See the documentation of ILockBytes for more info.
327
*/
328
static HRESULT WINAPI HGLOBALLockBytesImpl_WriteAt(
329
ILockBytes* iface,
330
ULARGE_INTEGER ulOffset, /* [in] */
331
const void* pv, /* [size_is][in] */
332
ULONG cb, /* [in] */
333
ULONG* pcbWritten) /* [out] */
334
{
335
HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
336
337
void* supportBuffer;
338
ULARGE_INTEGER newSize;
339
ULONG bytesWritten = 0;
340
341
/*
342
* If the caller is not interested in the number of bytes written,
343
* we use another buffer to avoid "if" statements in the code.
344
*/
345
if (pcbWritten == 0)
346
pcbWritten = &bytesWritten;
347
348
if (cb == 0)
349
{
350
return S_OK;
351
}
352
else
353
{
354
newSize.HighPart = 0;
355
newSize.LowPart = ulOffset.LowPart + cb;
356
}
357
358
/*
359
* Verify if we need to grow the stream
360
*/
361
if (newSize.LowPart > This->byteArraySize.LowPart)
362
{
363
/* grow stream */
364
if (ILockBytes_SetSize(iface, newSize) == STG_E_MEDIUMFULL)
365
return STG_E_MEDIUMFULL;
366
}
367
368
/*
369
* Lock the buffer in position and copy the data.
370
*/
371
supportBuffer = GlobalLock(This->supportHandle);
372
373
memcpy((char *) supportBuffer + ulOffset.LowPart, pv, cb);
374
375
/*
376
* Return the number of bytes written.
377
*/
378
*pcbWritten = cb;
379
380
/*
381
* Cleanup
382
*/
383
GlobalUnlock(This->supportHandle);
384
385
return S_OK;
386
}
387
388
/******************************************************************************
389
* This method is part of the ILockBytes interface.
390
*
391
* See the documentation of ILockBytes for more info.
392
*/
393
static HRESULT WINAPI HGLOBALLockBytesImpl_Flush(ILockBytes* iface)
394
{
395
return S_OK;
396
}
397
398
/******************************************************************************
399
* This method is part of the ILockBytes interface.
400
*
401
* It will change the size of the byte array.
402
*
403
* See the documentation of ILockBytes for more info.
404
*/
405
static HRESULT WINAPI HGLOBALLockBytesImpl_SetSize(
406
ILockBytes* iface,
407
ULARGE_INTEGER libNewSize) /* [in] */
408
{
409
HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
410
HGLOBAL supportHandle;
411
412
/*
413
* As documented.
414
*/
415
if (libNewSize.HighPart != 0)
416
return STG_E_INVALIDFUNCTION;
417
418
if (This->byteArraySize.LowPart == libNewSize.LowPart)
419
return S_OK;
420
421
/*
422
* Re allocate the HGlobal to fit the new size of the stream.
423
*/
424
supportHandle = GlobalReAlloc(This->supportHandle, libNewSize.LowPart, GMEM_MOVEABLE);
425
426
if (supportHandle == 0)
427
return STG_E_MEDIUMFULL;
428
429
This->supportHandle = supportHandle;
430
This->byteArraySize.LowPart = libNewSize.LowPart;
431
432
return S_OK;
433
}
434
435
/******************************************************************************
436
* This method is part of the ILockBytes interface.
437
*
438
* The global memory implementation of ILockBytes does not support locking.
439
*
440
* See the documentation of ILockBytes for more info.
441
*/
442
static HRESULT WINAPI HGLOBALLockBytesImpl_LockRegion(
443
ILockBytes* iface,
444
ULARGE_INTEGER libOffset, /* [in] */
445
ULARGE_INTEGER cb, /* [in] */
446
DWORD dwLockType) /* [in] */
447
{
448
return STG_E_INVALIDFUNCTION;
449
}
450
451
/******************************************************************************
452
* This method is part of the ILockBytes interface.
453
*
454
* The global memory implementation of ILockBytes does not support locking.
455
*
456
* See the documentation of ILockBytes for more info.
457
*/
458
static HRESULT WINAPI HGLOBALLockBytesImpl_UnlockRegion(
459
ILockBytes* iface,
460
ULARGE_INTEGER libOffset, /* [in] */
461
ULARGE_INTEGER cb, /* [in] */
462
DWORD dwLockType) /* [in] */
463
{
464
return STG_E_INVALIDFUNCTION;
465
}
466
467
/******************************************************************************
468
* This method is part of the ILockBytes interface.
469
*
470
* This method returns information about the current
471
* byte array object.
472
*
473
* See the documentation of ILockBytes for more info.
474
*/
475
static HRESULT WINAPI HGLOBALLockBytesImpl_Stat(
476
ILockBytes* iface,
477
STATSTG* pstatstg, /* [out] */
478
DWORD grfStatFlag) /* [in] */
479
{
480
HGLOBALLockBytesImpl* This = impl_from_ILockBytes(iface);
481
482
memset(pstatstg, 0, sizeof(STATSTG));
483
484
pstatstg->pwcsName = NULL;
485
pstatstg->type = STGTY_LOCKBYTES;
486
pstatstg->cbSize = This->byteArraySize;
487
488
return S_OK;
489
}
490
491
/*
492
* Virtual function table for the HGLOBALLockBytesImpl class.
493
*/
494
static const ILockBytesVtbl HGLOBALLockBytesImpl_Vtbl =
495
{
496
HGLOBALLockBytesImpl_QueryInterface,
497
HGLOBALLockBytesImpl_AddRef,
498
HGLOBALLockBytesImpl_Release,
499
HGLOBALLockBytesImpl_ReadAt,
500
HGLOBALLockBytesImpl_WriteAt,
501
HGLOBALLockBytesImpl_Flush,
502
HGLOBALLockBytesImpl_SetSize,
503
HGLOBALLockBytesImpl_LockRegion,
504
HGLOBALLockBytesImpl_UnlockRegion,
505
HGLOBALLockBytesImpl_Stat,
506
};
507
508