Sync to Wine-20050111:
Michael Stefaniuc <mstefani(a)redhat.de>
- Do not check for non NULL pointer before HeapFree'ing it. It's
redundant.
Eric Pouech <pouech-eric(a)wanadoo.fr>
- Fixed some errors in function prototypes.
- ReadFile and WriteFile must be passed a parameter for the number of
handled bytes when no overlapped operation is done.
- Removed excessive statement (break after return or goto, not useful
break, not needed vars...)
Robert Shearman <rob(a)codeweavers.com>
- Remove unnecessary WNDPROC casts.
- Document how thread-safety is ensured for each member of the
stub_manager and ifstub structs.
- Make stub_manager ref counted to ensure it doesn't get freed whilst
it is still being used.
- ifstubs are now freed only when the controlling stub_manager is freed.
- Rename stub_manager_ref/unref to stub_manager_ext_addref/release
respectively and make then take an unsigned long to prevent
malicious callers from passing in a negative value and corrupting
the ref count.
- Rename iid in wine_marshal_id to ipid and use IPIDs instead of IIDs in
the stub manager.
- The channel buffer can be NULL if the proxy is disconnected, so check
for this before releasing it.
- Make the ClassFactory proxy support aggregation.
- Document how thread-safety is ensured for each member of the
stub_manager and ifstub structs.
- Make stub_manager ref counted to ensure it doesn't get freed whilst
it is still being used.
- ifstubs are now freed only when the controlling stub_manager is freed.
- Rename stub_manager_ref/unref to stub_manager_ext_addref/release
respectively and make then take an unsigned long to prevent
malicious callers from passing in a negative value and corrupting
the ref count.
- The current architecture cannot handle pipes changing address, so use
a static array. Fixes memory corruption that sometimes occurs when
using multiple pipes.
- Fix race on apartment creation.
- Display errors in decimal to make searching for the meaning in
winerror.h easier.
- Move named pipe macros into rpc.c.
- Remove unneeded function.
- Implement COM local servers using table marshaling to avoid doing the
marshaling in a child thread where COM has not been initialized.
- Remove unneeded includes and the unused COMPOBJ_hInstance32 variable.
- Make the wine_marshal_id structure more like the DCOM OBJREF
structure, by replacing the process id field by apartment id (OXID),
changing the users of the process id field to use the new field and
renaming the objectid field to oid.
- Fix StdMarshalImpl_UnmarshalInterface to invalidate and release its
stub when doing a same apartment marshal.
- Fixed incorrect unsigned test.
- Add tracing for proxy ref count functions.
- Release the channel on proxy destruction.
- Implement proxy manager.
- Add documentation to several functions.
- Coding style changes according to the style Mike and I have agreed
upon for COM related files.
- Use OBJREF on the wire for generic marshaling functions.
- Add some function declarations to objbase.h.
- Add stubs for server ref counting.
- Implement HRESULT marshaling.
- Make struct oletls ref counted so that it is only detached from the
apartment on the final CoUninitialize.
- Decrease the size of the crit sec on destroying an apartment - it is
only needed for touching the apartment list.
- Small cleanups.
Mike Hearn <mh(a)codeweavers.com>
- Implement the COM stub manager, refactor the current stub code.
- Begin implementing interface stubs.
- Make apartment access thread-safe by introducing refcounting and
wider usage of the apartment lock.
- Rework OLE TLS management to eliminate uninitialised apartments and
parent chaining.
- Comment out an assert, as we don't yet implement IRemUnknown.
- Propagate apartments through the intermediate threads, make listener
thread apartment scoped.
- Rename the STUBMGR thread to more accurately reflect its purpose.
- Add a DCOM todo list.
Mike McCormack <mike(a)codeweavers.com>
- Test and fix a few problems with OLE storage streams.
- Allow COM to start services containing COM servers.
- Tests and fixes for StgOpenStorage.
- Test and fix StgCreateDocFile grfModes.
Paul Vriens <Paul.Vriens(a)xs4all.nl>
- use Interlocked* functions in AddRef and Release.
- store the result of the Interlocked functions and use only this.
Francois Gouget <fgouget(a)free.fr>
- Assorted spelling fixes.
Alexandre Julliard <julliard(a)winehq.org>
- Janitorial: C booleans must not be compared against TRUE.
Bill Medland <billmedland(a)mercuryspeed.com>
- Corrected testing for multithreaded (based upon observations by Paul
Vriens, Christian Costa and Robert Shearman).
- Added TRACE for investigating OXID errors.
Added: trunk/reactos/include/wine/list.h
Modified: trunk/reactos/include/wine/objidl.h
Modified: trunk/reactos/lib/ole32/Makefile.in
Modified: trunk/reactos/lib/ole32/bindctx.c
Modified: trunk/reactos/lib/ole32/clipboard.c
Modified: trunk/reactos/lib/ole32/compobj.c
Modified: trunk/reactos/lib/ole32/compobj_private.h
Modified: trunk/reactos/lib/ole32/compositemoniker.c
Modified: trunk/reactos/lib/ole32/datacache.c
Modified: trunk/reactos/lib/ole32/defaulthandler.c
Modified: trunk/reactos/lib/ole32/errorinfo.c
Modified: trunk/reactos/lib/ole32/filemoniker.c
Modified: trunk/reactos/lib/ole32/ftmarshal.c
Modified: trunk/reactos/lib/ole32/hglobalstream.c
Modified: trunk/reactos/lib/ole32/ifs.c
Modified: trunk/reactos/lib/ole32/ifs.h
Modified: trunk/reactos/lib/ole32/itemmoniker.c
Modified: trunk/reactos/lib/ole32/marshal.c
Modified: trunk/reactos/lib/ole32/memlockbytes.c
Modified: trunk/reactos/lib/ole32/moniker.c
Modified: trunk/reactos/lib/ole32/ole2.c
Modified: trunk/reactos/lib/ole32/oleobj.c
Modified: trunk/reactos/lib/ole32/oleproxy.c
Modified: trunk/reactos/lib/ole32/rpc.c
Modified: trunk/reactos/lib/ole32/stg_bigblockfile.c
Modified: trunk/reactos/lib/ole32/stg_stream.c
Modified: trunk/reactos/lib/ole32/storage32.c
_____
Added: trunk/reactos/include/wine/list.h
--- trunk/reactos/include/wine/list.h 2005-01-12 10:22:33 UTC (rev
12951)
+++ trunk/reactos/include/wine/list.h 2005-01-12 10:23:25 UTC (rev
12952)
@@ -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 */
_____
Modified: trunk/reactos/include/wine/objidl.h
--- trunk/reactos/include/wine/objidl.h 2005-01-12 10:22:33 UTC (rev
12951)
+++ trunk/reactos/include/wine/objidl.h 2005-01-12 10:23:25 UTC (rev
12952)
@@ -1943,4 +1943,67 @@
#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 */
_____
Modified: trunk/reactos/lib/ole32/Makefile.in
--- trunk/reactos/lib/ole32/Makefile.in 2005-01-12 10:22:33 UTC (rev
12951)
+++ trunk/reactos/lib/ole32/Makefile.in 2005-01-12 10:23:25 UTC (rev
12952)
@@ -35,7 +35,8 @@
rpc.c \
stg_bigblockfile.c \
stg_stream.c \
- storage32.c
+ storage32.c \
+ stubmanager.c
C_SRCS16 = \
memlockbytes16.c \
_____
Modified: trunk/reactos/lib/ole32/bindctx.c
--- trunk/reactos/lib/ole32/bindctx.c 2005-01-12 10:22:33 UTC (rev
12951)
+++ trunk/reactos/lib/ole32/bindctx.c 2005-01-12 10:23:25 UTC (rev
12952)
@@ -275,8 +275,7 @@
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; j<This->bindCtxTableLastIndex-1; j++)
@@ -302,8 +301,7 @@
{
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 @@
/* 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; j<This->bindCtxTableLastIndex-1; j++)
_____
Modified: trunk/reactos/lib/ole32/clipboard.c
--- trunk/reactos/lib/ole32/clipboard.c 2005-01-12 10:22:33 UTC (rev
12951)
+++ trunk/reactos/lib/ole32/clipboard.c 2005-01-12 10:23:25 UTC (rev
12952)
@@ -736,7 +736,7 @@
* 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 @@
/*
* Free the array of FORMATETC's
*/
- if (afmt)
- HeapFree(GetProcessHeap(), 0, afmt);
+ HeapFree(GetProcessHeap(), 0, afmt);
/*
* Close Windows clipboard
_____
Modified: trunk/reactos/lib/ole32/compobj.c
--- trunk/reactos/lib/ole32/compobj.c 2005-01-12 10:22:33 UTC (rev
12951)
+++ trunk/reactos/lib/ole32/compobj.c 2005-01-12 10:23:25 UTC (rev
12952)
@@ -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 @@
*
* 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 @@
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 @@
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 @@
* 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);
+
+ 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
- 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);
- }
- else if (!(model & COINIT_UNINITIALIZED)) {
- apt->parent = &MTA;
- apt->oxid = MTA.oxid;
- }
- EnterCriticalSection(&csApartment);
- if (create)
+ return apt;
+}
+
+DWORD COM_ApartmentAddRef(struct apartment *apt)
+{
+ return InterlockedIncrement(&apt->refs);
+}
+
+DWORD COM_ApartmentRelease(struct apartment *apt)
+{
+ DWORD ret;
+
+ ret = InterlockedDecrement(&apt->refs);
+ if (ret == 0)
{
- if (apts) apts->prev = apt;
- apt->next = apts;
- apts = apt;
+ 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;
}
- LeaveCriticalSection(&csApartment);
- NtCurrentTeb()->ReservedForOle = apt;
- return apt;
+
+ return ret;
}
-static void COM_DestroyApartment(APARTMENT *apt)
+/* 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);
- 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;
+ 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);
- if (apt->model & COINIT_APARTMENTTHREADED) {
- if (apt->win) DestroyWindow(apt->win);
- DeleteCriticalSection(&apt->cs);
- }
- CloseHandle(apt->thread);
- HeapFree(GetProcessHeap(), 0, apt);
+
+ return result;
}
-/* 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)
+HWND COM_GetApartmentWin(OXID oxid, BOOL ref)
{
APARTMENT *apt;
- HWND win = 0;
- EnterCriticalSection(&csApartment);
- apt = apts;
- while (apt && apt->oxid != oxid) apt = apt->next;
- if (apt) win = apt->win;
- LeaveCriticalSection(&csApartment);
- return win;
+ 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 @@
* 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 @@
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 @@
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 @@
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,19 +609,27 @@
*/
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;
+ }
+
/*
* Decrease the reference count.
* If we are back to 0 locks on the COM library, make sure we free
@@ -536,14 +642,6 @@
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 @@
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.
+ * 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.
*
- * 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.
- *
* 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 @@
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 @@
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 @@
*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 @@
*/
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 @@
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 @@
LPCLASSFACTORY lpclf = 0;
if (!COM_CurrentApt()) return CO_E_NOTINITIALIZED;
-
+
/*
* Sanity check
*/
@@ -1590,15 +1630,15 @@
* 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 @@
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 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 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;
[truncated at 1000 lines; 3210 more skipped]