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