ntdll: Move retrieving the startup info to the Unix library.
[wine.git] / dlls / ole32 / ifs.c
bloba144833c7af3e5a21a9c2b77ba29579bffbe227f
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <ctype.h>
22 #include <stdarg.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <assert.h>
27 #define COBJMACROS
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(olemalloc);
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 static const IMallocVtbl VT_IMalloc32;
50 struct allocator
52 IMalloc IMalloc_iface;
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 DWORD SpyedBlockTableLength;/* size of the table*/
60 static struct allocator Malloc32 = { .IMalloc_iface.lpVtbl = &VT_IMalloc32 };
62 /* with a spy active all calls from pre to post methods are threadsafe */
63 static CRITICAL_SECTION IMalloc32_SpyCS;
64 static CRITICAL_SECTION_DEBUG critsect_debug =
66 0, 0, &IMalloc32_SpyCS,
67 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
68 0, 0, { (DWORD_PTR)(__FILE__ ": IMalloc32_SpyCS") }
70 static CRITICAL_SECTION IMalloc32_SpyCS = { &critsect_debug, -1, 0, 0, 0, 0 };
72 /* resize the old table */
73 static BOOL SetSpyedBlockTableLength ( DWORD NewLength )
75 LPVOID *NewSpyedBlocks;
77 if (!Malloc32.SpyedBlocks) NewSpyedBlocks = LocalAlloc(LMEM_ZEROINIT, NewLength * sizeof(PVOID));
78 else NewSpyedBlocks = LocalReAlloc(Malloc32.SpyedBlocks, NewLength * sizeof(PVOID), LMEM_ZEROINIT | LMEM_MOVEABLE);
79 if (NewSpyedBlocks) {
80 Malloc32.SpyedBlocks = NewSpyedBlocks;
81 Malloc32.SpyedBlockTableLength = NewLength;
84 return NewSpyedBlocks != NULL;
87 /* add a location to the table */
88 static BOOL AddMemoryLocation(LPVOID * pMem)
90 LPVOID * Current;
92 /* allocate the table if not already allocated */
93 if (!Malloc32.SpyedBlockTableLength && !SetSpyedBlockTableLength(0x1000))
94 return FALSE;
96 /* find a free location */
97 Current = Malloc32.SpyedBlocks;
98 while (*Current) {
99 Current++;
100 if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) {
101 /* no more space in table, grow it */
102 DWORD old_length = Malloc32.SpyedBlockTableLength;
103 if (!SetSpyedBlockTableLength( Malloc32.SpyedBlockTableLength + 0x1000))
104 return FALSE;
105 Current = Malloc32.SpyedBlocks + old_length;
109 /* put the location in our table */
110 *Current = pMem;
111 Malloc32.SpyedAllocationsLeft++;
112 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
113 return TRUE;
116 static void** mallocspy_is_allocation_spyed(const void *mem)
118 void **current = Malloc32.SpyedBlocks;
120 while (*current != mem)
122 current++;
123 if (current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength)
124 return NULL;
127 return current;
130 static BOOL mallocspy_remove_spyed_memory(const void *mem)
132 void **current;
134 if (!Malloc32.SpyedBlockTableLength)
135 return FALSE;
137 if (!(current = mallocspy_is_allocation_spyed(mem)))
138 return FALSE;
140 Malloc32.SpyedAllocationsLeft--;
141 *current = NULL;
142 return TRUE;
145 /******************************************************************************
146 * IMalloc32_QueryInterface [VTABLE]
148 static HRESULT WINAPI IMalloc_fnQueryInterface(IMalloc *iface, REFIID refiid, void **obj)
150 TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
152 if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMalloc,refiid)) {
153 *obj = &Malloc32;
154 return S_OK;
156 return E_NOINTERFACE;
159 /******************************************************************************
160 * IMalloc32_AddRefRelease [VTABLE]
162 static ULONG WINAPI IMalloc_fnAddRefRelease(IMalloc *iface)
164 return 1;
167 /******************************************************************************
168 * IMalloc32_Alloc [VTABLE]
170 static void * WINAPI IMalloc_fnAlloc(IMalloc *iface, SIZE_T cb)
172 void *addr;
174 TRACE("(%ld)\n",cb);
176 if(Malloc32.pSpy) {
177 SIZE_T preAllocResult;
179 EnterCriticalSection(&IMalloc32_SpyCS);
180 preAllocResult = IMallocSpy_PreAlloc(Malloc32.pSpy, cb);
181 if ((cb != 0) && (preAllocResult == 0)) {
182 /* PreAlloc can force Alloc to fail, but not if cb == 0 */
183 TRACE("returning null\n");
184 LeaveCriticalSection(&IMalloc32_SpyCS);
185 return NULL;
189 addr = HeapAlloc(GetProcessHeap(),0,cb);
191 if(Malloc32.pSpy) {
192 addr = IMallocSpy_PostAlloc(Malloc32.pSpy, addr);
193 if (addr) AddMemoryLocation(addr);
194 LeaveCriticalSection(&IMalloc32_SpyCS);
197 TRACE("--(%p)\n",addr);
198 return addr;
201 /******************************************************************************
202 * IMalloc32_Realloc [VTABLE]
204 static void * WINAPI IMalloc_fnRealloc(IMalloc *iface, void *pv, SIZE_T cb)
206 void *pNewMemory;
208 TRACE("(%p,%ld)\n",pv,cb);
210 if(Malloc32.pSpy) {
211 void *pRealMemory;
212 BOOL fSpyed;
214 EnterCriticalSection(&IMalloc32_SpyCS);
215 fSpyed = mallocspy_remove_spyed_memory(pv);
216 cb = IMallocSpy_PreRealloc(Malloc32.pSpy, pv, cb, &pRealMemory, fSpyed);
218 /* check if can release the spy */
219 if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
220 IMallocSpy_Release(Malloc32.pSpy);
221 Malloc32.SpyReleasePending = FALSE;
222 Malloc32.pSpy = NULL;
223 LeaveCriticalSection(&IMalloc32_SpyCS);
226 if (0==cb) {
227 /* PreRealloc can force Realloc to fail */
228 if (Malloc32.pSpy)
229 LeaveCriticalSection(&IMalloc32_SpyCS);
230 return NULL;
233 pv = pRealMemory;
236 if (!pv) pNewMemory = HeapAlloc(GetProcessHeap(),0,cb);
237 else if (cb) pNewMemory = HeapReAlloc(GetProcessHeap(),0,pv,cb);
238 else {
239 HeapFree(GetProcessHeap(),0,pv);
240 pNewMemory = NULL;
243 if(Malloc32.pSpy) {
244 pNewMemory = IMallocSpy_PostRealloc(Malloc32.pSpy, pNewMemory, TRUE);
245 if (pNewMemory) AddMemoryLocation(pNewMemory);
246 LeaveCriticalSection(&IMalloc32_SpyCS);
249 TRACE("--(%p)\n",pNewMemory);
250 return pNewMemory;
253 /******************************************************************************
254 * IMalloc32_Free [VTABLE]
256 static void WINAPI IMalloc_fnFree(IMalloc *iface, void *mem)
258 BOOL spyed_block = FALSE, spy_active = FALSE;
260 TRACE("(%p)\n", mem);
262 if (!mem)
263 return;
265 if (Malloc32.pSpy)
267 EnterCriticalSection(&IMalloc32_SpyCS);
268 spyed_block = mallocspy_remove_spyed_memory(mem);
269 spy_active = TRUE;
270 mem = IMallocSpy_PreFree(Malloc32.pSpy, mem, spyed_block);
273 HeapFree(GetProcessHeap(), 0, mem);
275 if (spy_active)
277 IMallocSpy_PostFree(Malloc32.pSpy, spyed_block);
279 /* check if can release the spy */
280 if (Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft)
282 IMallocSpy_Release(Malloc32.pSpy);
283 Malloc32.SpyReleasePending = FALSE;
284 Malloc32.pSpy = NULL;
287 LeaveCriticalSection(&IMalloc32_SpyCS);
291 /******************************************************************************
292 * IMalloc32_GetSize [VTABLE]
294 * NOTES
295 * FIXME returns:
296 * win95: size allocated (4 byte boundaries)
297 * win2k: size originally requested !!! (allocated on 8 byte boundaries)
299 static SIZE_T WINAPI IMalloc_fnGetSize(IMalloc *iface, void *mem)
301 BOOL spyed_block = FALSE, spy_active = FALSE;
302 SIZE_T size;
304 TRACE("(%p)\n", mem);
306 if (!mem)
307 return (SIZE_T)-1;
309 if (Malloc32.pSpy)
311 EnterCriticalSection(&IMalloc32_SpyCS);
312 spyed_block = !!mallocspy_is_allocation_spyed(mem);
313 spy_active = TRUE;
314 mem = IMallocSpy_PreGetSize(Malloc32.pSpy, mem, spyed_block);
317 size = HeapSize(GetProcessHeap(), 0, mem);
319 if (spy_active)
321 size = IMallocSpy_PostGetSize(Malloc32.pSpy, size, spyed_block);
322 LeaveCriticalSection(&IMalloc32_SpyCS);
325 return size;
328 /******************************************************************************
329 * IMalloc32_DidAlloc [VTABLE]
331 static INT WINAPI IMalloc_fnDidAlloc(IMalloc *iface, void *mem)
333 BOOL spyed_block = FALSE, spy_active = FALSE;
334 int did_alloc;
336 TRACE("(%p)\n", mem);
338 if (!mem)
339 return -1;
341 if (Malloc32.pSpy)
343 EnterCriticalSection(&IMalloc32_SpyCS);
344 spyed_block = !!mallocspy_is_allocation_spyed(mem);
345 spy_active = TRUE;
346 mem = IMallocSpy_PreDidAlloc(Malloc32.pSpy, mem, spyed_block);
349 did_alloc = HeapValidate(GetProcessHeap(), 0, mem);
351 if (spy_active)
353 did_alloc = IMallocSpy_PostDidAlloc(Malloc32.pSpy, mem, spyed_block, did_alloc);
354 LeaveCriticalSection(&IMalloc32_SpyCS);
357 return did_alloc;
360 /******************************************************************************
361 * IMalloc32_HeapMinimize [VTABLE]
363 static void WINAPI IMalloc_fnHeapMinimize(IMalloc *iface)
365 BOOL spy_active = FALSE;
367 TRACE("()\n");
369 if (Malloc32.pSpy)
371 EnterCriticalSection(&IMalloc32_SpyCS);
372 spy_active = TRUE;
373 IMallocSpy_PreHeapMinimize(Malloc32.pSpy);
376 if (spy_active)
378 IMallocSpy_PostHeapMinimize(Malloc32.pSpy);
379 LeaveCriticalSection(&IMalloc32_SpyCS);
383 static const IMallocVtbl VT_IMalloc32 =
385 IMalloc_fnQueryInterface,
386 IMalloc_fnAddRefRelease,
387 IMalloc_fnAddRefRelease,
388 IMalloc_fnAlloc,
389 IMalloc_fnRealloc,
390 IMalloc_fnFree,
391 IMalloc_fnGetSize,
392 IMalloc_fnDidAlloc,
393 IMalloc_fnHeapMinimize
396 /******************************************************************************
397 * CoGetMalloc [OLE32.@]
399 * Retrieves the current IMalloc interface for the process.
401 * PARAMS
402 * context [I] Should always be MEMCTX_TASK.
403 * imalloc [O] Address where memory allocator object will be stored.
405 * RETURNS
406 * Success: S_OK.
407 * Failure: HRESULT code.
409 HRESULT WINAPI CoGetMalloc(DWORD context, IMalloc **imalloc)
411 if (context != MEMCTX_TASK) {
412 *imalloc = NULL;
413 return E_INVALIDARG;
416 *imalloc = &Malloc32.IMalloc_iface;
417 return S_OK;
420 /***********************************************************************
421 * CoTaskMemAlloc [OLE32.@]
423 * Allocates memory using the current process memory allocator.
425 * PARAMS
426 * size [I] Size of the memory block to allocate.
428 * RETURNS
429 * Success: Pointer to newly allocated memory block.
430 * Failure: NULL.
432 LPVOID WINAPI CoTaskMemAlloc(SIZE_T size)
434 return IMalloc_Alloc(&Malloc32.IMalloc_iface,size);
437 /***********************************************************************
438 * CoTaskMemFree [OLE32.@]
440 * Frees memory allocated from the current process memory allocator.
442 * PARAMS
443 * ptr [I] Memory block to free.
445 * RETURNS
446 * Nothing.
448 VOID WINAPI CoTaskMemFree(LPVOID ptr)
450 IMalloc_Free(&Malloc32.IMalloc_iface, ptr);
453 /***********************************************************************
454 * CoTaskMemRealloc [OLE32.@]
456 * Allocates memory using the current process memory allocator.
458 * PARAMS
459 * pvOld [I] Pointer to old memory block.
460 * size [I] Size of the new memory block.
462 * RETURNS
463 * Success: Pointer to newly allocated memory block.
464 * Failure: NULL.
466 LPVOID WINAPI CoTaskMemRealloc(LPVOID pvOld, SIZE_T size)
468 return IMalloc_Realloc(&Malloc32.IMalloc_iface, pvOld, size);
471 /***********************************************************************
472 * CoRegisterMallocSpy [OLE32.@]
474 * Registers an object that receives notifications on memory allocations and
475 * frees.
477 * PARAMS
478 * pMallocSpy [I] New spy object.
480 * RETURNS
481 * Success: S_OK.
482 * Failure: HRESULT code.
484 * NOTES
485 * if a mallocspy is already registered, we can't do it again since
486 * only the spy knows, how to free a memory block
488 HRESULT WINAPI CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy)
490 IMallocSpy* pSpy;
491 HRESULT hres = E_INVALIDARG;
493 TRACE("%p\n", pMallocSpy);
495 if(!pMallocSpy) return E_INVALIDARG;
497 EnterCriticalSection(&IMalloc32_SpyCS);
499 if (Malloc32.pSpy)
500 hres = CO_E_OBJISREG;
501 else if (SUCCEEDED(IMallocSpy_QueryInterface(pMallocSpy, &IID_IMallocSpy, (void**)&pSpy))) {
502 Malloc32.pSpy = pSpy;
503 hres = S_OK;
506 LeaveCriticalSection(&IMalloc32_SpyCS);
508 return hres;
511 /***********************************************************************
512 * CoRevokeMallocSpy [OLE32.@]
514 * Revokes a previously registered object that receives notifications on memory
515 * allocations and frees.
517 * PARAMS
518 * pMallocSpy [I] New spy object.
520 * RETURNS
521 * Success: S_OK.
522 * Failure: HRESULT code.
524 * NOTES
525 * we can't revoke a malloc spy as long as memory blocks allocated with
526 * the spy are active since only the spy knows how to free them
528 HRESULT WINAPI CoRevokeMallocSpy(void)
530 HRESULT hres = S_OK;
531 TRACE("\n");
533 EnterCriticalSection(&IMalloc32_SpyCS);
535 if (!Malloc32.pSpy)
536 hres = CO_E_OBJNOTREG;
537 else if (Malloc32.SpyedAllocationsLeft) {
538 TRACE("SpyReleasePending with %u allocations left\n", Malloc32.SpyedAllocationsLeft);
539 Malloc32.SpyReleasePending = TRUE;
540 hres = E_ACCESSDENIED;
541 } else {
542 IMallocSpy_Release(Malloc32.pSpy);
543 Malloc32.pSpy = NULL;
545 LeaveCriticalSection(&IMalloc32_SpyCS);
547 return hres;
550 /******************************************************************************
551 * IsValidInterface [OLE32.@]
553 * Determines whether a pointer is a valid interface.
555 * PARAMS
556 * punk [I] Interface to be tested.
558 * RETURNS
559 * TRUE, if the passed pointer is a valid interface, or FALSE otherwise.
561 BOOL WINAPI IsValidInterface(LPUNKNOWN punk)
563 return !(
564 IsBadReadPtr(punk,4) ||
565 IsBadReadPtr(punk->lpVtbl,4) ||
566 IsBadReadPtr(punk->lpVtbl->QueryInterface,9) ||
567 IsBadCodePtr((FARPROC)punk->lpVtbl->QueryInterface)