dinput: Enumerate user format object forwards.
[wine.git] / dlls / combase / malloc.c
blob5d5b61ca42ebe12519ce1c3823268d04b4c71f91
1 /*
2 * Copyright 1997 Marcus Meissner
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #define COBJMACROS
21 #include "oleauto.h"
23 #include "wine/debug.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(olemalloc);
27 static const IMallocVtbl allocator_vtbl;
29 struct allocator
31 IMalloc IMalloc_iface;
32 IMallocSpy *spy;
33 DWORD spyed_allocations;
34 BOOL spy_release_pending; /* CoRevokeMallocSpy called with spyed allocations left */
35 void **blocks;
36 DWORD blocks_length;
39 static struct allocator allocator = { .IMalloc_iface.lpVtbl = &allocator_vtbl };
41 static CRITICAL_SECTION allocspy_cs;
42 static CRITICAL_SECTION_DEBUG allocspy_cs_debug =
44 0, 0, &allocspy_cs,
45 { &allocspy_cs_debug.ProcessLocksList, &allocspy_cs_debug.ProcessLocksList },
46 0, 0, { (DWORD_PTR)(__FILE__ ": allocspy_cs") }
48 static CRITICAL_SECTION allocspy_cs = { &allocspy_cs_debug, -1, 0, 0, 0, 0 };
50 static BOOL mallocspy_grow(DWORD length)
52 void **blocks;
54 if (!allocator.blocks) blocks = LocalAlloc(LMEM_ZEROINIT, length * sizeof(void *));
55 else blocks = LocalReAlloc(allocator.blocks, length * sizeof(void *), LMEM_ZEROINIT | LMEM_MOVEABLE);
56 if (blocks)
58 allocator.blocks = blocks;
59 allocator.blocks_length = length;
62 return blocks != NULL;
65 static void mallocspy_add_mem(void *mem)
67 void **current;
69 if (!mem || (!allocator.blocks_length && !mallocspy_grow(0x1000)))
70 return;
72 /* Find a free location */
73 current = allocator.blocks;
74 while (*current)
76 current++;
77 if (current >= allocator.blocks + allocator.blocks_length)
79 DWORD old_length = allocator.blocks_length;
80 if (!mallocspy_grow(allocator.blocks_length + 0x1000))
81 return;
82 current = allocator.blocks + old_length;
86 *current = mem;
87 allocator.spyed_allocations++;
90 static void** mallocspy_is_allocation_spyed(const void *mem)
92 void **current = allocator.blocks;
94 while (*current != mem)
96 current++;
97 if (current >= allocator.blocks + allocator.blocks_length)
98 return NULL;
101 return current;
104 static BOOL mallocspy_remove_spyed_memory(const void *mem)
106 void **current;
108 if (!allocator.blocks_length)
109 return FALSE;
111 if (!(current = mallocspy_is_allocation_spyed(mem)))
112 return FALSE;
114 allocator.spyed_allocations--;
115 *current = NULL;
116 return TRUE;
119 static HRESULT WINAPI allocator_QueryInterface(IMalloc *iface, REFIID riid, void **obj)
121 TRACE("%s, %p.\n", debugstr_guid(riid), obj);
123 if (IsEqualIID(&IID_IUnknown, riid) || IsEqualIID(&IID_IMalloc, riid))
125 *obj = &allocator.IMalloc_iface;
126 return S_OK;
129 return E_NOINTERFACE;
132 static ULONG WINAPI allocator_AddRef(IMalloc *iface)
134 return 2;
137 static ULONG WINAPI allocator_Release(IMalloc *iface)
139 return 1;
142 static void * WINAPI allocator_Alloc(IMalloc *iface, SIZE_T cb)
144 void *addr;
146 TRACE("%Id.\n", cb);
148 if (allocator.spy)
150 SIZE_T preAllocResult;
152 EnterCriticalSection(&allocspy_cs);
153 preAllocResult = IMallocSpy_PreAlloc(allocator.spy, cb);
154 if (cb && !preAllocResult)
156 /* PreAlloc can force Alloc to fail, but not if cb == 0 */
157 TRACE("returning null\n");
158 LeaveCriticalSection(&allocspy_cs);
159 return NULL;
163 addr = HeapAlloc(GetProcessHeap(), 0, cb);
165 if (allocator.spy)
167 addr = IMallocSpy_PostAlloc(allocator.spy, addr);
168 mallocspy_add_mem(addr);
169 LeaveCriticalSection(&allocspy_cs);
172 TRACE("%p.\n",addr);
173 return addr;
176 static void * WINAPI allocator_Realloc(IMalloc *iface, void *pv, SIZE_T cb)
178 void *addr;
180 TRACE("%p, %Id.\n", pv, cb);
182 if (allocator.spy)
184 void *real_mem;
185 BOOL spyed;
187 EnterCriticalSection(&allocspy_cs);
188 spyed = mallocspy_remove_spyed_memory(pv);
189 cb = IMallocSpy_PreRealloc(allocator.spy, pv, cb, &real_mem, spyed);
191 /* check if can release the spy */
192 if (allocator.spy_release_pending && !allocator.spyed_allocations)
194 IMallocSpy_Release(allocator.spy);
195 allocator.spy_release_pending = FALSE;
196 allocator.spy = NULL;
197 LeaveCriticalSection(&allocspy_cs);
200 if (!cb)
202 /* PreRealloc can force Realloc to fail */
203 if (allocator.spy)
204 LeaveCriticalSection(&allocspy_cs);
205 return NULL;
208 pv = real_mem;
211 if (!pv) addr = HeapAlloc(GetProcessHeap(), 0, cb);
212 else if (cb) addr = HeapReAlloc(GetProcessHeap(), 0, pv, cb);
213 else
215 HeapFree(GetProcessHeap(), 0, pv);
216 addr = NULL;
219 if (allocator.spy)
221 addr = IMallocSpy_PostRealloc(allocator.spy, addr, TRUE);
222 mallocspy_add_mem(addr);
223 LeaveCriticalSection(&allocspy_cs);
226 TRACE("%p.\n", addr);
227 return addr;
230 static void WINAPI allocator_Free(IMalloc *iface, void *mem)
232 BOOL spyed_block = FALSE, spy_active = FALSE;
234 TRACE("%p.\n", mem);
236 if (!mem)
237 return;
239 if (allocator.spy)
241 EnterCriticalSection(&allocspy_cs);
242 spyed_block = mallocspy_remove_spyed_memory(mem);
243 spy_active = TRUE;
244 mem = IMallocSpy_PreFree(allocator.spy, mem, spyed_block);
247 HeapFree(GetProcessHeap(), 0, mem);
249 if (spy_active)
251 IMallocSpy_PostFree(allocator.spy, spyed_block);
253 /* check if can release the spy */
254 if (allocator.spy_release_pending && !allocator.spyed_allocations)
256 IMallocSpy_Release(allocator.spy);
257 allocator.spy_release_pending = FALSE;
258 allocator.spy = NULL;
261 LeaveCriticalSection(&allocspy_cs);
265 /******************************************************************************
266 * NOTES
267 * FIXME returns:
268 * win95: size allocated (4 byte boundaries)
269 * win2k: size originally requested !!! (allocated on 8 byte boundaries)
271 static SIZE_T WINAPI allocator_GetSize(IMalloc *iface, void *mem)
273 BOOL spyed_block = FALSE, spy_active = FALSE;
274 SIZE_T size;
276 TRACE("%p.\n", mem);
278 if (!mem)
279 return (SIZE_T)-1;
281 if (allocator.spy)
283 EnterCriticalSection(&allocspy_cs);
284 spyed_block = !!mallocspy_is_allocation_spyed(mem);
285 spy_active = TRUE;
286 mem = IMallocSpy_PreGetSize(allocator.spy, mem, spyed_block);
289 size = HeapSize(GetProcessHeap(), 0, mem);
291 if (spy_active)
293 size = IMallocSpy_PostGetSize(allocator.spy, size, spyed_block);
294 LeaveCriticalSection(&allocspy_cs);
297 return size;
300 static INT WINAPI allocator_DidAlloc(IMalloc *iface, void *mem)
302 BOOL spyed_block = FALSE, spy_active = FALSE;
303 int did_alloc;
305 TRACE("%p.\n", mem);
307 if (!mem)
308 return -1;
310 if (allocator.spy)
312 EnterCriticalSection(&allocspy_cs);
313 spyed_block = !!mallocspy_is_allocation_spyed(mem);
314 spy_active = TRUE;
315 mem = IMallocSpy_PreDidAlloc(allocator.spy, mem, spyed_block);
318 did_alloc = HeapValidate(GetProcessHeap(), 0, mem);
320 if (spy_active)
322 did_alloc = IMallocSpy_PostDidAlloc(allocator.spy, mem, spyed_block, did_alloc);
323 LeaveCriticalSection(&allocspy_cs);
326 return did_alloc;
329 static void WINAPI allocator_HeapMinimize(IMalloc *iface)
331 BOOL spy_active = FALSE;
333 TRACE("\n");
335 if (allocator.spy)
337 EnterCriticalSection(&allocspy_cs);
338 spy_active = TRUE;
339 IMallocSpy_PreHeapMinimize(allocator.spy);
342 if (spy_active)
344 IMallocSpy_PostHeapMinimize(allocator.spy);
345 LeaveCriticalSection(&allocspy_cs);
349 static const IMallocVtbl allocator_vtbl =
351 allocator_QueryInterface,
352 allocator_AddRef,
353 allocator_Release,
354 allocator_Alloc,
355 allocator_Realloc,
356 allocator_Free,
357 allocator_GetSize,
358 allocator_DidAlloc,
359 allocator_HeapMinimize
362 /******************************************************************************
363 * CoGetMalloc (combase.@)
365 HRESULT WINAPI CoGetMalloc(DWORD context, IMalloc **imalloc)
367 if (context != MEMCTX_TASK)
369 *imalloc = NULL;
370 return E_INVALIDARG;
373 *imalloc = &allocator.IMalloc_iface;
375 return S_OK;
378 /***********************************************************************
379 * CoTaskMemAlloc (combase.@)
381 void * WINAPI CoTaskMemAlloc(SIZE_T size)
383 return IMalloc_Alloc(&allocator.IMalloc_iface, size);
386 /***********************************************************************
387 * CoTaskMemFree (combase.@)
389 void WINAPI CoTaskMemFree(void *ptr)
391 IMalloc_Free(&allocator.IMalloc_iface, ptr);
394 /***********************************************************************
395 * CoTaskMemRealloc (combase.@)
397 void * WINAPI CoTaskMemRealloc(void *ptr, SIZE_T size)
399 return IMalloc_Realloc(&allocator.IMalloc_iface, ptr, size);
402 /***********************************************************************
403 * CoRegisterMallocSpy (combase.@)
405 HRESULT WINAPI CoRegisterMallocSpy(IMallocSpy *spy)
407 HRESULT hr = E_INVALIDARG;
409 TRACE("%p.\n", spy);
411 if (!spy) return E_INVALIDARG;
413 EnterCriticalSection(&allocspy_cs);
415 if (allocator.spy)
416 hr = CO_E_OBJISREG;
417 else if (SUCCEEDED(IMallocSpy_QueryInterface(spy, &IID_IMallocSpy, (void **)&spy)))
419 allocator.spy = spy;
420 hr = S_OK;
423 LeaveCriticalSection(&allocspy_cs);
425 return hr;
428 /***********************************************************************
429 * CoRevokeMallocSpy (combase.@)
431 HRESULT WINAPI CoRevokeMallocSpy(void)
433 HRESULT hr = S_OK;
435 TRACE("\n");
437 EnterCriticalSection(&allocspy_cs);
439 if (!allocator.spy)
440 hr = CO_E_OBJNOTREG;
441 else if (allocator.spyed_allocations)
443 allocator.spy_release_pending = TRUE;
444 hr = E_ACCESSDENIED;
446 else
448 IMallocSpy_Release(allocator.spy);
449 allocator.spy = NULL;
452 LeaveCriticalSection(&allocspy_cs);
454 return hr;