source: trunk/src/ole32/ifs.c@ 10367

Last change on this file since 10367 was 9400, checked in by sandervl, 23 years ago

Wine resync

File size: 16.8 KB
Line 
1/*
2 * basic interfaces
3 *
4 * Copyright 1997 Marcus Meissner
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20
21#include "config.h"
22
23#include <ctype.h>
24#include <stdlib.h>
25#include <string.h>
26#include <assert.h>
27
28#include "ole2.h"
29#include "windef.h"
30#include "winbase.h"
31#include "winerror.h"
32
33#include "wine/obj_base.h"
34
35#include "wine/debug.h"
36
37#ifdef __WIN32OS2__
38#define CRITICAL_SECTION_INIT(name) { (void *)(__FILE__ ": " name), -1, 0, 0, 0, 0 }
39#endif
40
41WINE_DEFAULT_DEBUG_CHANNEL(ole);
42
43/******************************************************************************
44 * IMalloc32 implementation
45 *
46 * NOTES
47 * For supporting CoRegisterMallocSpy the IMalloc implementation must know if
48 * a given memory block was allocated with a spy active.
49 *
50 *****************************************************************************/
51/* set the vtable later */
52extern ICOM_VTABLE(IMalloc) VT_IMalloc32;
53
54typedef struct {
55 ICOM_VFIELD(IMalloc);
56 DWORD dummy; /* nothing, we are static */
57 IMallocSpy * pSpy; /* the spy when active */
58 DWORD SpyedAllocationsLeft; /* number of spyed allocations left */
59 BOOL SpyReleasePending; /* CoRevokeMallocSpy called with spyed allocations left*/
60 LPVOID * SpyedBlocks; /* root of the table */
61 int SpyedBlockTableLength; /* size of the table*/
62} _Malloc32;
63
64/* this is the static object instance */
65_Malloc32 Malloc32 = {&VT_IMalloc32, 0, NULL, 0, 0, NULL, 0};
66
67/* with a spy active all calls from pre to post methods are threadsave */
68static CRITICAL_SECTION IMalloc32_SpyCS = CRITICAL_SECTION_INIT("IMalloc32_SpyCS");
69
70/* resize the old table */
71static int SetSpyedBlockTableLength ( int NewLength )
72{
73 Malloc32.SpyedBlocks = (LPVOID*)LocalReAlloc((HLOCAL)Malloc32.SpyedBlocks, NewLength, GMEM_ZEROINIT);
74 Malloc32.SpyedBlockTableLength = NewLength;
75 return Malloc32.SpyedBlocks ? 1 : 0;
76}
77
78/* add a location to the table */
79static int AddMemoryLocation(LPVOID * pMem)
80{
81 LPVOID * Current;
82
83 /* allocate the table if not already allocated */
84 if (!Malloc32.SpyedBlockTableLength) {
85 if (!SetSpyedBlockTableLength(0x1000)) return 0;
86 }
87
88 /* find a free location */
89 Current = Malloc32.SpyedBlocks;
90 while (*Current) {
91 Current++;
92 if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) {
93 /* no more space in table, grow it */
94 if (!SetSpyedBlockTableLength( Malloc32.SpyedBlockTableLength + 0x1000 )) return 0;
95 }
96 };
97
98 /* put the location in our table */
99 *Current = pMem;
100 Malloc32.SpyedAllocationsLeft++;
101 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
102 return 1;
103}
104
105static int RemoveMemoryLocation(LPVOID * pMem)
106{
107 LPVOID * Current = Malloc32.SpyedBlocks;
108
109 /* find the location */
110 while (*Current != pMem) {
111 Current++;
112 if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) return 0; /* not found */
113 }
114
115 /* location found */
116 Malloc32.SpyedAllocationsLeft--;
117 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
118 *Current = NULL;
119 return 1;
120}
121
122/******************************************************************************
123 * IMalloc32_QueryInterface [VTABLE]
124 */
125static HRESULT WINAPI IMalloc_fnQueryInterface(LPMALLOC iface,REFIID refiid,LPVOID *obj) {
126
127 TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
128
129 if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMalloc,refiid)) {
130 *obj = (LPMALLOC)&Malloc32;
131 return S_OK;
132 }
133 return E_NOINTERFACE;
134}
135
136/******************************************************************************
137 * IMalloc32_AddRefRelease [VTABLE]
138 */
139static ULONG WINAPI IMalloc_fnAddRefRelease (LPMALLOC iface) {
140 return 1;
141}
142
143/******************************************************************************
144 * IMalloc32_Alloc [VTABLE]
145 */
146static LPVOID WINAPI IMalloc_fnAlloc(LPMALLOC iface, DWORD cb) {
147
148 LPVOID addr;
149
150 TRACE("(%ld)\n",cb);
151
152 if(Malloc32.pSpy) {
153 EnterCriticalSection(&IMalloc32_SpyCS);
154 cb = IMallocSpy_PreAlloc(Malloc32.pSpy, cb);
155 if (0==cb) {
156 /* PreAlloc can force Alloc to fail */
157 LeaveCriticalSection(&IMalloc32_SpyCS);
158 return NULL;
159 }
160 }
161
162
163 addr = HeapAlloc(GetProcessHeap(),0,cb);
164
165 if(Malloc32.pSpy) {
166 addr = IMallocSpy_PostAlloc(Malloc32.pSpy, addr);
167 if (addr) AddMemoryLocation(addr);
168 LeaveCriticalSection(&IMalloc32_SpyCS);
169 }
170
171 TRACE("--(%p)\n",addr);
172 return addr;
173}
174
175/******************************************************************************
176 * IMalloc32_Realloc [VTABLE]
177 */
178static LPVOID WINAPI IMalloc_fnRealloc(LPMALLOC iface,LPVOID pv,DWORD cb) {
179
180 LPVOID pNewMemory;
181
182 TRACE("(%p,%ld)\n",pv,cb);
183
184 if(Malloc32.pSpy) {
185 LPVOID pRealMemory;
186 BOOL fSpyed;
187
188 EnterCriticalSection(&IMalloc32_SpyCS);
189 fSpyed = RemoveMemoryLocation(pv);
190 cb = IMallocSpy_PreRealloc(Malloc32.pSpy, pv, cb, &pRealMemory, fSpyed);
191
192 /* check if can release the spy */
193 if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
194 IMallocSpy_Release(Malloc32.pSpy);
195 Malloc32.SpyReleasePending = FALSE;
196 Malloc32.pSpy = NULL;
197 }
198
199 if (0==cb) {
200 /* PreRealloc can force Realloc to fail */
201 LeaveCriticalSection(&IMalloc32_SpyCS);
202 return NULL;
203 }
204 pv = pRealMemory;
205 }
206
207 pNewMemory = HeapReAlloc(GetProcessHeap(),0,pv,cb);
208
209 if(Malloc32.pSpy) {
210 pNewMemory = IMallocSpy_PostRealloc(Malloc32.pSpy, pNewMemory, TRUE);
211 if (pNewMemory) AddMemoryLocation(pNewMemory);
212 LeaveCriticalSection(&IMalloc32_SpyCS);
213 }
214
215 TRACE("--(%p)\n",pNewMemory);
216 return pNewMemory;
217}
218
219/******************************************************************************
220 * IMalloc32_Free [VTABLE]
221 */
222static VOID WINAPI IMalloc_fnFree(LPMALLOC iface,LPVOID pv) {
223
224 BOOL fSpyed = 0;
225
226 TRACE("(%p)\n",pv);
227
228 if(Malloc32.pSpy) {
229 EnterCriticalSection(&IMalloc32_SpyCS);
230 fSpyed = RemoveMemoryLocation(pv);
231 pv = IMallocSpy_PreFree(Malloc32.pSpy, pv, fSpyed);
232 }
233
234 HeapFree(GetProcessHeap(),0,pv);
235
236 if(Malloc32.pSpy) {
237 IMallocSpy_PostFree(Malloc32.pSpy, fSpyed);
238
239 /* check if can release the spy */
240 if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
241 IMallocSpy_Release(Malloc32.pSpy);
242 Malloc32.SpyReleasePending = FALSE;
243 Malloc32.pSpy = NULL;
244 }
245
246 LeaveCriticalSection(&IMalloc32_SpyCS);
247 }
248}
249
250/******************************************************************************
251 * IMalloc32_GetSize [VTABLE]
252 *
253 * NOTES
254 * FIXME returns:
255 * win95: size allocated (4 byte boundarys)
256 * win2k: size originally requested !!! (allocated on 8 byte boundarys)
257 */
258static DWORD WINAPI IMalloc_fnGetSize(LPMALLOC iface,LPVOID pv) {
259
260 DWORD cb;
261 BOOL fSpyed = 0;
262
263 TRACE("(%p)\n",pv);
264
265 if(Malloc32.pSpy) {
266 EnterCriticalSection(&IMalloc32_SpyCS);
267 pv = IMallocSpy_PreGetSize(Malloc32.pSpy, pv, fSpyed);
268 }
269
270 cb = HeapSize(GetProcessHeap(),0,pv);
271
272 if(Malloc32.pSpy) {
273 cb = IMallocSpy_PostGetSize(Malloc32.pSpy, cb, fSpyed);
274 LeaveCriticalSection(&IMalloc32_SpyCS);
275 }
276
277 return cb;
278}
279
280/******************************************************************************
281 * IMalloc32_DidAlloc [VTABLE]
282 */
283static INT WINAPI IMalloc_fnDidAlloc(LPMALLOC iface,LPVOID pv) {
284
285 BOOL fSpyed = 0;
286 int didAlloc;
287
288 TRACE("(%p)\n",pv);
289
290 if(Malloc32.pSpy) {
291 EnterCriticalSection(&IMalloc32_SpyCS);
292 pv = IMallocSpy_PreDidAlloc(Malloc32.pSpy, pv, fSpyed);
293 }
294
295 didAlloc = -1;
296
297 if(Malloc32.pSpy) {
298 didAlloc = IMallocSpy_PostDidAlloc(Malloc32.pSpy, pv, fSpyed, didAlloc);
299 LeaveCriticalSection(&IMalloc32_SpyCS);
300 }
301 return didAlloc;
302}
303
304/******************************************************************************
305 * IMalloc32_HeapMinimize [VTABLE]
306 */
307static VOID WINAPI IMalloc_fnHeapMinimize(LPMALLOC iface) {
308 TRACE("()\n");
309
310 if(Malloc32.pSpy) {
311 EnterCriticalSection(&IMalloc32_SpyCS);
312 IMallocSpy_PreHeapMinimize(Malloc32.pSpy);
313 }
314
315 if(Malloc32.pSpy) {
316 IMallocSpy_PostHeapMinimize(Malloc32.pSpy);
317 LeaveCriticalSection(&IMalloc32_SpyCS);
318 }
319}
320
321#ifdef __WIN32OS2__
322 ICOM_VTABLE(IMalloc) VT_IMalloc32 =
323#else
324static ICOM_VTABLE(IMalloc) VT_IMalloc32 =
325#endif
326{
327 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
328 IMalloc_fnQueryInterface,
329 IMalloc_fnAddRefRelease,
330 IMalloc_fnAddRefRelease,
331 IMalloc_fnAlloc,
332 IMalloc_fnRealloc,
333 IMalloc_fnFree,
334 IMalloc_fnGetSize,
335 IMalloc_fnDidAlloc,
336 IMalloc_fnHeapMinimize
337};
338
339/******************************************************************************
340 * IMallocSpy implementation
341 *****************************************************************************/
342
343/* set the vtable later */
344extern ICOM_VTABLE(IMallocSpy) VT_IMallocSpy;
345
346typedef struct {
347 ICOM_VFIELD(IMallocSpy);
348 DWORD ref;
349} _MallocSpy;
350
351/* this is the static object instance */
352_MallocSpy MallocSpy = {&VT_IMallocSpy, 0};
353
354/******************************************************************************
355 * IMalloc32_QueryInterface [VTABLE]
356 */
357static HRESULT WINAPI IMallocSpy_fnQueryInterface(LPMALLOCSPY iface,REFIID refiid,LPVOID *obj)
358{
359
360 TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
361
362 if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMallocSpy,refiid)) {
363 *obj = (LPMALLOC)&MallocSpy;
364 return S_OK;
365 }
366 return E_NOINTERFACE;
367}
368
369/******************************************************************************
370 * IMalloc32_AddRef [VTABLE]
371 */
372static ULONG WINAPI IMallocSpy_fnAddRef (LPMALLOCSPY iface)
373{
374
375 ICOM_THIS (_MallocSpy, iface);
376
377 TRACE ("(%p)->(count=%lu)\n", This, This->ref);
378
379 return ++(This->ref);
380}
381
382/******************************************************************************
383 * IMalloc32_AddRelease [VTABLE]
384 *
385 * NOTES
386 * Our MallocSpy is static. If the count reaches 0 we dump the leaks
387 */
388static ULONG WINAPI IMallocSpy_fnRelease (LPMALLOCSPY iface)
389{
390
391 ICOM_THIS (_MallocSpy, iface);
392
393 TRACE ("(%p)->(count=%lu)\n", This, This->ref);
394
395 if (!--(This->ref)) {
396 /* our allocation list MUST be empty here */
397 }
398 return This->ref;
399}
400
401static ULONG WINAPI IMallocSpy_fnPreAlloc(LPMALLOCSPY iface, ULONG cbRequest)
402{
403 ICOM_THIS (_MallocSpy, iface);
404 TRACE ("(%p)->(%lu)\n", This, cbRequest);
405 return cbRequest;
406}
407static PVOID WINAPI IMallocSpy_fnPostAlloc(LPMALLOCSPY iface, void* pActual)
408{
409 ICOM_THIS (_MallocSpy, iface);
410 TRACE ("(%p)->(%p)\n", This, pActual);
411 return pActual;
412}
413
414static PVOID WINAPI IMallocSpy_fnPreFree(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
415{
416 ICOM_THIS (_MallocSpy, iface);
417 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
418 return pRequest;
419}
420static void WINAPI IMallocSpy_fnPostFree(LPMALLOCSPY iface, BOOL fSpyed)
421{
422 ICOM_THIS (_MallocSpy, iface);
423 TRACE ("(%p)->(%u)\n", This, fSpyed);
424}
425
426static ULONG WINAPI IMallocSpy_fnPreRealloc(LPMALLOCSPY iface, void* pRequest, ULONG cbRequest, void** ppNewRequest, BOOL fSpyed)
427{
428 ICOM_THIS (_MallocSpy, iface);
429 TRACE ("(%p)->(%p %lu %u)\n", This, pRequest, cbRequest, fSpyed);
430 *ppNewRequest = pRequest;
431 return cbRequest;
432}
433
434static PVOID WINAPI IMallocSpy_fnPostRealloc(LPMALLOCSPY iface, void* pActual, BOOL fSpyed)
435{
436 ICOM_THIS (_MallocSpy, iface);
437 TRACE ("(%p)->(%p %u)\n", This, pActual, fSpyed);
438 return pActual;
439}
440
441static PVOID WINAPI IMallocSpy_fnPreGetSize(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
442{
443 ICOM_THIS (_MallocSpy, iface);
444 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
445 return pRequest;
446}
447
448static ULONG WINAPI IMallocSpy_fnPostGetSize(LPMALLOCSPY iface, ULONG cbActual, BOOL fSpyed)
449{
450 ICOM_THIS (_MallocSpy, iface);
451 TRACE ("(%p)->(%lu %u)\n", This, cbActual, fSpyed);
452 return cbActual;
453}
454
455static PVOID WINAPI IMallocSpy_fnPreDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
456{
457 ICOM_THIS (_MallocSpy, iface);
458 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
459 return pRequest;
460}
461
462static int WINAPI IMallocSpy_fnPostDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed, int fActual)
463{
464 ICOM_THIS (_MallocSpy, iface);
465 TRACE ("(%p)->(%p %u %u)\n", This, pRequest, fSpyed, fActual);
466 return fActual;
467}
468
469static int WINAPI IMallocSpy_fnPreHeapMinimize(LPMALLOCSPY iface)
470{
471 ICOM_THIS (_MallocSpy, iface);
472 TRACE ("(%p)->()\n", This);
473 return 0;
474}
475
476static int WINAPI IMallocSpy_fnPostHeapMinimize(LPMALLOCSPY iface)
477{
478 ICOM_THIS (_MallocSpy, iface);
479 TRACE ("(%p)->()\n", This);
480 return 0;
481}
482
483static void MallocSpyDumpLeaks() {
484 TRACE("leaks: %lu\n", Malloc32.SpyedAllocationsLeft);
485}
486
487#ifdef __WIN32OS2__
488 ICOM_VTABLE(IMallocSpy) VT_IMallocSpy =
489#else
490static ICOM_VTABLE(IMallocSpy) VT_IMallocSpy =
491#endif
492{
493 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
494 IMallocSpy_fnQueryInterface,
495 IMallocSpy_fnAddRef,
496 IMallocSpy_fnRelease,
497 IMallocSpy_fnPreAlloc,
498 IMallocSpy_fnPostAlloc,
499 IMallocSpy_fnPreFree,
500 IMallocSpy_fnPostFree,
501 IMallocSpy_fnPreRealloc,
502 IMallocSpy_fnPostRealloc,
503 IMallocSpy_fnPreGetSize,
504 IMallocSpy_fnPostGetSize,
505 IMallocSpy_fnPreDidAlloc,
506 IMallocSpy_fnPostDidAlloc,
507 IMallocSpy_fnPreHeapMinimize,
508 IMallocSpy_fnPostHeapMinimize
509};
510
511/******************************************************************************
512 * CoGetMalloc [OLE32.20]
513 *
514 * RETURNS
515 * The win32 IMalloc
516 */
517HRESULT WINAPI CoGetMalloc(DWORD dwMemContext, LPMALLOC *lpMalloc)
518{
519 *lpMalloc = (LPMALLOC)&Malloc32;
520 return S_OK;
521}
522
523/***********************************************************************
524 * CoTaskMemAlloc [OLE32.43]
525 * RETURNS
526 * pointer to newly allocated block
527 */
528LPVOID WINAPI CoTaskMemAlloc(ULONG size)
529{
530 return IMalloc_Alloc((LPMALLOC)&Malloc32,size);
531}
532/***********************************************************************
533 * CoTaskMemFree [OLE32.44]
534 */
535VOID WINAPI CoTaskMemFree(LPVOID ptr)
536{
537 IMalloc_Free((LPMALLOC)&Malloc32, ptr);
538}
539
540/***********************************************************************
541 * CoTaskMemRealloc [OLE32.45]
542 * RETURNS
543 * pointer to newly allocated block
544 */
545LPVOID WINAPI CoTaskMemRealloc(LPVOID pvOld, ULONG size)
546{
547 return IMalloc_Realloc((LPMALLOC)&Malloc32, pvOld, size);
548}
549
550/***********************************************************************
551 * CoRegisterMallocSpy [OLE32.37]
552 *
553 * NOTES
554 * if a mallocspy is already registered, we cant do it again since
555 * only the spy knows, how to free a memory block
556 */
557HRESULT WINAPI CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy)
558{
559 IMallocSpy* pSpy;
560 HRESULT hres = E_INVALIDARG;
561
562 TRACE("\n");
563
564 /* HACK TO ACTIVATE OUT SPY */
565 if (pMallocSpy == (LPVOID)-1) pMallocSpy =(IMallocSpy*)&MallocSpy;
566
567 if(Malloc32.pSpy) return CO_E_OBJISREG;
568
569 EnterCriticalSection(&IMalloc32_SpyCS);
570
571 if (SUCCEEDED(IUnknown_QueryInterface(pMallocSpy, &IID_IMallocSpy, (LPVOID*)&pSpy))) {
572 Malloc32.pSpy = pSpy;
573 hres = S_OK;
574 }
575
576 LeaveCriticalSection(&IMalloc32_SpyCS);
577
578 return hres;
579}
580
581/***********************************************************************
582 * CoRevokeMallocSpy [OLE32.41]
583 *
584 * NOTES
585 * we can't rewoke a malloc spy as long as memory blocks allocated with
586 * the spy are active since only the spy knows how to free them
587 */
588HRESULT WINAPI CoRevokeMallocSpy(void)
589{
590 HRESULT hres = S_OK;
591 TRACE("\n");
592
593 EnterCriticalSection(&IMalloc32_SpyCS);
594
595 /* if it's our spy it's time to dump the leaks */
596 if (Malloc32.pSpy == (IMallocSpy*)&MallocSpy) {
597 MallocSpyDumpLeaks();
598 }
599
600 if (Malloc32.SpyedAllocationsLeft) {
601 TRACE("SpyReleasePending with %lu allocations left\n", Malloc32.SpyedAllocationsLeft);
602 Malloc32.SpyReleasePending = TRUE;
603 hres = E_ACCESSDENIED;
604 } else {
605 IMallocSpy_Release(Malloc32.pSpy);
606 Malloc32.pSpy = NULL;
607 }
608 LeaveCriticalSection(&IMalloc32_SpyCS);
609
610 return S_OK;
611}
612
613/******************************************************************************
614 * IsValidInterface [OLE32.78]
615 *
616 * RETURNS
617 * True, if the passed pointer is a valid interface
618 */
619BOOL WINAPI IsValidInterface(
620 LPUNKNOWN punk /* [in] interface to be tested */
621) {
622 return !(
623 IsBadReadPtr(punk,4) ||
624 IsBadReadPtr(ICOM_VTBL(punk),4) ||
625#ifdef __WIN32OS2__
626 IsBadReadPtr(ICOM_VTBL(punk)->fnQueryInterface,9) ||
627 IsBadCodePtr((FARPROC)ICOM_VTBL(punk)->fnQueryInterface)
628#else
629 IsBadReadPtr(ICOM_VTBL(punk)->QueryInterface,9) ||
630 IsBadCodePtr((FARPROC)ICOM_VTBL(punk)->QueryInterface)
631#endif
632 );
633}
Note: See TracBrowser for help on using the repository browser.