Get rid of W->A calls.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <ctype.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
27
28 #include "ole2.h"
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winerror.h"
32
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(ole);
36
37 /******************************************************************************
38  *      IMalloc32 implementation
39  *
40  * NOTES
41  *  For supporting CoRegisterMallocSpy the IMalloc implementation must know if
42  *  a given memory block was allocated with a spy active.
43  *
44  *****************************************************************************/
45 /* set the vtable later */
46 extern ICOM_VTABLE(IMalloc) VT_IMalloc32;
47
48 typedef struct {
49         ICOM_VFIELD(IMalloc);
50         DWORD dummy;                /* nothing, we are static */
51         IMallocSpy * pSpy;          /* the spy when active */
52         DWORD SpyedAllocationsLeft; /* number of spyed allocations left */
53         BOOL SpyReleasePending;     /* CoRevokeMallocSpy called with spyed allocations left*/
54         LPVOID * SpyedBlocks;       /* root of the table */
55         int SpyedBlockTableLength;  /* size of the table*/
56 } _Malloc32;
57
58 /* this is the static object instance */
59 _Malloc32 Malloc32 = {&VT_IMalloc32, 0, NULL, 0, 0, NULL, 0};
60
61 /* with a spy active all calls from pre to post methods are threadsave */
62 static CRITICAL_SECTION IMalloc32_SpyCS = CRITICAL_SECTION_INIT("IMalloc32_SpyCS");
63
64 /* resize the old table */
65 static int SetSpyedBlockTableLength ( int NewLength )
66 {
67         Malloc32.SpyedBlocks = (LPVOID*)LocalReAlloc((HLOCAL)Malloc32.SpyedBlocks, NewLength, GMEM_ZEROINIT);
68         Malloc32.SpyedBlockTableLength = NewLength;
69         return Malloc32.SpyedBlocks ? 1 : 0;
70 }
71
72 /* add a location to the table */
73 static int AddMemoryLocation(LPVOID * pMem)
74 {
75         LPVOID * Current;
76
77         /* allocate the table if not already allocated */
78         if (!Malloc32.SpyedBlockTableLength) {
79             if (!SetSpyedBlockTableLength(0x1000)) return 0;
80         }
81
82         /* find a free location */
83         Current = Malloc32.SpyedBlocks;
84         while (*Current) {
85             Current++;
86             if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) {
87                 /* no more space in table, grow it */
88                 if (!SetSpyedBlockTableLength( Malloc32.SpyedBlockTableLength + 0x1000 )) return 0;
89             }
90         };
91
92         /* put the location in our table */
93         *Current = pMem;
94         Malloc32.SpyedAllocationsLeft++;
95         /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
96         return 1;
97 }
98
99 static int RemoveMemoryLocation(LPVOID * pMem)
100 {
101         LPVOID * Current = Malloc32.SpyedBlocks;
102
103         /* find the location */
104         while (*Current != pMem) {
105             Current++;
106             if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength)  return 0;      /* not found  */
107         }
108
109         /* location found */
110         Malloc32.SpyedAllocationsLeft--;
111         /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
112         *Current = NULL;
113         return 1;
114 }
115
116 /******************************************************************************
117  *      IMalloc32_QueryInterface        [VTABLE]
118  */
119 static HRESULT WINAPI IMalloc_fnQueryInterface(LPMALLOC iface,REFIID refiid,LPVOID *obj) {
120
121         TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
122
123         if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMalloc,refiid)) {
124                 *obj = (LPMALLOC)&Malloc32;
125                 return S_OK;
126         }
127         return E_NOINTERFACE;
128 }
129
130 /******************************************************************************
131  *      IMalloc32_AddRefRelease         [VTABLE]
132  */
133 static ULONG WINAPI IMalloc_fnAddRefRelease (LPMALLOC iface) {
134         return 1;
135 }
136
137 /******************************************************************************
138  *      IMalloc32_Alloc                 [VTABLE]
139  */
140 static LPVOID WINAPI IMalloc_fnAlloc(LPMALLOC iface, DWORD cb) {
141
142         LPVOID addr;
143
144         TRACE("(%ld)\n",cb);
145
146         if(Malloc32.pSpy) {
147             EnterCriticalSection(&IMalloc32_SpyCS);
148             cb = IMallocSpy_PreAlloc(Malloc32.pSpy, cb);
149             if (0==cb) {
150                 /* PreAlloc can force Alloc to fail */
151                 LeaveCriticalSection(&IMalloc32_SpyCS);
152                 return NULL;
153             }
154         }
155
156
157         addr = HeapAlloc(GetProcessHeap(),0,cb);
158
159         if(Malloc32.pSpy) {
160             addr = IMallocSpy_PostAlloc(Malloc32.pSpy, addr);
161             if (addr) AddMemoryLocation(addr);
162             LeaveCriticalSection(&IMalloc32_SpyCS);
163         }
164
165         TRACE("--(%p)\n",addr);
166         return addr;
167 }
168
169 /******************************************************************************
170  * IMalloc32_Realloc [VTABLE]
171  */
172 static LPVOID WINAPI IMalloc_fnRealloc(LPMALLOC iface,LPVOID pv,DWORD cb) {
173
174         LPVOID pNewMemory;
175
176         TRACE("(%p,%ld)\n",pv,cb);
177
178         if(Malloc32.pSpy) {
179             LPVOID pRealMemory;
180             BOOL fSpyed;
181
182             EnterCriticalSection(&IMalloc32_SpyCS);
183             fSpyed = RemoveMemoryLocation(pv);
184             cb = IMallocSpy_PreRealloc(Malloc32.pSpy, pv, cb, &pRealMemory, fSpyed);
185
186             /* check if can release the spy */
187             if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
188                 IMallocSpy_Release(Malloc32.pSpy);
189                 Malloc32.SpyReleasePending = FALSE;
190                 Malloc32.pSpy = NULL;
191             }
192
193             if (0==cb) {
194                 /* PreRealloc can force Realloc to fail */
195                 LeaveCriticalSection(&IMalloc32_SpyCS);
196                 return NULL;
197             }
198             pv = pRealMemory;
199         }
200
201         pNewMemory = HeapReAlloc(GetProcessHeap(),0,pv,cb);
202
203         if(Malloc32.pSpy) {
204             pNewMemory = IMallocSpy_PostRealloc(Malloc32.pSpy, pNewMemory, TRUE);
205             if (pNewMemory) AddMemoryLocation(pNewMemory);
206             LeaveCriticalSection(&IMalloc32_SpyCS);
207         }
208
209         TRACE("--(%p)\n",pNewMemory);
210         return pNewMemory;
211 }
212
213 /******************************************************************************
214  * IMalloc32_Free [VTABLE]
215  */
216 static VOID WINAPI IMalloc_fnFree(LPMALLOC iface,LPVOID pv) {
217
218         BOOL fSpyed = 0;
219
220         TRACE("(%p)\n",pv);
221
222         if(Malloc32.pSpy) {
223             EnterCriticalSection(&IMalloc32_SpyCS);
224             fSpyed = RemoveMemoryLocation(pv);
225             pv = IMallocSpy_PreFree(Malloc32.pSpy, pv, fSpyed);
226         }
227
228         HeapFree(GetProcessHeap(),0,pv);
229
230         if(Malloc32.pSpy) {
231             IMallocSpy_PostFree(Malloc32.pSpy, fSpyed);
232
233             /* check if can release the spy */
234             if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
235                 IMallocSpy_Release(Malloc32.pSpy);
236                 Malloc32.SpyReleasePending = FALSE;
237                 Malloc32.pSpy = NULL;
238             }
239
240             LeaveCriticalSection(&IMalloc32_SpyCS);
241         }
242 }
243
244 /******************************************************************************
245  * IMalloc32_GetSize [VTABLE]
246  *
247  * NOTES
248  *  FIXME returns:
249  *      win95:  size allocated (4 byte boundarys)
250  *      win2k:  size originally requested !!! (allocated on 8 byte boundarys)
251  */
252 static DWORD WINAPI IMalloc_fnGetSize(LPMALLOC iface,LPVOID pv) {
253
254         DWORD cb;
255         BOOL fSpyed = 0;
256
257         TRACE("(%p)\n",pv);
258
259         if(Malloc32.pSpy) {
260             EnterCriticalSection(&IMalloc32_SpyCS);
261             pv = IMallocSpy_PreGetSize(Malloc32.pSpy, pv, fSpyed);
262         }
263
264         cb = HeapSize(GetProcessHeap(),0,pv);
265
266         if(Malloc32.pSpy) {
267             cb = IMallocSpy_PostGetSize(Malloc32.pSpy, cb, fSpyed);
268             LeaveCriticalSection(&IMalloc32_SpyCS);
269         }
270
271         return cb;
272 }
273
274 /******************************************************************************
275  * IMalloc32_DidAlloc [VTABLE]
276  */
277 static INT WINAPI IMalloc_fnDidAlloc(LPMALLOC iface,LPVOID pv) {
278
279         BOOL fSpyed = 0;
280         int didAlloc;
281
282         TRACE("(%p)\n",pv);
283
284         if(Malloc32.pSpy) {
285             EnterCriticalSection(&IMalloc32_SpyCS);
286             pv = IMallocSpy_PreDidAlloc(Malloc32.pSpy, pv, fSpyed);
287         }
288
289         didAlloc = -1;
290
291         if(Malloc32.pSpy) {
292             didAlloc = IMallocSpy_PostDidAlloc(Malloc32.pSpy, pv, fSpyed, didAlloc);
293             LeaveCriticalSection(&IMalloc32_SpyCS);
294         }
295         return didAlloc;
296 }
297
298 /******************************************************************************
299  * IMalloc32_HeapMinimize [VTABLE]
300  */
301 static VOID WINAPI IMalloc_fnHeapMinimize(LPMALLOC iface) {
302         TRACE("()\n");
303
304         if(Malloc32.pSpy) {
305             EnterCriticalSection(&IMalloc32_SpyCS);
306             IMallocSpy_PreHeapMinimize(Malloc32.pSpy);
307         }
308
309         if(Malloc32.pSpy) {
310             IMallocSpy_PostHeapMinimize(Malloc32.pSpy);
311             LeaveCriticalSection(&IMalloc32_SpyCS);
312         }
313 }
314
315 static ICOM_VTABLE(IMalloc) VT_IMalloc32 =
316 {
317         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
318         IMalloc_fnQueryInterface,
319         IMalloc_fnAddRefRelease,
320         IMalloc_fnAddRefRelease,
321         IMalloc_fnAlloc,
322         IMalloc_fnRealloc,
323         IMalloc_fnFree,
324         IMalloc_fnGetSize,
325         IMalloc_fnDidAlloc,
326         IMalloc_fnHeapMinimize
327 };
328
329 /******************************************************************************
330  *      IMallocSpy implementation
331  *****************************************************************************/
332
333 /* set the vtable later */
334 extern ICOM_VTABLE(IMallocSpy) VT_IMallocSpy;
335
336 typedef struct {
337         ICOM_VFIELD(IMallocSpy);
338         DWORD ref;
339 } _MallocSpy;
340
341 /* this is the static object instance */
342 _MallocSpy MallocSpy = {&VT_IMallocSpy, 0};
343
344 /******************************************************************************
345  *      IMalloc32_QueryInterface        [VTABLE]
346  */
347 static HRESULT WINAPI IMallocSpy_fnQueryInterface(LPMALLOCSPY iface,REFIID refiid,LPVOID *obj)
348 {
349
350         TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
351
352         if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMallocSpy,refiid)) {
353                 *obj = (LPMALLOC)&MallocSpy;
354                 return S_OK;
355         }
356         return E_NOINTERFACE;
357 }
358
359 /******************************************************************************
360  *      IMalloc32_AddRef                [VTABLE]
361  */
362 static ULONG WINAPI IMallocSpy_fnAddRef (LPMALLOCSPY iface)
363 {
364
365     ICOM_THIS (_MallocSpy, iface);
366
367     TRACE ("(%p)->(count=%lu)\n", This, This->ref);
368
369     return ++(This->ref);
370 }
371
372 /******************************************************************************
373  *      IMalloc32_AddRelease            [VTABLE]
374  *
375  * NOTES
376  *   Our MallocSpy is static. If the count reaches 0 we dump the leaks
377  */
378 static ULONG WINAPI IMallocSpy_fnRelease (LPMALLOCSPY iface)
379 {
380
381     ICOM_THIS (_MallocSpy, iface);
382
383     TRACE ("(%p)->(count=%lu)\n", This, This->ref);
384
385     if (!--(This->ref)) {
386         /* our allocation list MUST be empty here */
387     }
388     return This->ref;
389 }
390
391 static ULONG WINAPI IMallocSpy_fnPreAlloc(LPMALLOCSPY iface, ULONG cbRequest)
392 {
393     ICOM_THIS (_MallocSpy, iface);
394     TRACE ("(%p)->(%lu)\n", This, cbRequest);
395     return cbRequest;
396 }
397 static PVOID WINAPI IMallocSpy_fnPostAlloc(LPMALLOCSPY iface, void* pActual)
398 {
399     ICOM_THIS (_MallocSpy, iface);
400     TRACE ("(%p)->(%p)\n", This, pActual);
401     return pActual;
402 }
403
404 static PVOID WINAPI IMallocSpy_fnPreFree(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
405 {
406     ICOM_THIS (_MallocSpy, iface);
407     TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
408     return pRequest;
409 }
410 static void  WINAPI IMallocSpy_fnPostFree(LPMALLOCSPY iface, BOOL fSpyed)
411 {
412     ICOM_THIS (_MallocSpy, iface);
413     TRACE ("(%p)->(%u)\n", This, fSpyed);
414 }
415
416 static ULONG WINAPI IMallocSpy_fnPreRealloc(LPMALLOCSPY iface, void* pRequest, ULONG cbRequest, void** ppNewRequest, BOOL fSpyed)
417 {
418     ICOM_THIS (_MallocSpy, iface);
419     TRACE ("(%p)->(%p %lu %u)\n", This, pRequest, cbRequest, fSpyed);
420     *ppNewRequest = pRequest;
421     return cbRequest;
422 }
423
424 static PVOID WINAPI IMallocSpy_fnPostRealloc(LPMALLOCSPY iface, void* pActual, BOOL fSpyed)
425 {
426     ICOM_THIS (_MallocSpy, iface);
427     TRACE ("(%p)->(%p %u)\n", This, pActual, fSpyed);
428     return pActual;
429 }
430
431 static PVOID WINAPI IMallocSpy_fnPreGetSize(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
432 {
433     ICOM_THIS (_MallocSpy, iface);
434     TRACE ("(%p)->(%p %u)\n", This,  pRequest, fSpyed);
435     return pRequest;
436 }
437
438 static ULONG WINAPI IMallocSpy_fnPostGetSize(LPMALLOCSPY iface, ULONG cbActual, BOOL fSpyed)
439 {
440     ICOM_THIS (_MallocSpy, iface);
441     TRACE ("(%p)->(%lu %u)\n", This, cbActual, fSpyed);
442     return cbActual;
443 }
444
445 static PVOID WINAPI IMallocSpy_fnPreDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
446 {
447     ICOM_THIS (_MallocSpy, iface);
448     TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
449     return pRequest;
450 }
451
452 static int WINAPI IMallocSpy_fnPostDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed, int fActual)
453 {
454     ICOM_THIS (_MallocSpy, iface);
455     TRACE ("(%p)->(%p %u %u)\n", This, pRequest, fSpyed, fActual);
456     return fActual;
457 }
458
459 static void WINAPI IMallocSpy_fnPreHeapMinimize(LPMALLOCSPY iface)
460 {
461     ICOM_THIS (_MallocSpy, iface);
462     TRACE ("(%p)->()\n", This);
463 }
464
465 static void WINAPI IMallocSpy_fnPostHeapMinimize(LPMALLOCSPY iface)
466 {
467     ICOM_THIS (_MallocSpy, iface);
468     TRACE ("(%p)->()\n", This);
469 }
470
471 static void MallocSpyDumpLeaks() {
472         TRACE("leaks: %lu\n", Malloc32.SpyedAllocationsLeft);
473 }
474
475 static ICOM_VTABLE(IMallocSpy) VT_IMallocSpy =
476 {
477         ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
478         IMallocSpy_fnQueryInterface,
479         IMallocSpy_fnAddRef,
480         IMallocSpy_fnRelease,
481         IMallocSpy_fnPreAlloc,
482         IMallocSpy_fnPostAlloc,
483         IMallocSpy_fnPreFree,
484         IMallocSpy_fnPostFree,
485         IMallocSpy_fnPreRealloc,
486         IMallocSpy_fnPostRealloc,
487         IMallocSpy_fnPreGetSize,
488         IMallocSpy_fnPostGetSize,
489         IMallocSpy_fnPreDidAlloc,
490         IMallocSpy_fnPostDidAlloc,
491         IMallocSpy_fnPreHeapMinimize,
492         IMallocSpy_fnPostHeapMinimize
493 };
494
495 /******************************************************************************
496  *              CoGetMalloc     [OLE32.20]
497  *
498  * RETURNS
499  *      The win32 IMalloc
500  */
501 HRESULT WINAPI CoGetMalloc(DWORD dwMemContext, LPMALLOC *lpMalloc)
502 {
503         *lpMalloc = (LPMALLOC)&Malloc32;
504         return S_OK;
505 }
506
507 /***********************************************************************
508  *           CoTaskMemAlloc     [OLE32.43]
509  * RETURNS
510  *      pointer to newly allocated block
511  */
512 LPVOID WINAPI CoTaskMemAlloc(ULONG size)
513 {
514         return IMalloc_Alloc((LPMALLOC)&Malloc32,size);
515 }
516 /***********************************************************************
517  *           CoTaskMemFree      [OLE32.44]
518  */
519 VOID WINAPI CoTaskMemFree(LPVOID ptr)
520 {
521         IMalloc_Free((LPMALLOC)&Malloc32, ptr);
522 }
523
524 /***********************************************************************
525  *           CoTaskMemRealloc   [OLE32.45]
526  * RETURNS
527  *      pointer to newly allocated block
528  */
529 LPVOID WINAPI CoTaskMemRealloc(LPVOID pvOld, ULONG size)
530 {
531         return IMalloc_Realloc((LPMALLOC)&Malloc32, pvOld, size);
532 }
533
534 /***********************************************************************
535  *           CoRegisterMallocSpy        [OLE32.37]
536  *
537  * NOTES
538  *  if a mallocspy is already registered, we cant do it again since
539  *  only the spy knows, how to free a memory block
540  */
541 HRESULT WINAPI CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy)
542 {
543         IMallocSpy* pSpy;
544         HRESULT hres = E_INVALIDARG;
545
546         TRACE("\n");
547
548         /* HACK TO ACTIVATE OUT SPY */
549         if (pMallocSpy == (LPVOID)-1) pMallocSpy =(IMallocSpy*)&MallocSpy;
550
551         if(Malloc32.pSpy) return CO_E_OBJISREG;
552
553         EnterCriticalSection(&IMalloc32_SpyCS);
554
555         if (SUCCEEDED(IUnknown_QueryInterface(pMallocSpy, &IID_IMallocSpy, (LPVOID*)&pSpy))) {
556             Malloc32.pSpy = pSpy;
557             hres = S_OK;
558         }
559
560         LeaveCriticalSection(&IMalloc32_SpyCS);
561
562         return hres;
563 }
564
565 /***********************************************************************
566  *           CoRevokeMallocSpy  [OLE32.41]
567  *
568  * NOTES
569  *  we can't rewoke a malloc spy as long as memory blocks allocated with
570  *  the spy are active since only the spy knows how to free them
571  */
572 HRESULT WINAPI CoRevokeMallocSpy(void)
573 {
574         HRESULT hres = S_OK;
575         TRACE("\n");
576
577         EnterCriticalSection(&IMalloc32_SpyCS);
578
579         /* if it's our spy it's time to dump the leaks */
580         if (Malloc32.pSpy == (IMallocSpy*)&MallocSpy) {
581             MallocSpyDumpLeaks();
582         }
583
584         if (Malloc32.SpyedAllocationsLeft) {
585             TRACE("SpyReleasePending with %lu allocations left\n", Malloc32.SpyedAllocationsLeft);
586             Malloc32.SpyReleasePending = TRUE;
587             hres = E_ACCESSDENIED;
588         } else {
589             IMallocSpy_Release(Malloc32.pSpy);
590             Malloc32.pSpy = NULL;
591         }
592         LeaveCriticalSection(&IMalloc32_SpyCS);
593
594         return S_OK;
595 }
596
597 /******************************************************************************
598  *              IsValidInterface        [OLE32.78]
599  *
600  * RETURNS
601  *  True, if the passed pointer is a valid interface
602  */
603 BOOL WINAPI IsValidInterface(
604         LPUNKNOWN punk  /* [in] interface to be tested */
605 ) {
606         return !(
607                 IsBadReadPtr(punk,4)                                    ||
608                 IsBadReadPtr(ICOM_VTBL(punk),4)                         ||
609                 IsBadReadPtr(ICOM_VTBL(punk)->QueryInterface,9) ||
610                 IsBadCodePtr((FARPROC)ICOM_VTBL(punk)->QueryInterface)
611         );
612 }