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