move mesa32 over to new dir
[reactos.git] / reactos / dll / ole32 / ifs.c
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 <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
28
29 #define COBJMACROS
30
31 #include "windef.h"
32 #include "winbase.h"
33 #include "winuser.h"
34 #include "ole2.h"
35 #include "winerror.h"
36
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(olemalloc);
40
41 /******************************************************************************
42 * IMalloc32 implementation
43 *
44 * NOTES
45 * For supporting CoRegisterMallocSpy the IMalloc implementation must know if
46 * a given memory block was allocated with a spy active.
47 *
48 *****************************************************************************/
49 /* set the vtable later */
50 static const IMallocVtbl VT_IMalloc32;
51
52 typedef struct {
53 const IMallocVtbl *lpVtbl;
54 DWORD dummy; /* nothing, we are static */
55 IMallocSpy * pSpy; /* the spy when active */
56 DWORD SpyedAllocationsLeft; /* number of spyed allocations left */
57 BOOL SpyReleasePending; /* CoRevokeMallocSpy called with spyed allocations left*/
58 LPVOID * SpyedBlocks; /* root of the table */
59 int SpyedBlockTableLength; /* size of the table*/
60 } _Malloc32;
61
62 /* this is the static object instance */
63 static _Malloc32 Malloc32 = {&VT_IMalloc32, 0, NULL, 0, 0, NULL, 0};
64
65 /* with a spy active all calls from pre to post methods are threadsave */
66 static CRITICAL_SECTION IMalloc32_SpyCS;
67 static CRITICAL_SECTION_DEBUG critsect_debug =
68 {
69 0, 0, &IMalloc32_SpyCS,
70 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
71 0, 0, { (DWORD_PTR)(__FILE__ ": IMalloc32_SpyCS") }
72 };
73 static CRITICAL_SECTION IMalloc32_SpyCS = { &critsect_debug, -1, 0, 0, 0, 0 };
74
75 /* resize the old table */
76 static int SetSpyedBlockTableLength ( int NewLength )
77 {
78 LPVOID *NewSpyedBlocks;
79
80 if (!Malloc32.SpyedBlocks) NewSpyedBlocks = LocalAlloc(LMEM_ZEROINIT, NewLength * sizeof(PVOID));
81 else NewSpyedBlocks = LocalReAlloc(Malloc32.SpyedBlocks, NewLength * sizeof(PVOID), LMEM_ZEROINIT);
82 if (NewSpyedBlocks) {
83 Malloc32.SpyedBlocks = NewSpyedBlocks;
84 Malloc32.SpyedBlockTableLength = NewLength;
85 }
86
87 return NewSpyedBlocks != NULL;
88 }
89
90 /* add a location to the table */
91 static int AddMemoryLocation(LPVOID * pMem)
92 {
93 LPVOID * Current;
94
95 /* allocate the table if not already allocated */
96 if (!Malloc32.SpyedBlockTableLength) {
97 if (!SetSpyedBlockTableLength(0x1000)) return 0;
98 }
99
100 /* find a free location */
101 Current = Malloc32.SpyedBlocks;
102 while (*Current) {
103 Current++;
104 if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) {
105 /* no more space in table, grow it */
106 if (!SetSpyedBlockTableLength( Malloc32.SpyedBlockTableLength + 0x1000 )) return 0;
107 }
108 };
109
110 /* put the location in our table */
111 *Current = pMem;
112 Malloc32.SpyedAllocationsLeft++;
113 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
114 return 1;
115 }
116
117 static int RemoveMemoryLocation(LPVOID * pMem)
118 {
119 LPVOID * Current;
120
121 /* allocate the table if not already allocated */
122 if (!Malloc32.SpyedBlockTableLength) {
123 if (!SetSpyedBlockTableLength(0x1000)) return 0;
124 }
125
126 Current = Malloc32.SpyedBlocks;
127
128 /* find the location */
129 while (*Current != pMem) {
130 Current++;
131 if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) return 0; /* not found */
132 }
133
134 /* location found */
135 Malloc32.SpyedAllocationsLeft--;
136 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
137 *Current = NULL;
138 return 1;
139 }
140
141 /******************************************************************************
142 * IMalloc32_QueryInterface [VTABLE]
143 */
144 static HRESULT WINAPI IMalloc_fnQueryInterface(LPMALLOC iface,REFIID refiid,LPVOID *obj) {
145
146 TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
147
148 if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMalloc,refiid)) {
149 *obj = (LPMALLOC)&Malloc32;
150 return S_OK;
151 }
152 return E_NOINTERFACE;
153 }
154
155 /******************************************************************************
156 * IMalloc32_AddRefRelease [VTABLE]
157 */
158 static ULONG WINAPI IMalloc_fnAddRefRelease (LPMALLOC iface) {
159 return 1;
160 }
161
162 /******************************************************************************
163 * IMalloc32_Alloc [VTABLE]
164 */
165 static LPVOID WINAPI IMalloc_fnAlloc(LPMALLOC iface, DWORD cb) {
166
167 LPVOID addr;
168
169 TRACE("(%ld)\n",cb);
170
171 if(Malloc32.pSpy) {
172 DWORD preAllocResult;
173
174 EnterCriticalSection(&IMalloc32_SpyCS);
175 preAllocResult = IMallocSpy_PreAlloc(Malloc32.pSpy, cb);
176 if ((cb != 0) && (preAllocResult == 0)) {
177 /* PreAlloc can force Alloc to fail, but not if cb == 0 */
178 TRACE("returning null\n");
179 LeaveCriticalSection(&IMalloc32_SpyCS);
180 return NULL;
181 }
182 }
183
184 addr = HeapAlloc(GetProcessHeap(),0,cb);
185
186 if(Malloc32.pSpy) {
187 addr = IMallocSpy_PostAlloc(Malloc32.pSpy, addr);
188 if (addr) AddMemoryLocation(addr);
189 LeaveCriticalSection(&IMalloc32_SpyCS);
190 }
191
192 TRACE("--(%p)\n",addr);
193 return addr;
194 }
195
196 /******************************************************************************
197 * IMalloc32_Realloc [VTABLE]
198 */
199 static LPVOID WINAPI IMalloc_fnRealloc(LPMALLOC iface,LPVOID pv,DWORD cb) {
200
201 LPVOID pNewMemory;
202
203 TRACE("(%p,%ld)\n",pv,cb);
204
205 if(Malloc32.pSpy) {
206 LPVOID pRealMemory;
207 BOOL fSpyed;
208
209 EnterCriticalSection(&IMalloc32_SpyCS);
210 fSpyed = RemoveMemoryLocation(pv);
211 cb = IMallocSpy_PreRealloc(Malloc32.pSpy, pv, cb, &pRealMemory, fSpyed);
212
213 /* check if can release the spy */
214 if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
215 IMallocSpy_Release(Malloc32.pSpy);
216 Malloc32.SpyReleasePending = FALSE;
217 Malloc32.pSpy = NULL;
218 }
219
220 if (0==cb) {
221 /* PreRealloc can force Realloc to fail */
222 LeaveCriticalSection(&IMalloc32_SpyCS);
223 return NULL;
224 }
225 pv = pRealMemory;
226 }
227
228 if (!pv) pNewMemory = HeapAlloc(GetProcessHeap(),0,cb);
229 else if (cb) pNewMemory = HeapReAlloc(GetProcessHeap(),0,pv,cb);
230 else {
231 HeapFree(GetProcessHeap(),0,pv);
232 pNewMemory = NULL;
233 }
234
235 if(Malloc32.pSpy) {
236 pNewMemory = IMallocSpy_PostRealloc(Malloc32.pSpy, pNewMemory, TRUE);
237 if (pNewMemory) AddMemoryLocation(pNewMemory);
238 LeaveCriticalSection(&IMalloc32_SpyCS);
239 }
240
241 TRACE("--(%p)\n",pNewMemory);
242 return pNewMemory;
243 }
244
245 /******************************************************************************
246 * IMalloc32_Free [VTABLE]
247 */
248 static VOID WINAPI IMalloc_fnFree(LPMALLOC iface,LPVOID pv) {
249
250 BOOL fSpyed = 0;
251
252 TRACE("(%p)\n",pv);
253
254 if(Malloc32.pSpy) {
255 EnterCriticalSection(&IMalloc32_SpyCS);
256 fSpyed = RemoveMemoryLocation(pv);
257 pv = IMallocSpy_PreFree(Malloc32.pSpy, pv, fSpyed);
258 }
259
260 HeapFree(GetProcessHeap(),0,pv);
261
262 if(Malloc32.pSpy) {
263 IMallocSpy_PostFree(Malloc32.pSpy, fSpyed);
264
265 /* check if can release the spy */
266 if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
267 IMallocSpy_Release(Malloc32.pSpy);
268 Malloc32.SpyReleasePending = FALSE;
269 Malloc32.pSpy = NULL;
270 }
271
272 LeaveCriticalSection(&IMalloc32_SpyCS);
273 }
274 }
275
276 /******************************************************************************
277 * IMalloc32_GetSize [VTABLE]
278 *
279 * NOTES
280 * FIXME returns:
281 * win95: size allocated (4 byte boundarys)
282 * win2k: size originally requested !!! (allocated on 8 byte boundarys)
283 */
284 static DWORD WINAPI IMalloc_fnGetSize(LPMALLOC iface,LPVOID pv) {
285
286 DWORD cb;
287 BOOL fSpyed = 0;
288
289 TRACE("(%p)\n",pv);
290
291 if(Malloc32.pSpy) {
292 EnterCriticalSection(&IMalloc32_SpyCS);
293 pv = IMallocSpy_PreGetSize(Malloc32.pSpy, pv, fSpyed);
294 }
295
296 cb = HeapSize(GetProcessHeap(),0,pv);
297
298 if(Malloc32.pSpy) {
299 cb = IMallocSpy_PostGetSize(Malloc32.pSpy, cb, fSpyed);
300 LeaveCriticalSection(&IMalloc32_SpyCS);
301 }
302
303 return cb;
304 }
305
306 /******************************************************************************
307 * IMalloc32_DidAlloc [VTABLE]
308 */
309 static INT WINAPI IMalloc_fnDidAlloc(LPMALLOC iface,LPVOID pv) {
310
311 BOOL fSpyed = 0;
312 int didAlloc;
313
314 TRACE("(%p)\n",pv);
315
316 if(Malloc32.pSpy) {
317 EnterCriticalSection(&IMalloc32_SpyCS);
318 pv = IMallocSpy_PreDidAlloc(Malloc32.pSpy, pv, fSpyed);
319 }
320
321 didAlloc = -1;
322
323 if(Malloc32.pSpy) {
324 didAlloc = IMallocSpy_PostDidAlloc(Malloc32.pSpy, pv, fSpyed, didAlloc);
325 LeaveCriticalSection(&IMalloc32_SpyCS);
326 }
327 return didAlloc;
328 }
329
330 /******************************************************************************
331 * IMalloc32_HeapMinimize [VTABLE]
332 */
333 static VOID WINAPI IMalloc_fnHeapMinimize(LPMALLOC iface) {
334 TRACE("()\n");
335
336 if(Malloc32.pSpy) {
337 EnterCriticalSection(&IMalloc32_SpyCS);
338 IMallocSpy_PreHeapMinimize(Malloc32.pSpy);
339 }
340
341 if(Malloc32.pSpy) {
342 IMallocSpy_PostHeapMinimize(Malloc32.pSpy);
343 LeaveCriticalSection(&IMalloc32_SpyCS);
344 }
345 }
346
347 static const IMallocVtbl VT_IMalloc32 =
348 {
349 IMalloc_fnQueryInterface,
350 IMalloc_fnAddRefRelease,
351 IMalloc_fnAddRefRelease,
352 IMalloc_fnAlloc,
353 IMalloc_fnRealloc,
354 IMalloc_fnFree,
355 IMalloc_fnGetSize,
356 IMalloc_fnDidAlloc,
357 IMalloc_fnHeapMinimize
358 };
359
360 /******************************************************************************
361 * IMallocSpy implementation
362 *****************************************************************************/
363
364 /* set the vtable later */
365 static const IMallocSpyVtbl VT_IMallocSpy;
366
367 typedef struct {
368 const IMallocSpyVtbl *lpVtbl;
369 LONG ref;
370 } _MallocSpy;
371
372 /* this is the static object instance */
373 static _MallocSpy MallocSpy = {&VT_IMallocSpy, 0};
374
375 /******************************************************************************
376 * IMalloc32_QueryInterface [VTABLE]
377 */
378 static HRESULT WINAPI IMallocSpy_fnQueryInterface(LPMALLOCSPY iface,REFIID refiid,LPVOID *obj)
379 {
380
381 TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
382
383 if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMallocSpy,refiid)) {
384 *obj = (LPMALLOC)&MallocSpy;
385 return S_OK;
386 }
387 return E_NOINTERFACE;
388 }
389
390 /******************************************************************************
391 * IMalloc32_AddRef [VTABLE]
392 */
393 static ULONG WINAPI IMallocSpy_fnAddRef (LPMALLOCSPY iface)
394 {
395
396 _MallocSpy *This = (_MallocSpy *)iface;
397 ULONG ref = InterlockedIncrement(&This->ref);
398
399 TRACE ("(%p)->(count=%lu)\n", This, ref - 1);
400
401 return ref;
402 }
403
404 /******************************************************************************
405 * IMalloc32_AddRelease [VTABLE]
406 *
407 * NOTES
408 * Our MallocSpy is static. If the count reaches 0 we dump the leaks
409 */
410 static ULONG WINAPI IMallocSpy_fnRelease (LPMALLOCSPY iface)
411 {
412
413 _MallocSpy *This = (_MallocSpy *)iface;
414 ULONG ref = InterlockedDecrement(&This->ref);
415
416 TRACE ("(%p)->(count=%lu)\n", This, ref + 1);
417
418 if (!ref) {
419 /* our allocation list MUST be empty here */
420 }
421 return ref;
422 }
423
424 static ULONG WINAPI IMallocSpy_fnPreAlloc(LPMALLOCSPY iface, ULONG cbRequest)
425 {
426 _MallocSpy *This = (_MallocSpy *)iface;
427 TRACE ("(%p)->(%lu)\n", This, cbRequest);
428 return cbRequest;
429 }
430 static PVOID WINAPI IMallocSpy_fnPostAlloc(LPMALLOCSPY iface, void* pActual)
431 {
432 _MallocSpy *This = (_MallocSpy *)iface;
433 TRACE ("(%p)->(%p)\n", This, pActual);
434 return pActual;
435 }
436
437 static PVOID WINAPI IMallocSpy_fnPreFree(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
438 {
439 _MallocSpy *This = (_MallocSpy *)iface;
440 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
441 return pRequest;
442 }
443 static void WINAPI IMallocSpy_fnPostFree(LPMALLOCSPY iface, BOOL fSpyed)
444 {
445 _MallocSpy *This = (_MallocSpy *)iface;
446 TRACE ("(%p)->(%u)\n", This, fSpyed);
447 }
448
449 static ULONG WINAPI IMallocSpy_fnPreRealloc(LPMALLOCSPY iface, void* pRequest, ULONG cbRequest, void** ppNewRequest, BOOL fSpyed)
450 {
451 _MallocSpy *This = (_MallocSpy *)iface;
452 TRACE ("(%p)->(%p %lu %u)\n", This, pRequest, cbRequest, fSpyed);
453 *ppNewRequest = pRequest;
454 return cbRequest;
455 }
456
457 static PVOID WINAPI IMallocSpy_fnPostRealloc(LPMALLOCSPY iface, void* pActual, BOOL fSpyed)
458 {
459 _MallocSpy *This = (_MallocSpy *)iface;
460 TRACE ("(%p)->(%p %u)\n", This, pActual, fSpyed);
461 return pActual;
462 }
463
464 static PVOID WINAPI IMallocSpy_fnPreGetSize(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
465 {
466 _MallocSpy *This = (_MallocSpy *)iface;
467 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
468 return pRequest;
469 }
470
471 static ULONG WINAPI IMallocSpy_fnPostGetSize(LPMALLOCSPY iface, ULONG cbActual, BOOL fSpyed)
472 {
473 _MallocSpy *This = (_MallocSpy *)iface;
474 TRACE ("(%p)->(%lu %u)\n", This, cbActual, fSpyed);
475 return cbActual;
476 }
477
478 static PVOID WINAPI IMallocSpy_fnPreDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
479 {
480 _MallocSpy *This = (_MallocSpy *)iface;
481 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
482 return pRequest;
483 }
484
485 static int WINAPI IMallocSpy_fnPostDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed, int fActual)
486 {
487 _MallocSpy *This = (_MallocSpy *)iface;
488 TRACE ("(%p)->(%p %u %u)\n", This, pRequest, fSpyed, fActual);
489 return fActual;
490 }
491
492 static void WINAPI IMallocSpy_fnPreHeapMinimize(LPMALLOCSPY iface)
493 {
494 _MallocSpy *This = (_MallocSpy *)iface;
495 TRACE ("(%p)->()\n", This);
496 }
497
498 static void WINAPI IMallocSpy_fnPostHeapMinimize(LPMALLOCSPY iface)
499 {
500 _MallocSpy *This = (_MallocSpy *)iface;
501 TRACE ("(%p)->()\n", This);
502 }
503
504 static void MallocSpyDumpLeaks(void) {
505 TRACE("leaks: %lu\n", Malloc32.SpyedAllocationsLeft);
506 }
507
508 static const IMallocSpyVtbl VT_IMallocSpy =
509 {
510 IMallocSpy_fnQueryInterface,
511 IMallocSpy_fnAddRef,
512 IMallocSpy_fnRelease,
513 IMallocSpy_fnPreAlloc,
514 IMallocSpy_fnPostAlloc,
515 IMallocSpy_fnPreFree,
516 IMallocSpy_fnPostFree,
517 IMallocSpy_fnPreRealloc,
518 IMallocSpy_fnPostRealloc,
519 IMallocSpy_fnPreGetSize,
520 IMallocSpy_fnPostGetSize,
521 IMallocSpy_fnPreDidAlloc,
522 IMallocSpy_fnPostDidAlloc,
523 IMallocSpy_fnPreHeapMinimize,
524 IMallocSpy_fnPostHeapMinimize
525 };
526
527 /******************************************************************************
528 * CoGetMalloc [OLE32.@]
529 *
530 * Retrieves the current IMalloc interface for the process.
531 *
532 * PARAMS
533 * dwMemContext [I]
534 * lpMalloc [O] Address where memory allocator object will be stored.
535 *
536 * RETURNS
537 * Success: S_OK.
538 * Failure: HRESULT code.
539 */
540 HRESULT WINAPI CoGetMalloc(DWORD dwMemContext, LPMALLOC *lpMalloc)
541 {
542 *lpMalloc = (LPMALLOC)&Malloc32;
543 return S_OK;
544 }
545
546 /***********************************************************************
547 * CoTaskMemAlloc [OLE32.@]
548 *
549 * Allocates memory using the current process memory allocator.
550 *
551 * PARAMS
552 * size [I] Size of the memory block to allocate.
553 *
554 * RETURNS
555 * Success: Pointer to newly allocated memory block.
556 * Failure: NULL.
557 */
558 LPVOID WINAPI CoTaskMemAlloc(ULONG size)
559 {
560 return IMalloc_Alloc((LPMALLOC)&Malloc32,size);
561 }
562
563 /***********************************************************************
564 * CoTaskMemFree [OLE32.@]
565 *
566 * Frees memory allocated from the current process memory allocator.
567 *
568 * PARAMS
569 * ptr [I] Memory block to free.
570 *
571 * RETURNS
572 * Nothing.
573 */
574 VOID WINAPI CoTaskMemFree(LPVOID ptr)
575 {
576 IMalloc_Free((LPMALLOC)&Malloc32, ptr);
577 }
578
579 /***********************************************************************
580 * CoTaskMemRealloc [OLE32.@]
581 *
582 * Allocates memory using the current process memory allocator.
583 *
584 * PARAMS
585 * pvOld [I] Pointer to old memory block.
586 * size [I] Size of the new memory block.
587 *
588 * RETURNS
589 * Success: Pointer to newly allocated memory block.
590 * Failure: NULL.
591 */
592 LPVOID WINAPI CoTaskMemRealloc(LPVOID pvOld, ULONG size)
593 {
594 return IMalloc_Realloc((LPMALLOC)&Malloc32, pvOld, size);
595 }
596
597 /***********************************************************************
598 * CoRegisterMallocSpy [OLE32.@]
599 *
600 * Registers an object that receives notifications on memory allocations and
601 * frees.
602 *
603 * PARAMS
604 * pMallocSpy [I] New spy object.
605 *
606 * RETURNS
607 * Success: S_OK.
608 * Failure: HRESULT code.
609 *
610 * NOTES
611 * if a mallocspy is already registered, we can't do it again since
612 * only the spy knows, how to free a memory block
613 */
614 HRESULT WINAPI CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy)
615 {
616 IMallocSpy* pSpy;
617 HRESULT hres = E_INVALIDARG;
618
619 TRACE("\n");
620
621 /* HACK TO ACTIVATE OUT SPY */
622 if (pMallocSpy == (LPVOID)-1) pMallocSpy =(IMallocSpy*)&MallocSpy;
623
624 if(Malloc32.pSpy) return CO_E_OBJISREG;
625
626 EnterCriticalSection(&IMalloc32_SpyCS);
627
628 if (SUCCEEDED(IUnknown_QueryInterface(pMallocSpy, &IID_IMallocSpy, (LPVOID*)&pSpy))) {
629 Malloc32.pSpy = pSpy;
630 hres = S_OK;
631 }
632
633 LeaveCriticalSection(&IMalloc32_SpyCS);
634
635 return hres;
636 }
637
638 /***********************************************************************
639 * CoRevokeMallocSpy [OLE32.@]
640 *
641 * Revokes a previousl registered object that receives notifications on memory
642 * allocations and frees.
643 *
644 * PARAMS
645 * pMallocSpy [I] New spy object.
646 *
647 * RETURNS
648 * Success: S_OK.
649 * Failure: HRESULT code.
650 *
651 * NOTES
652 * we can't revoke a malloc spy as long as memory blocks allocated with
653 * the spy are active since only the spy knows how to free them
654 */
655 HRESULT WINAPI CoRevokeMallocSpy(void)
656 {
657 HRESULT hres = S_OK;
658 TRACE("\n");
659
660 EnterCriticalSection(&IMalloc32_SpyCS);
661
662 /* if it's our spy it's time to dump the leaks */
663 if (Malloc32.pSpy == (IMallocSpy*)&MallocSpy) {
664 MallocSpyDumpLeaks();
665 }
666
667 if (Malloc32.SpyedAllocationsLeft) {
668 TRACE("SpyReleasePending with %lu allocations left\n", Malloc32.SpyedAllocationsLeft);
669 Malloc32.SpyReleasePending = TRUE;
670 hres = E_ACCESSDENIED;
671 } else {
672 IMallocSpy_Release(Malloc32.pSpy);
673 Malloc32.pSpy = NULL;
674 }
675 LeaveCriticalSection(&IMalloc32_SpyCS);
676
677 return S_OK;
678 }
679
680 /******************************************************************************
681 * IsValidInterface [OLE32.@]
682 *
683 * Determines whether a pointer is a valid interface.
684 *
685 * PARAMS
686 * punk [I] Interface to be tested.
687 *
688 * RETURNS
689 * TRUE, if the passed pointer is a valid interface, or FALSE otherwise.
690 */
691 BOOL WINAPI IsValidInterface(LPUNKNOWN punk)
692 {
693 return !(
694 IsBadReadPtr(punk,4) ||
695 IsBadReadPtr(punk->lpVtbl,4) ||
696 IsBadReadPtr(punk->lpVtbl->QueryInterface,9) ||
697 IsBadCodePtr((FARPROC)punk->lpVtbl->QueryInterface)
698 );
699 }