Intercept functions for 16-bit relay debugging by patching the
[wine] / dlls / 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, { 0, (DWORD)(__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 }