reactos/dll/win32/ole32/ifs.c

564 lines
15 KiB
C
Raw Normal View History

/*
* basic interfaces
*
* Copyright 1997 Marcus Meissner
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include <ctype.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#define COBJMACROS
#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "ole2.h"
#include "winerror.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(olemalloc);
/******************************************************************************
* IMalloc32 implementation
*
* NOTES
* For supporting CoRegisterMallocSpy the IMalloc implementation must know if
* a given memory block was allocated with a spy active.
*
*****************************************************************************/
/* set the vtable later */
Sync to Wine-20050628: Robert Shearman <rob@codeweavers.com> - Convert some registry helper functions to use unicode versions of CLSID & registry functions (untested). - Add registry entries for local-only OLE interfaces. - Change IUnknown to local interface. - IUnknown isn't a remotable interface so the stub manager shouldn't need a marshaller for it. - Change the RPC code to use the unicode versions of the CLSID & registry functions. - Don't disconnect proxies flagged with SORFP_NOLIFETIMEMGMT. It makes no sense and only causes trouble for proxies that depend on these proxies being available. - Change some of the registry helper functions to use the unicode versions of the CLSID & registry functions. - Reindent CoGetClassObject and output an error message if the class isn't registered. - Add tests for the touched functions. Dmitry Timoshkov <dmitry@codeweavers.com> - Make remaining OLE interface vtables const. Richard Cohen <richard@daijobu.co.uk> - Base FileMonikerImpl_Save() on XP. - Correct handling of Unicode strings & multibyte locales. - More error checking. - Change ERR to WARN. - Match Windows quick & dirty estimate for GetSizeMax(). Stefan Huehner <stefan@huehner.org> - Fix some more -Wstrict-prototypes warnings. Mike Hearn <mike@navi.cx> - Add some tracing to the IRemUnknown RpcProxyBuffer implementation. Eric Pouech <pouech-eric@wanadoo.fr> - Const correctness fixes. Richard Cohen <richard@daijobu.co.uk> - IEnum::Clone shouldn't do a Reset. Marcus Meissner <marcus@jet.franken.de> - Removed CLSID_CompositeMoniker (conflicting with static definition). Alexandre Julliard <julliard@winehq.org> - Sort entry points alphabetically. svn path=/trunk/; revision=17036
2005-08-03 22:31:39 +00:00
static const IMallocVtbl VT_IMalloc32;
typedef struct {
IMalloc IMalloc_iface;
DWORD dummy; /* nothing, we are static */
IMallocSpy * pSpy; /* the spy when active */
DWORD SpyedAllocationsLeft; /* number of spyed allocations left */
BOOL SpyReleasePending; /* CoRevokeMallocSpy called with spyed allocations left*/
LPVOID * SpyedBlocks; /* root of the table */
DWORD SpyedBlockTableLength;/* size of the table*/
} _Malloc32;
/* this is the static object instance */
static _Malloc32 Malloc32 = {{&VT_IMalloc32}, 0, NULL, 0, 0, NULL, 0};
/* with a spy active all calls from pre to post methods are threadsave */
static CRITICAL_SECTION IMalloc32_SpyCS;
static CRITICAL_SECTION_DEBUG critsect_debug =
{
0, 0, &IMalloc32_SpyCS,
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
Sync from Wine-20050830 to Wine-0_9_1: Francois Gouget <fgouget@free.fr> - Assorted spelling fixes. - Fix .spec declarations for functinos with 64bit arguments (reported by winapi_check). Mike Hearn <mh@codeweavers.com> - Robert Shearman <rob@codeweavers.com> Change stub manager to track the number of normal marshals instead of using the state machine so that multiple marshals of the same object and interface work correctly. Robert Shearman <rob@codeweavers.com> - Pass WM_QUIT to outer modal loop. - Fix the return codes during unmarshaling so that it returns failure codes instead of S_FALSE returned from IStream_Read. - Don't fail in CoRegisterClassObject if the class already exists and the REGCLS_MULTIPLEUSE flag is specified. - Fix ref-counting rules to match native DCOM Dlls. - Add exception handling for stubs. - Implement OleRegEnumVerbs. - The [string] attribute is only valid on byte, char and wchar_t types, so replace "unsigned short" by "WCHAR". - Implement OleIsRunning. - Add a stubbed out implementation of IAdviseSink and advise the delegate object to use it. - Initialize out pointer to NULL before access check in IStorage_CreateStorage. - WriteClassStg should return E_INVALIDARG if pstg is NULL instead of asserting. - ReadClassStg should return E_INVALIDARG if pstg is NULL instead of crashing and a NULL pclsid should cause it to return the same value. - Make the interfaces that should be supported by the data cache explicit so their is no confusion in this file as to what it should be implementing and what this object should implement. - Delegate some IOleObject methods to the server IOleObject if it is running. - Implement some IRunningObject functions that actually start the server and initialize it. - Remove redunant braces. - Compact multi-line comments that fit into one line. - Remove comments that state the obvious. - Remove extra brackets that are redundant because the -> operator binds tighter than &. - Change "this" to "This" to make code more like other interface implementations. - Remove redundant comparisons with NULL for pointers. - Re-arrange some functions and vtables so we don't have declarations for all of the functions in the file. - Fix a trace to refer to the object ID rather than the legacy MID. - Fix the error case of CoMarshalInterThreadInterface to release the stream. - Move all 16-bit functions to an appropriate 16-bit file. - Implement OLE object notifications, making sure to cope with the case of the advise holder not being created because no notifications are needed. - Implement a Stop function and use this to properly implement IOleObject_Close, IAdviseSink_OnClose and the destructor. - We shouldn't pass the application name into CreateProcess because the value stored in the registry could include arguments. - Extend COM_OpenKeyForCLSID to open a subkey and return an HRESULT. - Fix up the callers and reorganize CoGetClassObject to split out the inproc code into another function. Alex Villacís Lasso <a_villacis@palosanto.com> - Add NULL check for sinkInterface in DataCache_GetAdvise. - Add missing ! to fix a reversed condition check in OleCreateDefaultHandler, in order to match intent in comment. Vincent Béron <vberon@mecano.gme.usherb.ca> - Use the proper calling convention for 2 16-bit functions. Alexandre Julliard <julliard@winehq.org> - We are no longer generating .spec.c files. - Use a more portable scheme for storing the name of a critical section. - Fixed some traces to use the right printf format and avoid typecasts. - Removed unused debug channels. - We are no longer generating .dbg.c files. Richard Cohen <richard@daijobu.co.uk> - Relax the share mode validation for transacted storage, with a test. Eric Pouech <eric.pouech@wanadoo.fr> - Fixes for function prototypes without arguments. Michael Jung <mjung@iss.tu-darmstadt.de> - Added tracing to CoCreateInstance. Markus Amsler <markus.amsler@oribi.org> - Improve c2man Documented-Total count. svn path=/trunk/; revision=19370
2005-11-20 15:01:10 +00:00
0, 0, { (DWORD_PTR)(__FILE__ ": IMalloc32_SpyCS") }
};
static CRITICAL_SECTION IMalloc32_SpyCS = { &critsect_debug, -1, 0, 0, 0, 0 };
/* resize the old table */
static BOOL SetSpyedBlockTableLength ( DWORD NewLength )
{
LPVOID *NewSpyedBlocks;
if (!Malloc32.SpyedBlocks) NewSpyedBlocks = LocalAlloc(LMEM_ZEROINIT, NewLength * sizeof(PVOID));
else NewSpyedBlocks = LocalReAlloc(Malloc32.SpyedBlocks, NewLength * sizeof(PVOID), LMEM_ZEROINIT | LMEM_MOVEABLE);
if (NewSpyedBlocks) {
Malloc32.SpyedBlocks = NewSpyedBlocks;
Malloc32.SpyedBlockTableLength = NewLength;
}
return NewSpyedBlocks != NULL;
}
/* add a location to the table */
static BOOL AddMemoryLocation(LPVOID * pMem)
{
LPVOID * Current;
/* allocate the table if not already allocated */
if (!Malloc32.SpyedBlockTableLength && !SetSpyedBlockTableLength(0x1000))
return FALSE;
/* find a free location */
Current = Malloc32.SpyedBlocks;
while (*Current) {
Current++;
if (Current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength) {
/* no more space in table, grow it */
DWORD old_length = Malloc32.SpyedBlockTableLength;
if (!SetSpyedBlockTableLength( Malloc32.SpyedBlockTableLength + 0x1000))
return FALSE;
Current = Malloc32.SpyedBlocks + old_length;
}
};
/* put the location in our table */
*Current = pMem;
Malloc32.SpyedAllocationsLeft++;
/*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
return TRUE;
}
static void** mallocspy_is_allocation_spyed(const void *mem)
{
void **current = Malloc32.SpyedBlocks;
while (*current != mem)
{
current++;
if (current >= Malloc32.SpyedBlocks + Malloc32.SpyedBlockTableLength)
return NULL;
}
return current;
}
static BOOL RemoveMemoryLocation(LPCVOID pMem)
{
LPVOID * Current;
/* allocate the table if not already allocated */
if (!Malloc32.SpyedBlockTableLength && !SetSpyedBlockTableLength(0x1000))
return FALSE;
if (!(Current = mallocspy_is_allocation_spyed(pMem)))
return FALSE;
/* location found */
Malloc32.SpyedAllocationsLeft--;
/*TRACE("%lu\n",Malloc32.SpyedAllocationsLeft);*/
*Current = NULL;
return TRUE;
}
/******************************************************************************
* IMalloc32_QueryInterface [VTABLE]
*/
static HRESULT WINAPI IMalloc_fnQueryInterface(IMalloc *iface, REFIID refiid, void **obj)
{
TRACE("(%s,%p)\n",debugstr_guid(refiid),obj);
if (IsEqualIID(&IID_IUnknown,refiid) || IsEqualIID(&IID_IMalloc,refiid)) {
*obj = &Malloc32;
return S_OK;
}
return E_NOINTERFACE;
}
/******************************************************************************
* IMalloc32_AddRefRelease [VTABLE]
*/
static ULONG WINAPI IMalloc_fnAddRefRelease(IMalloc *iface)
{
return 1;
}
/******************************************************************************
* IMalloc32_Alloc [VTABLE]
*/
static void * WINAPI IMalloc_fnAlloc(IMalloc *iface, SIZE_T cb)
{
void *addr;
TRACE("(%ld)\n",cb);
if(Malloc32.pSpy) {
SIZE_T preAllocResult;
EnterCriticalSection(&IMalloc32_SpyCS);
preAllocResult = IMallocSpy_PreAlloc(Malloc32.pSpy, cb);
if ((cb != 0) && (preAllocResult == 0)) {
/* PreAlloc can force Alloc to fail, but not if cb == 0 */
TRACE("returning null\n");
LeaveCriticalSection(&IMalloc32_SpyCS);
return NULL;
}
}
addr = HeapAlloc(GetProcessHeap(),0,cb);
if(Malloc32.pSpy) {
addr = IMallocSpy_PostAlloc(Malloc32.pSpy, addr);
if (addr) AddMemoryLocation(addr);
LeaveCriticalSection(&IMalloc32_SpyCS);
}
TRACE("--(%p)\n",addr);
return addr;
}
/******************************************************************************
* IMalloc32_Realloc [VTABLE]
*/
static void * WINAPI IMalloc_fnRealloc(IMalloc *iface, void *pv, SIZE_T cb)
{
void *pNewMemory;
TRACE("(%p,%ld)\n",pv,cb);
if(Malloc32.pSpy) {
void *pRealMemory;
BOOL fSpyed;
EnterCriticalSection(&IMalloc32_SpyCS);
fSpyed = RemoveMemoryLocation(pv);
cb = IMallocSpy_PreRealloc(Malloc32.pSpy, pv, cb, &pRealMemory, fSpyed);
/* check if can release the spy */
if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
IMallocSpy_Release(Malloc32.pSpy);
Malloc32.SpyReleasePending = FALSE;
Malloc32.pSpy = NULL;
LeaveCriticalSection(&IMalloc32_SpyCS);
}
if (0==cb) {
/* PreRealloc can force Realloc to fail */
if (Malloc32.pSpy)
LeaveCriticalSection(&IMalloc32_SpyCS);
return NULL;
}
pv = pRealMemory;
}
if (!pv) pNewMemory = HeapAlloc(GetProcessHeap(),0,cb);
else if (cb) pNewMemory = HeapReAlloc(GetProcessHeap(),0,pv,cb);
else {
HeapFree(GetProcessHeap(),0,pv);
pNewMemory = NULL;
}
if(Malloc32.pSpy) {
pNewMemory = IMallocSpy_PostRealloc(Malloc32.pSpy, pNewMemory, TRUE);
if (pNewMemory) AddMemoryLocation(pNewMemory);
LeaveCriticalSection(&IMalloc32_SpyCS);
}
TRACE("--(%p)\n",pNewMemory);
return pNewMemory;
}
/******************************************************************************
* IMalloc32_Free [VTABLE]
*/
static void WINAPI IMalloc_fnFree(IMalloc *iface, void *pv)
{
BOOL fSpyed = FALSE;
TRACE("(%p)\n",pv);
if(!pv)
return;
if(Malloc32.pSpy) {
EnterCriticalSection(&IMalloc32_SpyCS);
fSpyed = RemoveMemoryLocation(pv);
pv = IMallocSpy_PreFree(Malloc32.pSpy, pv, fSpyed);
}
HeapFree(GetProcessHeap(),0,pv);
if(Malloc32.pSpy) {
IMallocSpy_PostFree(Malloc32.pSpy, fSpyed);
/* check if can release the spy */
if(Malloc32.SpyReleasePending && !Malloc32.SpyedAllocationsLeft) {
IMallocSpy_Release(Malloc32.pSpy);
Malloc32.SpyReleasePending = FALSE;
Malloc32.pSpy = NULL;
}
LeaveCriticalSection(&IMalloc32_SpyCS);
}
}
/******************************************************************************
* IMalloc32_GetSize [VTABLE]
*
* NOTES
* FIXME returns:
* win95: size allocated (4 byte boundarys)
* win2k: size originally requested !!! (allocated on 8 byte boundarys)
*/
static SIZE_T WINAPI IMalloc_fnGetSize(IMalloc *iface, void *mem)
{
BOOL spyed_block = FALSE, spy_active = FALSE;
SIZE_T size;
TRACE("(%p)\n", mem);
if (!mem)
return (SIZE_T)-1;
if (Malloc32.pSpy)
{
EnterCriticalSection(&IMalloc32_SpyCS);
spyed_block = !!mallocspy_is_allocation_spyed(mem);
spy_active = TRUE;
mem = IMallocSpy_PreGetSize(Malloc32.pSpy, mem, spyed_block);
}
size = HeapSize(GetProcessHeap(), 0, mem);
if (spy_active)
{
size = IMallocSpy_PostGetSize(Malloc32.pSpy, size, spyed_block);
LeaveCriticalSection(&IMalloc32_SpyCS);
}
return size;
}
/******************************************************************************
* IMalloc32_DidAlloc [VTABLE]
*/
static INT WINAPI IMalloc_fnDidAlloc(IMalloc *iface, void *mem)
{
BOOL spyed_block = FALSE, spy_active = FALSE;
int did_alloc;
TRACE("(%p)\n", mem);
if (!mem)
return -1;
if (Malloc32.pSpy)
{
EnterCriticalSection(&IMalloc32_SpyCS);
spyed_block = !!mallocspy_is_allocation_spyed(mem);
spy_active = TRUE;
mem = IMallocSpy_PreDidAlloc(Malloc32.pSpy, mem, spyed_block);
}
did_alloc = HeapValidate(GetProcessHeap(), 0, mem);
if (spy_active)
{
did_alloc = IMallocSpy_PostDidAlloc(Malloc32.pSpy, mem, spyed_block, did_alloc);
LeaveCriticalSection(&IMalloc32_SpyCS);
}
return did_alloc;
}
/******************************************************************************
* IMalloc32_HeapMinimize [VTABLE]
*/
static void WINAPI IMalloc_fnHeapMinimize(IMalloc *iface)
{
TRACE("()\n");
if(Malloc32.pSpy) {
EnterCriticalSection(&IMalloc32_SpyCS);
IMallocSpy_PreHeapMinimize(Malloc32.pSpy);
}
if(Malloc32.pSpy) {
IMallocSpy_PostHeapMinimize(Malloc32.pSpy);
LeaveCriticalSection(&IMalloc32_SpyCS);
}
}
Sync to Wine-20050628: Robert Shearman <rob@codeweavers.com> - Convert some registry helper functions to use unicode versions of CLSID & registry functions (untested). - Add registry entries for local-only OLE interfaces. - Change IUnknown to local interface. - IUnknown isn't a remotable interface so the stub manager shouldn't need a marshaller for it. - Change the RPC code to use the unicode versions of the CLSID & registry functions. - Don't disconnect proxies flagged with SORFP_NOLIFETIMEMGMT. It makes no sense and only causes trouble for proxies that depend on these proxies being available. - Change some of the registry helper functions to use the unicode versions of the CLSID & registry functions. - Reindent CoGetClassObject and output an error message if the class isn't registered. - Add tests for the touched functions. Dmitry Timoshkov <dmitry@codeweavers.com> - Make remaining OLE interface vtables const. Richard Cohen <richard@daijobu.co.uk> - Base FileMonikerImpl_Save() on XP. - Correct handling of Unicode strings & multibyte locales. - More error checking. - Change ERR to WARN. - Match Windows quick & dirty estimate for GetSizeMax(). Stefan Huehner <stefan@huehner.org> - Fix some more -Wstrict-prototypes warnings. Mike Hearn <mike@navi.cx> - Add some tracing to the IRemUnknown RpcProxyBuffer implementation. Eric Pouech <pouech-eric@wanadoo.fr> - Const correctness fixes. Richard Cohen <richard@daijobu.co.uk> - IEnum::Clone shouldn't do a Reset. Marcus Meissner <marcus@jet.franken.de> - Removed CLSID_CompositeMoniker (conflicting with static definition). Alexandre Julliard <julliard@winehq.org> - Sort entry points alphabetically. svn path=/trunk/; revision=17036
2005-08-03 22:31:39 +00:00
static const IMallocVtbl VT_IMalloc32 =
{
IMalloc_fnQueryInterface,
IMalloc_fnAddRefRelease,
IMalloc_fnAddRefRelease,
IMalloc_fnAlloc,
IMalloc_fnRealloc,
IMalloc_fnFree,
IMalloc_fnGetSize,
IMalloc_fnDidAlloc,
IMalloc_fnHeapMinimize
};
/******************************************************************************
* CoGetMalloc [OLE32.@]
*
* Retrieves the current IMalloc interface for the process.
*
* PARAMS
* context [I] Should always be MEMCTX_TASK.
* imalloc [O] Address where memory allocator object will be stored.
*
* RETURNS
* Success: S_OK.
* Failure: HRESULT code.
*/
HRESULT WINAPI CoGetMalloc(DWORD context, IMalloc **imalloc)
{
if (context != MEMCTX_TASK) {
*imalloc = NULL;
return E_INVALIDARG;
}
*imalloc = &Malloc32.IMalloc_iface;
return S_OK;
}
/***********************************************************************
* CoTaskMemAlloc [OLE32.@]
*
* Allocates memory using the current process memory allocator.
*
* PARAMS
* size [I] Size of the memory block to allocate.
*
* RETURNS
* Success: Pointer to newly allocated memory block.
* Failure: NULL.
*/
LPVOID WINAPI CoTaskMemAlloc(SIZE_T size)
{
return IMalloc_Alloc(&Malloc32.IMalloc_iface,size);
}
/***********************************************************************
* CoTaskMemFree [OLE32.@]
*
* Frees memory allocated from the current process memory allocator.
*
* PARAMS
* ptr [I] Memory block to free.
*
* RETURNS
* Nothing.
*/
VOID WINAPI CoTaskMemFree(LPVOID ptr)
{
IMalloc_Free(&Malloc32.IMalloc_iface, ptr);
}
/***********************************************************************
* CoTaskMemRealloc [OLE32.@]
*
* Allocates memory using the current process memory allocator.
*
* PARAMS
* pvOld [I] Pointer to old memory block.
* size [I] Size of the new memory block.
*
* RETURNS
* Success: Pointer to newly allocated memory block.
* Failure: NULL.
*/
LPVOID WINAPI CoTaskMemRealloc(LPVOID pvOld, SIZE_T size)
{
return IMalloc_Realloc(&Malloc32.IMalloc_iface, pvOld, size);
}
/***********************************************************************
* CoRegisterMallocSpy [OLE32.@]
*
* Registers an object that receives notifications on memory allocations and
* frees.
*
* PARAMS
* pMallocSpy [I] New spy object.
*
* RETURNS
* Success: S_OK.
* Failure: HRESULT code.
*
* NOTES
* if a mallocspy is already registered, we can't do it again since
* only the spy knows, how to free a memory block
*/
HRESULT WINAPI CoRegisterMallocSpy(LPMALLOCSPY pMallocSpy)
{
IMallocSpy* pSpy;
HRESULT hres = E_INVALIDARG;
TRACE("%p\n", pMallocSpy);
if(!pMallocSpy) return E_INVALIDARG;
EnterCriticalSection(&IMalloc32_SpyCS);
if (Malloc32.pSpy)
hres = CO_E_OBJISREG;
else if (SUCCEEDED(IMallocSpy_QueryInterface(pMallocSpy, &IID_IMallocSpy, (void**)&pSpy))) {
Malloc32.pSpy = pSpy;
hres = S_OK;
}
LeaveCriticalSection(&IMalloc32_SpyCS);
return hres;
}
/***********************************************************************
* CoRevokeMallocSpy [OLE32.@]
*
* Revokes a previously registered object that receives notifications on memory
* allocations and frees.
*
* PARAMS
* pMallocSpy [I] New spy object.
*
* RETURNS
* Success: S_OK.
* Failure: HRESULT code.
*
* NOTES
* we can't revoke a malloc spy as long as memory blocks allocated with
* the spy are active since only the spy knows how to free them
*/
HRESULT WINAPI CoRevokeMallocSpy(void)
{
HRESULT hres = S_OK;
TRACE("\n");
EnterCriticalSection(&IMalloc32_SpyCS);
if (!Malloc32.pSpy)
hres = CO_E_OBJNOTREG;
else if (Malloc32.SpyedAllocationsLeft) {
TRACE("SpyReleasePending with %u allocations left\n", Malloc32.SpyedAllocationsLeft);
Malloc32.SpyReleasePending = TRUE;
hres = E_ACCESSDENIED;
} else {
IMallocSpy_Release(Malloc32.pSpy);
Malloc32.pSpy = NULL;
}
LeaveCriticalSection(&IMalloc32_SpyCS);
return hres;
}
/******************************************************************************
* IsValidInterface [OLE32.@]
*
* Determines whether a pointer is a valid interface.
*
* PARAMS
* punk [I] Interface to be tested.
*
* RETURNS
* TRUE, if the passed pointer is a valid interface, or FALSE otherwise.
*/
BOOL WINAPI IsValidInterface(LPUNKNOWN punk)
{
return !(
IsBadReadPtr(punk,4) ||
IsBadReadPtr(punk->lpVtbl,4) ||
IsBadReadPtr(punk->lpVtbl->QueryInterface,9) ||
IsBadCodePtr((FARPROC)punk->lpVtbl->QueryInterface)
);
}