HeapReAlloc doesn't allocate memory.
[wine.git] / dlls / ole32 / ifs.c
blob54b84d4b60df073d772916f037633184d4486eec
1 /*
2 * basic interfaces
4 * Copyright 1997 Marcus Meissner
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.
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.
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
21 #include "config.h"
23 #include <ctype.h>
24 #include <stdarg.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <assert.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winuser.h"
32 #include "ole2.h"
33 #include "winerror.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(ole);
39 /******************************************************************************
40 * IMalloc32 implementation
42 * NOTES
43 * For supporting CoRegisterMallocSpy the IMalloc implementation must know if
44 * a given memory block was allocated with a spy active.
46 *****************************************************************************/
47 /* set the vtable later */
48 extern ICOM_VTABLE(IMalloc) VT_IMalloc32;
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;
60 /* this is the static object instance */
61 _Malloc32 Malloc32 = {&VT_IMalloc32, 0, NULL, 0, 0, NULL, 0};
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 =
67 0, 0, &IMalloc32_SpyCS,
68 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
69 0, 0, { 0, (DWORD)(__FILE__ ": IMalloc32_SpyCS") }
71 static CRITICAL_SECTION IMalloc32_SpyCS = { &critsect_debug, -1, 0, 0, 0, 0 };
73 /* resize the old table */
74 static int SetSpyedBlockTableLength ( int NewLength )
76 Malloc32.SpyedBlocks = (LPVOID*)LocalReAlloc((HLOCAL)Malloc32.SpyedBlocks, NewLength, GMEM_ZEROINIT);
77 Malloc32.SpyedBlockTableLength = NewLength;
78 return Malloc32.SpyedBlocks ? 1 : 0;
81 /* add a location to the table */
82 static int AddMemoryLocation(LPVOID * pMem)
84 LPVOID * Current;
86 /* allocate the table if not already allocated */
87 if (!Malloc32.SpyedBlockTableLength) {
88 if (!SetSpyedBlockTableLength(0x1000)) return 0;
91 /* find a free location */
92 Current = Malloc32.SpyedBlocks;
93 while (*Current) {
94 Current++;
95 if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) {
96 /* no more space in table, grow it */
97 if (!SetSpyedBlockTableLength( Malloc32.SpyedBlockTableLength + 0x1000 )) return 0;
101 /* put the location in our table */
102 *Current = pMem;
103 Malloc32.SpyedAllocationsLeft++;
104 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
105 return 1;
108 static int RemoveMemoryLocation(LPVOID * pMem)
110 LPVOID * Current = Malloc32.SpyedBlocks;
112 /* find the location */
113 while (*Current != pMem) {
114 Current++;
115 if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) return 0; /* not found */
118 /* location found */
119 Malloc32.SpyedAllocationsLeft--;
120 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
121 *Current = NULL;
122 return 1;
125 /******************************************************************************
126 * IMalloc32_QueryInterface [VTABLE]
128 static HRESULT WINAPI IMalloc_fnQueryInterface(LPMALLOC iface,REFIID refiid,LPVOID *obj) {
130 TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
132 if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMalloc,refiid)) {
133 *obj = (LPMALLOC)&Malloc32;
134 return S_OK;
136 return E_NOINTERFACE;
139 /******************************************************************************
140 * IMalloc32_AddRefRelease [VTABLE]
142 static ULONG WINAPI IMalloc_fnAddRefRelease (LPMALLOC iface) {
143 return 1;
146 /******************************************************************************
147 * IMalloc32_Alloc [VTABLE]
149 static LPVOID WINAPI IMalloc_fnAlloc(LPMALLOC iface, DWORD cb) {
151 LPVOID addr;
153 TRACE("(%ld)\n",cb);
155 if(Malloc32.pSpy) {
156 DWORD preAllocResult;
158 EnterCriticalSection(&IMalloc32_SpyCS);
159 preAllocResult = IMallocSpy_PreAlloc(Malloc32.pSpy, cb);
160 if ((cb != 0) && (preAllocResult == 0)) {
161 /* PreAlloc can force Alloc to fail, but not if cb == 0 */
162 TRACE("returning null\n");
163 LeaveCriticalSection(&IMalloc32_SpyCS);
164 return NULL;
168 addr = HeapAlloc(GetProcessHeap(),0,cb);
170 if(Malloc32.pSpy) {
171 addr = IMallocSpy_PostAlloc(Malloc32.pSpy, addr);
172 if (addr) AddMemoryLocation(addr);
173 LeaveCriticalSection(&IMalloc32_SpyCS);
176 TRACE("--(%p)\n",addr);
177 return addr;
180 /******************************************************************************
181 * IMalloc32_Realloc [VTABLE]
183 static LPVOID WINAPI IMalloc_fnRealloc(LPMALLOC iface,LPVOID pv,DWORD cb) {
185 LPVOID pNewMemory;
187 TRACE("(%p,%ld)\n",pv,cb);
189 if(Malloc32.pSpy) {
190 LPVOID pRealMemory;
191 BOOL fSpyed;
193 EnterCriticalSection(&IMalloc32_SpyCS);
194 fSpyed = RemoveMemoryLocation(pv);
195 cb = IMallocSpy_PreRealloc(Malloc32.pSpy, pv, cb, &pRealMemory, fSpyed);
197 /* check if can release the spy */
198 if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
199 IMallocSpy_Release(Malloc32.pSpy);
200 Malloc32.SpyReleasePending = FALSE;
201 Malloc32.pSpy = NULL;
204 if (0==cb) {
205 /* PreRealloc can force Realloc to fail */
206 LeaveCriticalSection(&IMalloc32_SpyCS);
207 return NULL;
209 pv = pRealMemory;
212 pNewMemory = HeapReAlloc(GetProcessHeap(),0,pv,cb);
214 if(Malloc32.pSpy) {
215 pNewMemory = IMallocSpy_PostRealloc(Malloc32.pSpy, pNewMemory, TRUE);
216 if (pNewMemory) AddMemoryLocation(pNewMemory);
217 LeaveCriticalSection(&IMalloc32_SpyCS);
220 TRACE("--(%p)\n",pNewMemory);
221 return pNewMemory;
224 /******************************************************************************
225 * IMalloc32_Free [VTABLE]
227 static VOID WINAPI IMalloc_fnFree(LPMALLOC iface,LPVOID pv) {
229 BOOL fSpyed = 0;
231 TRACE("(%p)\n",pv);
233 if(Malloc32.pSpy) {
234 EnterCriticalSection(&IMalloc32_SpyCS);
235 fSpyed = RemoveMemoryLocation(pv);
236 pv = IMallocSpy_PreFree(Malloc32.pSpy, pv, fSpyed);
239 HeapFree(GetProcessHeap(),0,pv);
241 if(Malloc32.pSpy) {
242 IMallocSpy_PostFree(Malloc32.pSpy, fSpyed);
244 /* check if can release the spy */
245 if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
246 IMallocSpy_Release(Malloc32.pSpy);
247 Malloc32.SpyReleasePending = FALSE;
248 Malloc32.pSpy = NULL;
251 LeaveCriticalSection(&IMalloc32_SpyCS);
255 /******************************************************************************
256 * IMalloc32_GetSize [VTABLE]
258 * NOTES
259 * FIXME returns:
260 * win95: size allocated (4 byte boundarys)
261 * win2k: size originally requested !!! (allocated on 8 byte boundarys)
263 static DWORD WINAPI IMalloc_fnGetSize(LPMALLOC iface,LPVOID pv) {
265 DWORD cb;
266 BOOL fSpyed = 0;
268 TRACE("(%p)\n",pv);
270 if(Malloc32.pSpy) {
271 EnterCriticalSection(&IMalloc32_SpyCS);
272 pv = IMallocSpy_PreGetSize(Malloc32.pSpy, pv, fSpyed);
275 cb = HeapSize(GetProcessHeap(),0,pv);
277 if(Malloc32.pSpy) {
278 cb = IMallocSpy_PostGetSize(Malloc32.pSpy, cb, fSpyed);
279 LeaveCriticalSection(&IMalloc32_SpyCS);
282 return cb;
285 /******************************************************************************
286 * IMalloc32_DidAlloc [VTABLE]
288 static INT WINAPI IMalloc_fnDidAlloc(LPMALLOC iface,LPVOID pv) {
290 BOOL fSpyed = 0;
291 int didAlloc;
293 TRACE("(%p)\n",pv);
295 if(Malloc32.pSpy) {
296 EnterCriticalSection(&IMalloc32_SpyCS);
297 pv = IMallocSpy_PreDidAlloc(Malloc32.pSpy, pv, fSpyed);
300 didAlloc = -1;
302 if(Malloc32.pSpy) {
303 didAlloc = IMallocSpy_PostDidAlloc(Malloc32.pSpy, pv, fSpyed, didAlloc);
304 LeaveCriticalSection(&IMalloc32_SpyCS);
306 return didAlloc;
309 /******************************************************************************
310 * IMalloc32_HeapMinimize [VTABLE]
312 static VOID WINAPI IMalloc_fnHeapMinimize(LPMALLOC iface) {
313 TRACE("()\n");
315 if(Malloc32.pSpy) {
316 EnterCriticalSection(&IMalloc32_SpyCS);
317 IMallocSpy_PreHeapMinimize(Malloc32.pSpy);
320 if(Malloc32.pSpy) {
321 IMallocSpy_PostHeapMinimize(Malloc32.pSpy);
322 LeaveCriticalSection(&IMalloc32_SpyCS);
326 static ICOM_VTABLE(IMalloc) VT_IMalloc32 =
328 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
329 IMalloc_fnQueryInterface,
330 IMalloc_fnAddRefRelease,
331 IMalloc_fnAddRefRelease,
332 IMalloc_fnAlloc,
333 IMalloc_fnRealloc,
334 IMalloc_fnFree,
335 IMalloc_fnGetSize,
336 IMalloc_fnDidAlloc,
337 IMalloc_fnHeapMinimize
340 /******************************************************************************
341 * IMallocSpy implementation
342 *****************************************************************************/
344 /* set the vtable later */
345 extern ICOM_VTABLE(IMallocSpy) VT_IMallocSpy;
347 typedef struct {
348 ICOM_VFIELD(IMallocSpy);
349 DWORD ref;
350 } _MallocSpy;
352 /* this is the static object instance */
353 _MallocSpy MallocSpy = {&VT_IMallocSpy, 0};
355 /******************************************************************************
356 * IMalloc32_QueryInterface [VTABLE]
358 static HRESULT WINAPI IMallocSpy_fnQueryInterface(LPMALLOCSPY iface,REFIID refiid,LPVOID *obj)
361 TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
363 if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMallocSpy,refiid)) {
364 *obj = (LPMALLOC)&MallocSpy;
365 return S_OK;
367 return E_NOINTERFACE;
370 /******************************************************************************
371 * IMalloc32_AddRef [VTABLE]
373 static ULONG WINAPI IMallocSpy_fnAddRef (LPMALLOCSPY iface)
376 ICOM_THIS (_MallocSpy, iface);
378 TRACE ("(%p)->(count=%lu)\n", This, This->ref);
380 return ++(This->ref);
383 /******************************************************************************
384 * IMalloc32_AddRelease [VTABLE]
386 * NOTES
387 * Our MallocSpy is static. If the count reaches 0 we dump the leaks
389 static ULONG WINAPI IMallocSpy_fnRelease (LPMALLOCSPY iface)
392 ICOM_THIS (_MallocSpy, iface);
394 TRACE ("(%p)->(count=%lu)\n", This, This->ref);
396 if (!--(This->ref)) {
397 /* our allocation list MUST be empty here */
399 return This->ref;
402 static ULONG WINAPI IMallocSpy_fnPreAlloc(LPMALLOCSPY iface, ULONG cbRequest)
404 ICOM_THIS (_MallocSpy, iface);
405 TRACE ("(%p)->(%lu)\n", This, cbRequest);
406 return cbRequest;
408 static PVOID WINAPI IMallocSpy_fnPostAlloc(LPMALLOCSPY iface, void* pActual)
410 ICOM_THIS (_MallocSpy, iface);
411 TRACE ("(%p)->(%p)\n", This, pActual);
412 return pActual;
415 static PVOID WINAPI IMallocSpy_fnPreFree(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
417 ICOM_THIS (_MallocSpy, iface);
418 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
419 return pRequest;
421 static void WINAPI IMallocSpy_fnPostFree(LPMALLOCSPY iface, BOOL fSpyed)
423 ICOM_THIS (_MallocSpy, iface);
424 TRACE ("(%p)->(%u)\n", This, fSpyed);
427 static ULONG WINAPI IMallocSpy_fnPreRealloc(LPMALLOCSPY iface, void* pRequest, ULONG cbRequest, void** ppNewRequest, BOOL fSpyed)
429 ICOM_THIS (_MallocSpy, iface);
430 TRACE ("(%p)->(%p %lu %u)\n", This, pRequest, cbRequest, fSpyed);
431 *ppNewRequest = pRequest;
432 return cbRequest;
435 static PVOID WINAPI IMallocSpy_fnPostRealloc(LPMALLOCSPY iface, void* pActual, BOOL fSpyed)
437 ICOM_THIS (_MallocSpy, iface);
438 TRACE ("(%p)->(%p %u)\n", This, pActual, fSpyed);
439 return pActual;
442 static PVOID WINAPI IMallocSpy_fnPreGetSize(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
444 ICOM_THIS (_MallocSpy, iface);
445 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
446 return pRequest;
449 static ULONG WINAPI IMallocSpy_fnPostGetSize(LPMALLOCSPY iface, ULONG cbActual, BOOL fSpyed)
451 ICOM_THIS (_MallocSpy, iface);
452 TRACE ("(%p)->(%lu %u)\n", This, cbActual, fSpyed);
453 return cbActual;
456 static PVOID WINAPI IMallocSpy_fnPreDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
458 ICOM_THIS (_MallocSpy, iface);
459 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
460 return pRequest;
463 static int WINAPI IMallocSpy_fnPostDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed, int fActual)
465 ICOM_THIS (_MallocSpy, iface);
466 TRACE ("(%p)->(%p %u %u)\n", This, pRequest, fSpyed, fActual);
467 return fActual;
470 static void WINAPI IMallocSpy_fnPreHeapMinimize(LPMALLOCSPY iface)
472 ICOM_THIS (_MallocSpy, iface);
473 TRACE ("(%p)->()\n", This);
476 static void WINAPI IMallocSpy_fnPostHeapMinimize(LPMALLOCSPY iface)
478 ICOM_THIS (_MallocSpy, iface);
479 TRACE ("(%p)->()\n", This);
482 static void MallocSpyDumpLeaks() {
483 TRACE("leaks: %lu\n", Malloc32.SpyedAllocationsLeft);
486 static ICOM_VTABLE(IMallocSpy) VT_IMallocSpy =
488 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
489 IMallocSpy_fnQueryInterface,
490 IMallocSpy_fnAddRef,
491 IMallocSpy_fnRelease,
492 IMallocSpy_fnPreAlloc,
493 IMallocSpy_fnPostAlloc,
494 IMallocSpy_fnPreFree,
495 IMallocSpy_fnPostFree,
496 IMallocSpy_fnPreRealloc,
497 IMallocSpy_fnPostRealloc,
498 IMallocSpy_fnPreGetSize,
499 IMallocSpy_fnPostGetSize,
500 IMallocSpy_fnPreDidAlloc,
501 IMallocSpy_fnPostDidAlloc,
502 IMallocSpy_fnPreHeapMinimize,
503 IMallocSpy_fnPostHeapMinimize
506 /******************************************************************************
507 * CoGetMalloc [OLE32.@]
509 * RETURNS
510 * The win32 IMalloc
512 HRESULT WINAPI CoGetMalloc(DWORD dwMemContext, LPMALLOC *lpMalloc)
514 *lpMalloc = (LPMALLOC)&Malloc32;
515 return S_OK;
518 /***********************************************************************
519 * CoTaskMemAlloc [OLE32.@]
520 * RETURNS
521 * pointer to newly allocated block
523 LPVOID WINAPI CoTaskMemAlloc(ULONG size)
525 return IMalloc_Alloc((LPMALLOC)&Malloc32,size);
527 /***********************************************************************
528 * CoTaskMemFree [OLE32.@]
530 VOID WINAPI CoTaskMemFree(LPVOID ptr)
532 IMalloc_Free((LPMALLOC)&Malloc32, ptr);
535 /***********************************************************************
536 * CoTaskMemRealloc [OLE32.@]
537 * RETURNS
538 * pointer to newly allocated block
540 LPVOID WINAPI CoTaskMemRealloc(LPVOID pvOld, ULONG size)
542 return IMalloc_Realloc((LPMALLOC)&Malloc32, pvOld, size);
545 /***********************************************************************
546 * CoRegisterMallocSpy [OLE32.@]
548 * NOTES
549 * if a mallocspy is already registered, we cant do it again since
550 * only the spy knows, how to free a memory block
552 HRESULT WINAPI CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy)
554 IMallocSpy* pSpy;
555 HRESULT hres = E_INVALIDARG;
557 TRACE("\n");
559 /* HACK TO ACTIVATE OUT SPY */
560 if (pMallocSpy == (LPVOID)-1) pMallocSpy =(IMallocSpy*)&MallocSpy;
562 if(Malloc32.pSpy) return CO_E_OBJISREG;
564 EnterCriticalSection(&IMalloc32_SpyCS);
566 if (SUCCEEDED(IUnknown_QueryInterface(pMallocSpy, &IID_IMallocSpy, (LPVOID*)&pSpy))) {
567 Malloc32.pSpy = pSpy;
568 hres = S_OK;
571 LeaveCriticalSection(&IMalloc32_SpyCS);
573 return hres;
576 /***********************************************************************
577 * CoRevokeMallocSpy [OLE32.@]
579 * NOTES
580 * we can't rewoke a malloc spy as long as memory blocks allocated with
581 * the spy are active since only the spy knows how to free them
583 HRESULT WINAPI CoRevokeMallocSpy(void)
585 HRESULT hres = S_OK;
586 TRACE("\n");
588 EnterCriticalSection(&IMalloc32_SpyCS);
590 /* if it's our spy it's time to dump the leaks */
591 if (Malloc32.pSpy == (IMallocSpy*)&MallocSpy) {
592 MallocSpyDumpLeaks();
595 if (Malloc32.SpyedAllocationsLeft) {
596 TRACE("SpyReleasePending with %lu allocations left\n", Malloc32.SpyedAllocationsLeft);
597 Malloc32.SpyReleasePending = TRUE;
598 hres = E_ACCESSDENIED;
599 } else {
600 IMallocSpy_Release(Malloc32.pSpy);
601 Malloc32.pSpy = NULL;
603 LeaveCriticalSection(&IMalloc32_SpyCS);
605 return S_OK;
608 /******************************************************************************
609 * IsValidInterface [OLE32.@]
611 * RETURNS
612 * True, if the passed pointer is a valid interface
614 BOOL WINAPI IsValidInterface(
615 LPUNKNOWN punk /* [in] interface to be tested */
617 return !(
618 IsBadReadPtr(punk,4) ||
619 IsBadReadPtr(punk->lpVtbl,4) ||
620 IsBadReadPtr(punk->lpVtbl->QueryInterface,9) ||
621 IsBadCodePtr((FARPROC)punk->lpVtbl->QueryInterface)