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;