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