Moved most of the 16-bit task support and NE module loader to
[wine/multimedia.git] / dlls / ole32 / ifs.c
blob42c18316578a1bbfc64d5c0515371591fee9f7d3
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
23 #include <ctype.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <assert.h>
28 #include "ole2.h"
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winerror.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(ole);
37 /******************************************************************************
38 * IMalloc32 implementation
40 * NOTES
41 * For supporting CoRegisterMallocSpy the IMalloc implementation must know if
42 * a given memory block was allocated with a spy active.
44 *****************************************************************************/
45 /* set the vtable later */
46 extern ICOM_VTABLE(IMalloc) VT_IMalloc32;
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;
58 /* this is the static object instance */
59 _Malloc32 Malloc32 = {&VT_IMalloc32, 0, NULL, 0, 0, NULL, 0};
61 /* with a spy active all calls from pre to post methods are threadsave */
62 static CRITICAL_SECTION IMalloc32_SpyCS;
63 static CRITICAL_SECTION_DEBUG critsect_debug =
65 0, 0, &IMalloc32_SpyCS,
66 { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
67 0, 0, { 0, (DWORD)(__FILE__ ": IMalloc32_SpyCS") }
69 static CRITICAL_SECTION IMalloc32_SpyCS = { &critsect_debug, -1, 0, 0, 0, 0 };
71 /* resize the old table */
72 static int SetSpyedBlockTableLength ( int NewLength )
74 Malloc32.SpyedBlocks = (LPVOID*)LocalReAlloc((HLOCAL)Malloc32.SpyedBlocks, NewLength, GMEM_ZEROINIT);
75 Malloc32.SpyedBlockTableLength = NewLength;
76 return Malloc32.SpyedBlocks ? 1 : 0;
79 /* add a location to the table */
80 static int AddMemoryLocation(LPVOID * pMem)
82 LPVOID * Current;
84 /* allocate the table if not already allocated */
85 if (!Malloc32.SpyedBlockTableLength) {
86 if (!SetSpyedBlockTableLength(0x1000)) return 0;
89 /* find a free location */
90 Current = Malloc32.SpyedBlocks;
91 while (*Current) {
92 Current++;
93 if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) {
94 /* no more space in table, grow it */
95 if (!SetSpyedBlockTableLength( Malloc32.SpyedBlockTableLength + 0x1000 )) return 0;
99 /* put the location in our table */
100 *Current = pMem;
101 Malloc32.SpyedAllocationsLeft++;
102 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
103 return 1;
106 static int RemoveMemoryLocation(LPVOID * pMem)
108 LPVOID * Current = Malloc32.SpyedBlocks;
110 /* find the location */
111 while (*Current != pMem) {
112 Current++;
113 if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) return 0; /* not found */
116 /* location found */
117 Malloc32.SpyedAllocationsLeft--;
118 /*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
119 *Current = NULL;
120 return 1;
123 /******************************************************************************
124 * IMalloc32_QueryInterface [VTABLE]
126 static HRESULT WINAPI IMalloc_fnQueryInterface(LPMALLOC iface,REFIID refiid,LPVOID *obj) {
128 TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
130 if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMalloc,refiid)) {
131 *obj = (LPMALLOC)&Malloc32;
132 return S_OK;
134 return E_NOINTERFACE;
137 /******************************************************************************
138 * IMalloc32_AddRefRelease [VTABLE]
140 static ULONG WINAPI IMalloc_fnAddRefRelease (LPMALLOC iface) {
141 return 1;
144 /******************************************************************************
145 * IMalloc32_Alloc [VTABLE]
147 static LPVOID WINAPI IMalloc_fnAlloc(LPMALLOC iface, DWORD cb) {
149 LPVOID addr;
151 TRACE("(%ld)\n",cb);
153 if(Malloc32.pSpy) {
154 DWORD preAllocResult;
156 EnterCriticalSection(&IMalloc32_SpyCS);
157 preAllocResult = IMallocSpy_PreAlloc(Malloc32.pSpy, cb);
158 if ((cb != 0) && (preAllocResult == 0)) {
159 /* PreAlloc can force Alloc to fail, but not if cb == 0 */
160 TRACE("returning null\n");
161 LeaveCriticalSection(&IMalloc32_SpyCS);
162 return NULL;
166 addr = HeapAlloc(GetProcessHeap(),0,cb);
168 if(Malloc32.pSpy) {
169 addr = IMallocSpy_PostAlloc(Malloc32.pSpy, addr);
170 if (addr) AddMemoryLocation(addr);
171 LeaveCriticalSection(&IMalloc32_SpyCS);
174 TRACE("--(%p)\n",addr);
175 return addr;
178 /******************************************************************************
179 * IMalloc32_Realloc [VTABLE]
181 static LPVOID WINAPI IMalloc_fnRealloc(LPMALLOC iface,LPVOID pv,DWORD cb) {
183 LPVOID pNewMemory;
185 TRACE("(%p,%ld)\n",pv,cb);
187 if(Malloc32.pSpy) {
188 LPVOID pRealMemory;
189 BOOL fSpyed;
191 EnterCriticalSection(&IMalloc32_SpyCS);
192 fSpyed = RemoveMemoryLocation(pv);
193 cb = IMallocSpy_PreRealloc(Malloc32.pSpy, pv, cb, &pRealMemory, fSpyed);
195 /* check if can release the spy */
196 if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
197 IMallocSpy_Release(Malloc32.pSpy);
198 Malloc32.SpyReleasePending = FALSE;
199 Malloc32.pSpy = NULL;
202 if (0==cb) {
203 /* PreRealloc can force Realloc to fail */
204 LeaveCriticalSection(&IMalloc32_SpyCS);
205 return NULL;
207 pv = pRealMemory;
210 pNewMemory = HeapReAlloc(GetProcessHeap(),0,pv,cb);
212 if(Malloc32.pSpy) {
213 pNewMemory = IMallocSpy_PostRealloc(Malloc32.pSpy, pNewMemory, TRUE);
214 if (pNewMemory) AddMemoryLocation(pNewMemory);
215 LeaveCriticalSection(&IMalloc32_SpyCS);
218 TRACE("--(%p)\n",pNewMemory);
219 return pNewMemory;
222 /******************************************************************************
223 * IMalloc32_Free [VTABLE]
225 static VOID WINAPI IMalloc_fnFree(LPMALLOC iface,LPVOID pv) {
227 BOOL fSpyed = 0;
229 TRACE("(%p)\n",pv);
231 if(Malloc32.pSpy) {
232 EnterCriticalSection(&IMalloc32_SpyCS);
233 fSpyed = RemoveMemoryLocation(pv);
234 pv = IMallocSpy_PreFree(Malloc32.pSpy, pv, fSpyed);
237 HeapFree(GetProcessHeap(),0,pv);
239 if(Malloc32.pSpy) {
240 IMallocSpy_PostFree(Malloc32.pSpy, fSpyed);
242 /* check if can release the spy */
243 if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
244 IMallocSpy_Release(Malloc32.pSpy);
245 Malloc32.SpyReleasePending = FALSE;
246 Malloc32.pSpy = NULL;
249 LeaveCriticalSection(&IMalloc32_SpyCS);
253 /******************************************************************************
254 * IMalloc32_GetSize [VTABLE]
256 * NOTES
257 * FIXME returns:
258 * win95: size allocated (4 byte boundarys)
259 * win2k: size originally requested !!! (allocated on 8 byte boundarys)
261 static DWORD WINAPI IMalloc_fnGetSize(LPMALLOC iface,LPVOID pv) {
263 DWORD cb;
264 BOOL fSpyed = 0;
266 TRACE("(%p)\n",pv);
268 if(Malloc32.pSpy) {
269 EnterCriticalSection(&IMalloc32_SpyCS);
270 pv = IMallocSpy_PreGetSize(Malloc32.pSpy, pv, fSpyed);
273 cb = HeapSize(GetProcessHeap(),0,pv);
275 if(Malloc32.pSpy) {
276 cb = IMallocSpy_PostGetSize(Malloc32.pSpy, cb, fSpyed);
277 LeaveCriticalSection(&IMalloc32_SpyCS);
280 return cb;
283 /******************************************************************************
284 * IMalloc32_DidAlloc [VTABLE]
286 static INT WINAPI IMalloc_fnDidAlloc(LPMALLOC iface,LPVOID pv) {
288 BOOL fSpyed = 0;
289 int didAlloc;
291 TRACE("(%p)\n",pv);
293 if(Malloc32.pSpy) {
294 EnterCriticalSection(&IMalloc32_SpyCS);
295 pv = IMallocSpy_PreDidAlloc(Malloc32.pSpy, pv, fSpyed);
298 didAlloc = -1;
300 if(Malloc32.pSpy) {
301 didAlloc = IMallocSpy_PostDidAlloc(Malloc32.pSpy, pv, fSpyed, didAlloc);
302 LeaveCriticalSection(&IMalloc32_SpyCS);
304 return didAlloc;
307 /******************************************************************************
308 * IMalloc32_HeapMinimize [VTABLE]
310 static VOID WINAPI IMalloc_fnHeapMinimize(LPMALLOC iface) {
311 TRACE("()\n");
313 if(Malloc32.pSpy) {
314 EnterCriticalSection(&IMalloc32_SpyCS);
315 IMallocSpy_PreHeapMinimize(Malloc32.pSpy);
318 if(Malloc32.pSpy) {
319 IMallocSpy_PostHeapMinimize(Malloc32.pSpy);
320 LeaveCriticalSection(&IMalloc32_SpyCS);
324 static ICOM_VTABLE(IMalloc) VT_IMalloc32 =
326 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
327 IMalloc_fnQueryInterface,
328 IMalloc_fnAddRefRelease,
329 IMalloc_fnAddRefRelease,
330 IMalloc_fnAlloc,
331 IMalloc_fnRealloc,
332 IMalloc_fnFree,
333 IMalloc_fnGetSize,
334 IMalloc_fnDidAlloc,
335 IMalloc_fnHeapMinimize
338 /******************************************************************************
339 * IMallocSpy implementation
340 *****************************************************************************/
342 /* set the vtable later */
343 extern ICOM_VTABLE(IMallocSpy) VT_IMallocSpy;
345 typedef struct {
346 ICOM_VFIELD(IMallocSpy);
347 DWORD ref;
348 } _MallocSpy;
350 /* this is the static object instance */
351 _MallocSpy MallocSpy = {&VT_IMallocSpy, 0};
353 /******************************************************************************
354 * IMalloc32_QueryInterface [VTABLE]
356 static HRESULT WINAPI IMallocSpy_fnQueryInterface(LPMALLOCSPY iface,REFIID refiid,LPVOID *obj)
359 TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
361 if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMallocSpy,refiid)) {
362 *obj = (LPMALLOC)&MallocSpy;
363 return S_OK;
365 return E_NOINTERFACE;
368 /******************************************************************************
369 * IMalloc32_AddRef [VTABLE]
371 static ULONG WINAPI IMallocSpy_fnAddRef (LPMALLOCSPY iface)
374 ICOM_THIS (_MallocSpy, iface);
376 TRACE ("(%p)->(count=%lu)\n", This, This->ref);
378 return ++(This->ref);
381 /******************************************************************************
382 * IMalloc32_AddRelease [VTABLE]
384 * NOTES
385 * Our MallocSpy is static. If the count reaches 0 we dump the leaks
387 static ULONG WINAPI IMallocSpy_fnRelease (LPMALLOCSPY iface)
390 ICOM_THIS (_MallocSpy, iface);
392 TRACE ("(%p)->(count=%lu)\n", This, This->ref);
394 if (!--(This->ref)) {
395 /* our allocation list MUST be empty here */
397 return This->ref;
400 static ULONG WINAPI IMallocSpy_fnPreAlloc(LPMALLOCSPY iface, ULONG cbRequest)
402 ICOM_THIS (_MallocSpy, iface);
403 TRACE ("(%p)->(%lu)\n", This, cbRequest);
404 return cbRequest;
406 static PVOID WINAPI IMallocSpy_fnPostAlloc(LPMALLOCSPY iface, void* pActual)
408 ICOM_THIS (_MallocSpy, iface);
409 TRACE ("(%p)->(%p)\n", This, pActual);
410 return pActual;
413 static PVOID WINAPI IMallocSpy_fnPreFree(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
415 ICOM_THIS (_MallocSpy, iface);
416 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
417 return pRequest;
419 static void WINAPI IMallocSpy_fnPostFree(LPMALLOCSPY iface, BOOL fSpyed)
421 ICOM_THIS (_MallocSpy, iface);
422 TRACE ("(%p)->(%u)\n", This, fSpyed);
425 static ULONG WINAPI IMallocSpy_fnPreRealloc(LPMALLOCSPY iface, void* pRequest, ULONG cbRequest, void** ppNewRequest, BOOL fSpyed)
427 ICOM_THIS (_MallocSpy, iface);
428 TRACE ("(%p)->(%p %lu %u)\n", This, pRequest, cbRequest, fSpyed);
429 *ppNewRequest = pRequest;
430 return cbRequest;
433 static PVOID WINAPI IMallocSpy_fnPostRealloc(LPMALLOCSPY iface, void* pActual, BOOL fSpyed)
435 ICOM_THIS (_MallocSpy, iface);
436 TRACE ("(%p)->(%p %u)\n", This, pActual, fSpyed);
437 return pActual;
440 static PVOID WINAPI IMallocSpy_fnPreGetSize(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
442 ICOM_THIS (_MallocSpy, iface);
443 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
444 return pRequest;
447 static ULONG WINAPI IMallocSpy_fnPostGetSize(LPMALLOCSPY iface, ULONG cbActual, BOOL fSpyed)
449 ICOM_THIS (_MallocSpy, iface);
450 TRACE ("(%p)->(%lu %u)\n", This, cbActual, fSpyed);
451 return cbActual;
454 static PVOID WINAPI IMallocSpy_fnPreDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed)
456 ICOM_THIS (_MallocSpy, iface);
457 TRACE ("(%p)->(%p %u)\n", This, pRequest, fSpyed);
458 return pRequest;
461 static int WINAPI IMallocSpy_fnPostDidAlloc(LPMALLOCSPY iface, void* pRequest, BOOL fSpyed, int fActual)
463 ICOM_THIS (_MallocSpy, iface);
464 TRACE ("(%p)->(%p %u %u)\n", This, pRequest, fSpyed, fActual);
465 return fActual;
468 static void WINAPI IMallocSpy_fnPreHeapMinimize(LPMALLOCSPY iface)
470 ICOM_THIS (_MallocSpy, iface);
471 TRACE ("(%p)->()\n", This);
474 static void WINAPI IMallocSpy_fnPostHeapMinimize(LPMALLOCSPY iface)
476 ICOM_THIS (_MallocSpy, iface);
477 TRACE ("(%p)->()\n", This);
480 static void MallocSpyDumpLeaks() {
481 TRACE("leaks: %lu\n", Malloc32.SpyedAllocationsLeft);
484 static ICOM_VTABLE(IMallocSpy) VT_IMallocSpy =
486 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
487 IMallocSpy_fnQueryInterface,
488 IMallocSpy_fnAddRef,
489 IMallocSpy_fnRelease,
490 IMallocSpy_fnPreAlloc,
491 IMallocSpy_fnPostAlloc,
492 IMallocSpy_fnPreFree,
493 IMallocSpy_fnPostFree,
494 IMallocSpy_fnPreRealloc,
495 IMallocSpy_fnPostRealloc,
496 IMallocSpy_fnPreGetSize,
497 IMallocSpy_fnPostGetSize,
498 IMallocSpy_fnPreDidAlloc,
499 IMallocSpy_fnPostDidAlloc,
500 IMallocSpy_fnPreHeapMinimize,
501 IMallocSpy_fnPostHeapMinimize
504 /******************************************************************************
505 * CoGetMalloc [OLE32.20]
507 * RETURNS
508 * The win32 IMalloc
510 HRESULT WINAPI CoGetMalloc(DWORD dwMemContext, LPMALLOC *lpMalloc)
512 *lpMalloc = (LPMALLOC)&Malloc32;
513 return S_OK;
516 /***********************************************************************
517 * CoTaskMemAlloc [OLE32.43]
518 * RETURNS
519 * pointer to newly allocated block
521 LPVOID WINAPI CoTaskMemAlloc(ULONG size)
523 return IMalloc_Alloc((LPMALLOC)&Malloc32,size);
525 /***********************************************************************
526 * CoTaskMemFree [OLE32.44]
528 VOID WINAPI CoTaskMemFree(LPVOID ptr)
530 IMalloc_Free((LPMALLOC)&Malloc32, ptr);
533 /***********************************************************************
534 * CoTaskMemRealloc [OLE32.45]
535 * RETURNS
536 * pointer to newly allocated block
538 LPVOID WINAPI CoTaskMemRealloc(LPVOID pvOld, ULONG size)
540 return IMalloc_Realloc((LPMALLOC)&Malloc32, pvOld, size);
543 /***********************************************************************
544 * CoRegisterMallocSpy [OLE32.37]
546 * NOTES
547 * if a mallocspy is already registered, we cant do it again since
548 * only the spy knows, how to free a memory block
550 HRESULT WINAPI CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy)
552 IMallocSpy* pSpy;
553 HRESULT hres = E_INVALIDARG;
555 TRACE("\n");
557 /* HACK TO ACTIVATE OUT SPY */
558 if (pMallocSpy == (LPVOID)-1) pMallocSpy =(IMallocSpy*)&MallocSpy;
560 if(Malloc32.pSpy) return CO_E_OBJISREG;
562 EnterCriticalSection(&IMalloc32_SpyCS);
564 if (SUCCEEDED(IUnknown_QueryInterface(pMallocSpy, &IID_IMallocSpy, (LPVOID*)&pSpy))) {
565 Malloc32.pSpy = pSpy;
566 hres = S_OK;
569 LeaveCriticalSection(&IMalloc32_SpyCS);
571 return hres;
574 /***********************************************************************
575 * CoRevokeMallocSpy [OLE32.41]
577 * NOTES
578 * we can't rewoke a malloc spy as long as memory blocks allocated with
579 * the spy are active since only the spy knows how to free them
581 HRESULT WINAPI CoRevokeMallocSpy(void)
583 HRESULT hres = S_OK;
584 TRACE("\n");
586 EnterCriticalSection(&IMalloc32_SpyCS);
588 /* if it's our spy it's time to dump the leaks */
589 if (Malloc32.pSpy == (IMallocSpy*)&MallocSpy) {
590 MallocSpyDumpLeaks();
593 if (Malloc32.SpyedAllocationsLeft) {
594 TRACE("SpyReleasePending with %lu allocations left\n", Malloc32.SpyedAllocationsLeft);
595 Malloc32.SpyReleasePending = TRUE;
596 hres = E_ACCESSDENIED;
597 } else {
598 IMallocSpy_Release(Malloc32.pSpy);
599 Malloc32.pSpy = NULL;
601 LeaveCriticalSection(&IMalloc32_SpyCS);
603 return S_OK;
606 /******************************************************************************
607 * IsValidInterface [OLE32.78]
609 * RETURNS
610 * True, if the passed pointer is a valid interface
612 BOOL WINAPI IsValidInterface(
613 LPUNKNOWN punk /* [in] interface to be tested */
615 return !(
616 IsBadReadPtr(punk,4) ||
617 IsBadReadPtr(punk->lpVtbl,4) ||
618 IsBadReadPtr(punk->lpVtbl->QueryInterface,9) ||
619 IsBadCodePtr((FARPROC)punk->lpVtbl->QueryInterface)