From 8d07772195db2d80e298cac784b037bbfd579549 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A9=20van=20Geldorp?= Date: Wed, 12 Jan 2005 10:23:25 +0000 Subject: [PATCH] Sync to Wine-20050111: Michael Stefaniuc - Do not check for non NULL pointer before HeapFree'ing it. It's redundant. Eric Pouech - Fixed some errors in function prototypes. - ReadFile and WriteFile must be passed a parameter for the number of handled bytes when no overlapped operation is done. - Removed excessive statement (break after return or goto, not useful break, not needed vars...) Robert Shearman - Remove unnecessary WNDPROC casts. - Document how thread-safety is ensured for each member of the stub_manager and ifstub structs. - Make stub_manager ref counted to ensure it doesn't get freed whilst it is still being used. - ifstubs are now freed only when the controlling stub_manager is freed. - Rename stub_manager_ref/unref to stub_manager_ext_addref/release respectively and make then take an unsigned long to prevent malicious callers from passing in a negative value and corrupting the ref count. - Rename iid in wine_marshal_id to ipid and use IPIDs instead of IIDs in the stub manager. - The channel buffer can be NULL if the proxy is disconnected, so check for this before releasing it. - Make the ClassFactory proxy support aggregation. - Document how thread-safety is ensured for each member of the stub_manager and ifstub structs. - Make stub_manager ref counted to ensure it doesn't get freed whilst it is still being used. - ifstubs are now freed only when the controlling stub_manager is freed. - Rename stub_manager_ref/unref to stub_manager_ext_addref/release respectively and make then take an unsigned long to prevent malicious callers from passing in a negative value and corrupting the ref count. - The current architecture cannot handle pipes changing address, so use a static array. Fixes memory corruption that sometimes occurs when using multiple pipes. - Fix race on apartment creation. - Display errors in decimal to make searching for the meaning in winerror.h easier. - Move named pipe macros into rpc.c. - Remove unneeded function. - Implement COM local servers using table marshaling to avoid doing the marshaling in a child thread where COM has not been initialized. - Remove unneeded includes and the unused COMPOBJ_hInstance32 variable. - Make the wine_marshal_id structure more like the DCOM OBJREF structure, by replacing the process id field by apartment id (OXID), changing the users of the process id field to use the new field and renaming the objectid field to oid. - Fix StdMarshalImpl_UnmarshalInterface to invalidate and release its stub when doing a same apartment marshal. - Fixed incorrect unsigned test. - Add tracing for proxy ref count functions. - Release the channel on proxy destruction. - Implement proxy manager. - Add documentation to several functions. - Coding style changes according to the style Mike and I have agreed upon for COM related files. - Use OBJREF on the wire for generic marshaling functions. - Add some function declarations to objbase.h. - Add stubs for server ref counting. - Implement HRESULT marshaling. - Make struct oletls ref counted so that it is only detached from the apartment on the final CoUninitialize. - Decrease the size of the crit sec on destroying an apartment - it is only needed for touching the apartment list. - Small cleanups. Mike Hearn - Implement the COM stub manager, refactor the current stub code. - Begin implementing interface stubs. - Make apartment access thread-safe by introducing refcounting and wider usage of the apartment lock. - Rework OLE TLS management to eliminate uninitialised apartments and parent chaining. - Comment out an assert, as we don't yet implement IRemUnknown. - Propagate apartments through the intermediate threads, make listener thread apartment scoped. - Rename the STUBMGR thread to more accurately reflect its purpose. - Add a DCOM todo list. Mike McCormack - Test and fix a few problems with OLE storage streams. - Allow COM to start services containing COM servers. - Tests and fixes for StgOpenStorage. - Test and fix StgCreateDocFile grfModes. Paul Vriens - use Interlocked* functions in AddRef and Release. - store the result of the Interlocked functions and use only this. Francois Gouget - Assorted spelling fixes. Alexandre Julliard - Janitorial: C booleans must not be compared against TRUE. Bill Medland - Corrected testing for multithreaded (based upon observations by Paul Vriens, Christian Costa and Robert Shearman). - Added TRACE for investigating OXID errors. svn path=/trunk/; revision=12952 --- reactos/include/wine/list.h | 153 +++ reactos/include/wine/objidl.h | 63 ++ reactos/lib/ole32/Makefile.in | 3 +- reactos/lib/ole32/bindctx.c | 9 +- reactos/lib/ole32/clipboard.c | 5 +- reactos/lib/ole32/compobj.c | 493 +++++----- reactos/lib/ole32/compobj_private.h | 187 ++-- reactos/lib/ole32/compositemoniker.c | 2 +- reactos/lib/ole32/datacache.c | 3 +- reactos/lib/ole32/defaulthandler.c | 30 +- reactos/lib/ole32/errorinfo.c | 40 +- reactos/lib/ole32/filemoniker.c | 7 +- reactos/lib/ole32/ftmarshal.c | 2 - reactos/lib/ole32/hglobalstream.c | 3 +- reactos/lib/ole32/ifs.c | 12 +- reactos/lib/ole32/ifs.h | 2 +- reactos/lib/ole32/itemmoniker.c | 8 +- reactos/lib/ole32/marshal.c | 1303 +++++++++++++++++--------- reactos/lib/ole32/memlockbytes.c | 3 - reactos/lib/ole32/moniker.c | 6 +- reactos/lib/ole32/ole2.c | 19 +- reactos/lib/ole32/oleobj.c | 11 +- reactos/lib/ole32/oleproxy.c | 27 +- reactos/lib/ole32/rpc.c | 399 ++++++-- reactos/lib/ole32/stg_bigblockfile.c | 3 +- reactos/lib/ole32/stg_stream.c | 3 + reactos/lib/ole32/storage32.c | 82 +- 27 files changed, 1959 insertions(+), 919 deletions(-) create mode 100644 reactos/include/wine/list.h diff --git a/reactos/include/wine/list.h b/reactos/include/wine/list.h new file mode 100644 index 00000000000..92b84d8303b --- /dev/null +++ b/reactos/include/wine/list.h @@ -0,0 +1,153 @@ +/* + * Linked lists support + * + * Copyright (C) 2002 Alexandre Julliard + * + * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __WINE_SERVER_LIST_H +#define __WINE_SERVER_LIST_H + +struct list +{ + struct list *next; + struct list *prev; +}; + +/* Define a list like so: + * + * struct gadget + * { + * struct list entry; <-- doesn't have to be the first item in the struct + * int a, b; + * }; + * + * static struct list global_gadgets = LIST_INIT( global_gadgets ); + * + * or + * + * struct some_global_thing + * { + * struct list gadgets; + * }; + * + * list_init( &some_global_thing->gadgets ); + * + * Manipulate it like this: + * + * list_add_head( &global_gadgets, &new_gadget->entry ); + * list_remove( &new_gadget->entry ); + * list_add_after( &some_random_gadget->entry, &new_gadget->entry ); + * + * And to iterate over it: + * + * struct list *cursor; + * LIST_FOR_EACH( cursor, &global_gadgets ) + * { + * struct gadget *gadget = LIST_ENTRY( cursor, struct gadget, entry ); + * } + * + */ + +/* add an element after the specified one */ +inline static void list_add_after( struct list *elem, struct list *to_add ) +{ + to_add->next = elem->next; + to_add->prev = elem; + elem->next->prev = to_add; + elem->next = to_add; +} + +/* add an element before the specified one */ +inline static void list_add_before( struct list *elem, struct list *to_add ) +{ + to_add->next = elem; + to_add->prev = elem->prev; + elem->prev->next = to_add; + elem->prev = to_add; +} + +/* add element at the head of the list */ +inline static void list_add_head( struct list *list, struct list *elem ) +{ + list_add_after( list, elem ); +} + +/* add element at the tail of the list */ +inline static void list_add_tail( struct list *list, struct list *elem ) +{ + list_add_before( list, elem ); +} + +/* remove an element from its list */ +inline static void list_remove( struct list *elem ) +{ + elem->next->prev = elem->prev; + elem->prev->next = elem->next; +} + +/* get the next element */ +inline static struct list *list_next( struct list *list, struct list *elem ) +{ + struct list *ret = elem->next; + if (elem->next == list) ret = NULL; + return ret; +} + +/* get the previous element */ +inline static struct list *list_prev( struct list *list, struct list *elem ) +{ + struct list *ret = elem->prev; + if (elem->prev == list) ret = NULL; + return ret; +} + +/* get the first element */ +inline static struct list *list_head( struct list *list ) +{ + return list_next( list, list ); +} + +/* get the last element */ +inline static struct list *list_tail( struct list *list ) +{ + return list_prev( list, list ); +} + +/* check if a list is empty */ +inline static int list_empty( struct list *list ) +{ + return list->next == list; +} + +/* initialize a list */ +inline static void list_init( struct list *list ) +{ + list->next = list->prev = list; +} + +/* iterate through the list */ +#define LIST_FOR_EACH(cursor,list) \ + for ((cursor) = (list)->next; (cursor) != (list); (cursor) = (cursor)->next) + +/* macros for statically initialized lists */ +#define LIST_INIT(list) { &(list), &(list) } + +/* get pointer to object containing list element */ +#define LIST_ENTRY(elem, type, field) \ + ((type *)((char *)(elem) - (unsigned int)(&((type *)0)->field))) + +#endif /* __WINE_SERVER_LIST_H */ diff --git a/reactos/include/wine/objidl.h b/reactos/include/wine/objidl.h index d118b9051dc..b9f9eecf0c1 100644 --- a/reactos/include/wine/objidl.h +++ b/reactos/include/wine/objidl.h @@ -1943,4 +1943,67 @@ void __RPC_STUB IGlobalInterfaceTable_GetInterfaceFromGlobal_Stub( #endif /* __IGlobalInterfaceTable_INTERFACE_DEFINED__ */ +#ifndef __IInternalUnknown_FWD_DEFINED__ +#define __IInternalUnknown_FWD_DEFINED__ +typedef struct IInternalUnknown IInternalUnknown; +#endif + +/***************************************************************************** + * IInternalUnknown interface + */ +#ifndef __IInternalUnknown_INTERFACE_DEFINED__ +#define __IInternalUnknown_INTERFACE_DEFINED__ + +DEFINE_GUID(IID_IInternalUnknown, 0x00000021, 0x0000, 0x0000, 0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x46); +#if defined(__cplusplus) && !defined(CINTERFACE) +struct IInternalUnknown : public IUnknown +{ + virtual HRESULT STDMETHODCALLTYPE QueryInternalInterface( + REFIID riid, + void** ppv) = 0; + +}; +#else +typedef struct IInternalUnknownVtbl IInternalUnknownVtbl; +struct IInternalUnknown { + const IInternalUnknownVtbl* lpVtbl; +}; +struct IInternalUnknownVtbl { + BEGIN_INTERFACE + + /*** IUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInterface)( + IInternalUnknown* This, + REFIID riid, + void** ppvObject); + + ULONG (STDMETHODCALLTYPE *AddRef)( + IInternalUnknown* This); + + ULONG (STDMETHODCALLTYPE *Release)( + IInternalUnknown* This); + + /*** IInternalUnknown methods ***/ + HRESULT (STDMETHODCALLTYPE *QueryInternalInterface)( + IInternalUnknown* This, + REFIID riid, + void** ppv); + + END_INTERFACE +}; + +#ifdef COBJMACROS +/*** IUnknown methods ***/ +#define IInternalUnknown_QueryInterface(p,a,b) (p)->lpVtbl->QueryInterface(p,a,b) +#define IInternalUnknown_AddRef(p) (p)->lpVtbl->AddRef(p) +#define IInternalUnknown_Release(p) (p)->lpVtbl->Release(p) +/*** IInternalUnknown methods ***/ +#define IInternalUnknown_QueryInternalInterface(p,a,b) (p)->lpVtbl->QueryInternalInterface(p,a,b) +#endif + +#endif + +#endif /* __IInternalUnknown_INTERFACE_DEFINED__ */ + + #endif /* __WINE_OBJIDL_H */ diff --git a/reactos/lib/ole32/Makefile.in b/reactos/lib/ole32/Makefile.in index 59f42bef30e..229f1367c1a 100644 --- a/reactos/lib/ole32/Makefile.in +++ b/reactos/lib/ole32/Makefile.in @@ -35,7 +35,8 @@ C_SRCS = \ rpc.c \ stg_bigblockfile.c \ stg_stream.c \ - storage32.c + storage32.c \ + stubmanager.c C_SRCS16 = \ memlockbytes16.c \ diff --git a/reactos/lib/ole32/bindctx.c b/reactos/lib/ole32/bindctx.c index 9fab4715c6b..58a647df18d 100644 --- a/reactos/lib/ole32/bindctx.c +++ b/reactos/lib/ole32/bindctx.c @@ -275,8 +275,7 @@ HRESULT WINAPI BindCtxImpl_RevokeObjectBound(IBindCtx* iface, IUnknown* punk) if(This->bindCtxTable[index].pObj) IUnknown_Release(This->bindCtxTable[index].pObj); - if(This->bindCtxTable[index].pkeyObj) - HeapFree(GetProcessHeap(),0,This->bindCtxTable[index].pkeyObj); + HeapFree(GetProcessHeap(),0,This->bindCtxTable[index].pkeyObj); /* left-shift all elements in the right side of the current revoked object */ for(j=index; jbindCtxTableLastIndex-1; j++) @@ -302,8 +301,7 @@ HRESULT WINAPI BindCtxImpl_ReleaseBoundObjects(IBindCtx* iface) { if(This->bindCtxTable[i].pObj) IUnknown_Release(This->bindCtxTable[i].pObj); - if(This->bindCtxTable[i].pkeyObj) - HeapFree(GetProcessHeap(),0,This->bindCtxTable[i].pkeyObj); + HeapFree(GetProcessHeap(),0,This->bindCtxTable[i].pkeyObj); } This->bindCtxTableLastIndex = 0; @@ -472,8 +470,7 @@ HRESULT WINAPI BindCtxImpl_RevokeObjectParam(IBindCtx* iface,LPOLESTR ppenum) /* release the object if it's found */ if(This->bindCtxTable[index].pObj) IUnknown_Release(This->bindCtxTable[index].pObj); - if(This->bindCtxTable[index].pkeyObj) - HeapFree(GetProcessHeap(),0,This->bindCtxTable[index].pkeyObj); + HeapFree(GetProcessHeap(),0,This->bindCtxTable[index].pkeyObj); /* remove the object from the table with a left-shifting of all objects in the right side */ for(j=index; jbindCtxTableLastIndex-1; j++) diff --git a/reactos/lib/ole32/clipboard.c b/reactos/lib/ole32/clipboard.c index 9bbd6932430..e21eb5bc061 100644 --- a/reactos/lib/ole32/clipboard.c +++ b/reactos/lib/ole32/clipboard.c @@ -736,7 +736,7 @@ static HWND OLEClipbrd_CreateWindow() * We don't bother doing this since the FindClassByAtom code * would have to be changed to deal with this idiosyncrasy. */ wcex.style = CS_GLOBALCLASS; - wcex.lpfnWndProc = (WNDPROC)OLEClipbrd_WndProc; + wcex.lpfnWndProc = OLEClipbrd_WndProc; wcex.hInstance = 0; wcex.lpszClassName = OLEClipbrd_WNDCLASS; @@ -1489,8 +1489,7 @@ CLEANUP: /* * Free the array of FORMATETC's */ - if (afmt) - HeapFree(GetProcessHeap(), 0, afmt); + HeapFree(GetProcessHeap(), 0, afmt); /* * Close Windows clipboard diff --git a/reactos/lib/ole32/compobj.c b/reactos/lib/ole32/compobj.c index 17cff88167f..1ed832a8a12 100644 --- a/reactos/lib/ole32/compobj.c +++ b/reactos/lib/ole32/compobj.c @@ -21,6 +21,44 @@ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Note + * 1. COINIT_MULTITHREADED is 0; it is the lack of COINIT_APARTMENTTHREADED + * Therefore do not test against COINIT_MULTITHREADED + * + * TODO list: (items bunched together depend on each other) + * + * - Switch wine_marshal_id to use IPIDs not IIDs + * - Once that's done, replace wine_marshal_id with STDOBJREF + * + * - Rewrite the CoLockObjectExternal code, it does totally the wrong + * thing currently (should be controlling the stub manager) + * + * - Make the MTA dynamically allocated and refcounted + * - Free the ReservedForOle data in DllMain(THREAD_DETACH) + * + * - Implement the service control manager (in rpcss) to keep track + * of registered class objects: ISCM::ServerRegisterClsid et al + * - Implement the OXID resolver so we don't need magic pipe names for + * clients and servers to meet up + * - Flip our marshalling on top of the RPC runtime transport API, + * so we no longer use named pipes to communicate + * - Rework threading so re-entrant calls don't need to be sent on + * the incoming pipe + * - Implement RPC thread affinity (should fix InstallShield painting + * problems) + * + * - Implement IRemUnknown and marshalling for it, then use that for + * reffing/unreffing the stub manager from a proxy instead of our + * current hack of simply reffing the stub manager once when it's + * registered. + * - Implement table marshalling, then use it to let us do the final + * rework of the threading + * + * - Make our custom marshalling use NDR to be wire compatible with + * native DCOM + * + * */ #include "config.h" @@ -61,15 +99,15 @@ typedef LPCSTR LPCOLESTR16; * * TODO: Most of these things will have to be made thread-safe. */ -HINSTANCE COMPOBJ_hInstance32 = 0; static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk); -static void COM_RevokeAllClasses(); -static void COM_ExternalLockFreeList(); +static void COM_RevokeAllClasses(void); +static void COM_ExternalLockFreeList(void); const CLSID CLSID_StdGlobalInterfaceTable = { 0x00000323, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} }; -APARTMENT MTA, *apts; +APARTMENT MTA; +static struct list apts = LIST_INIT( apts ); static CRITICAL_SECTION csApartment; static CRITICAL_SECTION_DEBUG critsect_debug = @@ -102,7 +140,7 @@ typedef struct tagRegisteredClass DWORD runContext; DWORD connectFlags; DWORD dwCookie; - HANDLE hThread; /* only for localserver */ + LPSTREAM pMarshaledData; /* FIXME: only really need to store OXID and IPID */ struct tagRegisteredClass* nextClass; } RegisteredClass; @@ -206,6 +244,7 @@ static void COM_UninitMTA(void) MTA.oxid = 0; } + /* creates an apartment structure which stores OLE thread-local * information. Call with COINIT_UNINITIALIZED to create an apartment * that will be initialized with a model later. Note: do not call @@ -213,81 +252,138 @@ static void COM_UninitMTA(void) * with a different COINIT value */ APARTMENT* COM_CreateApartment(DWORD model) { - APARTMENT *apt; - BOOL create = (NtCurrentTeb()->ReservedForOle == NULL); + APARTMENT *apt = COM_CurrentApt(); - if (create) + if (!apt) { + if (!(model & COINIT_APARTMENTTHREADED)) /* See note 1 above */ + { + TRACE("thread 0x%lx is entering the multithreaded apartment\n", GetCurrentThreadId()); + COM_CurrentInfo()->apt = &MTA; + return COM_CurrentInfo()->apt; + } + + TRACE("creating new apartment, model=%ld\n", model); + apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(APARTMENT)); apt->tid = GetCurrentThreadId(); DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &apt->thread, THREAD_ALL_ACCESS, FALSE, 0); - } - else - apt = NtCurrentTeb()->ReservedForOle; - apt->model = model; - if (model & COINIT_APARTMENTTHREADED) { - /* FIXME: how does windoze create OXIDs? */ - apt->oxid = MTA.oxid | GetCurrentThreadId(); - apt->win = CreateWindowA(aptWinClass, NULL, 0, - 0, 0, 0, 0, - 0, 0, OLE32_hInstance, NULL); - InitializeCriticalSection(&apt->cs); + list_init(&apt->proxies); + list_init(&apt->stubmgrs); + apt->oidc = 1; + apt->refs = 1; + InitializeCriticalSection(&apt->cs); + + apt->model = model; + + /* we don't ref the apartment as CoInitializeEx will do it for us */ + + if (model & COINIT_APARTMENTTHREADED) + { + /* FIXME: how does windoze create OXIDs? */ + apt->oxid = MTA.oxid | GetCurrentThreadId(); + TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid)); + apt->win = CreateWindowA(aptWinClass, NULL, 0, + 0, 0, 0, 0, + 0, 0, OLE32_hInstance, NULL); + } + + EnterCriticalSection(&csApartment); + list_add_head(&apts, &apt->entry); + LeaveCriticalSection(&csApartment); + + COM_CurrentInfo()->apt = apt; } - else if (!(model & COINIT_UNINITIALIZED)) { - apt->parent = &MTA; - apt->oxid = MTA.oxid; - } - EnterCriticalSection(&csApartment); - if (create) - { - if (apts) apts->prev = apt; - apt->next = apts; - apts = apt; - } - LeaveCriticalSection(&csApartment); - NtCurrentTeb()->ReservedForOle = apt; + return apt; } -static void COM_DestroyApartment(APARTMENT *apt) +DWORD COM_ApartmentAddRef(struct apartment *apt) { - EnterCriticalSection(&csApartment); - if (apt->prev) apt->prev->next = apt->next; - if (apt->next) apt->next->prev = apt->prev; - if (apts == apt) apts = apt->next; - apt->prev = NULL; apt->next = NULL; - LeaveCriticalSection(&csApartment); - if (apt->model & COINIT_APARTMENTTHREADED) { - if (apt->win) DestroyWindow(apt->win); - DeleteCriticalSection(&apt->cs); - } - CloseHandle(apt->thread); - HeapFree(GetProcessHeap(), 0, apt); + return InterlockedIncrement(&apt->refs); } -/* The given OXID must be local to this process: you cannot use apartment - windows to send RPCs to other processes. This all needs to move to rpcrt4 */ -HWND COM_GetApartmentWin(OXID oxid) +DWORD COM_ApartmentRelease(struct apartment *apt) { - APARTMENT *apt; - HWND win = 0; + DWORD ret; + + ret = InterlockedDecrement(&apt->refs); + if (ret == 0) + { + TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid)); + + EnterCriticalSection(&csApartment); + list_remove(&apt->entry); + LeaveCriticalSection(&csApartment); + + MARSHAL_Disconnect_Proxies(apt); + + if (apt->win) DestroyWindow(apt->win); + + if (!list_empty(&apt->stubmgrs)) + { + FIXME("Destroy outstanding stubs\n"); + } + + if (apt->filter) IUnknown_Release(apt->filter); + + + DeleteCriticalSection(&apt->cs); + CloseHandle(apt->thread); + HeapFree(GetProcessHeap(), 0, apt); + + apt = NULL; + } + + return ret; +} + +/* The given OXID must be local to this process: you cannot use + * apartment windows to send RPCs to other processes. This all needs + * to move to rpcrt4. + * + * The ref parameter is here mostly to ensure people remember that + * they get one, you should normally take a ref for thread safety. + */ +APARTMENT *COM_ApartmentFromOXID(OXID oxid, BOOL ref) +{ + APARTMENT *result = NULL; + struct list *cursor; EnterCriticalSection(&csApartment); - apt = apts; - while (apt && apt->oxid != oxid) apt = apt->next; - if (apt) win = apt->win; + LIST_FOR_EACH( cursor, &apts ) + { + struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry ); + if (apt->oxid == oxid) + { + result = apt; + if (ref) COM_ApartmentAddRef(result); + break; + } + } LeaveCriticalSection(&csApartment); - return win; + + return result; +} + +HWND COM_GetApartmentWin(OXID oxid, BOOL ref) +{ + APARTMENT *apt; + + apt = COM_ApartmentFromOXID(oxid, ref); + if (!apt) return NULL; + + return apt->win; } /* Currently inter-thread marshalling is not fully implemented, so this does nothing */ static LRESULT CALLBACK COM_AptWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { return DefWindowProcA(hWnd, msg, wParam, lParam); -} +} /***************************************************************************** * This section contains OpenDllList implemantation @@ -418,8 +514,7 @@ HRESULT WINAPI CoInitialize( * CoUninitialize */ HRESULT WINAPI CoInitializeEx( - LPVOID lpReserved, /* [in] pointer to win32 malloc interface - (obsolete, should be NULL) */ + LPVOID lpReserved, /* [in] pointer to win32 malloc interface (obsolete, should be NULL) */ DWORD dwCoInit /* [in] A value from COINIT specifies the threading model */ ) { @@ -433,21 +528,6 @@ HRESULT WINAPI CoInitializeEx( ERR("(%p, %x) - Bad parameter passed-in %p, must be an old Windows Application\n", lpReserved, (int)dwCoInit, lpReserved); } - apt = NtCurrentTeb()->ReservedForOle; - if (apt && !(apt->model == COINIT_UNINITIALIZED)) - { - if (dwCoInit != apt->model) - { - /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine - code then we are probably using the wrong threading model to implement that API. */ - ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit); - return RPC_E_CHANGED_MODE; - } - hr = S_FALSE; - } - else - hr = S_OK; - /* * Check the lock count. If this is the first time going through the initialize * process, we have to initialize the libraries. @@ -463,13 +543,25 @@ HRESULT WINAPI CoInitializeEx( COM_InitMTA(); + /* we may need to defer this until after apartment initialisation */ RunningObjectTableImpl_Initialize(); } - if (!apt || apt->model == COINIT_UNINITIALIZED) apt = COM_CreateApartment(dwCoInit); + if (!(apt = COM_CurrentInfo()->apt)) + { + apt = COM_CreateApartment(dwCoInit); + if (!apt) return E_OUTOFMEMORY; + } + else if (dwCoInit != apt->model) + { + /* Changing the threading model after it's been set is illegal. If this warning is triggered by Wine + code then we are probably using the wrong threading model to implement that API. */ + ERR("Attempt to change threading model of this apartment from 0x%lx to 0x%lx\n", apt->model, dwCoInit); + COM_ApartmentRelease(apt); + return RPC_E_CHANGED_MODE; + } - InterlockedIncrement(&apt->inits); - if (hr == S_OK) NtCurrentTeb()->ReservedForOle = apt; + COM_CurrentInfo()->inits++; return hr; } @@ -480,14 +572,20 @@ HRESULT WINAPI CoInitializeEx( void COM_FlushMessageQueue(void) { MSG message; - APARTMENT *apt = NtCurrentTeb()->ReservedForOle; + APARTMENT *apt = COM_CurrentApt(); if (!apt || !apt->win) return; TRACE("Flushing STA message queue\n"); - while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE)) { - if (message.hwnd != apt->win) continue; + while (PeekMessageA(&message, NULL, 0, 0, PM_REMOVE)) + { + if (message.hwnd != apt->win) + { + WARN("discarding message 0x%x for window %p\n", message.message, message.hwnd); + continue; + } + TranslateMessage(&message); DispatchMessageA(&message); } @@ -511,17 +609,25 @@ void COM_FlushMessageQueue(void) */ void WINAPI CoUninitialize(void) { + struct oletls * info = COM_CurrentInfo(); LONG lCOMRefCnt; - APARTMENT *apt; TRACE("()\n"); - apt = NtCurrentTeb()->ReservedForOle; - if (!apt) return; - if (InterlockedDecrement(&apt->inits)==0) { - NtCurrentTeb()->ReservedForOle = NULL; - COM_DestroyApartment(apt); - apt = NULL; + /* will only happen on OOM */ + if (!info) return; + + /* sanity check */ + if (!info->inits) + { + ERR("Mismatched CoUninitialize\n"); + return; + } + + if (!--info->inits) + { + COM_ApartmentRelease(info->apt); + info->apt = NULL; } /* @@ -536,14 +642,6 @@ void WINAPI CoUninitialize(void) RunningObjectTableImpl_UnInitialize(); - /* disconnect proxies to release the corresponding stubs. - * It is confirmed in "Essential COM" in the sub-chapter on - * "Lifecycle Management and Marshalling" that the native version also - * does some kind of proxy cleanup in this function. - * FIXME: does it just disconnect or completely destroy the proxies? - * FIXME: should this be in the apartment destructor? */ - MARSHAL_Disconnect_Proxies(); - /* Release the references to the registered class objects */ COM_RevokeAllClasses(); @@ -1091,117 +1189,24 @@ end: return hr; } -static DWORD WINAPI -_LocalServerThread(LPVOID param) { - HANDLE hPipe; - char pipefn[200]; - RegisteredClass *newClass = (RegisteredClass*)param; - HRESULT hres; - IStream *pStm; - STATSTG ststg; - unsigned char *buffer; - int buflen; - IClassFactory *classfac; - LARGE_INTEGER seekto; - ULARGE_INTEGER newpos; - ULONG res; - - TRACE("Starting threader for %s.\n",debugstr_guid(&newClass->classIdentifier)); - - strcpy(pipefn,PIPEPREF); - WINE_StringFromCLSID(&newClass->classIdentifier,pipefn+strlen(PIPEPREF)); - - hPipe = CreateNamedPipeA( pipefn, PIPE_ACCESS_DUPLEX, - PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, - 4096, 4096, NMPWAIT_USE_DEFAULT_WAIT, NULL ); - if (hPipe == INVALID_HANDLE_VALUE) { - FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError()); - return 1; - } - while (1) { - if (!ConnectNamedPipe(hPipe,NULL)) { - ERR("Failure during ConnectNamedPipe %lx, ABORT!\n",GetLastError()); - break; - } - - TRACE("marshalling IClassFactory to client\n"); - - hres = IUnknown_QueryInterface(newClass->classObject,&IID_IClassFactory,(LPVOID*)&classfac); - if (hres) return hres; - - hres = CreateStreamOnHGlobal(0,TRUE,&pStm); - if (hres) { - FIXME("Failed to create stream on hglobal.\n"); - return hres; - } - hres = CoMarshalInterface(pStm,&IID_IClassFactory,(LPVOID)classfac,0,NULL,0); - if (hres) { - FIXME("CoMarshalInterface failed, %lx!\n",hres); - return hres; - } - - IUnknown_Release(classfac); /* is this right? */ - - hres = IStream_Stat(pStm,&ststg,0); - if (hres) return hres; - - buflen = ststg.cbSize.u.LowPart; - buffer = HeapAlloc(GetProcessHeap(),0,buflen); - seekto.u.LowPart = 0; - seekto.u.HighPart = 0; - hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos); - if (hres) { - FIXME("IStream_Seek failed, %lx\n",hres); - return hres; - } - - hres = IStream_Read(pStm,buffer,buflen,&res); - if (hres) { - FIXME("Stream Read failed, %lx\n",hres); - return hres; - } - - IStream_Release(pStm); - - WriteFile(hPipe,buffer,buflen,&res,NULL); - FlushFileBuffers(hPipe); - DisconnectNamedPipe(hPipe); - - TRACE("done marshalling IClassFactory\n"); - } - CloseHandle(hPipe); - return 0; -} - /****************************************************************************** * CoRegisterClassObject [OLE32.@] - * - * This method will register the class object for a given class - * ID. Servers housed in EXE files use this method instead of - * exporting DllGetClassObject to allow other code to connect to their - * objects. * - * When a class object (an object which implements IClassFactory) is - * registered in this way, a new thread is started which listens for - * connections on a named pipe specific to the registered CLSID. When - * something else connects to it, it writes out the marshalled - * IClassFactory interface to the pipe. The code on the other end uses - * this buffer to unmarshal the class factory, and can then call - * methods on it. - * - * In Windows, such objects are registered with the RPC endpoint - * mapper, not with a unique named pipe. - * - * MSDN claims that multiple interface registrations are legal, but we - * can't do that with our current implementation. + * Registers the class object for a given class ID. Servers housed in EXE + * files use this method instead of exporting DllGetClassObject to allow + * other code to connect to their objects. * * RETURNS - * S_OK on success, - * E_INVALIDARG if lpdwRegister or pUnk are NULL, + * S_OK on success, + * E_INVALIDARG if lpdwRegister or pUnk are NULL, * CO_E_OBJISREG if the object is already registered. We should not return this. * * SEE ALSO * CoRevokeClassObject, CoGetClassObject + * + * BUGS + * MSDN claims that multiple interface registrations are legal, but we + * can't do that with our current implementation. */ HRESULT WINAPI CoRegisterClassObject( REFCLSID rclsid, /* [in] CLSID of the object to register */ @@ -1220,6 +1225,12 @@ HRESULT WINAPI CoRegisterClassObject( if ( (lpdwRegister==0) || (pUnk==0) ) return E_INVALIDARG; + if (!COM_CurrentApt()) + { + ERR("COM was not initialized\n"); + return CO_E_NOTINITIALIZED; + } + *lpdwRegister = 0; /* @@ -1243,7 +1254,7 @@ HRESULT WINAPI CoRegisterClassObject( newClass->connectFlags = flags; /* * Use the address of the chain node as the cookie since we are sure it's - * unique. + * unique. FIXME: not on 64-bit platforms. */ newClass->dwCookie = (DWORD)newClass; newClass->nextClass = firstRegisteredClass; @@ -1261,10 +1272,30 @@ HRESULT WINAPI CoRegisterClassObject( *lpdwRegister = newClass->dwCookie; if (dwClsContext & CLSCTX_LOCAL_SERVER) { - DWORD tid; + IClassFactory *classfac; - STUBMGR_Start(); - newClass->hThread=CreateThread(NULL,0,_LocalServerThread,newClass,0,&tid); + hr = IUnknown_QueryInterface(newClass->classObject, &IID_IClassFactory, + (LPVOID*)&classfac); + if (hr) return hr; + + hr = CreateStreamOnHGlobal(0, TRUE, &newClass->pMarshaledData); + if (hr) { + FIXME("Failed to create stream on hglobal, %lx\n", hr); + IUnknown_Release(classfac); + return hr; + } + hr = CoMarshalInterface(newClass->pMarshaledData, &IID_IClassFactory, + (LPVOID)classfac, MSHCTX_LOCAL, NULL, + MSHLFLAGS_TABLESTRONG); + if (hr) { + FIXME("CoMarshalInterface failed, %lx!\n",hr); + IUnknown_Release(classfac); + return hr; + } + + IUnknown_Release(classfac); + + RPC_StartLocalServer(&newClass->classIdentifier, newClass->pMarshaledData); } return S_OK; } @@ -1310,6 +1341,15 @@ HRESULT WINAPI CoRevokeClassObject( */ IUnknown_Release(curClass->classObject); + if (curClass->pMarshaledData) + { + LARGE_INTEGER zero; + memset(&zero, 0, sizeof(zero)); + /* FIXME: stop local server thread */ + IStream_Seek(curClass->pMarshaledData, zero, SEEK_SET, NULL); + CoReleaseMarshalData(curClass->pMarshaledData); + } + /* * Free the memory used by the chain node. */ @@ -1509,7 +1549,7 @@ HRESULT WINAPI GetClassFile(LPCOLESTR filePathName,CLSID *pclsid) pat=ReadPatternFromRegistry(i,j); hFile=CreateFileW(filePathName,,,,,,hFile); SetFilePosition(hFile,pat.offset); - ReadFile(hFile,buf,pat.size,NULL,NULL); + ReadFile(hFile,buf,pat.size,&r,NULL); if (memcmp(buf&pat.mask,pat.pattern.pat.size)==0){ *pclsid=ReadCLSIDFromRegistry(i); @@ -1573,7 +1613,7 @@ HRESULT WINAPI CoCreateInstance( LPCLASSFACTORY lpclf = 0; if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED; - + /* * Sanity check */ @@ -1590,15 +1630,15 @@ HRESULT WINAPI CoCreateInstance( * Rather than create a class factory, we can just check for it here */ if (IsEqualIID(rclsid, &CLSID_StdGlobalInterfaceTable)) { - if (StdGlobalInterfaceTableInstance == NULL) + if (StdGlobalInterfaceTableInstance == NULL) StdGlobalInterfaceTableInstance = StdGlobalInterfaceTable_Construct(); hres = IGlobalInterfaceTable_QueryInterface( (IGlobalInterfaceTable*) StdGlobalInterfaceTableInstance, iid, ppv); if (hres) return hres; - + TRACE("Retrieved GIT (%p)\n", *ppv); return S_OK; } - + /* * Get a class factory to construct the object we want. */ @@ -1982,6 +2022,8 @@ HRESULT WINAPI CoLockObjectExternal( BOOL fLock, /* [in] do lock */ BOOL fLastUnlockReleases) /* [in] unlock all */ { + TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n", + pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE"); if (fLock) { /* @@ -2015,19 +2057,19 @@ HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) { */ HRESULT WINAPI CoGetState(IUnknown ** ppv) { - APARTMENT * apt = COM_CurrentInfo(); + HRESULT hr = E_FAIL; - FIXME("\n"); + *ppv = NULL; - if(apt && apt->state) { - IUnknown_AddRef(apt->state); - *ppv = apt->state; - FIXME("-- %p\n", *ppv); - return S_OK; - } - *ppv = NULL; - return E_FAIL; + if (COM_CurrentInfo()->state) + { + IUnknown_AddRef(COM_CurrentInfo()->state); + *ppv = COM_CurrentInfo()->state; + TRACE("apt->state=%p\n", COM_CurrentInfo()->state); + hr = S_OK; + } + return hr; } /*********************************************************************** @@ -2036,22 +2078,17 @@ HRESULT WINAPI CoGetState(IUnknown ** ppv) */ HRESULT WINAPI CoSetState(IUnknown * pv) { - APARTMENT * apt = COM_CurrentInfo(); + if (pv) IUnknown_AddRef(pv); - if (!apt) apt = COM_CreateApartment(COINIT_UNINITIALIZED); + if (COM_CurrentInfo()->state) + { + TRACE("-- release %p now\n", COM_CurrentInfo()->state); + IUnknown_Release(COM_CurrentInfo()->state); + } - FIXME("(%p),stub!\n", pv); + COM_CurrentInfo()->state = pv; - if (pv) { - IUnknown_AddRef(pv); - } - - if (apt->state) { - TRACE("-- release %p now\n", apt->state); - IUnknown_Release(apt->state); - } - apt->state = pv; - return S_OK; + return S_OK; } @@ -2206,7 +2243,7 @@ HRESULT WINAPI CoGetTreatAsClass(REFCLSID clsidOld, LPCLSID clsidNew) done: if (hkey) RegCloseKey(hkey); return res; - + } /*********************************************************************** diff --git a/reactos/lib/ole32/compobj_private.h b/reactos/lib/ole32/compobj_private.h index 2ba004eef90..e950eeaca33 100644 --- a/reactos/lib/ole32/compobj_private.h +++ b/reactos/lib/ole32/compobj_private.h @@ -5,6 +5,7 @@ * Copyright 1999 Sylvain St-Germain * Copyright 2002 Marcus Meissner * Copyright 2003 Ove Kåven, TransGaming Technologies + * Copyright 2004 Mike Hearn, CodeWeavers Inc * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -28,6 +29,8 @@ #include +#include "wine/list.h" + #include "windef.h" #include "winbase.h" #include "wtypes.h" @@ -35,12 +38,8 @@ #include "winreg.h" #include "winternl.h" -/* Windows maps COINIT values to 0x80 for apartment threaded, 0x140 - * for free threaded, and 0 for uninitialized apartments. There is - * no real advantage in us doing this and certainly no release version - * of an app should be poking around with these flags. So we need a - * special value for uninitialized */ -#define COINIT_UNINITIALIZED 0x100 +struct apartment; + /* exported interface */ typedef struct tagXIF { @@ -56,7 +55,7 @@ typedef struct tagXIF { /* exported object */ typedef struct tagXOBJECT { IRpcStubBufferVtbl *lpVtbl; - struct tagAPARTMENT *parent; + struct apartment *parent; struct tagXOBJECT *next; LPUNKNOWN obj; /* object identity (IUnknown) */ OID oid; /* object ID */ @@ -65,51 +64,54 @@ typedef struct tagXOBJECT { DWORD refs; /* external reference count */ } XOBJECT; -/* imported interface */ -typedef struct tagIIF { - struct tagIIF *next; +/* imported interface proxy */ +struct ifproxy +{ + struct list entry; LPVOID iface; /* interface pointer */ IID iid; /* interface ID */ IPID ipid; /* imported interface ID */ LPRPCPROXYBUFFER proxy; /* interface proxy */ DWORD refs; /* imported (public) references */ - HRESULT hres; /* result of proxy creation attempt */ -} IIF; +}; -/* imported object */ -typedef struct tagIOBJECT { - IRemUnknownVtbl *lpVtbl; - struct tagAPARTMENT *parent; - struct tagIOBJECT *next; +/* imported object / proxy manager */ +struct proxy_manager +{ + const IInternalUnknownVtbl *lpVtbl; + struct apartment *parent; + struct list entry; LPRPCCHANNELBUFFER chan; /* channel to object */ OXID oxid; /* object exported ID */ OID oid; /* object ID */ - IPID ipid; /* first imported interface ID */ - IIF *ifaces; /* imported interfaces */ + struct list interfaces; /* imported interfaces */ DWORD refs; /* proxy reference count */ -} IOBJECT; + CRITICAL_SECTION cs; /* thread safety for this object and children */ +}; -/* apartment */ -typedef struct tagAPARTMENT { - struct tagAPARTMENT *next, *prev, *parent; +/* this needs to become a COM object that implements IRemUnknown */ +struct apartment +{ + struct list entry; + + DWORD refs; /* refcount of the apartment */ DWORD model; /* threading model */ - DWORD inits; /* CoInitialize count */ DWORD tid; /* thread id */ HANDLE thread; /* thread handle */ OXID oxid; /* object exporter ID */ - OID oidc; /* object ID counter */ + OID oidc; /* object ID counter, starts at 1, zero is invalid OID */ HWND win; /* message window */ CRITICAL_SECTION cs; /* thread safety */ LPMESSAGEFILTER filter; /* message filter */ XOBJECT *objs; /* exported objects */ - IOBJECT *proxies; /* imported objects */ - LPUNKNOWN state; /* state object (see Co[Get,Set]State) */ - LPVOID ErrorInfo; /* thread error info */ -} APARTMENT; + struct list proxies; /* imported objects */ + DWORD listenertid; /* id of apartment_listener_thread */ + struct list stubmgrs; /* stub managers for exported objects */ +}; -extern APARTMENT MTA, *apts; +typedef struct apartment APARTMENT; -extern void* StdGlobalInterfaceTable_Construct(); +extern void* StdGlobalInterfaceTable_Construct(void); extern void StdGlobalInterfaceTable_Destroy(void* self); extern HRESULT StdGlobalInterfaceTable_GetFactory(LPVOID *ppv); @@ -118,74 +120,123 @@ extern HRESULT create_marshalled_proxy(REFCLSID rclsid, REFIID iid, LPVOID *ppv) extern void* StdGlobalInterfaceTableInstance; -#define PIPEPREF "\\\\.\\pipe\\" -#define OLESTUBMGR PIPEPREF"WINE_OLE_StubMgr" - /* Standard Marshalling definitions */ typedef struct _wine_marshal_id { - DWORD processid; - DWORD objectid; /* unique value corresp. IUnknown of object */ - IID iid; + OXID oxid; /* id of apartment */ + OID oid; /* id of stub manager */ + IPID ipid; /* id of interface pointer */ } wine_marshal_id; inline static BOOL MARSHAL_Compare_Mids(wine_marshal_id *mid1,wine_marshal_id *mid2) { return - (mid1->processid == mid2->processid) && - (mid1->objectid == mid2->objectid) && - IsEqualIID(&(mid1->iid),&(mid2->iid)) + (mid1->oxid == mid2->oxid) && + (mid1->oid == mid2->oid) && + IsEqualGUID(&(mid1->ipid),&(mid2->ipid)) ; } -/* compare without interface compare */ -inline static BOOL -MARSHAL_Compare_Mids_NoInterface(wine_marshal_id *mid1, wine_marshal_id *mid2) { - return - (mid1->processid == mid2->processid) && - (mid1->objectid == mid2->objectid) - ; -} - -HRESULT MARSHAL_Find_Stub_Buffer(wine_marshal_id *mid,IRpcStubBuffer **stub); -void MARSHAL_Invalidate_Stub_From_MID(wine_marshal_id *mid); -HRESULT MARSHAL_Disconnect_Proxies(); - +HRESULT MARSHAL_Disconnect_Proxies(APARTMENT *apt); HRESULT MARSHAL_GetStandardMarshalCF(LPVOID *ppv); -void STUBMGR_Start(); +/* Thread-safety Annotation Legend: + * + * RO - The value is read only. It never changes after creation, so no + * locking is required. + * LOCK - The value is written to only using Interlocked* functions. + * CS - The value is read or written to with a critical section held. + * The identifier following "CS" is the specific critical section that + * must be used. + */ + +/* an interface stub */ +struct ifstub +{ + struct list entry; /* entry in stub_manager->ifstubs list (CS stub_manager->lock) */ + IRpcStubBuffer *stubbuffer; /* RO */ + IID iid; /* RO */ + IPID ipid; /* RO */ + IUnknown *iface; /* RO */ + BOOL table; /* CS stub_manager->lock */ +}; + + +/* stub managers hold refs on the object and each interface stub */ +struct stub_manager +{ + struct list entry; /* entry in apartment stubmgr list (CS apt->cs) */ + struct list ifstubs; /* list of active ifstubs for the object (CS lock) */ + CRITICAL_SECTION lock; + APARTMENT *apt; /* owning apt (RO) */ + + ULONG extrefs; /* number of 'external' references (LOCK) */ + ULONG refs; /* internal reference count (CS apt->cs) */ + OID oid; /* apartment-scoped unique identifier (RO) */ + IUnknown *object; /* the object we are managing the stub for (RO) */ + ULONG next_ipid; /* currently unused (LOCK) */ +}; + +ULONG stub_manager_int_addref(struct stub_manager *This); +ULONG stub_manager_int_release(struct stub_manager *This); +struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object); +ULONG stub_manager_ext_addref(struct stub_manager *m, ULONG refs); +ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs); +IRpcStubBuffer *stub_manager_ipid_to_stubbuffer(struct stub_manager *m, const IPID *iid); +struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *sb, IUnknown *iptr, REFIID iid, BOOL tablemarshal); +struct stub_manager *get_stub_manager(OXID oxid, OID oid); +struct stub_manager *get_stub_manager_from_object(OXID oxid, void *object); + +IRpcStubBuffer *mid_to_stubbuffer(wine_marshal_id *mid); + +void start_apartment_listener_thread(void); extern HRESULT PIPE_GetNewPipeBuf(wine_marshal_id *mid, IRpcChannelBuffer **pipebuf); +void RPC_StartLocalServer(REFCLSID clsid, IStream *stream); /* This function initialize the Running Object Table */ -HRESULT WINAPI RunningObjectTableImpl_Initialize(); +HRESULT WINAPI RunningObjectTableImpl_Initialize(void); /* This function uninitialize the Running Object Table */ -HRESULT WINAPI RunningObjectTableImpl_UnInitialize(); +HRESULT WINAPI RunningObjectTableImpl_UnInitialize(void); /* This function decomposes a String path to a String Table containing all the elements ("\" or "subDirectory" or "Directory" or "FileName") of the path */ int WINAPI FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable); HRESULT WINAPI __CLSIDFromStringA(LPCSTR idstr, CLSID *id); +/* compobj.c */ +APARTMENT *COM_CreateApartment(DWORD model); +APARTMENT *COM_ApartmentFromOXID(OXID oxid, BOOL ref); +DWORD COM_ApartmentAddRef(struct apartment *apt); +DWORD COM_ApartmentRelease(struct apartment *apt); + +/* this is what is stored in TEB->ReservedForOle */ +struct oletls +{ + struct apartment *apt; + IErrorInfo *errorinfo; /* see errorinfo.c */ + IUnknown *state; /* see CoSetState */ + DWORD inits; /* number of times CoInitializeEx called */ +}; + /* * Per-thread values are stored in the TEB on offset 0xF80, * see http://www.microsoft.com/msj/1099/bugslayer/bugslayer1099.htm */ -static inline APARTMENT* COM_CurrentInfo(void) + +/* will create if necessary */ +static inline struct oletls *COM_CurrentInfo(void) { - APARTMENT* apt = NtCurrentTeb()->ReservedForOle; - return apt; -} -static inline APARTMENT* COM_CurrentApt(void) -{ - APARTMENT* apt = COM_CurrentInfo(); - if (apt && apt->parent) apt = apt->parent; - return apt; + if (!NtCurrentTeb()->ReservedForOle) + NtCurrentTeb()->ReservedForOle = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct oletls)); + + return NtCurrentTeb()->ReservedForOle; } -/* compobj.c */ -APARTMENT* COM_CreateApartment(DWORD model); -HWND COM_GetApartmentWin(OXID oxid); +static inline APARTMENT* COM_CurrentApt(void) +{ + return COM_CurrentInfo()->apt; +} #define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field)) diff --git a/reactos/lib/ole32/compositemoniker.c b/reactos/lib/ole32/compositemoniker.c index 839c8e89d48..94c5bb7c01b 100644 --- a/reactos/lib/ole32/compositemoniker.c +++ b/reactos/lib/ole32/compositemoniker.c @@ -445,7 +445,7 @@ HRESULT WINAPI CompositeMonikerImpl_GetSizeMax(IMoniker* iface,ULARGE_INTEGER* p IMoniker_Enum(iface,TRUE,&enumMk); - while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)==TRUE){ + while(IEnumMoniker_Next(enumMk,1,&pmk,NULL)){ IMoniker_GetSizeMax(pmk,&ptmpSize); diff --git a/reactos/lib/ole32/datacache.c b/reactos/lib/ole32/datacache.c index 8caef4e4cf6..867ec85c54b 100644 --- a/reactos/lib/ole32/datacache.c +++ b/reactos/lib/ole32/datacache.c @@ -1132,8 +1132,7 @@ static HRESULT WINAPI DataCache_GetData( cleanup: - if (mfBits) - HeapFree(GetProcessHeap(), 0, mfBits); + HeapFree(GetProcessHeap(), 0, mfBits); if (pStream) IStream_Release(pStream); diff --git a/reactos/lib/ole32/defaulthandler.c b/reactos/lib/ole32/defaulthandler.c index 62af03a615c..14a06121d80 100644 --- a/reactos/lib/ole32/defaulthandler.c +++ b/reactos/lib/ole32/defaulthandler.c @@ -514,17 +514,10 @@ static void DefaultHandler_Destroy( /* * Free the strings idenfitying the object */ - if (ptrToDestroy->containerApp!=NULL) - { - HeapFree( GetProcessHeap(), 0, ptrToDestroy->containerApp ); - ptrToDestroy->containerApp = NULL; - } - - if (ptrToDestroy->containerObj!=NULL) - { - HeapFree( GetProcessHeap(), 0, ptrToDestroy->containerObj ); - ptrToDestroy->containerObj = NULL; - } + HeapFree( GetProcessHeap(), 0, ptrToDestroy->containerApp ); + ptrToDestroy->containerApp = NULL; + HeapFree( GetProcessHeap(), 0, ptrToDestroy->containerObj ); + ptrToDestroy->containerObj = NULL; /* * Release our reference to the data cache. @@ -822,17 +815,10 @@ static HRESULT WINAPI DefaultHandler_SetHostNames( /* * Be sure to cleanup before re-assinging the strings. */ - if (this->containerApp!=NULL) - { - HeapFree( GetProcessHeap(), 0, this->containerApp ); - this->containerApp = NULL; - } - - if (this->containerObj!=NULL) - { - HeapFree( GetProcessHeap(), 0, this->containerObj ); - this->containerObj = NULL; - } + HeapFree( GetProcessHeap(), 0, this->containerApp ); + this->containerApp = NULL; + HeapFree( GetProcessHeap(), 0, this->containerObj ); + this->containerObj = NULL; /* * Copy the string supplied. diff --git a/reactos/lib/ole32/errorinfo.c b/reactos/lib/ole32/errorinfo.c index 4adae830c70..5c127347f3f 100644 --- a/reactos/lib/ole32/errorinfo.c +++ b/reactos/lib/ole32/errorinfo.c @@ -20,7 +20,7 @@ * NOTES: * * The errorinfo is a per-thread object. The reference is stored in the - * TEB at offset 0xf80 + * TEB at offset 0xf80. */ #include @@ -149,13 +149,13 @@ static ISupportErrorInfoVtbl ISupportErrorInfoImpl_VTable; converts a objectpointer to This */ #define _IErrorInfo_Offset ((int)(&(((ErrorInfoImpl*)0)->lpvtei))) -#define _ICOM_THIS_From_IErrorInfo(class, name) class* This = (class*)(((char*)name)-_IErrorInfo_Offset); +#define _ICOM_THIS_From_IErrorInfo(class, name) class* This = (class*)(((char*)name)-_IErrorInfo_Offset) #define _ICreateErrorInfo_Offset ((int)(&(((ErrorInfoImpl*)0)->lpvtcei))) -#define _ICOM_THIS_From_ICreateErrorInfo(class, name) class* This = (class*)(((char*)name)-_ICreateErrorInfo_Offset); +#define _ICOM_THIS_From_ICreateErrorInfo(class, name) class* This = (class*)(((char*)name)-_ICreateErrorInfo_Offset) #define _ISupportErrorInfo_Offset ((int)(&(((ErrorInfoImpl*)0)->lpvtsei))) -#define _ICOM_THIS_From_ISupportErrorInfo(class, name) class* This = (class*)(((char*)name)-_ISupportErrorInfo_Offset); +#define _ICOM_THIS_From_ISupportErrorInfo(class, name) class* This = (class*)(((char*)name)-_ISupportErrorInfo_Offset) /* converts This to a objectpointer @@ -227,15 +227,17 @@ static ULONG WINAPI IErrorInfoImpl_Release( IErrorInfo* iface) { _ICOM_THIS_From_IErrorInfo(ErrorInfoImpl, iface); - TRACE("(%p)->(count=%lu)\n",This,This->ref); + ULONG ref = InterlockedDecrement(&This->ref); - if (!InterlockedDecrement(&This->ref)) + TRACE("(%p)->(count=%lu)\n",This,ref+1); + + if (!ref) { TRACE("-- destroying IErrorInfo(%p)\n",This); HeapFree(GetProcessHeap(),0,This); return 0; } - return This->ref; + return ref; } static HRESULT WINAPI IErrorInfoImpl_GetGUID( @@ -483,20 +485,20 @@ HRESULT WINAPI CreateErrorInfo(ICreateErrorInfo **pperrinfo) */ HRESULT WINAPI GetErrorInfo(ULONG dwReserved, IErrorInfo **pperrinfo) { - APARTMENT * apt = COM_CurrentInfo(); - - TRACE("(%ld, %p, %p)\n", dwReserved, pperrinfo, COM_CurrentInfo()->ErrorInfo); + TRACE("(%ld, %p, %p)\n", dwReserved, pperrinfo, COM_CurrentInfo()->errorinfo); if(!pperrinfo) return E_INVALIDARG; - if (!apt || !apt->ErrorInfo) + + if (!COM_CurrentInfo()->errorinfo) { *pperrinfo = NULL; return S_FALSE; } - *pperrinfo = (IErrorInfo*)(apt->ErrorInfo); + *pperrinfo = COM_CurrentInfo()->errorinfo; + /* clear thread error state */ - apt->ErrorInfo = NULL; + COM_CurrentInfo()->errorinfo = NULL; return S_OK; } @@ -506,18 +508,16 @@ HRESULT WINAPI GetErrorInfo(ULONG dwReserved, IErrorInfo **pperrinfo) HRESULT WINAPI SetErrorInfo(ULONG dwReserved, IErrorInfo *perrinfo) { IErrorInfo * pei; - APARTMENT * apt = COM_CurrentInfo(); TRACE("(%ld, %p)\n", dwReserved, perrinfo); - if (!apt) apt = COM_CreateApartment(COINIT_UNINITIALIZED); - /* release old errorinfo */ - pei = (IErrorInfo*)apt->ErrorInfo; - if(pei) IErrorInfo_Release(pei); + pei = COM_CurrentInfo()->errorinfo; + if (pei) IErrorInfo_Release(pei); /* set to new value */ - apt->ErrorInfo = perrinfo; - if(perrinfo) IErrorInfo_AddRef(perrinfo); + COM_CurrentInfo()->errorinfo = perrinfo; + if (perrinfo) IErrorInfo_AddRef(perrinfo); + return S_OK; } diff --git a/reactos/lib/ole32/filemoniker.c b/reactos/lib/ole32/filemoniker.c index 182a2c67564..d9536989e8e 100644 --- a/reactos/lib/ole32/filemoniker.c +++ b/reactos/lib/ole32/filemoniker.c @@ -325,8 +325,7 @@ HRESULT WINAPI FileMonikerImpl_Load(IMoniker* iface,IStream* pStm) return E_FAIL; } - if (This->filePathName!=NULL) - HeapFree(GetProcessHeap(),0,This->filePathName); + HeapFree(GetProcessHeap(),0,This->filePathName); This->filePathName=filePathW; @@ -540,9 +539,7 @@ HRESULT WINAPI FileMonikerImpl_Destroy(FileMonikerImpl* This) { TRACE("(%p)\n",This); - if (This->filePathName!=NULL) - HeapFree(GetProcessHeap(),0,This->filePathName); - + HeapFree(GetProcessHeap(),0,This->filePathName); HeapFree(GetProcessHeap(),0,This); return S_OK; diff --git a/reactos/lib/ole32/ftmarshal.c b/reactos/lib/ole32/ftmarshal.c index 915ff3e0723..3c6a9d346a7 100644 --- a/reactos/lib/ole32/ftmarshal.c +++ b/reactos/lib/ole32/ftmarshal.c @@ -156,8 +156,6 @@ HRESULT WINAPI FTMarshalImpl_GetMarshalSizeMax (LPMARSHAL iface, REFIID riid, vo hres = IMarshal_GetMarshalSizeMax (pMarshal, riid, pv, dwDestContext, pvDestContext, mshlflags, pSize); IMarshal_Release (pMarshal); return hres; - - return S_OK; } HRESULT WINAPI FTMarshalImpl_MarshalInterface (LPMARSHAL iface, IStream * pStm, REFIID riid, void *pv, diff --git a/reactos/lib/ole32/hglobalstream.c b/reactos/lib/ole32/hglobalstream.c index 13a9d612eeb..0fbeab48765 100644 --- a/reactos/lib/ole32/hglobalstream.c +++ b/reactos/lib/ole32/hglobalstream.c @@ -598,8 +598,9 @@ HRESULT WINAPI HGLOBALStreamImpl_Seek( * If the file pointer ends-up after the end of the stream, the next Write operation will * make the file larger. This is how it is documented. */ + if (dlibMove.QuadPart < 0 && newPosition.QuadPart < -dlibMove.QuadPart) return STG_E_INVALIDFUNCTION; + newPosition.QuadPart = RtlLargeIntegerAdd(newPosition.QuadPart, dlibMove.QuadPart); - if (newPosition.QuadPart < 0) return STG_E_INVALIDFUNCTION; if (plibNewPosition) *plibNewPosition = newPosition; This->currentPosition = newPosition; diff --git a/reactos/lib/ole32/ifs.c b/reactos/lib/ole32/ifs.c index 8af7ca5f56d..325f08444d1 100644 --- a/reactos/lib/ole32/ifs.c +++ b/reactos/lib/ole32/ifs.c @@ -394,10 +394,11 @@ static ULONG WINAPI IMallocSpy_fnAddRef (LPMALLOCSPY iface) { _MallocSpy *This = (_MallocSpy *)iface; + ULONG ref = InterlockedIncrement(&This->ref); - TRACE ("(%p)->(count=%lu)\n", This, This->ref); + TRACE ("(%p)->(count=%lu)\n", This, ref - 1); - return ++(This->ref); + return ref; } /****************************************************************************** @@ -410,13 +411,14 @@ static ULONG WINAPI IMallocSpy_fnRelease (LPMALLOCSPY iface) { _MallocSpy *This = (_MallocSpy *)iface; + ULONG ref = InterlockedDecrement(&This->ref); - TRACE ("(%p)->(count=%lu)\n", This, This->ref); + TRACE ("(%p)->(count=%lu)\n", This, ref + 1); - if (!--(This->ref)) { + if (!ref) { /* our allocation list MUST be empty here */ } - return This->ref; + return ref; } static ULONG WINAPI IMallocSpy_fnPreAlloc(LPMALLOCSPY iface, ULONG cbRequest) diff --git a/reactos/lib/ole32/ifs.h b/reactos/lib/ole32/ifs.h index 55a6bc0fd9c..72a5c527219 100644 --- a/reactos/lib/ole32/ifs.h +++ b/reactos/lib/ole32/ifs.h @@ -55,7 +55,7 @@ typedef struct IMalloc16 *LPMALLOC16; /**********************************************************************/ -extern LPMALLOC16 IMalloc16_Constructor(); +extern LPMALLOC16 IMalloc16_Constructor(void); /**********************************************************************/ diff --git a/reactos/lib/ole32/itemmoniker.c b/reactos/lib/ole32/itemmoniker.c index be769ddbe44..4c1e4e3c8d1 100644 --- a/reactos/lib/ole32/itemmoniker.c +++ b/reactos/lib/ole32/itemmoniker.c @@ -415,12 +415,8 @@ HRESULT WINAPI ItemMonikerImpl_Destroy(ItemMonikerImpl* This) { TRACE("(%p)\n",This); - if (This->itemName) - HeapFree(GetProcessHeap(),0,This->itemName); - - if (This->itemDelimiter) - HeapFree(GetProcessHeap(),0,This->itemDelimiter); - + HeapFree(GetProcessHeap(),0,This->itemName); + HeapFree(GetProcessHeap(),0,This->itemDelimiter); HeapFree(GetProcessHeap(),0,This); return S_OK; diff --git a/reactos/lib/ole32/marshal.c b/reactos/lib/ole32/marshal.c index 9c89a7d9b2c..2962d538255 100644 --- a/reactos/lib/ole32/marshal.c +++ b/reactos/lib/ole32/marshal.c @@ -1,7 +1,9 @@ /* * Marshalling library * - * Copyright 2002 Marcus Meissner + * Copyright 2002 Marcus Meissner + * Copyright 2004 Mike Hearn, for CodeWeavers + * Copyright 2004 Rob Shearman, for CodeWeavers * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -33,16 +35,13 @@ #include "winuser.h" #include "objbase.h" #include "ole2.h" -#include "ole2ver.h" #include "rpc.h" #include "winerror.h" #include "winreg.h" -#include "wownt32.h" #include "wtypes.h" #include "wine/unicode.h" -#include "wine/winbase16.h" + #include "compobj_private.h" -#include "ifs.h" #include "wine/debug.h" @@ -58,6 +57,13 @@ extern const CLSID CLSID_DfMarshal; * Process Identifier, Object IUnknown ptr, IID * * Note that the IUnknown_QI(ob,xiid,&ppv) always returns the SAME ppv value! + * + * In Windows, a different triple is used: OXID (apt id), OID (stub + * manager id), IPID (interface ptr/stub id). + * + * OXIDs identify an apartment and are network scoped + * OIDs identify a stub manager and are apartment scoped + * IPIDs identify an interface stub and are apartment scoped */ inline static HRESULT @@ -75,121 +81,347 @@ typedef struct _wine_marshal_data { DWORD mshlflags; } wine_marshal_data; -typedef struct _mid2unknown { - wine_marshal_id mid; - LPUNKNOWN pUnk; -} mid2unknown; +IRpcStubBuffer *mid_to_stubbuffer(wine_marshal_id *mid) +{ + IRpcStubBuffer *ret; + struct stub_manager *m; -typedef struct _mid2stub { - wine_marshal_id mid; - IRpcStubBuffer *stub; - LPUNKNOWN pUnkServer; - BOOL valid; -} mid2stub; + if (!(m = get_stub_manager(mid->oxid, mid->oid))) + { + WARN("unknown OID %s\n", wine_dbgstr_longlong(mid->oid)); + return NULL; + } -static mid2stub *stubs = NULL; -static int nrofstubs = 0; + ret = stub_manager_ipid_to_stubbuffer(m, &mid->ipid); -static mid2unknown *proxies = NULL; -static int nrofproxies = 0; + stub_manager_int_release(m); + return ret; +} -void MARSHAL_Invalidate_Stub_From_MID(wine_marshal_id *mid) { - int i; +/* creates a new stub manager and sets mid->oid when mid->oid == 0 */ +static HRESULT register_ifstub(wine_marshal_id *mid, REFIID riid, IUnknown *obj, IRpcStubBuffer *stub, BOOL tablemarshal) +{ + struct stub_manager *manager = NULL; + struct ifstub *ifstub; - for (i=0;ioid of zero means create a new stub manager */ + + if (mid->oid && (manager = get_stub_manager(mid->oxid, mid->oid))) + { + TRACE("registering new ifstub on pre-existing manager\n"); + } + else + { + struct apartment *apt; - if (MARSHAL_Compare_Mids(mid,&(stubs[i].mid))) { - stubs[i].valid = FALSE; - return; - } + TRACE("constructing new stub manager\n"); + + apt = COM_ApartmentFromOXID(mid->oxid, TRUE); + manager = new_stub_manager(apt, obj); + COM_ApartmentRelease(apt); + if (!manager) return E_OUTOFMEMORY; + + mid->oid = manager->oid; } - - return; -} -HRESULT -MARSHAL_Find_Stub_Buffer(wine_marshal_id *mid,IRpcStubBuffer **stub) { - int i; - - for (i=0;iipid = ifstub->ipid; - if (MARSHAL_Compare_Mids(mid,&(stubs[i].mid))) { - *pUnk = stubs[i].pUnkServer; - IUnknown_AddRef((*pUnk)); - return S_OK; - } - } - return E_FAIL; -} - -static HRESULT -MARSHAL_Register_Stub(wine_marshal_id *mid,LPUNKNOWN pUnk,IRpcStubBuffer *stub) { - LPUNKNOWN xPunk; - if (!MARSHAL_Find_Stub(mid,&xPunk)) { - FIXME("Already have entry for (%lx/%s)!\n",mid->objectid,debugstr_guid(&(mid->iid))); - return S_OK; - } - if (nrofstubs) - stubs=HeapReAlloc(GetProcessHeap(),0,stubs,sizeof(stubs[0])*(nrofstubs+1)); - else - stubs=HeapAlloc(GetProcessHeap(),0,sizeof(stubs[0])); - if (!stubs) return E_OUTOFMEMORY; - stubs[nrofstubs].stub = stub; - stubs[nrofstubs].pUnkServer = pUnk; - memcpy(&(stubs[nrofstubs].mid),mid,sizeof(*mid)); - stubs[nrofstubs].valid = TRUE; /* set to false when released by ReleaseMarshalData */ - nrofstubs++; + stub_manager_int_release(manager); return S_OK; } -HRESULT -MARSHAL_Disconnect_Proxies() { - int i; - TRACE("Disconnecting %d proxies\n", nrofproxies); - for (i = 0; i < nrofproxies; i++) - IRpcProxyBuffer_Disconnect((IRpcProxyBuffer*)proxies[i].pUnk); - +/* Client-side identity of the server object */ + +static void proxy_manager_destroy(struct proxy_manager * This); +static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found); + +static HRESULT WINAPI ClientIdentity_QueryInterface(IInternalUnknown * iface, REFIID riid, void ** ppv) +{ + struct proxy_manager * This = (struct proxy_manager *)iface; + HRESULT hr; + struct ifproxy * ifproxy; + + TRACE("%s\n", debugstr_guid(riid)); + + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IInternalUnknown)) + { + *ppv = (void *)iface; + IInternalUnknown_AddRef(iface); + return S_OK; + } + + hr = proxy_manager_find_ifproxy(This, riid, &ifproxy); + if (hr == S_OK) + { + *ppv = ifproxy->iface; + IUnknown_AddRef((IUnknown *)*ppv); + return S_OK; + } + + FIXME("interface not found %s\n", debugstr_guid(riid)); + + /* FIXME: call IRemUnknown::RemQueryInterface */ + return E_NOINTERFACE; +} + +static ULONG WINAPI ClientIdentity_AddRef(IInternalUnknown * iface) +{ + struct proxy_manager * This = (struct proxy_manager *)iface; + TRACE("%p - before %ld\n", iface, This->refs); + return InterlockedIncrement(&This->refs); +} + +static ULONG WINAPI ClientIdentity_Release(IInternalUnknown * iface) +{ + struct proxy_manager * This = (struct proxy_manager *)iface; + ULONG refs = InterlockedDecrement(&This->refs); + TRACE("%p - after %ld\n", iface, refs); + if (!refs) + proxy_manager_destroy(This); + return refs; +} + +static HRESULT WINAPI ClientIdentity_QueryInternalInterface(IInternalUnknown * iface, REFIID riid, void ** ppv) +{ + FIXME("(%s, %p): stub!\n", debugstr_guid(riid), ppv); + return E_NOINTERFACE; +} + +static const IInternalUnknownVtbl ClientIdentity_Vtbl = +{ + ClientIdentity_QueryInterface, + ClientIdentity_AddRef, + ClientIdentity_Release, + ClientIdentity_QueryInternalInterface +}; + +static HRESULT ifproxy_get_public_ref(struct ifproxy * This) +{ + /* FIXME: call IRemUnknown::RemAddRef if necessary */ return S_OK; } -static HRESULT -MARSHAL_Register_Proxy(wine_marshal_id *mid,LPUNKNOWN punk) { - int i; +static HRESULT ifproxy_release_public_refs(struct ifproxy * This) +{ + /* FIXME: call IRemUnknown::RemRelease */ + return S_OK; +} - for (i=0;iproxy); +} + +static void ifproxy_destroy(struct ifproxy * This) +{ + /* release public references to this object so that the stub can know + * when to destroy itself */ + ifproxy_release_public_refs(This); + + list_remove(&This->entry); + + if (This->proxy) IRpcProxyBuffer_Release(This->proxy); + HeapFree(GetProcessHeap(), 0, This); +} + +static HRESULT proxy_manager_construct(APARTMENT * apt, OXID oxid, OID oid, IRpcChannelBuffer * channel, struct proxy_manager ** proxy_manager) +{ + struct proxy_manager * This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + if (!This) return E_OUTOFMEMORY; + + This->lpVtbl = &ClientIdentity_Vtbl; + + list_init(&This->entry); + list_init(&This->interfaces); + + InitializeCriticalSection(&This->cs); + + /* the apartment the object was unmarshaled into */ + This->parent = apt; + + /* the source apartment and id of the object */ + This->oxid = oxid; + This->oid = oid; + + This->refs = 0; /* will be incremented on creation of first proxy */ + + This->chan = channel; /* FIXME: we should take the binding strings and construct the channel in this function */ + + EnterCriticalSection(&apt->cs); + list_add_head(&apt->proxies, &This->entry); + LeaveCriticalSection(&apt->cs); + + *proxy_manager = This; + return S_OK; +} + +static HRESULT proxy_manager_create_ifproxy(struct proxy_manager * This, IPID ipid, REFIID riid, ULONG cPublicRefs, struct ifproxy ** iif_out) +{ + HRESULT hr; + IPSFactoryBuffer * psfb; + struct ifproxy * ifproxy = HeapAlloc(GetProcessHeap(), 0, sizeof(*ifproxy)); + if (!ifproxy) return E_OUTOFMEMORY; + + list_init(&ifproxy->entry); + + ifproxy->ipid = ipid; + ifproxy->iid = *riid; + ifproxy->refs = cPublicRefs; + ifproxy->proxy = NULL; + + hr = get_facbuf_for_iid(riid, &psfb); + if (hr == S_OK) + { + /* important note: the outer unknown is set to the proxy manager. + * This ensures the COM identity rules are not violated, by having a + * one-to-one mapping of objects on the proxy side to objects on the + * stub side, no matter which interface you view the object through */ + hr = IPSFactoryBuffer_CreateProxy(psfb, (IUnknown *)&This->lpVtbl, riid, + &ifproxy->proxy, &ifproxy->iface); + IPSFactoryBuffer_Release(psfb); + } + + if (hr == S_OK) + hr = IRpcProxyBuffer_Connect(ifproxy->proxy, This->chan); + + /* get at least one external reference to the object to keep it alive */ + if (hr == S_OK) + hr = ifproxy_get_public_ref(ifproxy); + + if (hr == S_OK) + { + EnterCriticalSection(&This->cs); + list_add_tail(&This->interfaces, &ifproxy->entry); + LeaveCriticalSection(&This->cs); + + *iif_out = ifproxy; } - if (nrofproxies) - proxies = HeapReAlloc(GetProcessHeap(),0,proxies,sizeof(proxies[0])*(nrofproxies+1)); else - proxies = HeapAlloc(GetProcessHeap(),0,sizeof(proxies[0])); - memcpy(&(proxies[nrofproxies].mid),mid,sizeof(*mid)); - proxies[nrofproxies].pUnk = punk; - nrofproxies++; - IUnknown_AddRef(punk); + ifproxy_destroy(ifproxy); + + return hr; +} + +static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found) +{ + HRESULT hr = E_NOINTERFACE; /* assume not found */ + struct list * cursor; + + EnterCriticalSection(&This->cs); + LIST_FOR_EACH(cursor, &This->interfaces) + { + struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry); + if (IsEqualIID(riid, &ifproxy->iid)) + { + *ifproxy_found = ifproxy; + hr = S_OK; + break; + } + } + LeaveCriticalSection(&This->cs); + + return hr; +} + +static void proxy_manager_disconnect(struct proxy_manager * This) +{ + struct list * cursor; + + EnterCriticalSection(&This->cs); + + LIST_FOR_EACH(cursor, &This->interfaces) + { + struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry); + ifproxy_disconnect(ifproxy); + } + + /* apartment is being destroyed so don't keep a pointer around to it */ + This->parent = NULL; + + LeaveCriticalSection(&This->cs); +} + +static void proxy_manager_destroy(struct proxy_manager * This) +{ + struct list * cursor; + + if (This->parent) + { + EnterCriticalSection(&This->parent->cs); + + /* remove ourself from the list of proxy objects in the apartment */ + LIST_FOR_EACH(cursor, &This->parent->proxies) + { + if (cursor == &This->entry) + { + list_remove(&This->entry); + break; + } + } + + LeaveCriticalSection(&This->parent->cs); + } + + /* destroy all of the interface proxies */ + while (!(cursor = list_head(&This->interfaces))) + { + struct ifproxy * ifproxy = LIST_ENTRY(cursor, struct ifproxy, entry); + ifproxy_destroy(ifproxy); + } + + IRpcChannelBuffer_Release(This->chan); + + DeleteCriticalSection(&This->cs); + + HeapFree(GetProcessHeap(), 0, This); +} + +static BOOL find_proxy_manager(APARTMENT * apt, OXID oxid, OID oid, struct proxy_manager ** proxy_found) +{ + BOOL found = FALSE; + struct list * cursor; + + EnterCriticalSection(&apt->cs); + LIST_FOR_EACH(cursor, &apt->proxies) + { + struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry); + if ((oxid == proxy->oxid) && (oid == proxy->oid)) + { + *proxy_found = proxy; + found = TRUE; + break; + } + } + LeaveCriticalSection(&apt->cs); + return found; +} + +HRESULT MARSHAL_Disconnect_Proxies(APARTMENT *apt) +{ + struct list * cursor; + + EnterCriticalSection(&apt->cs); + LIST_FOR_EACH(cursor, &apt->proxies) + { + struct proxy_manager * proxy = LIST_ENTRY(cursor, struct proxy_manager, entry); + proxy_manager_disconnect(proxy); + } + LeaveCriticalSection(&apt->cs); + return S_OK; } @@ -254,134 +486,155 @@ StdMarshalImpl_MarshalInterface( LPMARSHAL iface, IStream *pStm,REFIID riid, void* pv, DWORD dwDestContext, void* pvDestContext, DWORD mshlflags ) { - wine_marshal_id mid; - wine_marshal_data md; - IUnknown *pUnk; - ULONG res; - HRESULT hres; - IRpcStubBuffer *stub; - IPSFactoryBuffer *psfacbuf; - + wine_marshal_id mid; + wine_marshal_data md; + IUnknown *pUnk; + ULONG res; + HRESULT hres; + IRpcStubBuffer *stubbuffer; + IPSFactoryBuffer *psfacbuf; + BOOL tablemarshal; + struct stub_manager *manager; + TRACE("(...,%s,...)\n",debugstr_guid(riid)); - IUnknown_QueryInterface((LPUNKNOWN)pv,&IID_IUnknown,(LPVOID*)&pUnk); - mid.processid = GetCurrentProcessId(); - mid.objectid = (DWORD)pUnk; /* FIXME */ - IUnknown_Release(pUnk); - memcpy(&mid.iid,riid,sizeof(mid.iid)); - md.dwDestContext = dwDestContext; - md.mshlflags = mshlflags; - hres = IStream_Write(pStm,&mid,sizeof(mid),&res); - if (hres) return hres; - hres = IStream_Write(pStm,&md,sizeof(md),&res); - if (hres) return hres; + start_apartment_listener_thread(); /* just to be sure we have one running. */ - if (SUCCEEDED(MARSHAL_Find_Stub_Buffer(&mid,&stub))) { - /* Find_Stub_Buffer gives us a ref but we want to keep it, as if we'd created a new one */ - TRACE("Found RpcStubBuffer %p\n", stub); - return S_OK; - } hres = get_facbuf_for_iid(riid,&psfacbuf); if (hres) return hres; - hres = IPSFactoryBuffer_CreateStub(psfacbuf,riid,pv,&stub); + hres = IPSFactoryBuffer_CreateStub(psfacbuf,riid,pv,&stubbuffer); IPSFactoryBuffer_Release(psfacbuf); if (hres) { - FIXME("Failed to create a stub for %s\n",debugstr_guid(riid)); + FIXME("Failed to create an RpcStubBuffer from PSFactory for %s\n",debugstr_guid(riid)); return hres; } - IUnknown_QueryInterface((LPUNKNOWN)pv,riid,(LPVOID*)&pUnk); - MARSHAL_Register_Stub(&mid,pUnk,stub); + + tablemarshal = ((mshlflags & MSHLFLAGS_TABLESTRONG) || (mshlflags & MSHLFLAGS_TABLEWEAK)); + if (tablemarshal) FIXME("table marshalling unimplemented\n"); + + /* now fill out the MID */ + mid.oxid = COM_CurrentApt()->oxid; + + IUnknown_QueryInterface((LPUNKNOWN)pv, riid, (LPVOID*)&pUnk); + + if ((manager = get_stub_manager_from_object(mid.oxid, pUnk))) + { + mid.oid = manager->oid; + stub_manager_int_release(manager); + } + else + { + mid.oid = 0; /* will be set by register_ifstub */ + } + + hres = register_ifstub(&mid, riid, pUnk, stubbuffer, tablemarshal); + IUnknown_Release(pUnk); + + if (hres) + { + FIXME("Failed to create ifstub, hres=0x%lx\n", hres); + return hres; + } + + hres = IStream_Write(pStm,&mid,sizeof(mid),&res); + if (hres) return hres; + + /* and then the marshal data */ + md.dwDestContext = dwDestContext; + md.mshlflags = mshlflags; + hres = IStream_Write(pStm,&md,sizeof(md),&res); + if (hres) return hres; + return S_OK; } static HRESULT WINAPI -StdMarshalImpl_UnmarshalInterface( - LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv -) { +StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, void **ppv) +{ + struct stub_manager *stubmgr; wine_marshal_id mid; wine_marshal_data md; ULONG res; HRESULT hres; - IPSFactoryBuffer *psfacbuf; - IRpcProxyBuffer *rpcproxy; IRpcChannelBuffer *chanbuf; + struct proxy_manager *proxy_manager; + APARTMENT *apt = COM_CurrentApt(); TRACE("(...,%s,....)\n",debugstr_guid(riid)); + + if (!apt) return CO_E_NOTINITIALIZED; + hres = IStream_Read(pStm,&mid,sizeof(mid),&res); if (hres) return hres; hres = IStream_Read(pStm,&md,sizeof(md),&res); if (hres) return hres; - if (SUCCEEDED(MARSHAL_Find_Stub(&mid,(LPUNKNOWN*)ppv))) { - FIXME("Calling back to ourselves for %s!\n",debugstr_guid(riid)); - return S_OK; - } - if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_NULL)) { - /* should return proxy manager IUnknown object */ - FIXME("Special treatment required for IID of %s\n", debugstr_guid(riid)); - } - hres = get_facbuf_for_iid(riid,&psfacbuf); - if (hres) return hres; - hres = IPSFactoryBuffer_CreateProxy(psfacbuf,NULL,riid,&rpcproxy,ppv); - if (hres) { - FIXME("Failed to create a proxy for %s\n",debugstr_guid(riid)); - return hres; + + /* check if we're marshalling back to ourselves */ + /* FIXME: commented out until we can get the tests passing with it uncommented. */ + if (/*(apt->oxid == mid.oxid) &&*/ (stubmgr = get_stub_manager(mid.oxid, mid.oid))) + { + TRACE("Unmarshalling object marshalled in same apartment for iid %s, returning original object %p\n", debugstr_guid(riid), stubmgr->object); + + hres = IUnknown_QueryInterface(stubmgr->object, riid, ppv); + if ((md.mshlflags & MSHLFLAGS_TABLESTRONG) || (md.mshlflags & MSHLFLAGS_TABLEWEAK)) + FIXME("table marshalling unimplemented\n"); + + /* unref the ifstub. FIXME: only do this on success? */ + stub_manager_ext_release(stubmgr, 1); + + stub_manager_int_release(stubmgr); + return hres; } - MARSHAL_Register_Proxy(&mid, (LPUNKNOWN) rpcproxy); - - hres = PIPE_GetNewPipeBuf(&mid,&chanbuf); - IPSFactoryBuffer_Release(psfacbuf); - if (hres) { - ERR("Failed to get an rpc channel buffer for %s\n",debugstr_guid(riid)); - } else { - /* Connect the channel buffer to the proxy and release the no longer - * needed proxy. - * NOTE: The proxy should have taken an extra reference because it also - * aggregates the object, so we can safely release our reference to it. */ - IRpcProxyBuffer_Connect(rpcproxy,chanbuf); - IRpcProxyBuffer_Release(rpcproxy); - /* IRpcProxyBuffer takes a reference on the channel buffer and - * we no longer need it, so release it */ - IRpcChannelBuffer_Release(chanbuf); + if (!find_proxy_manager(apt, mid.oxid, mid.oid, &proxy_manager)) + { + hres = PIPE_GetNewPipeBuf(&mid,&chanbuf); + if (hres == S_OK) + hres = proxy_manager_construct(apt, mid.oxid, mid.oid, chanbuf, &proxy_manager); } + + if (hres == S_OK) + { + struct ifproxy * ifproxy; + hres = proxy_manager_find_ifproxy(proxy_manager, riid, &ifproxy); + if (hres == S_OK) + IUnknown_AddRef((IUnknown *)ifproxy->iface); + else if (hres == E_NOINTERFACE) + hres = proxy_manager_create_ifproxy(proxy_manager, mid.ipid, riid, 1, &ifproxy); + + if (hres == S_OK) + *ppv = ifproxy->iface; /* AddRef'd above */ + } + return hres; } static HRESULT WINAPI StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm) { - wine_marshal_id mid; - ULONG res; - HRESULT hres; - IRpcStubBuffer *stub = NULL; - int i; + wine_marshal_id mid; + ULONG res; + HRESULT hres; + struct stub_manager *stubmgr; - hres = IStream_Read(pStm,&mid,sizeof(mid),&res); - if (hres) return hres; + TRACE("iface=%p, pStm=%p\n", iface, pStm); + + hres = IStream_Read(pStm,&mid,sizeof(mid),&res); + if (hres) return hres; - for (i=0; i < nrofstubs; i++) - { - if (!stubs[i].valid) continue; + if (!(stubmgr = get_stub_manager(mid.oxid, mid.oid))) + { + ERR("could not map MID to stub manager, oxid=%s, oid=%s\n", + wine_dbgstr_longlong(mid.oxid), wine_dbgstr_longlong(mid.oid)); + return RPC_E_INVALID_OBJREF; + } + + stub_manager_ext_release(stubmgr, 1); - if (MARSHAL_Compare_Mids(&mid, &(stubs[i].mid))) - { - stub = stubs[i].stub; - break; - } - } + stub_manager_int_release(stubmgr); - if (!stub) - { - FIXME("Could not map MID to stub??\n"); - return E_FAIL; - } - - res = IRpcStubBuffer_Release(stub); - stubs[i].valid = FALSE; - TRACE("stub refcount of %p is %ld\n", stub, res); - - return S_OK; + return S_OK; } static HRESULT WINAPI @@ -402,37 +655,57 @@ IMarshalVtbl stdmvtbl = { StdMarshalImpl_DisconnectObject }; +static HRESULT StdMarshalImpl_Construct(REFIID riid, void** ppvObject) +{ + StdMarshalImpl * pStdMarshal = + HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(StdMarshalImpl)); + if (!pStdMarshal) + return E_OUTOFMEMORY; + pStdMarshal->lpvtbl = &stdmvtbl; + pStdMarshal->ref = 0; + return IMarshal_QueryInterface((IMarshal*)pStdMarshal, riid, ppvObject); +} + /*********************************************************************** * CoGetStandardMarshal [OLE32.@] * - * When the COM library in the client process receives a marshalled - * interface pointer, it looks for a CLSID to be used in creating a proxy - * for the purposes of unmarshalling the packet. If the packet does not - * contain a CLSID for the proxy, COM calls CoGetStandardMarshal, passing a - * NULL pUnk value. - * This function creates a standard proxy in the client process and returns - * a pointer to that proxy's implementation of IMarshal. - * COM uses this pointer to call CoUnmarshalInterface to retrieve the pointer - * to the requested interface. + * Gets or creates a standard marshal object. + * + * PARAMS + * riid [I] Interface identifier of the pUnk object. + * pUnk [I] Optional. Object to get the marshal object for. + * dwDestContext [I] Destination. Used to enable or disable optimizations. + * pvDestContext [I] Reserved. Must be NULL. + * mshlflags [I] Flags affecting the marshaling process. + * ppMarshal [O] Address where marshal object will be stored. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * NOTES + * + * The function retrieves the IMarshal object associated with an object if + * that object is currently an active stub, otherwise a new marshal object is + * created. */ -HRESULT WINAPI -CoGetStandardMarshal( - REFIID riid,IUnknown *pUnk,DWORD dwDestContext,LPVOID pvDestContext, - DWORD mshlflags, LPMARSHAL *pMarshal -) { +HRESULT WINAPI CoGetStandardMarshal(REFIID riid, IUnknown *pUnk, + DWORD dwDestContext, LPVOID pvDestContext, + DWORD mshlflags, LPMARSHAL *ppMarshal) +{ StdMarshalImpl *dm; if (pUnk == NULL) { FIXME("(%s,NULL,%lx,%p,%lx,%p), unimplemented yet.\n", - debugstr_guid(riid),dwDestContext,pvDestContext,mshlflags,pMarshal + debugstr_guid(riid),dwDestContext,pvDestContext,mshlflags,ppMarshal ); return E_FAIL; } TRACE("(%s,%p,%lx,%p,%lx,%p)\n", - debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags,pMarshal + debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags,ppMarshal ); - *pMarshal = HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl)); - dm = (StdMarshalImpl*) *pMarshal; + *ppMarshal = HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl)); + dm = (StdMarshalImpl*) *ppMarshal; if (!dm) return E_FAIL; dm->lpvtbl = &stdmvtbl; dm->ref = 1; @@ -444,205 +717,383 @@ CoGetStandardMarshal( return S_OK; } -/* Helper function for getting Marshaler */ -static HRESULT WINAPI -_GetMarshaller(REFIID riid, IUnknown *pUnk,DWORD dwDestContext, - void *pvDestContext, DWORD mshlFlags, LPMARSHAL *pMarshal -) { - HRESULT hres; +/*********************************************************************** + * get_marshaler [internal] + * + * Retrieves an IMarshal interface for an object. + */ +static HRESULT get_marshaler(REFIID riid, IUnknown *pUnk, DWORD dwDestContext, + void *pvDestContext, DWORD mshlFlags, + LPMARSHAL *pMarshal) +{ + HRESULT hr; - if (!pUnk) - return E_POINTER; - hres = IUnknown_QueryInterface(pUnk,&IID_IMarshal,(LPVOID*)pMarshal); - if (hres) - hres = CoGetStandardMarshal(riid,pUnk,dwDestContext,pvDestContext,mshlFlags,pMarshal); - return hres; + if (!pUnk) + return E_POINTER; + hr = IUnknown_QueryInterface(pUnk, &IID_IMarshal, (LPVOID*)pMarshal); + if (hr) + hr = CoGetStandardMarshal(riid, pUnk, dwDestContext, pvDestContext, + mshlFlags, pMarshal); + return hr; +} + +/*********************************************************************** + * get_unmarshaler_from_stream [internal] + * + * Creates an IMarshal* object according to the data marshaled to the stream. + * The function leaves the stream pointer at the start of the data written + * to the stream by the IMarshal* object. + */ +static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal) +{ + HRESULT hr; + ULONG res; + OBJREF objref; + + /* read common OBJREF header */ + hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res); + if (hr || (res != FIELD_OFFSET(OBJREF, u_objref))) + { + ERR("Failed to read common OBJREF header, 0x%08lx\n", hr); + return STG_E_READFAULT; + } + + /* sanity check on header */ + if (objref.signature != OBJREF_SIGNATURE) + { + ERR("Bad OBJREF signature 0x%08lx\n", objref.signature); + return RPC_E_INVALID_OBJREF; + } + + /* FIXME: handler marshaling */ + if (objref.flags & OBJREF_STANDARD) + { + TRACE("Using standard unmarshaling\n"); + hr = StdMarshalImpl_Construct(&IID_IMarshal, (LPVOID*)marshal); + } + else if (objref.flags & OBJREF_CUSTOM) + { + ULONG custom_header_size = FIELD_OFFSET(OBJREF, u_objref.u_custom.size) - + FIELD_OFFSET(OBJREF, u_objref.u_custom); + TRACE("Using custom unmarshaling\n"); + /* read constant sized OR_CUSTOM data from stream */ + hr = IStream_Read(stream, &objref.u_objref.u_custom, + custom_header_size, &res); + if (hr || (res != custom_header_size)) + { + ERR("Failed to read OR_CUSTOM header, 0x%08lx\n", hr); + return STG_E_READFAULT; + } + /* now create the marshaler specified in the stream */ + hr = CoCreateInstance(&objref.u_objref.u_custom.clsid, NULL, + CLSCTX_INPROC_SERVER, &IID_IMarshal, + (LPVOID*)marshal); + } + else + { + FIXME("Invalid or unimplemented marshaling type specified: %lx\n", + objref.flags); + return RPC_E_INVALID_OBJREF; + } + + if (hr) + ERR("Failed to create marshal, 0x%08lx\n", hr); + + return hr; } /*********************************************************************** * CoGetMarshalSizeMax [OLE32.@] + * + * Gets the maximum amount of data that will be needed by a marshal. + * + * PARAMS + * pulSize [O] Address where maximum marshal size will be stored. + * riid [I] Identifier of the interface to marshal. + * pUnk [I] Pointer to the object to marshal. + * dwDestContext [I] Destination. Used to enable or disable optimizations. + * pvDestContext [I] Reserved. Must be NULL. + * mshlFlags [I] Flags that affect the marshaling. See CoMarshalInterface(). + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * SEE ALSO + * CoMarshalInterface(). */ -HRESULT WINAPI -CoGetMarshalSizeMax(ULONG *pulSize, REFIID riid, IUnknown *pUnk, - DWORD dwDestContext, void *pvDestContext, DWORD mshlFlags -) { - HRESULT hres; - LPMARSHAL pMarshal; +HRESULT WINAPI CoGetMarshalSizeMax(ULONG *pulSize, REFIID riid, IUnknown *pUnk, + DWORD dwDestContext, void *pvDestContext, + DWORD mshlFlags) +{ + HRESULT hr; + LPMARSHAL pMarshal; + CLSID marshaler_clsid; - hres = _GetMarshaller(riid,pUnk,dwDestContext,pvDestContext,mshlFlags,&pMarshal); - if (hres) - return hres; - hres = IMarshal_GetMarshalSizeMax(pMarshal,riid,pUnk,dwDestContext,pvDestContext,mshlFlags,pulSize); - *pulSize += sizeof(wine_marshal_id)+sizeof(wine_marshal_data)+sizeof(CLSID); - IMarshal_Release(pMarshal); - return hres; + hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal); + if (hr) + return hr; + + hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext, + pvDestContext, mshlFlags, &marshaler_clsid); + if (hr) + { + ERR("IMarshal::GetUnmarshalClass failed, 0x%08lx\n", hr); + IMarshal_Release(pMarshal); + return hr; + } + + hr = IMarshal_GetMarshalSizeMax(pMarshal, riid, pUnk, dwDestContext, + pvDestContext, mshlFlags, pulSize); + /* add on the size of the common header */ + *pulSize += FIELD_OFFSET(OBJREF, u_objref); + + /* if custom marshaling, add on size of custom header */ + if (!IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal)) + *pulSize += FIELD_OFFSET(OBJREF, u_objref.u_custom.size) - + FIELD_OFFSET(OBJREF, u_objref.u_custom); + + IMarshal_Release(pMarshal); + return hr; } /*********************************************************************** * CoMarshalInterface [OLE32.@] + * + * Marshals an interface into a stream so that the object can then be + * unmarshaled from another COM apartment and used remotely. + * + * PARAMS + * pStream [I] Stream the object will be marshaled into. + * riid [I] Identifier of the interface to marshal. + * pUnk [I] Pointer to the object to marshal. + * dwDestContext [I] Destination. Used to enable or disable optimizations. + * pvDestContext [I] Reserved. Must be NULL. + * mshlFlags [I] Flags that affect the marshaling. See notes. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * NOTES + * + * The mshlFlags parameter can take one or more of the following flags: + *| MSHLFLAGS_NORMAL - Unmarshal once, releases stub on last proxy release. + *| MSHLFLAGS_TABLESTRONG - Unmarshal many, release when CoReleaseMarshalData() called. + *| MSHLFLAGS_TABLEWEAK - Unmarshal many, releases stub on last proxy release. + *| MSHLFLAGS_NOPING - No automatic garbage collection (and so reduces network traffic). + * + * If a marshaled object is not unmarshaled, then CoReleaseMarshalData() must + * be called in order to release the resources used in the marshaling. + * + * SEE ALSO + * CoUnmarshalInterface(), CoReleaseMarshalData(). */ -HRESULT WINAPI -CoMarshalInterface( IStream *pStm, REFIID riid, IUnknown *pUnk, - DWORD dwDestContext, void *pvDestContext, DWORD mshlflags -) { - HRESULT hres; - LPMARSHAL pMarshal; - CLSID xclsid; - ULONG writeres; - wine_marshal_id mid; - wine_marshal_data md; - ULONG res; - IUnknown *pUnknown; +HRESULT WINAPI CoMarshalInterface(IStream *pStream, REFIID riid, IUnknown *pUnk, + DWORD dwDestContext, void *pvDestContext, + DWORD mshlFlags) +{ + HRESULT hr; + CLSID marshaler_clsid; + OBJREF objref; + IStream * pMarshalStream = NULL; + LPMARSHAL pMarshal; - TRACE("(%p, %s, %p, %lx, %p, %lx)\n", - pStm,debugstr_guid(riid),pUnk,dwDestContext,pvDestContext,mshlflags - ); + TRACE("(%p, %s, %p, %lx, %p, %lx)\n", pStream, debugstr_guid(riid), pUnk, + dwDestContext, pvDestContext, mshlFlags); - if (pUnk == NULL) - return E_INVALIDARG; + if (pUnk == NULL) + return E_INVALIDARG; - STUBMGR_Start(); /* Just to be sure we have one running. */ - mid.processid = GetCurrentProcessId(); - IUnknown_QueryInterface(pUnk,&IID_IUnknown,(LPVOID*)&pUnknown); - mid.objectid = (DWORD)pUnknown; - IUnknown_Release(pUnknown); - memcpy(&mid.iid,riid,sizeof(mid.iid)); - md.dwDestContext = dwDestContext; - md.mshlflags = mshlflags; - hres = IStream_Write(pStm,&mid,sizeof(mid),&res); - if (hres) return hres; - hres = IStream_Write(pStm,&md,sizeof(md),&res); - if (hres) return hres; - hres = _GetMarshaller(riid,pUnk,dwDestContext,pvDestContext,mshlflags,&pMarshal); - if (hres) { - FIXME("Failed to get marshaller, %lx?\n",hres); - return hres; - } - hres = IMarshal_GetUnmarshalClass(pMarshal,riid,pUnk,dwDestContext,pvDestContext,mshlflags,&xclsid); - if (hres) { - FIXME("IMarshal:GetUnmarshalClass failed, %lx\n",hres); - goto release_marshal; - } - hres = IStream_Write(pStm,&xclsid,sizeof(xclsid),&writeres); - if (hres) { - FIXME("Stream write failed, %lx\n",hres); - goto release_marshal; - } + objref.signature = OBJREF_SIGNATURE; + objref.iid = *riid; - TRACE("Calling IMarshal::MarshalInterace\n"); - hres = IMarshal_MarshalInterface(pMarshal,pStm,riid,pUnk,dwDestContext,pvDestContext,mshlflags); - - if (hres) { - if (IsEqualGUID(riid,&IID_IOleObject)) { - ERR("WINE currently cannot marshal IOleObject interfaces. This means you cannot embed/link OLE objects between applications.\n"); - } else { - FIXME("Failed to marshal the interface %s, %lx?\n",debugstr_guid(riid),hres); + /* get the marshaler for the specified interface */ + hr = get_marshaler(riid, pUnk, dwDestContext, pvDestContext, mshlFlags, &pMarshal); + if (hr) + { + ERR("Failed to get marshaller, 0x%08lx\n", hr); + return hr; } - } -release_marshal: - IMarshal_Release(pMarshal); - return hres; -} + hr = IMarshal_GetUnmarshalClass(pMarshal, riid, pUnk, dwDestContext, + pvDestContext, mshlFlags, &marshaler_clsid); + if (hr) + { + ERR("IMarshal::GetUnmarshalClass failed, 0x%08lx\n", hr); + goto cleanup; + } + + /* FIXME: implement handler marshaling too */ + if (IsEqualCLSID(&marshaler_clsid, &CLSID_DfMarshal)) + { + TRACE("Using standard marshaling\n"); + objref.flags = OBJREF_STANDARD; + pMarshalStream = pStream; + } + else + { + TRACE("Using custom marshaling\n"); + objref.flags = OBJREF_CUSTOM; + /* we do custom marshaling into a memory stream so that we know what + * size to write into the OR_CUSTOM header */ + hr = CreateStreamOnHGlobal(NULL, TRUE, &pMarshalStream); + if (hr) + { + ERR("CreateStreamOnHGLOBAL failed with 0x%08lx\n", hr); + goto cleanup; + } + } + + /* write the common OBJREF header to the stream */ + hr = IStream_Write(pStream, &objref, FIELD_OFFSET(OBJREF, u_objref), NULL); + if (hr) + { + ERR("Failed to write OBJREF header to stream, 0x%08lx\n", hr); + goto cleanup; + } + + TRACE("Calling IMarshal::MarshalInterace\n"); + /* call helper object to do the actual marshaling */ + hr = IMarshal_MarshalInterface(pMarshal, pMarshalStream, riid, pUnk, dwDestContext, + pvDestContext, mshlFlags); + + if (hr) + { + ERR("Failed to marshal the interface %s, %lx\n", debugstr_guid(riid), hr); + goto cleanup; + } + + if (objref.flags & OBJREF_CUSTOM) + { + ULONG custom_header_size = FIELD_OFFSET(OBJREF, u_objref.u_custom.size) - + FIELD_OFFSET(OBJREF, u_objref.u_custom); + HGLOBAL hGlobal; + LPVOID data; + hr = GetHGlobalFromStream(pMarshalStream, &hGlobal); + if (hr) + { + ERR("Couldn't get HGLOBAL from stream\n"); + hr = E_UNEXPECTED; + goto cleanup; + } + objref.u_objref.u_custom.cbExtension = 0; + objref.u_objref.u_custom.size = GlobalSize(hGlobal); + /* write constant sized OR_CUSTOM data into stream */ + hr = IStream_Write(pStream, &objref.u_objref.u_custom, + custom_header_size, NULL); + if (hr) + { + ERR("Failed to write OR_CUSTOM header to stream with 0x%08lx\n", hr); + goto cleanup; + } + + data = GlobalLock(hGlobal); + if (!data) + { + ERR("GlobalLock failed\n"); + hr = E_UNEXPECTED; + goto cleanup; + } + /* write custom marshal data */ + hr = IStream_Write(pStream, data, objref.u_objref.u_custom.size, NULL); + if (hr) + { + ERR("Failed to write custom marshal data with 0x%08lx\n", hr); + goto cleanup; + } + GlobalUnlock(hGlobal); + } + +cleanup: + if (pMarshalStream && (objref.flags & OBJREF_CUSTOM)) + IStream_Release(pMarshalStream); + IMarshal_Release(pMarshal); + return hr; +} /*********************************************************************** * CoUnmarshalInterface [OLE32.@] + * + * Unmarshals an object from a stream by creating a proxy to the remote + * object, if necessary. + * + * PARAMS + * + * pStream [I] Stream containing the marshaled object. + * riid [I] Interface identifier of the object to create a proxy to. + * ppv [O] Address where proxy will be stored. + * + * RETURNS + * + * Success: S_OK. + * Failure: HRESULT code. + * + * SEE ALSO + * CoMarshalInterface(). */ -HRESULT WINAPI -CoUnmarshalInterface(IStream *pStm, REFIID riid, LPVOID *ppv) { - HRESULT hres; - wine_marshal_id mid; - wine_marshal_data md; - ULONG res; - LPMARSHAL pMarshal; - LPUNKNOWN pUnk; - CLSID xclsid; +HRESULT WINAPI CoUnmarshalInterface(IStream *pStream, REFIID riid, LPVOID *ppv) +{ + HRESULT hr; + LPMARSHAL pMarshal; - TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(riid),ppv); + TRACE("(%p, %s, %p)\n", pStream, debugstr_guid(riid), ppv); - hres = IStream_Read(pStm,&mid,sizeof(mid),&res); - if (hres) { - FIXME("Stream read 1 failed, %lx, (%ld of %d)\n",hres,res,sizeof(mid)); - return hres; - } - hres = IStream_Read(pStm,&md,sizeof(md),&res); - if (hres) { - FIXME("Stream read 2 failed, %lx, (%ld of %d)\n",hres,res,sizeof(md)); - return hres; - } - hres = IStream_Read(pStm,&xclsid,sizeof(xclsid),&res); - if (hres) { - FIXME("Stream read 3 failed, %lx, (%ld of %d)\n",hres,res,sizeof(xclsid)); - return hres; - } - hres=CoCreateInstance(&xclsid,NULL,CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER,&IID_IMarshal,(void**)&pUnk); - if (hres) { - FIXME("Failed to create instance of unmarshaller %s.\n",debugstr_guid(&xclsid)); - return hres; - } - hres = _GetMarshaller(riid,pUnk,md.dwDestContext,NULL,md.mshlflags,&pMarshal); - if (hres) { - FIXME("Failed to get unmarshaller, %lx?\n",hres); - return hres; - } - hres = IMarshal_UnmarshalInterface(pMarshal,pStm,riid,ppv); - if (hres) { - FIXME("Failed to Unmarshal the interface, %lx?\n",hres); - goto release_marshal; - } -release_marshal: - IMarshal_Release(pMarshal); - return hres; + hr = get_unmarshaler_from_stream(pStream, &pMarshal); + if (hr != S_OK) + return hr; + + /* call the helper object to do the actual unmarshaling */ + hr = IMarshal_UnmarshalInterface(pMarshal, pStream, riid, ppv); + if (hr) + ERR("IMarshal::UnmarshalInterface failed, 0x%08lx\n", hr); + + IMarshal_Release(pMarshal); + return hr; } /*********************************************************************** * CoReleaseMarshalData [OLE32.@] + * + * Releases resources associated with an object that has been marshaled into + * a stream. + * + * PARAMS + * + * pStream [I] The stream that the object has been marshaled into. + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT error code. + * + * NOTES + * + * Call this function to release resources associated with a normal or + * table-weak marshal that will not be unmarshaled, and all table-strong + * marshals when they are no longer needed. + * + * SEE ALSO + * CoMarshalInterface(), CoUnmarshalInterface(). */ -HRESULT WINAPI -CoReleaseMarshalData(IStream *pStm) { - HRESULT hres; - wine_marshal_id mid; - wine_marshal_data md; - ULONG res; - LPMARSHAL pMarshal; - LPUNKNOWN pUnk; - CLSID xclsid; +HRESULT WINAPI CoReleaseMarshalData(IStream *pStream) +{ + HRESULT hr; + LPMARSHAL pMarshal; - TRACE("(%p)\n",pStm); + TRACE("(%p)\n", pStream); - hres = IStream_Read(pStm,&mid,sizeof(mid),&res); - if (hres) { - FIXME("Stream read 1 failed, %lx, (%ld of %d)\n",hres,res,sizeof(mid)); - return hres; - } - hres = IStream_Read(pStm,&md,sizeof(md),&res); - if (hres) { - FIXME("Stream read 2 failed, %lx, (%ld of %d)\n",hres,res,sizeof(md)); - return hres; - } - hres = IStream_Read(pStm,&xclsid,sizeof(xclsid),&res); - if (hres) { - FIXME("Stream read 3 failed, %lx, (%ld of %d)\n",hres,res,sizeof(xclsid)); - return hres; - } - hres=CoCreateInstance(&xclsid,NULL,CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER,&IID_IMarshal,(void**)(char*)&pUnk); - if (hres) { - FIXME("Failed to create instance of unmarshaller %s.\n",debugstr_guid(&xclsid)); - return hres; - } - hres = IUnknown_QueryInterface(pUnk,&IID_IMarshal,(LPVOID*)(char*)&pMarshal); - if (hres) { - FIXME("Failed to get IMarshal iface, %lx?\n",hres); - return hres; - } - hres = IMarshal_ReleaseMarshalData(pMarshal,pStm); - if (hres) { - FIXME("Failed to releasemarshaldata the interface, %lx?\n",hres); - } - IMarshal_Release(pMarshal); - IUnknown_Release(pUnk); - return hres; + hr = get_unmarshaler_from_stream(pStream, &pMarshal); + if (hr != S_OK) + return hr; + + /* call the helper object to do the releasing of marshal data */ + hr = IMarshal_ReleaseMarshalData(pMarshal, pStream); + if (hr) + ERR("IMarshal::ReleaseMarshalData failed with error 0x%08lx\n", hr); + + IMarshal_Release(pMarshal); + return hr; } @@ -660,12 +1111,11 @@ CoReleaseMarshalData(IStream *pStm) { * Success: S_OK * Failure: E_OUTOFMEMORY and other COM error codes * - * SEE + * SEE ALSO * CoMarshalInterface(), CoUnmarshalInterface() and CoGetInterfaceAndReleaseStream() */ -HRESULT WINAPI -CoMarshalInterThreadInterfaceInStream( - REFIID riid, LPUNKNOWN pUnk, LPSTREAM * ppStm) +HRESULT WINAPI CoMarshalInterThreadInterfaceInStream( + REFIID riid, LPUNKNOWN pUnk, LPSTREAM * ppStm) { ULARGE_INTEGER xpos; LARGE_INTEGER seekto; @@ -698,11 +1148,11 @@ CoMarshalInterThreadInterfaceInStream( * Success: S_OK * Failure: A COM error code * - * SEE + * SEE ALSO * CoMarshalInterThreadInterfaceInStream() and CoUnmarshalInteface() */ -HRESULT WINAPI -CoGetInterfaceAndReleaseStream(LPSTREAM pStm,REFIID riid, LPVOID *ppv) +HRESULT WINAPI CoGetInterfaceAndReleaseStream(LPSTREAM pStm, REFIID riid, + LPVOID *ppv) { HRESULT hres; @@ -713,55 +1163,58 @@ CoGetInterfaceAndReleaseStream(LPSTREAM pStm,REFIID riid, LPVOID *ppv) return hres; } -static HRESULT WINAPI -SMCF_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) { - *ppv = NULL; - if (IsEqualIID(riid,&IID_IUnknown) || IsEqualIID(riid,&IID_IClassFactory)) { - *ppv = (LPVOID)iface; - return S_OK; - } - return E_NOINTERFACE; +static HRESULT WINAPI StdMarshalCF_QueryInterface(LPCLASSFACTORY iface, + REFIID riid, LPVOID *ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IClassFactory)) + { + *ppv = (LPVOID)iface; + return S_OK; + } + return E_NOINTERFACE; } -static ULONG WINAPI SMCF_AddRef(LPCLASSFACTORY iface) { return 2; } -static ULONG WINAPI SMCF_Release(LPCLASSFACTORY iface) { return 1; } -static HRESULT WINAPI -SMCF_CreateInstance( - LPCLASSFACTORY iface, LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv -) { - if (IsEqualIID(riid,&IID_IMarshal)) { - StdMarshalImpl *dm; - dm=(StdMarshalImpl*)HeapAlloc(GetProcessHeap(),0,sizeof(StdMarshalImpl)); - if (!dm) - return E_FAIL; - dm->lpvtbl = &stdmvtbl; - dm->ref = 1; - *ppv = (LPVOID)dm; - return S_OK; - } +static ULONG WINAPI StdMarshalCF_AddRef(LPCLASSFACTORY iface) +{ + return 2; /* non-heap based object */ +} + +static ULONG WINAPI StdMarshalCF_Release(LPCLASSFACTORY iface) +{ + return 1; /* non-heap based object */ +} + +static HRESULT WINAPI StdMarshalCF_CreateInstance(LPCLASSFACTORY iface, + LPUNKNOWN pUnk, REFIID riid, LPVOID *ppv) +{ + if (IsEqualIID(riid,&IID_IMarshal)) + return StdMarshalImpl_Construct(riid, ppv); + FIXME("(%s), not supported.\n",debugstr_guid(riid)); return E_NOINTERFACE; } -static HRESULT WINAPI -SMCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) { +static HRESULT WINAPI StdMarshalCF_LockServer(LPCLASSFACTORY iface, BOOL fLock) +{ FIXME("(%d), stub!\n",fLock); return S_OK; } -static IClassFactoryVtbl dfmarshalcfvtbl = { - SMCF_QueryInterface, - SMCF_AddRef, - SMCF_Release, - SMCF_CreateInstance, - SMCF_LockServer +static IClassFactoryVtbl StdMarshalCFVtbl = +{ + StdMarshalCF_QueryInterface, + StdMarshalCF_AddRef, + StdMarshalCF_Release, + StdMarshalCF_CreateInstance, + StdMarshalCF_LockServer }; -static IClassFactoryVtbl *pdfmarshalcfvtbl = &dfmarshalcfvtbl; +static IClassFactoryVtbl *StdMarshalCF = &StdMarshalCFVtbl; -HRESULT -MARSHAL_GetStandardMarshalCF(LPVOID *ppv) { - *ppv = &pdfmarshalcfvtbl; - return S_OK; +HRESULT MARSHAL_GetStandardMarshalCF(LPVOID *ppv) +{ + *ppv = &StdMarshalCF; + return S_OK; } /*********************************************************************** @@ -770,18 +1223,17 @@ MARSHAL_GetStandardMarshalCF(LPVOID *ppv) { * Marshals an HRESULT value into a stream. * * PARAMS - * pStm [I] Stream that hresult will be marshaled into. - * hresult [I] HRESULT to be marshaled. + * pStm [I] Stream that hresult will be marshalled into. + * hresult [I] HRESULT to be marshalled. * * RETURNS * Success: S_OK * Failure: A COM error code * - * SEE + * SEE ALSO * CoUnmarshalHresult(). */ -HRESULT WINAPI -CoMarshalHresult(LPSTREAM pStm, HRESULT hresult) +HRESULT WINAPI CoMarshalHresult(LPSTREAM pStm, HRESULT hresult) { return IStream_Write(pStm, &hresult, sizeof(hresult), NULL); } @@ -792,18 +1244,17 @@ CoMarshalHresult(LPSTREAM pStm, HRESULT hresult) * Unmarshals an HRESULT value from a stream. * * PARAMS - * pStm [I] Stream that hresult will be unmarshaled from. - * phresult [I] Pointer to HRESULT where the value will be unmarshaled to. + * pStm [I] Stream that hresult will be unmarshalled from. + * phresult [I] Pointer to HRESULT where the value will be unmarshalled to. * * RETURNS * Success: S_OK * Failure: A COM error code * - * SEE + * SEE ALSO * CoMarshalHresult(). */ -HRESULT WINAPI -CoUnmarshalHresult(LPSTREAM pStm, HRESULT * phresult) +HRESULT WINAPI CoUnmarshalHresult(LPSTREAM pStm, HRESULT * phresult) { return IStream_Read(pStm, phresult, sizeof(*phresult), NULL); } diff --git a/reactos/lib/ole32/memlockbytes.c b/reactos/lib/ole32/memlockbytes.c index 8bb10ae00dc..1f74c5367c4 100644 --- a/reactos/lib/ole32/memlockbytes.c +++ b/reactos/lib/ole32/memlockbytes.c @@ -32,13 +32,10 @@ #include "windef.h" #include "winbase.h" #include "winuser.h" -#include "wine/winbase16.h" #include "objbase.h" #include "ole2.h" #include "winerror.h" -#include "ifs.h" - #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); diff --git a/reactos/lib/ole32/moniker.c b/reactos/lib/ole32/moniker.c index b114c59854d..f0fcdd5550d 100644 --- a/reactos/lib/ole32/moniker.c +++ b/reactos/lib/ole32/moniker.c @@ -86,9 +86,9 @@ static HRESULT WINAPI RunningObjectTableImpl_NoteChangeTime(IRunningObjectTable* static HRESULT WINAPI RunningObjectTableImpl_GetTimeOfLastChange(IRunningObjectTable* iface, IMoniker* pmkObjectName,FILETIME* pfiletime); static HRESULT WINAPI RunningObjectTableImpl_EnumRunning(IRunningObjectTable* iface, IEnumMoniker** ppenumMoniker); /* Local functions*/ -HRESULT WINAPI RunningObjectTableImpl_Initialize(); -HRESULT WINAPI RunningObjectTableImpl_UnInitialize(); -HRESULT WINAPI RunningObjectTableImpl_Destroy(); +HRESULT WINAPI RunningObjectTableImpl_Initialize(void); +HRESULT WINAPI RunningObjectTableImpl_UnInitialize(void); +HRESULT WINAPI RunningObjectTableImpl_Destroy(void); HRESULT WINAPI RunningObjectTableImpl_GetObjectIndex(RunningObjectTableImpl* This,DWORD identReg,IMoniker* pmk,DWORD *indx); /* Virtual function table for the IRunningObjectTable class. */ diff --git a/reactos/lib/ole32/ole2.c b/reactos/lib/ole32/ole2.c index 515752327df..2a428123d62 100644 --- a/reactos/lib/ole32/ole2.c +++ b/reactos/lib/ole32/ole2.c @@ -129,8 +129,8 @@ static void OLEUTL_ReadRegistryDWORDValue(HKEY regKey, DWORD* pdwValue); /****************************************************************************** * These are the prototypes of the utility methods used to manage a shared menu */ -static void OLEMenu_Initialize(); -static void OLEMenu_UnInitialize(); +static void OLEMenu_Initialize(void); +static void OLEMenu_UnInitialize(void); BOOL OLEMenu_InstallHooks( DWORD tid ); BOOL OLEMenu_UnInstallHooks( DWORD tid ); OleMenuHookItem * OLEMenu_IsHookInstalled( DWORD tid ); @@ -142,14 +142,14 @@ LRESULT CALLBACK OLEMenu_GetMsgProc(INT code, WPARAM wParam, LPARAM lParam); /****************************************************************************** * These are the prototypes of the OLE Clipboard initialization methods (in clipboard.c) */ -void OLEClipbrd_UnInitialize(); -void OLEClipbrd_Initialize(); +void OLEClipbrd_UnInitialize(void); +void OLEClipbrd_Initialize(void); /****************************************************************************** * These are the prototypes of the utility methods used for OLE Drag n Drop */ -static void OLEDD_Initialize(); -static void OLEDD_UnInitialize(); +static void OLEDD_Initialize(void); +static void OLEDD_UnInitialize(void); static void OLEDD_InsertDropTarget( DropTargetNode* nodeToAdd); static DropTargetNode* OLEDD_ExtractDropTarget( @@ -169,7 +169,7 @@ static void OLEDD_TrackStateChange( TrackerWindowInfo* trackerInfo, POINT mousePos, DWORD keyState); -static DWORD OLEDD_GetButtonState(); +static DWORD OLEDD_GetButtonState(void); /****************************************************************************** @@ -985,8 +985,7 @@ BOOL OLEMenu_UnInstallHooks( DWORD tid ) CLEANUP: /* Release the hook table entry */ - if (pHookItem) - HeapFree(pHookItem->hHeap, 0, pHookItem ); + HeapFree(pHookItem->hHeap, 0, pHookItem ); return FALSE; } @@ -1602,7 +1601,7 @@ static void OLEDD_Initialize() ZeroMemory (&wndClass, sizeof(WNDCLASSA)); wndClass.style = CS_GLOBALCLASS; - wndClass.lpfnWndProc = (WNDPROC)OLEDD_DragTrackerWindowProc; + wndClass.lpfnWndProc = OLEDD_DragTrackerWindowProc; wndClass.cbClsExtra = 0; wndClass.cbWndExtra = sizeof(TrackerWindowInfo*); wndClass.hCursor = 0; diff --git a/reactos/lib/ole32/oleobj.c b/reactos/lib/ole32/oleobj.c index e3bbe30db71..e83c59268c5 100644 --- a/reactos/lib/ole32/oleobj.c +++ b/reactos/lib/ole32/oleobj.c @@ -50,7 +50,7 @@ typedef struct OleAdviseHolderImpl } OleAdviseHolderImpl; -static LPOLEADVISEHOLDER OleAdviseHolderImpl_Constructor(); +static LPOLEADVISEHOLDER OleAdviseHolderImpl_Constructor(void); static void OleAdviseHolderImpl_Destructor(OleAdviseHolderImpl* ptrToDestroy); static HRESULT WINAPI OleAdviseHolderImpl_QueryInterface(LPOLEADVISEHOLDER,REFIID,LPVOID*); static ULONG WINAPI OleAdviseHolderImpl_AddRef(LPOLEADVISEHOLDER); @@ -181,8 +181,11 @@ static ULONG WINAPI OleAdviseHolderImpl_AddRef( LPOLEADVISEHOLDER iface) { OleAdviseHolderImpl *This = (OleAdviseHolderImpl *)iface; - TRACE("(%p)->(ref=%ld)\n", This, This->ref); - return ++(This->ref); + ULONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p)->(ref=%ld)\n", This, ref - 1); + + return ref; } /****************************************************************************** @@ -377,7 +380,7 @@ typedef struct DataAdviseHolder /************************************************************************** * DataAdviseHolder method prototypes */ -static IDataAdviseHolder* DataAdviseHolder_Constructor(); +static IDataAdviseHolder* DataAdviseHolder_Constructor(void); static void DataAdviseHolder_Destructor(DataAdviseHolder* ptrToDestroy); static HRESULT WINAPI DataAdviseHolder_QueryInterface( IDataAdviseHolder* iface, diff --git a/reactos/lib/ole32/oleproxy.c b/reactos/lib/ole32/oleproxy.c index c38dc8feec9..5532988d533 100644 --- a/reactos/lib/ole32/oleproxy.c +++ b/reactos/lib/ole32/oleproxy.c @@ -271,6 +271,7 @@ typedef struct _CFProxy { DWORD ref; IRpcChannelBuffer *chanbuf; + IUnknown *outer_unknown; } CFProxy; static HRESULT WINAPI IRpcProxyBufferImpl_QueryInterface(LPRPCPROXYBUFFER iface,REFIID riid,LPVOID *ppv) { @@ -317,6 +318,8 @@ static void WINAPI IRpcProxyBufferImpl_Disconnect(LPRPCPROXYBUFFER iface) { static HRESULT WINAPI CFProxy_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) { + ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface); + if (This->outer_unknown) return IUnknown_QueryInterface(This->outer_unknown, riid, ppv); *ppv = NULL; if (IsEqualIID(&IID_IClassFactory,riid) || IsEqualIID(&IID_IUnknown,riid)) { *ppv = (LPVOID)iface; @@ -331,15 +334,22 @@ CFProxy_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) { static ULONG WINAPI CFProxy_AddRef(LPCLASSFACTORY iface) { ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface); + if (This->outer_unknown) return IUnknown_AddRef(This->outer_unknown); return InterlockedIncrement(&This->ref); } static ULONG WINAPI CFProxy_Release(LPCLASSFACTORY iface) { ULONG ref; ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface); - - ref = InterlockedDecrement(&This->ref); - if (!ref) HeapFree(GetProcessHeap(),0,This); + if (This->outer_unknown) + ref = IUnknown_Release(This->outer_unknown); + else + ref = InterlockedDecrement(&This->ref); + + if (!ref) { + if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf); + HeapFree(GetProcessHeap(),0,This); + } return ref; } @@ -425,7 +435,7 @@ static IClassFactoryVtbl cfproxyvt = { }; static HRESULT -CFProxy_Construct(LPVOID *ppv,LPVOID *ppProxy) { +CFProxy_Construct(IUnknown *pUnkOuter, LPVOID *ppv,LPVOID *ppProxy) { CFProxy *cf; cf = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFProxy)); @@ -434,10 +444,13 @@ CFProxy_Construct(LPVOID *ppv,LPVOID *ppProxy) { cf->lpvtbl_cf = &cfproxyvt; cf->lpvtbl_proxy = &pspbvtbl; - /* 1 reference for the proxy and 1 for the object */ - cf->ref = 2; + /* 1 reference for the proxy... */ + cf->ref = 1; + cf->outer_unknown = pUnkOuter; *ppv = &(cf->lpvtbl_cf); *ppProxy = &(cf->lpvtbl_proxy); + /* ...and 1 for the object */ + IUnknown_AddRef((IUnknown *)*ppv); return S_OK; } @@ -465,7 +478,7 @@ PSFacBuf_CreateProxy( if (IsEqualIID(&IID_IClassFactory,riid) || IsEqualIID(&IID_IUnknown,riid) ) - return CFProxy_Construct(ppv,(LPVOID*)ppProxy); + return CFProxy_Construct(pUnkOuter, ppv,(LPVOID*)ppProxy); FIXME("proxying not implemented for (%s) yet!\n",debugstr_guid(riid)); return E_FAIL; } diff --git a/reactos/lib/ole32/rpc.c b/reactos/lib/ole32/rpc.c index 53dbd00085c..158016fab20 100644 --- a/reactos/lib/ole32/rpc.c +++ b/reactos/lib/ole32/rpc.c @@ -33,18 +33,14 @@ #include "windef.h" #include "winbase.h" #include "winuser.h" +#include "winsvc.h" #include "objbase.h" #include "ole2.h" -#include "ole2ver.h" #include "rpc.h" #include "winerror.h" #include "winreg.h" -#include "wownt32.h" #include "wtypes.h" #include "wine/unicode.h" -#include "wine/winbase16.h" -#include "compobj_private.h" -#include "ifs.h" #include "compobj_private.h" @@ -52,6 +48,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); +#define PIPEPREF "\\\\.\\pipe\\" +#define OLESTUBMGR PIPEPREF"WINE_OLE_StubMgr" + #define REQTYPE_REQUEST 0 typedef struct _wine_rpc_request_header { DWORD reqid; @@ -96,18 +95,24 @@ static wine_rpc_request **reqs = NULL; static int nrofreqs = 0; /* This pipe is _thread_ based, each thread which talks to a remote - * apartment (mid) has its own pipe */ + * apartment (mid) has its own pipe. The same structure is used both + * for outgoing and incoming RPCs. + */ typedef struct _wine_pipe { wine_marshal_id mid; /* target mid */ - DWORD tid; /* thread which owns this outgoing pipe */ + DWORD tid; /* thread which owns this pipe */ HANDLE hPipe; int pending; HANDLE hThread; CRITICAL_SECTION crit; + + APARTMENT *apt; /* apartment of the marshalling thread for the stub dispatch case */ } wine_pipe; -static wine_pipe *pipes = NULL; +#define MAX_WINE_PIPES 256 + +static wine_pipe pipes[MAX_WINE_PIPES]; static int nrofpipes = 0; typedef struct _PipeBuf { @@ -115,14 +120,13 @@ typedef struct _PipeBuf { DWORD ref; wine_marshal_id mid; - wine_pipe *pipe; } PipeBuf; static HRESULT WINAPI read_pipe(HANDLE hf, LPVOID ptr, DWORD size) { DWORD res; if (!ReadFile(hf,ptr,size,&res,NULL)) { - FIXME("Failed to read from %p, le is %lx\n",hf,GetLastError()); + FIXME("Failed to read from %p, le is %ld\n",hf,GetLastError()); return E_FAIL; } if (res!=size) { @@ -162,7 +166,7 @@ static HRESULT WINAPI write_pipe(HANDLE hf, LPVOID ptr, DWORD size) { DWORD res; if (!WriteFile(hf,ptr,size,&res,NULL)) { - FIXME("Failed to write to %p, le is %lx\n",hf,GetLastError()); + FIXME("Failed to write to %p, le is %ld\n",hf,GetLastError()); return E_FAIL; } if (res!=size) { @@ -172,30 +176,30 @@ write_pipe(HANDLE hf, LPVOID ptr, DWORD size) { return S_OK; } -static DWORD WINAPI _StubReaderThread(LPVOID); +static DWORD WINAPI stub_dispatch_thread(LPVOID); static HRESULT PIPE_RegisterPipe(wine_marshal_id *mid, HANDLE hPipe, BOOL startreader) { int i; char pipefn[100]; - wine_pipe *new_pipes; for (i=0;iprocessid) + if (pipes[i].mid.oxid==mid->oxid) return S_OK; - if (pipes) - new_pipes=(wine_pipe*)HeapReAlloc(GetProcessHeap(),0,pipes,sizeof(pipes[0])*(nrofpipes+1)); - else - new_pipes=(wine_pipe*)HeapAlloc(GetProcessHeap(),0,sizeof(pipes[0])); - if (!new_pipes) return E_OUTOFMEMORY; - pipes = new_pipes; - sprintf(pipefn,OLESTUBMGR"_%08lx",mid->processid); + if (nrofpipes + 1 >= MAX_WINE_PIPES) + { + FIXME("Out of pipes, please increase MAX_WINE_PIPES\n"); + return E_OUTOFMEMORY; + } + sprintf(pipefn,OLESTUBMGR"_%08lx%08lx",(DWORD)(mid->oxid >> 32),(DWORD)mid->oxid); memcpy(&(pipes[nrofpipes].mid),mid,sizeof(*mid)); pipes[nrofpipes].hPipe = hPipe; + pipes[nrofpipes].apt = COM_CurrentApt(); + assert( pipes[nrofpipes].apt ); InitializeCriticalSection(&(pipes[nrofpipes].crit)); nrofpipes++; if (startreader) { - pipes[nrofpipes-1].hThread = CreateThread(NULL,0,_StubReaderThread,(LPVOID)(pipes+(nrofpipes-1)),0,&(pipes[nrofpipes-1].tid)); + pipes[nrofpipes-1].hThread = CreateThread(NULL,0,stub_dispatch_thread,(LPVOID)(pipes+(nrofpipes-1)),0,&(pipes[nrofpipes-1].tid)); } else { pipes[nrofpipes-1].tid = GetCurrentThreadId(); } @@ -206,7 +210,7 @@ static HANDLE PIPE_FindByMID(wine_marshal_id *mid) { int i; for (i=0;iprocessid) && + if ((pipes[i].mid.oxid==mid->oxid) && (GetCurrentThreadId()==pipes[i].tid) ) return pipes[i].hPipe; @@ -217,7 +221,7 @@ static wine_pipe* PIPE_GetFromMID(wine_marshal_id *mid) { int i; for (i=0;iprocessid) && + if ((pipes[i].mid.oxid==mid->oxid) && (GetCurrentThreadId()==pipes[i].tid) ) return pipes+i; @@ -303,8 +307,6 @@ PipeBuf_Release(LPRPCCHANNELBUFFER iface) { if (ref) return ref; - FIXME("Free all stuff\n"); - memcpy(&header.mid, &This->mid, sizeof(wine_marshal_id)); pipe = PIPE_FindByMID(&This->mid); @@ -333,16 +335,18 @@ PipeBuf_GetBuffer( static HRESULT COM_InvokeAndRpcSend(wine_rpc_request *req) { - IRpcStubBuffer *stub; + IRpcStubBuffer *stub; RPCOLEMESSAGE msg; HRESULT hres; DWORD reqtype; - hres = MARSHAL_Find_Stub_Buffer(&(req->reqh.mid),&stub); - if (hres) { + if (!(stub = mid_to_stubbuffer(&(req->reqh.mid)))) + { ERR("Stub not found?\n"); - return hres; + return E_FAIL; } + + IUnknown_AddRef(stub); msg.Buffer = req->Buffer; msg.iMethod = req->reqh.iMethod; msg.cbBuffer = req->reqh.cbBuffer; @@ -378,10 +382,6 @@ RPC_QueueRequestAndWait(wine_rpc_request *req) { FIXME("no pipe found.\n"); return E_POINTER; } - if (GetCurrentProcessId() == req->reqh.mid.processid) { - ERR("In current process?\n"); - return E_FAIL; - } req->hPipe = xpipe->hPipe; req->state = REQSTATE_REQ_WAITING_FOR_REPLY; reqtype = REQTYPE_REQUEST; @@ -423,7 +423,7 @@ PipeBuf_SendReceive( TRACE("()\n"); - if (This->mid.processid == GetCurrentProcessId()) { + if (This->mid.oxid == COM_CurrentApt()->oxid) { ERR("Need to call directly!\n"); return E_FAIL; } @@ -489,7 +489,7 @@ PIPE_GetNewPipeBuf(wine_marshal_id *mid, IRpcChannelBuffer **pipebuf) { hPipe = PIPE_FindByMID(mid); if (hPipe == INVALID_HANDLE_VALUE) { char pipefn[200]; - sprintf(pipefn,OLESTUBMGR"_%08lx",mid->processid); + sprintf(pipefn,OLESTUBMGR"_%08lx%08lx",(DWORD)(mid->oxid >> 32),(DWORD)mid->oxid); hPipe = CreateFileA( pipefn, GENERIC_READ|GENERIC_WRITE, @@ -506,7 +506,7 @@ PIPE_GetNewPipeBuf(wine_marshal_id *mid, IRpcChannelBuffer **pipebuf) { hres = PIPE_RegisterPipe(mid, hPipe, FALSE); if (hres) return hres; memset(&ourid,0,sizeof(ourid)); - ourid.processid = GetCurrentProcessId(); + ourid.oxid = COM_CurrentApt()->oxid; if (!WriteFile(hPipe,&ourid,sizeof(ourid),&res,NULL)||(res!=sizeof(ourid))) { ERR("Failed writing startup mid!\n"); return E_FAIL; @@ -569,6 +569,116 @@ create_server(REFCLSID rclsid) { return S_OK; } + +/* + * start_local_service() - start a service given its name and parameters + */ +static DWORD +start_local_service(LPCWSTR name, DWORD num, LPWSTR *params) +{ + SC_HANDLE handle, hsvc; + DWORD r = ERROR_FUNCTION_FAILED; + + TRACE("Starting service %s %ld params\n", debugstr_w(name), num); + + handle = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (!handle) + return r; + hsvc = OpenServiceW(handle, name, SC_MANAGER_ALL_ACCESS); + if (hsvc) + { + if(StartServiceW(hsvc, num, (LPCWSTR*)params)) + r = ERROR_SUCCESS; + else + r = GetLastError(); + if (r==ERROR_SERVICE_ALREADY_RUNNING) + r = ERROR_SUCCESS; + CloseServiceHandle(hsvc); + } + CloseServiceHandle(handle); + + TRACE("StartService returned error %ld (%s)\n", r, r?"ok":"failed"); + + return r; +} + +/* + * create_local_service() - start a COM server in a service + * + * To start a Local Service, we read the AppID value under + * the class's CLSID key, then open the HKCR\\AppId key specified + * there and check for a LocalService value. + * + * Note: Local Services are not supported under Windows 9x + */ +static HRESULT +create_local_service(REFCLSID rclsid) +{ + HRESULT hres = REGDB_E_READREGDB; + WCHAR buf[40], keyname[50]; + static const WCHAR szClsId[] = { 'C','L','S','I','D','\\',0 }; + static const WCHAR szAppId[] = { 'A','p','p','I','d',0 }; + static const WCHAR szAppIdKey[] = { 'A','p','p','I','d','\\',0 }; + static const WCHAR szLocalService[] = { + 'L','o','c','a','l','S','e','r','v','i','c','e',0 }; + static const WCHAR szServiceParams[] = { + 'S','e','r','v','i','c','e','P','a','r','a','m','s',0}; + HKEY hkey; + LONG r; + DWORD type, sz; + + TRACE("Attempting to start Local service for %s\n", debugstr_guid(rclsid)); + + /* read the AppID value under the class's key */ + strcpyW(keyname,szClsId); + StringFromGUID2(rclsid,&keyname[6],39); + r = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &hkey); + if (r!=ERROR_SUCCESS) + return hres; + sz = sizeof buf; + r = RegQueryValueExW(hkey, szAppId, NULL, &type, (LPBYTE)buf, &sz); + RegCloseKey(hkey); + if (r!=ERROR_SUCCESS || type!=REG_SZ) + return hres; + + /* read the LocalService and ServiceParameters values from the AppID key */ + strcpyW(keyname, szAppIdKey); + strcatW(keyname, buf); + r = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &hkey); + if (r!=ERROR_SUCCESS) + return hres; + sz = sizeof buf; + r = RegQueryValueExW(hkey, szLocalService, NULL, &type, (LPBYTE)buf, &sz); + if (r==ERROR_SUCCESS && type==REG_SZ) + { + DWORD num_args = 0; + LPWSTR args[1] = { NULL }; + + /* + * FIXME: I'm not really sure how to deal with the service parameters. + * I suspect that the string returned from RegQueryValueExW + * should be split into a number of arguments by spaces. + * It would make more sense if ServiceParams contained a + * REG_MULTI_SZ here, but it's a REG_SZ for the services + * that I'm interested in for the moment. + */ + r = RegQueryValueExW(hkey, szServiceParams, NULL, &type, NULL, &sz); + if (r == ERROR_SUCCESS && type == REG_SZ && sz) + { + args[0] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sz); + num_args++; + RegQueryValueExW(hkey, szServiceParams, NULL, &type, (LPBYTE)args[0], &sz); + } + r = start_local_service(buf, num_args, args); + if (r==ERROR_SUCCESS) + hres = S_OK; + HeapFree(GetProcessHeap(),0,args[0]); + } + RegCloseKey(hkey); + + return hres; +} + /* http://msdn.microsoft.com/library/en-us/dnmsj99/html/com0199.asp, Figure 4 */ HRESULT create_marshalled_proxy(REFCLSID rclsid, REFIID iid, LPVOID *ppv) { HRESULT hres; @@ -588,6 +698,8 @@ HRESULT create_marshalled_proxy(REFCLSID rclsid, REFIID iid, LPVOID *ppv) { WINE_StringFromCLSID(rclsid,pipefn+strlen(PIPEPREF)); while (tries++hPipe; HRESULT hres = S_OK; - TRACE("STUB reader thread %lx\n",GetCurrentProcessId()); + TRACE("starting for apartment OXID %08lx%08lx\n", (DWORD)(xpipe->mid.oxid >> 32), (DWORD)(xpipe->mid.oxid)); + + /* join marshalling apartment. fixme: this stuff is all very wrong, threading needs to work like native */ + NtCurrentTeb()->ReservedForOle = xpipe->apt; + while (!hres) { int i; + hres = COM_RpcReceive(xpipe); if (hres) break; @@ -754,18 +870,41 @@ _StubReaderThread(LPVOID param) { } } } - FIXME("Failed with hres %lx\n",hres); + + /* fixme: this thread never quits naturally */ + WARN("exiting with hres %lx\n",hres); CloseHandle(xhPipe); return 0; } -static DWORD WINAPI -_StubMgrThread(LPVOID param) { +struct apartment_listener_params +{ + APARTMENT *apt; + HANDLE event; +}; + +/* This thread listens on a named pipe for each apartment that exports + * objects. It deals with incoming connection requests. Each time a + * client connects a separate thread is spawned for that particular + * connection. + * + * This architecture is different in native DCOM. + */ +static DWORD WINAPI apartment_listener_thread(LPVOID p) +{ char pipefn[200]; HANDLE listenPipe; + struct apartment_listener_params * params = (struct apartment_listener_params *)p; + APARTMENT *apt = params->apt; + HANDLE event = params->event; - sprintf(pipefn,OLESTUBMGR"_%08lx",GetCurrentProcessId()); - TRACE("Stub Manager Thread starting on (%s)\n",pipefn); + HeapFree(GetProcessHeap(), 0, params); + + /* we must join the marshalling threads apartment. we already have a ref here */ + NtCurrentTeb()->ReservedForOle = apt; + + sprintf(pipefn,OLESTUBMGR"_%08lx%08lx", (DWORD)(apt->oxid >> 32), (DWORD)(apt->oxid)); + TRACE("Apartment listener thread starting on (%s)\n",pipefn); while (1) { listenPipe = CreateNamedPipeA( @@ -778,28 +917,148 @@ _StubMgrThread(LPVOID param) { NMPWAIT_USE_DEFAULT_WAIT, NULL ); + + /* tell function that started this thread that we have attempted to created the + * named pipe. */ + if (event) { + SetEvent(event); + event = NULL; + } + if (listenPipe == INVALID_HANDLE_VALUE) { - FIXME("pipe creation failed for %s, le is %lx\n",pipefn,GetLastError()); + FIXME("pipe creation failed for %s, error %ld\n",pipefn,GetLastError()); return 1; /* permanent failure, so quit stubmgr thread */ } - if (!ConnectNamedPipe(listenPipe,NULL)) { - ERR("Failure during ConnectNamedPipe %lx!\n",GetLastError()); + + /* an already connected pipe is not an error */ + if (!ConnectNamedPipe(listenPipe,NULL) && + (GetLastError() != ERROR_PIPE_CONNECTED)) { + ERR("Failure during ConnectNamedPipe %ld!\n",GetLastError()); CloseHandle(listenPipe); continue; } + PIPE_StartRequestThread(listenPipe); } return 0; } -void -STUBMGR_Start() { - static BOOL stubMgrRunning = FALSE; - DWORD tid; +void start_apartment_listener_thread() +{ + APARTMENT *apt = COM_CurrentApt(); + + assert( apt ); + + TRACE("apt->listenertid=%ld\n", apt->listenertid); - if (!stubMgrRunning) { - stubMgrRunning = TRUE; - CreateThread(NULL,0,_StubMgrThread,NULL,0,&tid); - Sleep(2000); /* actually we just try opening the pipe until it succeeds */ - } + /* apt->listenertid is a hack which needs to die at some point, as + * it leaks information into the apartment structure. in fact, + * this thread isn't quite correct anyway as native RPC doesn't + * use a thread per apartment at all, instead the dispatch thread + * either enters the apartment to perform the RPC (for MTAs, RTAs) + * or does a context switch into it for STAs. + */ + + if (!apt->listenertid) + { + HANDLE thread; + HANDLE event = CreateEventW(NULL, TRUE, FALSE, NULL); + struct apartment_listener_params * params = HeapAlloc(GetProcessHeap(), 0, sizeof(*params)); + + params->apt = apt; + params->event = event; + thread = CreateThread(NULL, 0, apartment_listener_thread, params, 0, &apt->listenertid); + CloseHandle(thread); + /* wait for pipe to be created before returning, otherwise we + * might try to use it and fail */ + WaitForSingleObject(event, INFINITE); + CloseHandle(event); + } +} + +struct local_server_params +{ + CLSID clsid; + IStream *stream; +}; + +static DWORD WINAPI local_server_thread(LPVOID param) +{ + struct local_server_params * lsp = (struct local_server_params *)param; + HANDLE hPipe; + char pipefn[200]; + HRESULT hres; + IStream *pStm = lsp->stream; + STATSTG ststg; + unsigned char *buffer; + int buflen; + LARGE_INTEGER seekto; + ULARGE_INTEGER newpos; + ULONG res; + + TRACE("Starting threader for %s.\n",debugstr_guid(&lsp->clsid)); + + strcpy(pipefn,PIPEPREF); + WINE_StringFromCLSID(&lsp->clsid,pipefn+strlen(PIPEPREF)); + + HeapFree(GetProcessHeap(), 0, lsp); + + hPipe = CreateNamedPipeA( pipefn, PIPE_ACCESS_DUPLEX, + PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, + 4096, 4096, NMPWAIT_USE_DEFAULT_WAIT, NULL ); + if (hPipe == INVALID_HANDLE_VALUE) { + FIXME("pipe creation failed for %s, le is %ld\n",pipefn,GetLastError()); + return 1; + } + while (1) { + if (!ConnectNamedPipe(hPipe,NULL)) { + ERR("Failure during ConnectNamedPipe %ld, ABORT!\n",GetLastError()); + break; + } + + TRACE("marshalling IClassFactory to client\n"); + + hres = IStream_Stat(pStm,&ststg,0); + if (hres) return hres; + + buflen = ststg.cbSize.u.LowPart; + buffer = HeapAlloc(GetProcessHeap(),0,buflen); + seekto.u.LowPart = 0; + seekto.u.HighPart = 0; + hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos); + if (hres) { + FIXME("IStream_Seek failed, %lx\n",hres); + return hres; + } + + hres = IStream_Read(pStm,buffer,buflen,&res); + if (hres) { + FIXME("Stream Read failed, %lx\n",hres); + return hres; + } + + IStream_Release(pStm); + + WriteFile(hPipe,buffer,buflen,&res,NULL); + FlushFileBuffers(hPipe); + DisconnectNamedPipe(hPipe); + + TRACE("done marshalling IClassFactory\n"); + } + CloseHandle(hPipe); + return 0; +} + +void RPC_StartLocalServer(REFCLSID clsid, IStream *stream) +{ + DWORD tid; + HANDLE thread; + struct local_server_params *lsp = HeapAlloc(GetProcessHeap(), 0, sizeof(*lsp)); + + lsp->clsid = *clsid; + lsp->stream = stream; + + thread = CreateThread(NULL, 0, local_server_thread, lsp, 0, &tid); + CloseHandle(thread); + /* FIXME: failure handling */ } diff --git a/reactos/lib/ole32/stg_bigblockfile.c b/reactos/lib/ole32/stg_bigblockfile.c index 050eb537d57..47ed3384c44 100644 --- a/reactos/lib/ole32/stg_bigblockfile.c +++ b/reactos/lib/ole32/stg_bigblockfile.c @@ -423,6 +423,7 @@ void BIGBLOCKFILE_SetSize(LPBIGBLOCKFILE This, ULARGE_INTEGER newSize) if (This->fileBased) { char buf[10]; + DWORD w; /* * close file-mapping object, must be done before call to SetEndFile @@ -445,7 +446,7 @@ void BIGBLOCKFILE_SetSize(LPBIGBLOCKFILE This, ULARGE_INTEGER newSize) */ memset(buf, '0', 10); SetFilePointer(This->hfile, newSize.u.LowPart, NULL, FILE_BEGIN); - WriteFile(This->hfile, buf, 10, NULL, NULL); + WriteFile(This->hfile, buf, 10, &w, NULL); /* * END HACK */ diff --git a/reactos/lib/ole32/stg_stream.c b/reactos/lib/ole32/stg_stream.c index 5070ede59fc..e6569f5d1b4 100644 --- a/reactos/lib/ole32/stg_stream.c +++ b/reactos/lib/ole32/stg_stream.c @@ -447,6 +447,9 @@ HRESULT WINAPI StgStreamImpl_Write( return STG_E_ACCESSDENIED; } + if (!pv) + return STG_E_INVALIDPOINTER; + /* * If the caller is not interested in the number of bytes written, * we use another buffer to avoid "if" statements in the code. diff --git a/reactos/lib/ole32/storage32.c b/reactos/lib/ole32/storage32.c index c9ee7f2dce7..633657f319a 100644 --- a/reactos/lib/ole32/storage32.c +++ b/reactos/lib/ole32/storage32.c @@ -51,6 +51,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(storage); #define FILE_BEGIN 0 +#define STGM_SHARE_MODE(stgm) ((stgm)&0xf0) /* Used for OleConvertIStorageToOLESTREAM and OleConvertOLESTREAMToIStorage */ #define OLESTREAM_ID 0x501 @@ -872,18 +873,23 @@ HRESULT WINAPI StorageBaseImpl_CreateStream( if (pwcsName == 0) return STG_E_INVALIDNAME; + if (reserved1 || reserved2) + return STG_E_INVALIDPARAMETER; + /* * Validate the STGM flags */ if ( FAILED( validateSTGM(grfMode) )) return STG_E_INVALIDFLAG; + if ( !(grfMode & STGM_SHARE_EXCLUSIVE) ) + return STG_E_INVALIDFLAG; + /* * As documented. */ - if ( !(grfMode & STGM_SHARE_EXCLUSIVE) || - (grfMode & STGM_DELETEONRELEASE) || - (grfMode & STGM_TRANSACTED) ) + if ((grfMode & STGM_DELETEONRELEASE) || + (grfMode & STGM_TRANSACTED)) return STG_E_INVALIDFUNCTION; /* @@ -1680,7 +1686,7 @@ HRESULT WINAPI StorageImpl_DestroyElement( This->rootPropertySetIndex, &parentProperty); - assert(res==TRUE); + assert(res); /* * Second, check to see if by any chance the actual storage (This) is not @@ -2395,8 +2401,7 @@ void StorageImpl_Destroy( { TRACE("(%p)\n", This); - if(This->pwcsName) - HeapFree(GetProcessHeap(), 0, This->pwcsName); + HeapFree(GetProcessHeap(), 0, This->pwcsName); BlockChainStream_Destroy(This->smallBlockRootChain); BlockChainStream_Destroy(This->rootBlockChain); @@ -5426,6 +5431,8 @@ HRESULT WINAPI StgCreateDocfile( */ if (ppstgOpen == 0) return STG_E_INVALIDPOINTER; + if (reserved != 0) + return STG_E_INVALIDPARAMETER; /* * Validate the STGM flags @@ -5433,6 +5440,14 @@ HRESULT WINAPI StgCreateDocfile( if ( FAILED( validateSTGM(grfMode) )) return STG_E_INVALIDFLAG; + /* StgCreateDocFile always opens for write */ + if (!(grfMode & (STGM_WRITE|STGM_READWRITE))) + return STG_E_INVALIDFLAG; + + /* always opens non-shared */ + if (!(grfMode & STGM_SHARE_EXCLUSIVE)) + return STG_E_INVALIDFLAG; + /* * Generate a unique name. */ @@ -5493,6 +5508,8 @@ HRESULT WINAPI StgCreateDocfile( if (hFile == INVALID_HANDLE_VALUE) { + if(GetLastError() == ERROR_FILE_EXISTS) + return STG_E_FILEALREADYEXISTS; return E_FAIL; } @@ -5564,18 +5581,44 @@ HRESULT WINAPI StgOpenStorage( snbExclude, reserved, ppstgOpen); /* - * Perform a sanity check + * Perform sanity checks */ - if (( pwcsName == 0) || (ppstgOpen == 0) ) + if (pwcsName == 0) + { + hr = STG_E_INVALIDNAME; + goto end; + } + + if (ppstgOpen == 0) { hr = STG_E_INVALIDPOINTER; goto end; } + if (reserved) + { + hr = STG_E_INVALIDPARAMETER; + goto end; + } + + /* + * Validate the sharing mode + */ + switch(STGM_SHARE_MODE(grfMode)) + { + case STGM_SHARE_EXCLUSIVE: + case STGM_SHARE_DENY_WRITE: + break; + default: + hr = STG_E_INVALIDFLAG; + goto end; + } + /* * Validate the STGM flags */ - if ( FAILED( validateSTGM(grfMode) )) + if ( FAILED( validateSTGM(grfMode) ) || + (grfMode&STGM_CREATE)) { hr = STG_E_INVALIDFLAG; goto end; @@ -5600,8 +5643,6 @@ HRESULT WINAPI StgOpenStorage( FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, 0); - length = GetFileSize(hFile, NULL); - if (hFile==INVALID_HANDLE_VALUE) { DWORD last_error = GetLastError(); @@ -5634,6 +5675,8 @@ HRESULT WINAPI StgOpenStorage( goto end; } + length = GetFileSize(hFile, NULL); + /* * Allocate and initialize the new IStorage32object. */ @@ -7355,15 +7398,9 @@ HRESULT WINAPI OleConvertOLESTREAMToIStorage ( /* Free allocated memory */ for(i=0; i < 2; i++) { - if(pOleStreamData[i].pData != NULL) - { - HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData); - } - if(pOleStreamData[i].pstrOleObjFileName != NULL) - { - HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName); - pOleStreamData[i].pstrOleObjFileName = NULL; - } + HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData); + HeapFree(GetProcessHeap(),0,pOleStreamData[i].pstrOleObjFileName); + pOleStreamData[i].pstrOleObjFileName = NULL; } return hRes; } @@ -7432,10 +7469,7 @@ HRESULT WINAPI OleConvertIStorageToOLESTREAM ( /* Free allocated memory */ for(i=0; i < 2; i++) { - if(pOleStreamData[i].pData != NULL) - { - HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData); - } + HeapFree(GetProcessHeap(),0,pOleStreamData[i].pData); } return hRes;