207dd8640aebe7d36c48bc0891ddeaa5b95c1ebb
[reactos.git] / reactos / dll / win32 / 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include "precomp.h"
22
23 WINE_DEFAULT_DEBUG_CHANNEL(olemalloc);
24
25 /******************************************************************************
26 * IMalloc32 implementation
27 *
28 * NOTES
29 * For supporting CoRegisterMallocSpy the IMalloc implementation must know if
30 * a given memory block was allocated with a spy active.
31 *
32 *****************************************************************************/
33 /* set the vtable later */
34 static const IMallocVtbl VT_IMalloc32;
35
36 typedef struct {
37 IMalloc IMalloc_iface;
38 DWORD dummy; /* nothing, we are static */
39 IMallocSpy * pSpy; /* the spy when active */
40 DWORD SpyedAllocationsLeft; /* number of spyed allocations left */
41 BOOL SpyReleasePending; /* CoRevokeMallocSpy called with spyed allocations left*/
42 LPVOID * SpyedBlocks; /* root of the table */
43 DWORD SpyedBlockTableLength;/* size of the table*/
44 } _Malloc32;
45
46 /* this is the static object instance */
47 static _Malloc32 Malloc32 = {{&VT_IMalloc32}, 0, NULL, 0, 0, NULL, 0};
48
49 /* with a spy active all calls from pre to post methods are threadsave */
50 static CRITICAL_SECTION IMalloc32_SpyCS;
51 static CRITICAL_SECTION_DEBUG critsect_debug =
52 {
53 0, 0, &IMalloc32_SpyCS,
54 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
55 0, 0, { (DWORD_PTR)(__FILE__ ": IMalloc32_SpyCS") }
56 };
57 static CRITICAL_SECTION IMalloc32_SpyCS = { &critsect_debug, -1, 0, 0, 0, 0 };
58
59 /* resize the old table */
60 static BOOL SetSpyedBlockTableLength ( DWORD NewLength )
61 {
62 LPVOID *NewSpyedBlocks;
63
64 if (!Malloc32.SpyedBlocks) NewSpyedBlocks = LocalAlloc(LMEM_ZEROINIT, NewLength * sizeof(PVOID));
65 else NewSpyedBlocks = LocalReAlloc(Malloc32.SpyedBlocks, NewLength * sizeof(PVOID), LMEM_ZEROINIT | LMEM_MOVEABLE);
66 if (NewSpyedBlocks) {
67 Malloc32.SpyedBlocks = NewSpyedBlocks;
68 Malloc32.SpyedBlockTableLength = NewLength;
69 }
70
71 return NewSpyedBlocks != NULL;
72 }
73
74 /* add a location to the table */
75 static BOOL AddMemoryLocation(LPVOID * pMem)
76 {
77 LPVOID * Current;
78
79 /* allocate the table if not already allocated */
80 if (!Malloc32.SpyedBlockTableLength && !SetSpyedBlockTableLength(0x1000))
81 return FALSE;
82
83 /* find a free location */
84 Current = Malloc32.SpyedBlocks;
85 while (*Current) {
86 Current++;
87 if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) {
88 /* no more space in table, grow it */
89 DWORD old_length = Malloc32.SpyedBlockTableLength;
90 if (!SetSpyedBlockTableLength( Malloc32.SpyedBlockTableLength + 0x1000))
91 return FALSE;
92 Current = Malloc32.SpyedBlocks + old_length;
93 }
94 };
95
96 /* put the location in our table */
97 *Current = pMem;
98 Malloc32.SpyedAllocationsLeft++;
99 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
100 return TRUE;
101 }
102
103 static BOOL RemoveMemoryLocation(LPCVOID pMem)
104 {
105 LPVOID * Current;
106
107 /* allocate the table if not already allocated */
108 if (!Malloc32.SpyedBlockTableLength && !SetSpyedBlockTableLength(0x1000))
109 return FALSE;
110
111 Current = Malloc32.SpyedBlocks;
112
113 /* find the location */
114 while (*Current != pMem) {
115 Current++;
116 if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength)
117 return FALSE; /* not found */
118 }
119
120 /* location found */
121 Malloc32.SpyedAllocationsLeft--;
122 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
123 *Current = NULL;
124 return TRUE;
125 }
126
127 /******************************************************************************
128 * IMalloc32_QueryInterface [VTABLE]
129 */
130 static HRESULT WINAPI IMalloc_fnQueryInterface(LPMALLOC iface,REFIID refiid,LPVOID *obj) {
131
132 TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
133
134 if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMalloc,refiid)) {
135 *obj = &Malloc32;
136 return S_OK;
137 }
138 return E_NOINTERFACE;
139 }
140
141 /******************************************************************************
142 * IMalloc32_AddRefRelease [VTABLE]
143 */
144 static ULONG WINAPI IMalloc_fnAddRefRelease (LPMALLOC iface) {
145 return 1;
146 }
147
148 /******************************************************************************
149 * IMalloc32_Alloc [VTABLE]
150 */
151 static LPVOID WINAPI IMalloc_fnAlloc(LPMALLOC iface, SIZE_T cb) {
152
153 LPVOID addr;
154
155 TRACE("(%d)\n",cb);
156
157 if(Malloc32.pSpy) {
158 DWORD preAllocResult;
159
160 EnterCriticalSection(&IMalloc32_SpyCS);
161 preAllocResult = IMallocSpy_PreAlloc(Malloc32.pSpy, cb);
162 if ((cb != 0) && (preAllocResult == 0)) {
163 /* PreAlloc can force Alloc to fail, but not if cb == 0 */
164 TRACE("returning null\n");
165 LeaveCriticalSection(&IMalloc32_SpyCS);
166 return NULL;
167 }
168 }
169
170 addr = HeapAlloc(GetProcessHeap(),0,cb);
171
172 if(Malloc32.pSpy) {
173 addr = IMallocSpy_PostAlloc(Malloc32.pSpy, addr);
174 if (addr) AddMemoryLocation(addr);
175 LeaveCriticalSection(&IMalloc32_SpyCS);
176 }
177
178 TRACE("--(%p)\n",addr);
179 return addr;
180 }
181
182 /******************************************************************************
183 * IMalloc32_Realloc [VTABLE]
184 */
185 static LPVOID WINAPI IMalloc_fnRealloc(LPMALLOC iface,LPVOID pv,SIZE_T cb) {
186
187 LPVOID pNewMemory;
188
189 TRACE("(%p,%d)\n",pv,cb);
190
191 if(Malloc32.pSpy) {
192 LPVOID pRealMemory;
193 BOOL fSpyed;
194
195 EnterCriticalSection(&IMalloc32_SpyCS);
196 fSpyed = RemoveMemoryLocation(pv);
197 cb = IMallocSpy_PreRealloc(Malloc32.pSpy, pv, cb, &pRealMemory, fSpyed);
198
199 /* check if can release the spy */
200 if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
201 IMallocSpy_Release(Malloc32.pSpy);
202 Malloc32.SpyReleasePending = FALSE;
203 Malloc32.pSpy = NULL;
204 LeaveCriticalSection(&IMalloc32_SpyCS);
205 }
206
207 if (0==cb) {
208 /* PreRealloc can force Realloc to fail */
209 if (Malloc32.pSpy)
210 LeaveCriticalSection(&IMalloc32_SpyCS);
211 return NULL;
212 }
213
214 pv = pRealMemory;
215 }
216
217 if (!pv) pNewMemory = HeapAlloc(GetProcessHeap(),0,cb);
218 else if (cb) pNewMemory = HeapReAlloc(GetProcessHeap(),0,pv,cb);
219 else {
220 HeapFree(GetProcessHeap(),0,pv);
221 pNewMemory = NULL;
222 }
223
224 if(Malloc32.pSpy) {
225 pNewMemory = IMallocSpy_PostRealloc(Malloc32.pSpy, pNewMemory, TRUE);
226 if (pNewMemory) AddMemoryLocation(pNewMemory);
227 LeaveCriticalSection(&IMalloc32_SpyCS);
228 }
229
230 TRACE("--(%p)\n",pNewMemory);
231 return pNewMemory;
232 }
233
234 /******************************************************************************
235 * IMalloc32_Free [VTABLE]
236 */
237 static VOID WINAPI IMalloc_fnFree(LPMALLOC iface,LPVOID pv) {
238
239 BOOL fSpyed = FALSE;
240
241 TRACE("(%p)\n",pv);
242
243 if(Malloc32.pSpy) {
244 EnterCriticalSection(&IMalloc32_SpyCS);
245 fSpyed = RemoveMemoryLocation(pv);
246 pv = IMallocSpy_PreFree(Malloc32.pSpy, pv, fSpyed);
247 }
248
249 HeapFree(GetProcessHeap(),0,pv);
250
251 if(Malloc32.pSpy) {
252 IMallocSpy_PostFree(Malloc32.pSpy, fSpyed);
253
254 /* check if can release the spy */
255 if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
256 IMallocSpy_Release(Malloc32.pSpy);
257 Malloc32.SpyReleasePending = FALSE;
258 Malloc32.pSpy = NULL;
259 }
260
261 LeaveCriticalSection(&IMalloc32_SpyCS);
262 }
263 }
264
265 /******************************************************************************
266 * IMalloc32_GetSize [VTABLE]
267 *
268 * NOTES
269 * FIXME returns:
270 * win95: size allocated (4 byte boundarys)
271 * win2k: size originally requested !!! (allocated on 8 byte boundarys)
272 */
273 static SIZE_T WINAPI IMalloc_fnGetSize(LPMALLOC iface,LPVOID pv) {
274
275 DWORD cb;
276 BOOL fSpyed = FALSE;
277
278 TRACE("(%p)\n",pv);
279
280 if(Malloc32.pSpy) {
281 EnterCriticalSection(&IMalloc32_SpyCS);
282 pv = IMallocSpy_PreGetSize(Malloc32.pSpy, pv, fSpyed);
283 }
284
285 cb = HeapSize(GetProcessHeap(),0,pv);
286
287 if(Malloc32.pSpy) {
288 cb = IMallocSpy_PostGetSize(Malloc32.pSpy, cb, fSpyed);
289 LeaveCriticalSection(&IMalloc32_SpyCS);
290 }
291
292 return cb;
293 }
294
295 /******************************************************************************
296 * IMalloc32_DidAlloc [VTABLE]
297 */
298 static INT WINAPI IMalloc_fnDidAlloc(LPMALLOC iface,LPVOID pv) {
299
300 BOOL fSpyed = FALSE;
301 int didAlloc;
302
303 TRACE("(%p)\n",pv);
304
305 if(Malloc32.pSpy) {
306 EnterCriticalSection(&IMalloc32_SpyCS);
307 pv = IMallocSpy_PreDidAlloc(Malloc32.pSpy, pv, fSpyed);
308 }
309
310 didAlloc = -1;
311
312 if(Malloc32.pSpy) {
313 didAlloc = IMallocSpy_PostDidAlloc(Malloc32.pSpy, pv, fSpyed, didAlloc);
314 LeaveCriticalSection(&IMalloc32_SpyCS);
315 }
316 return didAlloc;
317 }
318
319 /******************************************************************************
320 * IMalloc32_HeapMinimize [VTABLE]
321 */
322 static VOID WINAPI IMalloc_fnHeapMinimize(LPMALLOC iface) {
323 TRACE("()\n");
324
325 if(Malloc32.pSpy) {
326 EnterCriticalSection(&IMalloc32_SpyCS);
327 IMallocSpy_PreHeapMinimize(Malloc32.pSpy);
328 }
329
330 if(Malloc32.pSpy) {
331 IMallocSpy_PostHeapMinimize(Malloc32.pSpy);
332 LeaveCriticalSection(&IMalloc32_SpyCS);
333 }
334 }
335
336 static const IMallocVtbl VT_IMalloc32 =
337 {
338 IMalloc_fnQueryInterface,
339 IMalloc_fnAddRefRelease,
340 IMalloc_fnAddRefRelease,
341 IMalloc_fnAlloc,
342 IMalloc_fnRealloc,
343 IMalloc_fnFree,
344 IMalloc_fnGetSize,
345 IMalloc_fnDidAlloc,
346 IMalloc_fnHeapMinimize
347 };
348
349 /******************************************************************************
350 * CoGetMalloc [OLE32.@]
351 *
352 * Retrieves the current IMalloc interface for the process.
353 *
354 * PARAMS
355 * dwMemContext [I]
356 * lpMalloc [O] Address where memory allocator object will be stored.
357 *
358 * RETURNS
359 * Success: S_OK.
360 * Failure: HRESULT code.
361 */
362 HRESULT WINAPI CoGetMalloc(DWORD dwMemContext, LPMALLOC *lpMalloc)
363 {
364 *lpMalloc = &Malloc32.IMalloc_iface;
365 return S_OK;
366 }
367
368 /***********************************************************************
369 * CoTaskMemAlloc [OLE32.@]
370 *
371 * Allocates memory using the current process memory allocator.
372 *
373 * PARAMS
374 * size [I] Size of the memory block to allocate.
375 *
376 * RETURNS
377 * Success: Pointer to newly allocated memory block.
378 * Failure: NULL.
379 */
380 LPVOID WINAPI CoTaskMemAlloc(ULONG size)
381 {
382 return IMalloc_Alloc(&Malloc32.IMalloc_iface,size);
383 }
384
385 /***********************************************************************
386 * CoTaskMemFree [OLE32.@]
387 *
388 * Frees memory allocated from the current process memory allocator.
389 *
390 * PARAMS
391 * ptr [I] Memory block to free.
392 *
393 * RETURNS
394 * Nothing.
395 */
396 VOID WINAPI CoTaskMemFree(LPVOID ptr)
397 {
398 IMalloc_Free(&Malloc32.IMalloc_iface, ptr);
399 }
400
401 /***********************************************************************
402 * CoTaskMemRealloc [OLE32.@]
403 *
404 * Allocates memory using the current process memory allocator.
405 *
406 * PARAMS
407 * pvOld [I] Pointer to old memory block.
408 * size [I] Size of the new memory block.
409 *
410 * RETURNS
411 * Success: Pointer to newly allocated memory block.
412 * Failure: NULL.
413 */
414 LPVOID WINAPI CoTaskMemRealloc(LPVOID pvOld, ULONG size)
415 {
416 return IMalloc_Realloc(&Malloc32.IMalloc_iface, pvOld, size);
417 }
418
419 /***********************************************************************
420 * CoRegisterMallocSpy [OLE32.@]
421 *
422 * Registers an object that receives notifications on memory allocations and
423 * frees.
424 *
425 * PARAMS
426 * pMallocSpy [I] New spy object.
427 *
428 * RETURNS
429 * Success: S_OK.
430 * Failure: HRESULT code.
431 *
432 * NOTES
433 * if a mallocspy is already registered, we can't do it again since
434 * only the spy knows, how to free a memory block
435 */
436 HRESULT WINAPI CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy)
437 {
438 IMallocSpy* pSpy;
439 HRESULT hres = E_INVALIDARG;
440
441 TRACE("\n");
442
443 if(Malloc32.pSpy) return CO_E_OBJISREG;
444
445 EnterCriticalSection(&IMalloc32_SpyCS);
446
447 if (SUCCEEDED(IMallocSpy_QueryInterface(pMallocSpy, &IID_IMallocSpy, (void**)&pSpy))) {
448 Malloc32.pSpy = pSpy;
449 hres = S_OK;
450 }
451
452 LeaveCriticalSection(&IMalloc32_SpyCS);
453
454 return hres;
455 }
456
457 /***********************************************************************
458 * CoRevokeMallocSpy [OLE32.@]
459 *
460 * Revokes a previously registered object that receives notifications on memory
461 * allocations and frees.
462 *
463 * PARAMS
464 * pMallocSpy [I] New spy object.
465 *
466 * RETURNS
467 * Success: S_OK.
468 * Failure: HRESULT code.
469 *
470 * NOTES
471 * we can't revoke a malloc spy as long as memory blocks allocated with
472 * the spy are active since only the spy knows how to free them
473 */
474 HRESULT WINAPI CoRevokeMallocSpy(void)
475 {
476 HRESULT hres = S_OK;
477 TRACE("\n");
478
479 EnterCriticalSection(&IMalloc32_SpyCS);
480
481 if (Malloc32.SpyedAllocationsLeft) {
482 TRACE("SpyReleasePending with %u allocations left\n", Malloc32.SpyedAllocationsLeft);
483 Malloc32.SpyReleasePending = TRUE;
484 hres = E_ACCESSDENIED;
485 } else {
486 IMallocSpy_Release(Malloc32.pSpy);
487 Malloc32.pSpy = NULL;
488 }
489 LeaveCriticalSection(&IMalloc32_SpyCS);
490
491 return hres;
492 }
493
494 /******************************************************************************
495 * IsValidInterface [OLE32.@]
496 *
497 * Determines whether a pointer is a valid interface.
498 *
499 * PARAMS
500 * punk [I] Interface to be tested.
501 *
502 * RETURNS
503 * TRUE, if the passed pointer is a valid interface, or FALSE otherwise.
504 */
505 BOOL WINAPI IsValidInterface(LPUNKNOWN punk)
506 {
507 return !(
508 IsBadReadPtr(punk,4) ||
509 IsBadReadPtr(punk->lpVtbl,4) ||
510 IsBadReadPtr(punk->lpVtbl->QueryInterface,9) ||
511 IsBadCodePtr((FARPROC)punk->lpVtbl->QueryInterface)
512 );
513 }