Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/ole32/compobj.c | 56 ++++++++++++++++++------------------ dlls/ole32/compobj_private.h | 24 ++++++++-------- dlls/ole32/marshal.c | 19 ++++++------ dlls/ole32/rpc.c | 10 +++---- dlls/ole32/stubmanager.c | 26 ++++++++--------- 5 files changed, 67 insertions(+), 68 deletions(-)
diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index d45cbcc1734..4bd8c2474b6 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -71,8 +71,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); * This section defines variables internal to the COM module. */
-static APARTMENT *MTA; /* protected by csApartment */ -static APARTMENT *MainApartment; /* the first STA apartment */ +static struct apartment *MTA; /* protected by csApartment */ +static struct apartment *MainApartment; /* the first STA apartment */ static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
static CRITICAL_SECTION csApartment; @@ -174,7 +174,7 @@ struct LocalServer { IServiceProvider IServiceProvider_iface; LONG ref; - APARTMENT *apt; + struct apartment *apt; IStream *marshal_stream; };
@@ -608,9 +608,9 @@ static DWORD apartment_addref(struct apartment *apt)
/* allocates memory and fills in the necessary fields for a new apartment * object. must be called inside apartment cs */ -static APARTMENT *apartment_construct(DWORD model) +static struct apartment *apartment_construct(DWORD model) { - APARTMENT *apt; + struct apartment *apt;
TRACE("creating new apartment, model=%d\n", model);
@@ -651,9 +651,9 @@ static APARTMENT *apartment_construct(DWORD model) /* gets and existing apartment if one exists or otherwise creates an apartment * structure which stores OLE apartment-local information and stores a pointer * to it in the thread-local storage */ -static APARTMENT *apartment_get_or_create(DWORD model) +static struct apartment *apartment_get_or_create(DWORD model) { - APARTMENT *apt = COM_CurrentApt(); + struct apartment *apt = COM_CurrentApt();
if (!apt) { @@ -699,7 +699,7 @@ static APARTMENT *apartment_get_or_create(DWORD model) return apt; }
-static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model) +static inline BOOL apartment_is_model(const struct apartment *apt, DWORD model) { return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED)); } @@ -707,9 +707,9 @@ static inline BOOL apartment_is_model(const APARTMENT *apt, DWORD model) /* gets the multi-threaded apartment if it exists. The caller must * release the reference from the apartment as soon as the apartment pointer * is no longer required. */ -static APARTMENT *apartment_find_mta(void) +static struct apartment *apartment_find_mta(void) { - APARTMENT *apt; + struct apartment *apt;
EnterCriticalSection(&csApartment);
@@ -723,9 +723,9 @@ static APARTMENT *apartment_find_mta(void)
/* Return the current apartment if it exists, or, failing that, the MTA. Caller * must free the returned apartment in either case. */ -APARTMENT *apartment_get_current_or_mta(void) +struct apartment *apartment_get_current_or_mta(void) { - APARTMENT *apt = COM_CurrentApt(); + struct apartment *apt = COM_CurrentApt(); if (apt) { apartment_addref(apt); @@ -959,7 +959,7 @@ static ULONG WINAPI LocalServer_Release(IServiceProvider *iface) static HRESULT WINAPI LocalServer_QueryService(IServiceProvider *iface, REFGUID guid, REFIID riid, void **ppv) { LocalServer *This = impl_from_IServiceProvider(iface); - APARTMENT *apt = COM_CurrentApt(); + struct apartment *apt = COM_CurrentApt(); RegisteredClass *iter; HRESULT hres = E_FAIL;
@@ -991,7 +991,7 @@ static const IServiceProviderVtbl LocalServerVtbl = { LocalServer_QueryService };
-static HRESULT get_local_server_stream(APARTMENT *apt, IStream **ret) +static HRESULT get_local_server_stream(struct apartment *apt, IStream **ret) { HRESULT hres = S_OK;
@@ -1057,7 +1057,7 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject( { HRESULT hr = E_INVALIDARG; RegisteredClass *curClass; - APARTMENT *apt; + struct apartment *apt;
TRACE("(%08x)\n",dwRegister);
@@ -1242,9 +1242,9 @@ DWORD apartment_release(struct apartment *apt) * The ref parameter is here mostly to ensure people remember that * they get one, you should normally take a ref for thread safety. */ -APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref) +struct apartment *apartment_findfromoxid(OXID oxid, BOOL ref) { - APARTMENT *result = NULL; + struct apartment *result = NULL; struct list *cursor;
EnterCriticalSection(&csApartment); @@ -1266,9 +1266,9 @@ APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref) /* gets the apartment which has a given creator thread ID. The caller must * release the reference from the apartment as soon as the apartment pointer * is no longer required. */ -APARTMENT *apartment_findfromtid(DWORD tid) +struct apartment *apartment_findfromtid(DWORD tid) { - APARTMENT *result = NULL; + struct apartment *result = NULL; struct list *cursor;
EnterCriticalSection(&csApartment); @@ -1290,9 +1290,9 @@ APARTMENT *apartment_findfromtid(DWORD tid) /* gets the main apartment if it exists. The caller must * release the reference from the apartment as soon as the apartment pointer * is no longer required. */ -static APARTMENT *apartment_findmain(void) +static struct apartment *apartment_findmain(void) { - APARTMENT *result; + struct apartment *result;
EnterCriticalSection(&csApartment);
@@ -1548,7 +1548,7 @@ static HRESULT apartment_hostobject_in_hostapt(
if (!multi_threaded && main_apartment) { - APARTMENT *host_apt = apartment_findmain(); + struct apartment *host_apt = apartment_findmain(); if (host_apt) { apartment_hwnd = apartment_getwindow(host_apt); @@ -1601,7 +1601,7 @@ static HRESULT apartment_hostobject_in_hostapt( * us to create the thread for the host apartment */ if (!apartment_hwnd && !multi_threaded && main_apartment) { - APARTMENT *host_apt = apartment_findmain(); + struct apartment *host_apt = apartment_findmain(); if (host_apt) { apartment_hwnd = apartment_getwindow(host_apt); @@ -2008,7 +2008,7 @@ HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved ) struct stub_manager *manager; HRESULT hr; IMarshal *marshal; - APARTMENT *apt; + struct apartment *apt;
TRACE("(%p, 0x%08x)\n", lpUnk, reserved);
@@ -2203,7 +2203,7 @@ HRESULT WINAPI CoRegisterClassObject( RegisteredClass* newClass; LPUNKNOWN foundObject; HRESULT hr; - APARTMENT *apt; + struct apartment *apt;
TRACE("(%s,%p,0x%08x,0x%08x,%p)\n", debugstr_guid(rclsid),pUnk,dwClsContext,flags,lpdwRegister); @@ -2321,7 +2321,7 @@ static enum comclass_threadingmodel get_threading_model(const struct class_reg_d return data->u.actctx.threading_model; }
-static HRESULT get_inproc_class_object(APARTMENT *apt, const struct class_reg_data *regdata, +static HRESULT get_inproc_class_object(struct apartment *apt, const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, BOOL hostifnecessary, void **ppv) { @@ -2405,7 +2405,7 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject( struct class_reg_data clsreg = { 0 }; IUnknown *regClassObject; HRESULT hres = E_UNEXPECTED; - APARTMENT *apt; + struct apartment *apt;
TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
@@ -3150,7 +3150,7 @@ HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier) { struct oletls *info = COM_CurrentInfo(); - APARTMENT *apt; + struct apartment *apt;
TRACE("(%p, %p)\n", type, qualifier);
diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h index 003cf767cb4..7958b119bc2 100644 --- a/dlls/ole32/compobj_private.h +++ b/dlls/ole32/compobj_private.h @@ -40,7 +40,6 @@ #include "winternl.h"
struct apartment; -typedef struct apartment APARTMENT; typedef struct LocalServer LocalServer;
DEFINE_OLEGUID( CLSID_DfMarshal, 0x0000030b, 0, 0 ); @@ -89,7 +88,7 @@ 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) */ + struct apartment *apt; /* owning apt (RO) */
ULONG extrefs; /* number of 'external' references (CS lock) */ ULONG refs; /* internal reference count (CS apt->cs) */ @@ -203,17 +202,18 @@ ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs, BOOL tablewea struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *sb, REFIID iid, DWORD dest_context, void *dest_context_data, MSHLFLAGS flags) DECLSPEC_HIDDEN; struct ifstub *stub_manager_find_ifstub(struct stub_manager *m, REFIID iid, MSHLFLAGS flags) DECLSPEC_HIDDEN; -struct stub_manager *get_stub_manager(APARTMENT *apt, OID oid) DECLSPEC_HIDDEN; -struct stub_manager *get_stub_manager_from_object(APARTMENT *apt, IUnknown *object, BOOL alloc) DECLSPEC_HIDDEN; +struct stub_manager *get_stub_manager(struct apartment *apt, OID oid) DECLSPEC_HIDDEN; +struct stub_manager *get_stub_manager_from_object(struct apartment *apt, IUnknown *object, BOOL alloc) DECLSPEC_HIDDEN; BOOL stub_manager_notify_unmarshal(struct stub_manager *m, const IPID *ipid) DECLSPEC_HIDDEN; BOOL stub_manager_is_table_marshaled(struct stub_manager *m, const IPID *ipid) DECLSPEC_HIDDEN; void stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs, const IPID *ipid, BOOL tableweak) DECLSPEC_HIDDEN; void stub_manager_disconnect(struct stub_manager *m) DECLSPEC_HIDDEN; -HRESULT ipid_get_dispatch_params(const IPID *ipid, APARTMENT **stub_apt, struct stub_manager **manager, IRpcStubBuffer **stub, +HRESULT ipid_get_dispatch_params(const IPID *ipid, struct apartment **stub_apt, struct stub_manager **manager, IRpcStubBuffer **stub, IRpcChannelBuffer **chan, IID *iid, IUnknown **iface) DECLSPEC_HIDDEN; -HRESULT start_apartment_remote_unknown(APARTMENT *apt) DECLSPEC_HIDDEN; +HRESULT start_apartment_remote_unknown(struct apartment *apt) DECLSPEC_HIDDEN;
-HRESULT marshal_object(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *obj, DWORD dest_context, void *dest_context_data, MSHLFLAGS mshlflags) DECLSPEC_HIDDEN; +HRESULT marshal_object(struct apartment *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *obj, DWORD dest_context, + void *dest_context_data, MSHLFLAGS mshlflags) DECLSPEC_HIDDEN;
/* RPC Backend */
@@ -223,7 +223,7 @@ void RPC_StartRemoting(struct apartment *apt) DECLSPEC_HIDDEN; HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, const OXID_INFO *oxid_info, const IID *iid, DWORD dest_context, void *dest_context_data, - IRpcChannelBuffer **chan, APARTMENT *apt) DECLSPEC_HIDDEN; + IRpcChannelBuffer **chan, struct apartment *apt) DECLSPEC_HIDDEN; HRESULT RPC_CreateServerChannel(DWORD dest_context, void *dest_context_data, IRpcChannelBuffer **chan) DECLSPEC_HIDDEN; void RPC_ExecuteCall(struct dispatch_params *params) DECLSPEC_HIDDEN; HRESULT RPC_RegisterInterface(REFIID riid) DECLSPEC_HIDDEN; @@ -246,8 +246,8 @@ void OLEDD_UnInitialize(void) DECLSPEC_HIDDEN;
/* Apartment Functions */
-APARTMENT *apartment_findfromoxid(OXID oxid, BOOL ref) DECLSPEC_HIDDEN; -APARTMENT *apartment_findfromtid(DWORD tid) DECLSPEC_HIDDEN; +struct apartment *apartment_findfromoxid(OXID oxid, BOOL ref) DECLSPEC_HIDDEN; +struct apartment *apartment_findfromtid(DWORD tid) DECLSPEC_HIDDEN; DWORD apartment_release(struct apartment *apt) DECLSPEC_HIDDEN; HRESULT apartment_disconnectproxies(struct apartment *apt) DECLSPEC_HIDDEN; static inline HRESULT apartment_getoxid(const struct apartment *apt, OXID *oxid) @@ -259,7 +259,7 @@ HRESULT apartment_createwindowifneeded(struct apartment *apt) DECLSPEC_HIDDEN; HWND apartment_getwindow(const struct apartment *apt) DECLSPEC_HIDDEN; HRESULT enter_apartment(struct oletls *info, DWORD model) DECLSPEC_HIDDEN; void leave_apartment(struct oletls *info) DECLSPEC_HIDDEN; -APARTMENT *apartment_get_current_or_mta(void) DECLSPEC_HIDDEN; +struct apartment *apartment_get_current_or_mta(void) DECLSPEC_HIDDEN;
/* DCOM messages used by the apartment window (not compatible with native) */ #define DM_EXECUTERPC (WM_USER + 0) /* WPARAM = 0, LPARAM = (struct dispatch_params *) */ @@ -282,7 +282,7 @@ static inline struct oletls *COM_CurrentInfo(void) return NtCurrentTeb()->ReservedForOle; }
-static inline APARTMENT* COM_CurrentApt(void) +static inline struct apartment * COM_CurrentApt(void) { return COM_CurrentInfo()->apt; } diff --git a/dlls/ole32/marshal.c b/dlls/ole32/marshal.c index 343d1c834f7..9fb68e66f07 100644 --- a/dlls/ole32/marshal.c +++ b/dlls/ole32/marshal.c @@ -85,7 +85,7 @@ static inline struct proxy_manager *impl_from_IClientSecurity( IClientSecurity * return CONTAINING_RECORD(iface, struct proxy_manager, IClientSecurity_iface); }
-static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, +static HRESULT unmarshal_object(const STDOBJREF *stdobjref, struct apartment *apt, MSHCTX dest_context, void *dest_context_data, REFIID riid, const OXID_INFO *oxid_info, void **object); @@ -118,7 +118,7 @@ static inline HRESULT get_facbuf_for_iid(REFIID riid, IPSFactoryBuffer **facbuf) }
/* marshals an object into a STDOBJREF structure */ -HRESULT marshal_object(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *object, +HRESULT marshal_object(struct apartment *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *object, DWORD dest_context, void *dest_context_data, MSHLFLAGS mshlflags) { struct stub_manager *manager; @@ -310,7 +310,7 @@ static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, UL * the interfaces were returned */ if (SUCCEEDED(hr)) { - APARTMENT *apt = apartment_get_current_or_mta(); + struct apartment *apt = apartment_get_current_or_mta();
/* try to unmarshal each object returned to us */ for (i = 0; i < nonlocal_mqis; i++) @@ -791,7 +791,7 @@ static void ifproxy_destroy(struct ifproxy * This) }
static HRESULT proxy_manager_construct( - APARTMENT * apt, ULONG sorflags, OXID oxid, OID oid, + struct apartment * apt, ULONG sorflags, OXID oxid, OID oid, const OXID_INFO *oxid_info, struct proxy_manager ** proxy_manager) { struct proxy_manager * This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); @@ -1197,7 +1197,7 @@ static void proxy_manager_destroy(struct proxy_manager * This) /* finds the proxy manager corresponding to a given OXID and OID that has * been unmarshaled in the specified apartment. The caller must release the * reference to the proxy_manager when the object is no longer used. */ -static BOOL find_proxy_manager(APARTMENT * apt, OXID oxid, OID oid, struct proxy_manager ** proxy_found) +static BOOL find_proxy_manager(struct apartment * apt, OXID oxid, OID oid, struct proxy_manager ** proxy_found) { BOOL found = FALSE; struct list * cursor; @@ -1306,7 +1306,7 @@ StdMarshalImpl_MarshalInterface( { ULONG res; HRESULT hres; - APARTMENT *apt; + struct apartment *apt; OBJREF objref;
TRACE("(...,%s,...)\n", debugstr_guid(riid)); @@ -1337,7 +1337,7 @@ StdMarshalImpl_MarshalInterface( /* helper for StdMarshalImpl_UnmarshalInterface - does the unmarshaling with * no questions asked about the rules surrounding same-apartment unmarshals * and table marshaling */ -static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, +static HRESULT unmarshal_object(const STDOBJREF *stdobjref, struct apartment *apt, MSHCTX dest_context, void *dest_context_data, REFIID riid, const OXID_INFO *oxid_info, void **object) @@ -1413,8 +1413,7 @@ static HRESULT std_unmarshal_interface(MSHCTX dest_context, void *dest_context_d struct OR_STANDARD obj; ULONG res; HRESULT hres; - APARTMENT *apt; - APARTMENT *stub_apt; + struct apartment *apt, *stub_apt; OXID oxid;
TRACE("(...,%s,....)\n", debugstr_guid(riid)); @@ -1540,7 +1539,7 @@ static HRESULT std_release_marshal_data(IStream *pStm) ULONG res; HRESULT hres; struct stub_manager *stubmgr; - APARTMENT *apt; + struct apartment *apt;
hres = IStream_Read(pStm, &obj, FIELD_OFFSET(struct OR_STANDARD, saResAddr.aStringArray), &res); if (hres != S_OK) return STG_E_READFAULT; diff --git a/dlls/ole32/rpc.c b/dlls/ole32/rpc.c index bd825fd6c10..d0b0f49319d 100644 --- a/dlls/ole32/rpc.c +++ b/dlls/ole32/rpc.c @@ -630,7 +630,7 @@ static HRESULT WINAPI ClientRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, ULONG extension_count; IPID ipid; HRESULT hr; - APARTMENT *apt = NULL; + struct apartment *apt = NULL;
TRACE("(%p)->(%p,%s)\n", This, olemsg, debugstr_guid(riid));
@@ -803,7 +803,7 @@ static DWORD WINAPI rpc_sendreceive_thread(LPVOID param) return 0; }
-static inline HRESULT ClientRpcChannelBuffer_IsCorrectApartment(ClientRpcChannelBuffer *This, APARTMENT *apt) +static inline HRESULT ClientRpcChannelBuffer_IsCorrectApartment(ClientRpcChannelBuffer *This, struct apartment *apt) { OXID oxid; if (!apt) @@ -827,7 +827,7 @@ static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER ifac ORPC_EXTENT_ARRAY orpc_ext_array; WIRE_ORPC_EXTENT *first_wire_orpc_extent = NULL; HRESULT hrFault = S_OK; - APARTMENT *apt = apartment_get_current_or_mta(); + struct apartment *apt = apartment_get_current_or_mta();
TRACE("(%p) iMethod=%d\n", olemsg, olemsg->iMethod);
@@ -1095,7 +1095,7 @@ static const IRpcChannelBufferVtbl ServerRpcChannelBufferVtbl = HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, const OXID_INFO *oxid_info, const IID *iid, DWORD dest_context, void *dest_context_data, - IRpcChannelBuffer **chan, APARTMENT *apt) + IRpcChannelBuffer **chan, struct apartment *apt) { ClientRpcChannelBuffer *This; WCHAR endpoint[200]; @@ -1444,7 +1444,7 @@ static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg) { struct dispatch_params *params; struct stub_manager *stub_manager; - APARTMENT *apt; + struct apartment *apt; IPID ipid; HRESULT hr;
diff --git a/dlls/ole32/stubmanager.c b/dlls/ole32/stubmanager.c index 5f604d42910..16f9c3dc52c 100644 --- a/dlls/ole32/stubmanager.c +++ b/dlls/ole32/stubmanager.c @@ -177,7 +177,7 @@ struct ifstub *stub_manager_find_ifstub(struct stub_manager *m, REFIID iid, MSHL /* creates a new stub manager and adds it into the apartment. caller must * release stub manager when it is no longer required. the apartment and * external refs together take one implicit ref */ -static struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object) +static struct stub_manager *new_stub_manager(struct apartment *apt, IUnknown *object) { struct stub_manager *sm; HRESULT hres; @@ -311,7 +311,7 @@ static ULONG stub_manager_int_addref(struct stub_manager *This) ULONG stub_manager_int_release(struct stub_manager *This) { ULONG refs; - APARTMENT *apt = This->apt; + struct apartment *apt = This->apt;
EnterCriticalSection(&apt->cs); refs = --This->refs; @@ -334,7 +334,7 @@ ULONG stub_manager_int_release(struct stub_manager *This) /* gets the stub manager associated with an object - caller must have * a reference to the apartment while a reference to the stub manager is held. * it must also call release on the stub manager when it is no longer needed */ -struct stub_manager *get_stub_manager_from_object(APARTMENT *apt, IUnknown *obj, BOOL alloc) +struct stub_manager *get_stub_manager_from_object(struct apartment *apt, IUnknown *obj, BOOL alloc) { struct stub_manager *result = NULL; struct list *cursor; @@ -377,7 +377,7 @@ struct stub_manager *get_stub_manager_from_object(APARTMENT *apt, IUnknown *obj, /* gets the stub manager associated with an object id - caller must have * a reference to the apartment while a reference to the stub manager is held. * it must also call release on the stub manager when it is no longer needed */ -struct stub_manager *get_stub_manager(APARTMENT *apt, OID oid) +struct stub_manager *get_stub_manager(struct apartment *apt, OID oid) { struct stub_manager *result = NULL; struct list *cursor; @@ -471,7 +471,7 @@ ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs, BOOL tablewea /* gets the stub manager associated with an ipid - caller must have * a reference to the apartment while a reference to the stub manager is held. * it must also call release on the stub manager when it is no longer needed */ -static struct stub_manager *get_stub_manager_from_ipid(APARTMENT *apt, const IPID *ipid, struct ifstub **ifstub) +static struct stub_manager *get_stub_manager_from_ipid(struct apartment *apt, const IPID *ipid, struct ifstub **ifstub) { struct stub_manager *result = NULL; struct list *cursor; @@ -498,7 +498,7 @@ static struct stub_manager *get_stub_manager_from_ipid(APARTMENT *apt, const IPI return result; }
-static HRESULT ipid_to_ifstub(const IPID *ipid, APARTMENT **stub_apt, +static HRESULT ipid_to_ifstub(const IPID *ipid, struct apartment **stub_apt, struct stub_manager **stubmgr_ret, struct ifstub **ifstub) { /* FIXME: hack for IRemUnknown */ @@ -521,7 +521,7 @@ static HRESULT ipid_to_ifstub(const IPID *ipid, APARTMENT **stub_apt, return S_OK; }
-static HRESULT ipid_to_stub_manager(const IPID *ipid, APARTMENT **stub_apt, struct stub_manager **stub) +static HRESULT ipid_to_stub_manager(const IPID *ipid, struct apartment **stub_apt, struct stub_manager **stub) { struct ifstub *ifstub; return ipid_to_ifstub(ipid, stub_apt, stub, &ifstub); @@ -530,14 +530,14 @@ static HRESULT ipid_to_stub_manager(const IPID *ipid, APARTMENT **stub_apt, stru /* gets the apartment, stub and channel of an object. the caller must * release the references to all objects (except iface) if the function * returned success, otherwise no references are returned. */ -HRESULT ipid_get_dispatch_params(const IPID *ipid, APARTMENT **stub_apt, +HRESULT ipid_get_dispatch_params(const IPID *ipid, struct apartment **stub_apt, struct stub_manager **manager, IRpcStubBuffer **stub, IRpcChannelBuffer **chan, IID *iid, IUnknown **iface) { struct stub_manager *stubmgr; struct ifstub *ifstub; - APARTMENT *apt; + struct apartment *apt; HRESULT hr;
hr = ipid_to_ifstub(ipid, &apt, &stubmgr, &ifstub); @@ -703,7 +703,7 @@ static HRESULT WINAPI RemUnknown_RemQueryInterface(IRemUnknown *iface, HRESULT hr; USHORT i; USHORT successful_qis = 0; - APARTMENT *apt; + struct apartment *apt; struct stub_manager *stubmgr; struct ifstub *ifstub; DWORD dest_context; @@ -750,7 +750,7 @@ static HRESULT WINAPI RemUnknown_RemAddRef(IRemUnknown *iface,
for (i = 0; i < cInterfaceRefs; i++) { - APARTMENT *apt; + struct apartment *apt; struct stub_manager *stubmgr;
pResults[i] = ipid_to_stub_manager(&InterfaceRefs[i].ipid, &apt, &stubmgr); @@ -782,7 +782,7 @@ static HRESULT WINAPI RemUnknown_RemRelease(IRemUnknown *iface,
for (i = 0; i < cInterfaceRefs; i++) { - APARTMENT *apt; + struct apartment *apt; struct stub_manager *stubmgr;
hr = ipid_to_stub_manager(&InterfaceRefs[i].ipid, &apt, &stubmgr); @@ -815,7 +815,7 @@ static const IRemUnknownVtbl RemUnknown_Vtbl = };
/* starts the IRemUnknown listener for the current apartment */ -HRESULT start_apartment_remote_unknown(APARTMENT *apt) +HRESULT start_apartment_remote_unknown(struct apartment *apt) { IRemUnknown *pRemUnknown; HRESULT hr = S_OK;
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/ole32/compobj.c | 10 +++------- dlls/ole32/compobj_private.h | 2 +- dlls/ole32/marshal.c | 4 ++-- dlls/ole32/stubmanager.c | 2 +- 4 files changed, 7 insertions(+), 11 deletions(-)
diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index 4bd8c2474b6..a68cab0fe98 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -1237,12 +1237,8 @@ DWORD apartment_release(struct apartment *apt) return ret; }
-/* The given OXID must be local to this process: - * - * The ref parameter is here mostly to ensure people remember that - * they get one, you should normally take a ref for thread safety. - */ -struct apartment *apartment_findfromoxid(OXID oxid, BOOL ref) +/* The given OXID must be local to this process */ +struct apartment *apartment_findfromoxid(OXID oxid) { struct apartment *result = NULL; struct list *cursor; @@ -1254,7 +1250,7 @@ struct apartment *apartment_findfromoxid(OXID oxid, BOOL ref) if (apt->oxid == oxid) { result = apt; - if (ref) apartment_addref(result); + apartment_addref(result); break; } } diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h index 7958b119bc2..6e8b7ae2cfc 100644 --- a/dlls/ole32/compobj_private.h +++ b/dlls/ole32/compobj_private.h @@ -246,7 +246,7 @@ void OLEDD_UnInitialize(void) DECLSPEC_HIDDEN;
/* Apartment Functions */
-struct apartment *apartment_findfromoxid(OXID oxid, BOOL ref) DECLSPEC_HIDDEN; +struct apartment *apartment_findfromoxid(OXID oxid) DECLSPEC_HIDDEN; struct apartment *apartment_findfromtid(DWORD tid) DECLSPEC_HIDDEN; DWORD apartment_release(struct apartment *apt) DECLSPEC_HIDDEN; HRESULT apartment_disconnectproxies(struct apartment *apt) DECLSPEC_HIDDEN; diff --git a/dlls/ole32/marshal.c b/dlls/ole32/marshal.c index 9fb68e66f07..8cc35354d53 100644 --- a/dlls/ole32/marshal.c +++ b/dlls/ole32/marshal.c @@ -1468,7 +1468,7 @@ static HRESULT std_unmarshal_interface(MSHCTX dest_context, void *dest_context_d * ignore table marshaling and normal marshaling rules regarding number of * unmarshals, etc, but if you abuse these rules then your proxy could end * up returning RPC_E_DISCONNECTED. */ - if ((stub_apt = apartment_findfromoxid(obj.std.oxid, TRUE))) + if ((stub_apt = apartment_findfromoxid(obj.std.oxid))) { if ((stubmgr = get_stub_manager(stub_apt, obj.std.oid))) { @@ -1555,7 +1555,7 @@ static HRESULT std_release_marshal_data(IStream *pStm) wine_dbgstr_longlong(obj.std.oid), wine_dbgstr_guid(&obj.std.ipid));
- if (!(apt = apartment_findfromoxid(obj.std.oxid, TRUE))) + if (!(apt = apartment_findfromoxid(obj.std.oxid))) { WARN("Could not map OXID %s to apartment object\n", wine_dbgstr_longlong(obj.std.oxid)); diff --git a/dlls/ole32/stubmanager.c b/dlls/ole32/stubmanager.c index 16f9c3dc52c..338b89750ef 100644 --- a/dlls/ole32/stubmanager.c +++ b/dlls/ole32/stubmanager.c @@ -503,7 +503,7 @@ static HRESULT ipid_to_ifstub(const IPID *ipid, struct apartment **stub_apt, { /* FIXME: hack for IRemUnknown */ if (ipid->Data2 == 0xffff) - *stub_apt = apartment_findfromoxid(*(const OXID *)ipid->Data4, TRUE); + *stub_apt = apartment_findfromoxid(*(const OXID *)ipid->Data4); else *stub_apt = apartment_findfromtid(ipid->Data2); if (!*stub_apt)
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=77580
Your paranoid android.
=== debiant (64 bit WoW report) ===
ole32: clipboard.c:1557: Test failed: gle 5 clipboard.c:1563: Test failed: got 00000000 clipboard.c:1565: Test failed: got 00000000 clipboard.c:1567: Test failed: gle 1418 clipboard.c:1597: Test failed: cf 0010 clipboard.c:1601: Test failed: tymed 0 clipboard.c:1605: Test failed: cf 0007 clipboard.c:1614: Test failed: cf 000d clipboard.c:1618: Test succeeded inside todo block: tymed 5 clipboard.c:1621: Test failed: got 00000001 clipboard.c:1623: Test failed: cf 000d clipboard.c:1630: Test failed: got 00000001 clipboard.c:1638: Test failed: got 00000001 clipboard.c:1639: Test failed: cf 000d clipboard.c:1643: Test failed: tymed 5 clipboard.c:1651: Test failed: got 80040064 clipboard.c:1653: Test failed: got 0 clipboard.c:1658: Test failed: got 80040064 clipboard.c:1659: Test failed: got 0
Signed-off-by: Huw Davies huw@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/ole32/Makefile.in | 1 + dlls/ole32/apartment.c | 1289 +++++++++++++++++++++++++++++ dlls/ole32/compobj.c | 1497 ++++------------------------------ dlls/ole32/compobj_private.h | 20 +- 4 files changed, 1456 insertions(+), 1351 deletions(-) create mode 100644 dlls/ole32/apartment.c
diff --git a/dlls/ole32/Makefile.in b/dlls/ole32/Makefile.in index 1c1e28fa4c5..5a2b21dee4f 100644 --- a/dlls/ole32/Makefile.in +++ b/dlls/ole32/Makefile.in @@ -8,6 +8,7 @@ EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \ antimoniker.c \ + apartment.c \ bindctx.c \ classmoniker.c \ clipboard.c \ diff --git a/dlls/ole32/apartment.c b/dlls/ole32/apartment.c new file mode 100644 index 00000000000..456e6c80a36 --- /dev/null +++ b/dlls/ole32/apartment.c @@ -0,0 +1,1289 @@ +/* + * Copyright 1995 Martin von Loewis + * Copyright 1998 Justin Bradford + * Copyright 1999 Francis Beaudet + * Copyright 1999 Sylvain St-Germain + * Copyright 2002 Marcus Meissner + * Copyright 2004 Mike Hearn + * Copyright 2005-2006 Robert 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 + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * + */ + +#include <stdarg.h> +#include <assert.h> + +#define COBJMACROS +#define NONAMELESSUNION + +#include "windef.h" +#include "winbase.h" +#include "servprov.h" + +#include "compobj_private.h" + +#include "wine/debug.h" +#include "wine/list.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ole); + +enum comclass_threadingmodel +{ + ThreadingModel_Apartment = 1, + ThreadingModel_Free = 2, + ThreadingModel_No = 3, + ThreadingModel_Both = 4, + ThreadingModel_Neutral = 5 +}; + +enum class_reg_data_origin +{ + CLASS_REG_ACTCTX, + CLASS_REG_REGISTRY, +}; + +struct class_reg_data +{ + enum class_reg_data_origin origin; + union + { + struct + { + const WCHAR *module_name; + DWORD threading_model; + HANDLE hactctx; + } actctx; + HKEY hkey; + } u; +}; + +static struct apartment *mta; +static struct apartment *main_sta; /* the first STA */ +static struct list apts = LIST_INIT(apts); + +static CRITICAL_SECTION apt_cs; +static CRITICAL_SECTION_DEBUG apt_cs_debug = +{ + 0, 0, &apt_cs, + { &apt_cs_debug.ProcessLocksList, &apt_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": apt_cs") } +}; +static CRITICAL_SECTION apt_cs = { &apt_cs_debug, -1, 0, 0, 0, 0 }; + +static struct list dlls = LIST_INIT(dlls); + +static CRITICAL_SECTION dlls_cs; +static CRITICAL_SECTION_DEBUG dlls_cs_debug = +{ + 0, 0, &dlls_cs, + { &dlls_cs_debug.ProcessLocksList, &dlls_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": dlls_cs") } +}; +static CRITICAL_SECTION dlls_cs = { &dlls_cs_debug, -1, 0, 0, 0, 0 }; + +typedef HRESULT (WINAPI *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, void **obj); +typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void); + +struct opendll +{ + LONG refs; + LPWSTR library_name; + HANDLE library; + DllGetClassObjectFunc DllGetClassObject; + DllCanUnloadNowFunc DllCanUnloadNow; + struct list entry; +}; + +struct apartment_loaded_dll +{ + struct list entry; + struct opendll *dll; + DWORD unload_time; + BOOL multi_threaded; +}; + +static struct opendll *apartment_get_dll(const WCHAR *library_name) +{ + struct opendll *ptr, *ret = NULL; + + EnterCriticalSection(&dlls_cs); + LIST_FOR_EACH_ENTRY(ptr, &dlls, struct opendll, entry) + { + if (!wcsicmp(library_name, ptr->library_name) && + (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroyed if == 1 */) + { + ret = ptr; + break; + } + } + LeaveCriticalSection(&dlls_cs); + + return ret; +} + +/* caller must ensure that library_name is not already in the open dll list */ +static HRESULT apartment_add_dll(const WCHAR *library_name, struct opendll **ret) +{ + struct opendll *entry; + int len; + HRESULT hr = S_OK; + HANDLE hLibrary; + DllCanUnloadNowFunc DllCanUnloadNow; + DllGetClassObjectFunc DllGetClassObject; + + TRACE("%s\n", debugstr_w(library_name)); + + *ret = apartment_get_dll(library_name); + if (*ret) return S_OK; + + /* Load outside of dlls lock to avoid dependency on the loader lock */ + hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH); + if (!hLibrary) + { + ERR("couldn't load in-process dll %s\n", debugstr_w(library_name)); + /* failure: DLL could not be loaded */ + return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */ + } + + /* DllCanUnloadNow is optional */ + DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow"); + DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject"); + if (!DllGetClassObject) + { + /* failure: the dll did not export DllGetClassObject */ + ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name)); + FreeLibrary(hLibrary); + return CO_E_DLLNOTFOUND; + } + + EnterCriticalSection(&dlls_cs); + + *ret = apartment_get_dll(library_name); + if (*ret) + { + /* another caller to this function already added the dll while we + * weren't in the critical section */ + FreeLibrary(hLibrary); + } + else + { + len = lstrlenW(library_name); + entry = heap_alloc(sizeof(*entry)); + if (entry) + entry->library_name = heap_alloc((len + 1) * sizeof(WCHAR)); + if (entry && entry->library_name) + { + memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR)); + entry->library = hLibrary; + entry->refs = 1; + entry->DllCanUnloadNow = DllCanUnloadNow; + entry->DllGetClassObject = DllGetClassObject; + list_add_tail(&dlls, &entry->entry); + *ret = entry; + } + else + { + heap_free(entry); + hr = E_OUTOFMEMORY; + FreeLibrary(hLibrary); + } + } + + LeaveCriticalSection(&dlls_cs); + + return hr; +} + +/* pass FALSE for free_entry to release a reference without destroying the + * entry if it reaches zero or TRUE otherwise */ +static void apartment_release_dll(struct opendll *entry, BOOL free_entry) +{ + if (!InterlockedDecrement(&entry->refs) && free_entry) + { + EnterCriticalSection(&dlls_cs); + list_remove(&entry->entry); + LeaveCriticalSection(&dlls_cs); + + TRACE("freeing %p\n", entry->library); + FreeLibrary(entry->library); + + heap_free(entry->library_name); + heap_free(entry); + } +} + +/* frees memory associated with active dll list */ +static void apartment_release_dlls(void) +{ + struct opendll *entry, *cursor2; + EnterCriticalSection(&dlls_cs); + LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &dlls, struct opendll, entry) + { + list_remove(&entry->entry); + heap_free(entry->library_name); + heap_free(entry); + } + LeaveCriticalSection(&dlls_cs); + DeleteCriticalSection(&dlls_cs); +} + +/* + * This is a marshallable object exposing registered local servers. + * IServiceProvider is used only because it happens meet requirements + * and already has proxy/stub code. If more functionality is needed, + * a custom interface may be used instead. + */ +struct local_server +{ + IServiceProvider IServiceProvider_iface; + LONG refcount; + struct apartment *apt; + IStream *marshal_stream; +}; + +static inline struct local_server *impl_from_IServiceProvider(IServiceProvider *iface) +{ + return CONTAINING_RECORD(iface, struct local_server, IServiceProvider_iface); +} + +static HRESULT WINAPI local_server_QueryInterface(IServiceProvider *iface, REFIID riid, void **obj) +{ + struct local_server *local_server = impl_from_IServiceProvider(iface); + + TRACE("%p, %s, %p\n", iface, debugstr_guid(riid), obj); + + if (IsEqualGUID(riid, &IID_IUnknown) || + IsEqualGUID(riid, &IID_IServiceProvider)) + { + *obj = &local_server->IServiceProvider_iface; + } + else + { + *obj = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown *)*obj); + return S_OK; +} + +static ULONG WINAPI local_server_AddRef(IServiceProvider *iface) +{ + struct local_server *local_server = impl_from_IServiceProvider(iface); + LONG refcount = InterlockedIncrement(&local_server->refcount); + + TRACE("%p, refcount %d\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI local_server_Release(IServiceProvider *iface) +{ + struct local_server *local_server = impl_from_IServiceProvider(iface); + LONG refcount = InterlockedDecrement(&local_server->refcount); + + TRACE("%p, refcount %d\n", iface, refcount); + + if (!refcount) + { + assert(!local_server->apt); + heap_free(local_server); + } + + return refcount; +} + +static HRESULT WINAPI local_server_QueryService(IServiceProvider *iface, REFGUID guid, REFIID riid, void **obj) +{ + struct local_server *local_server = impl_from_IServiceProvider(iface); + struct apartment *apt = COM_CurrentApt(); + HRESULT hr = E_FAIL; + IUnknown *unk; + + TRACE("%p, %s, %s, %p\n", iface, debugstr_guid(guid), debugstr_guid(riid), obj); + + if (!local_server->apt) + return E_UNEXPECTED; + + if (SUCCEEDED(COM_GetRegisteredClassObject(apt, guid, CLSCTX_LOCAL_SERVER, &unk))) + { + hr = IUnknown_QueryInterface(unk, riid, obj); + IUnknown_Release(unk); + } + + return hr; +} + +static const IServiceProviderVtbl local_server_vtbl = +{ + local_server_QueryInterface, + local_server_AddRef, + local_server_Release, + local_server_QueryService +}; + +HRESULT apartment_get_local_server_stream(struct apartment *apt, IStream **ret) +{ + HRESULT hr = S_OK; + + EnterCriticalSection(&apt->cs); + + if (!apt->local_server) + { + struct local_server *obj; + + obj = heap_alloc(sizeof(*obj)); + if (obj) + { + obj->IServiceProvider_iface.lpVtbl = &local_server_vtbl; + obj->refcount = 1; + obj->apt = apt; + + hr = CreateStreamOnHGlobal(0, TRUE, &obj->marshal_stream); + if (SUCCEEDED(hr)) + { + hr = CoMarshalInterface(obj->marshal_stream, &IID_IServiceProvider, (IUnknown *)&obj->IServiceProvider_iface, + MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG); + if (FAILED(hr)) + IStream_Release(obj->marshal_stream); + } + + if (SUCCEEDED(hr)) + apt->local_server = obj; + else + heap_free(obj); + } + else + hr = E_OUTOFMEMORY; + } + + if (SUCCEEDED(hr)) + hr = IStream_Clone(apt->local_server->marshal_stream, ret); + + LeaveCriticalSection(&apt->cs); + + if (FAILED(hr)) + ERR("Failed: %#x\n", hr); + + return hr; +} + +/* Creates new apartment for given model */ +static struct apartment *apartment_construct(DWORD model) +{ + struct apartment *apt; + + TRACE("creating new apartment, model %d\n", model); + + apt = heap_alloc_zero(sizeof(*apt)); + apt->tid = GetCurrentThreadId(); + + list_init(&apt->proxies); + list_init(&apt->stubmgrs); + list_init(&apt->loaded_dlls); + list_init(&apt->usage_cookies); + apt->ipidc = 0; + apt->refs = 1; + apt->remunk_exported = FALSE; + apt->oidc = 1; + InitializeCriticalSection(&apt->cs); + DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment"); + + apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED); + + if (apt->multi_threaded) + { + /* FIXME: should be randomly generated by in an RPC call to rpcss */ + apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe; + } + else + { + /* FIXME: should be randomly generated by in an RPC call to rpcss */ + apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId(); + } + + TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid)); + + list_add_head(&apts, &apt->entry); + + return apt; +} + +/* Frees unused libraries loaded into apartment */ +void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay) +{ + struct apartment_loaded_dll *entry, *next; + + EnterCriticalSection(&apt->cs); + LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry) + { + if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK)) + { + DWORD real_delay = delay; + + if (real_delay == INFINITE) + { + /* DLLs that return multi-threaded objects aren't unloaded + * straight away to cope for programs that have races between + * last object destruction and threads in the DLLs that haven't + * finished, despite DllCanUnloadNow returning S_OK */ + if (entry->multi_threaded) + real_delay = 10 * 60 * 1000; /* 10 minutes */ + else + real_delay = 0; + } + + if (!real_delay || (entry->unload_time && ((int)(GetTickCount() - entry->unload_time) > 0))) + { + list_remove(&entry->entry); + apartment_release_dll(entry->dll, TRUE); + heap_free(entry); + } + else + { + entry->unload_time = GetTickCount() + real_delay; + if (!entry->unload_time) entry->unload_time = 1; + } + } + else if (entry->unload_time) + entry->unload_time = 0; + } + LeaveCriticalSection(&apt->cs); +} + +void apartment_release(struct apartment *apt) +{ + DWORD refcount; + + EnterCriticalSection(&apt_cs); + + refcount = InterlockedDecrement(&apt->refs); + TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), refcount); + + if (apt->being_destroyed) + { + LeaveCriticalSection(&apt_cs); + return; + } + + /* destruction stuff that needs to happen under global */ + if (!refcount) + { + apt->being_destroyed = TRUE; + if (apt == mta) mta = NULL; + else if (apt == main_sta) main_sta = NULL; + list_remove(&apt->entry); + } + + LeaveCriticalSection(&apt_cs); + + if (!refcount) + { + struct list *cursor, *cursor2; + + TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid)); + + if (apt->local_server) + { + struct local_server *local_server = apt->local_server; + LARGE_INTEGER zero; + + memset(&zero, 0, sizeof(zero)); + IStream_Seek(local_server->marshal_stream, zero, STREAM_SEEK_SET, NULL); + CoReleaseMarshalData(local_server->marshal_stream); + IStream_Release(local_server->marshal_stream); + local_server->marshal_stream = NULL; + + apt->local_server = NULL; + local_server->apt = NULL; + IServiceProvider_Release(&local_server->IServiceProvider_iface); + } + + /* Release the references to the registered class objects */ + COM_RevokeAllClasses(apt); + + /* no locking is needed for this apartment, because no other thread + * can access it at this point */ + + apartment_disconnectproxies(apt); + + if (apt->win) DestroyWindow(apt->win); + if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0); + + LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs) + { + struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry); + /* release the implicit reference given by the fact that the + * stub has external references (it must do since it is in the + * stub manager list in the apartment and all non-apartment users + * must have a ref on the apartment and so it cannot be destroyed). + */ + stub_manager_int_release(stubmgr); + } + + /* if this assert fires, then another thread took a reference to a + * stub manager without taking a reference to the containing + * apartment, which it must do. */ + assert(list_empty(&apt->stubmgrs)); + + if (apt->filter) IMessageFilter_Release(apt->filter); + + /* free as many unused libraries as possible... */ + apartment_freeunusedlibraries(apt, 0); + + /* ... and free the memory for the apartment loaded dll entry and + * release the dll list reference without freeing the library for the + * rest */ + while ((cursor = list_head(&apt->loaded_dlls))) + { + struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry); + apartment_release_dll(apartment_loaded_dll->dll, FALSE); + list_remove(cursor); + heap_free(apartment_loaded_dll); + } + + DEBUG_CLEAR_CRITSEC_NAME(&apt->cs); + DeleteCriticalSection(&apt->cs); + + heap_free(apt); + } +} + +static DWORD apartment_addref(struct apartment *apt) +{ + DWORD refs = InterlockedIncrement(&apt->refs); + TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1); + return refs; +} + +/* Gets existing apartment or creates a new one and enters it */ +static struct apartment *apartment_get_or_create(DWORD model) +{ + struct apartment *apt = COM_CurrentApt(); + + if (!apt) + { + if (model & COINIT_APARTMENTTHREADED) + { + EnterCriticalSection(&apt_cs); + + apt = apartment_construct(model); + if (!main_sta) + { + main_sta = apt; + apt->main = TRUE; + TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid)); + } + + LeaveCriticalSection(&apt_cs); + + if (apt->main) + apartment_createwindowifneeded(apt); + } + else + { + EnterCriticalSection(&apt_cs); + + /* The multi-threaded apartment (MTA) contains zero or more threads interacting + * with free threaded (ie thread safe) COM objects. There is only ever one MTA + * in a process */ + if (mta) + { + TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(mta->oxid)); + apartment_addref(mta); + } + else + mta = apartment_construct(model); + + apt = mta; + + LeaveCriticalSection(&apt_cs); + } + COM_CurrentInfo()->apt = apt; + } + + return apt; +} + +struct apartment *apartment_get_mta(void) +{ + struct apartment *apt; + + EnterCriticalSection(&apt_cs); + + if ((apt = mta)) + apartment_addref(apt); + + LeaveCriticalSection(&apt_cs); + + return apt; +} + +/* Return the current apartment if it exists, or, failing that, the MTA. Caller + * must free the returned apartment in either case. */ +struct apartment *apartment_get_current_or_mta(void) +{ + struct apartment *apt = COM_CurrentApt(); + if (apt) + { + apartment_addref(apt); + return apt; + } + return apartment_get_mta(); +} + +/* The given OXID must be local to this process */ +struct apartment *apartment_findfromoxid(OXID oxid) +{ + struct apartment *result = NULL; + struct list *cursor; + + EnterCriticalSection(&apt_cs); + LIST_FOR_EACH( cursor, &apts ) + { + struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry ); + if (apt->oxid == oxid) + { + result = apt; + apartment_addref(result); + break; + } + } + LeaveCriticalSection(&apt_cs); + + return result; +} + +/* gets the apartment which has a given creator thread ID. The caller must + * release the reference from the apartment as soon as the apartment pointer + * is no longer required. */ +struct apartment *apartment_findfromtid(DWORD tid) +{ + struct apartment *result = NULL; + struct list *cursor; + + EnterCriticalSection(&apt_cs); + LIST_FOR_EACH( cursor, &apts ) + { + struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry ); + if (apt->tid == tid) + { + result = apt; + apartment_addref(result); + break; + } + } + LeaveCriticalSection(&apt_cs); + + return result; +} + +/* gets the main apartment if it exists. The caller must + * release the reference from the apartment as soon as the apartment pointer + * is no longer required. */ +static struct apartment *apartment_findmain(void) +{ + struct apartment *result; + + EnterCriticalSection(&apt_cs); + + result = main_sta; + if (result) apartment_addref(result); + + LeaveCriticalSection(&apt_cs); + + return result; +} + +struct host_object_params +{ + struct class_reg_data regdata; + CLSID clsid; /* clsid of object to marshal */ + IID iid; /* interface to marshal */ + HANDLE event; /* event signalling when ready for multi-threaded case */ + HRESULT hr; /* result for multi-threaded case */ + IStream *stream; /* stream that the object will be marshaled into */ + BOOL apartment_threaded; /* is the component purely apartment-threaded? */ +}; + +/* Returns expanded dll path from the registry or activation context. */ +static BOOL get_object_dll_path(const struct class_reg_data *regdata, WCHAR *dst, DWORD dstlen) +{ + DWORD ret; + + if (regdata->origin == CLASS_REG_REGISTRY) + { + DWORD keytype; + WCHAR src[MAX_PATH]; + DWORD dwLength = dstlen * sizeof(WCHAR); + + if ((ret = RegQueryValueExW(regdata->u.hkey, NULL, NULL, &keytype, (BYTE*)src, &dwLength)) == ERROR_SUCCESS) + { + if (keytype == REG_EXPAND_SZ) + { + if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA; + } + else + { + const WCHAR *quote_start; + quote_start = wcschr(src, '"'); + if (quote_start) + { + const WCHAR *quote_end = wcschr(quote_start + 1, '"'); + if (quote_end) + { + memmove(src, quote_start + 1, (quote_end - quote_start - 1) * sizeof(WCHAR)); + src[quote_end - quote_start - 1] = '\0'; + } + } + lstrcpynW(dst, src, dstlen); + } + } + return !ret; + } + else + { + ULONG_PTR cookie; + + *dst = 0; + ActivateActCtx(regdata->u.actctx.hactctx, &cookie); + ret = SearchPathW(NULL, regdata->u.actctx.module_name, L".dll", dstlen, dst, NULL); + DeactivateActCtx(0, cookie); + return *dst != 0; + } +} + +/* gets the specified class object by loading the appropriate DLL, if + * necessary and calls the DllGetClassObject function for the DLL */ +static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath, + BOOL apartment_threaded, + REFCLSID rclsid, REFIID riid, void **ppv) +{ + HRESULT hr = S_OK; + BOOL found = FALSE; + struct apartment_loaded_dll *apartment_loaded_dll; + + if (!wcsicmp(dllpath, L"ole32.dll")) + { + /* we don't need to control the lifetime of this dll, so use the local + * implementation of DllGetClassObject directly */ + TRACE("calling ole32!DllGetClassObject\n"); + hr = DllGetClassObject(rclsid, riid, ppv); + + if (hr != S_OK) + ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr, debugstr_w(dllpath)); + + return hr; + } + + EnterCriticalSection(&apt->cs); + + LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry) + if (!wcsicmp(dllpath, apartment_loaded_dll->dll->library_name)) + { + TRACE("found %s already loaded\n", debugstr_w(dllpath)); + found = TRUE; + break; + } + + if (!found) + { + apartment_loaded_dll = heap_alloc(sizeof(*apartment_loaded_dll)); + if (!apartment_loaded_dll) + hr = E_OUTOFMEMORY; + if (SUCCEEDED(hr)) + { + apartment_loaded_dll->unload_time = 0; + apartment_loaded_dll->multi_threaded = FALSE; + hr = apartment_add_dll(dllpath, &apartment_loaded_dll->dll); + if (FAILED(hr)) + heap_free(apartment_loaded_dll); + } + if (SUCCEEDED(hr)) + { + TRACE("added new loaded dll %s\n", debugstr_w(dllpath)); + list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry); + } + } + + LeaveCriticalSection(&apt->cs); + + if (SUCCEEDED(hr)) + { + /* one component being multi-threaded overrides any number of + * apartment-threaded components */ + if (!apartment_threaded) + apartment_loaded_dll->multi_threaded = TRUE; + + TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject); + /* OK: get the ClassObject */ + hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv); + + if (hr != S_OK) + ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr, debugstr_w(dllpath)); + } + + return hr; +} + +static HRESULT apartment_hostobject(struct apartment *apt, + const struct host_object_params *params); + +struct host_thread_params +{ + COINIT threading_model; + HANDLE ready_event; + HWND apartment_hwnd; +}; + +/* thread for hosting an object to allow an object to appear to be created in + * an apartment with an incompatible threading model */ +static DWORD CALLBACK apartment_hostobject_thread(void *p) +{ + struct host_thread_params *params = p; + MSG msg; + HRESULT hr; + struct apartment *apt; + + TRACE("\n"); + + hr = CoInitializeEx(NULL, params->threading_model); + if (FAILED(hr)) return hr; + + apt = COM_CurrentApt(); + if (params->threading_model == COINIT_APARTMENTTHREADED) + { + apartment_createwindowifneeded(apt); + params->apartment_hwnd = apartment_getwindow(apt); + } + else + params->apartment_hwnd = NULL; + + /* force the message queue to be created before signaling parent thread */ + PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); + + SetEvent(params->ready_event); + params = NULL; /* can't touch params after here as it may be invalid */ + + while (GetMessageW(&msg, NULL, 0, 0)) + { + if (!msg.hwnd && (msg.message == DM_HOSTOBJECT)) + { + struct host_object_params *obj_params = (struct host_object_params *)msg.lParam; + obj_params->hr = apartment_hostobject(apt, obj_params); + SetEvent(obj_params->event); + } + else + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + + TRACE("exiting\n"); + + CoUninitialize(); + + return S_OK; +} + +/* finds or creates a host apartment, creates the object inside it and returns + * a proxy to it so that the object can be used in the apartment of the + * caller of this function */ +static HRESULT apartment_hostobject_in_hostapt(struct apartment *apt, BOOL multi_threaded, + BOOL main_apartment, const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, void **ppv) +{ + struct host_object_params params; + HWND apartment_hwnd = NULL; + DWORD apartment_tid = 0; + HRESULT hr; + + if (!multi_threaded && main_apartment) + { + struct apartment *host_apt = apartment_findmain(); + if (host_apt) + { + apartment_hwnd = apartment_getwindow(host_apt); + apartment_release(host_apt); + } + } + + if (!apartment_hwnd) + { + EnterCriticalSection(&apt->cs); + + if (!apt->host_apt_tid) + { + struct host_thread_params thread_params; + HANDLE handles[2]; + DWORD wait_value; + + thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED; + handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL); + thread_params.apartment_hwnd = NULL; + handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid); + if (!handles[1]) + { + CloseHandle(handles[0]); + LeaveCriticalSection(&apt->cs); + return E_OUTOFMEMORY; + } + wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE); + CloseHandle(handles[0]); + CloseHandle(handles[1]); + if (wait_value == WAIT_OBJECT_0) + apt->host_apt_hwnd = thread_params.apartment_hwnd; + else + { + LeaveCriticalSection(&apt->cs); + return E_OUTOFMEMORY; + } + } + + if (multi_threaded || !main_apartment) + { + apartment_hwnd = apt->host_apt_hwnd; + apartment_tid = apt->host_apt_tid; + } + + LeaveCriticalSection(&apt->cs); + } + + /* another thread may have become the main apartment in the time it took + * us to create the thread for the host apartment */ + if (!apartment_hwnd && !multi_threaded && main_apartment) + { + struct apartment *host_apt = apartment_findmain(); + if (host_apt) + { + apartment_hwnd = apartment_getwindow(host_apt); + apartment_release(host_apt); + } + } + + params.regdata = *regdata; + params.clsid = *rclsid; + params.iid = *riid; + hr = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream); + if (FAILED(hr)) + return hr; + params.apartment_threaded = !multi_threaded; + if (multi_threaded) + { + params.hr = S_OK; + params.event = CreateEventW(NULL, FALSE, FALSE, NULL); + if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)¶ms)) + hr = E_OUTOFMEMORY; + else + { + WaitForSingleObject(params.event, INFINITE); + hr = params.hr; + } + CloseHandle(params.event); + } + else + { + if (!apartment_hwnd) + { + ERR("host apartment didn't create window\n"); + hr = E_OUTOFMEMORY; + } + else + hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms); + } + if (SUCCEEDED(hr)) + hr = CoUnmarshalInterface(params.stream, riid, ppv); + IStream_Release(params.stream); + return hr; +} + +static enum comclass_threadingmodel get_threading_model(const struct class_reg_data *data) +{ + if (data->origin == CLASS_REG_REGISTRY) + { + WCHAR threading_model[10 /* lstrlenW(L"apartment")+1 */]; + DWORD dwLength = sizeof(threading_model); + DWORD keytype; + DWORD ret; + + ret = RegQueryValueExW(data->u.hkey, L"ThreadingModel", NULL, &keytype, (BYTE*)threading_model, &dwLength); + if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ)) + threading_model[0] = '\0'; + + if (!wcsicmp(threading_model, L"Apartment")) return ThreadingModel_Apartment; + if (!wcsicmp(threading_model, L"Free")) return ThreadingModel_Free; + if (!wcsicmp(threading_model, L"Both")) return ThreadingModel_Both; + + /* there's not specific handling for this case */ + if (threading_model[0]) return ThreadingModel_Neutral; + return ThreadingModel_No; + } + else + return data->u.actctx.threading_model; +} + +HRESULT apartment_get_inproc_class_object(struct apartment *apt, const struct class_reg_data *regdata, + REFCLSID rclsid, REFIID riid, BOOL hostifnecessary, void **ppv) +{ + WCHAR dllpath[MAX_PATH+1]; + BOOL apartment_threaded; + + if (hostifnecessary) + { + enum comclass_threadingmodel model = get_threading_model(regdata); + + if (model == ThreadingModel_Apartment) + { + apartment_threaded = TRUE; + if (apt->multi_threaded) + return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, regdata, rclsid, riid, ppv); + } + else if (model == ThreadingModel_Free) + { + apartment_threaded = FALSE; + if (!apt->multi_threaded) + return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, regdata, rclsid, riid, ppv); + } + /* everything except "Apartment", "Free" and "Both" */ + else if (model != ThreadingModel_Both) + { + apartment_threaded = TRUE; + /* everything else is main-threaded */ + if (model != ThreadingModel_No) + FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model, debugstr_guid(rclsid)); + + if (apt->multi_threaded || !apt->main) + return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, regdata, rclsid, riid, ppv); + } + else + apartment_threaded = FALSE; + } + else + apartment_threaded = !apt->multi_threaded; + + if (!get_object_dll_path(regdata, dllpath, ARRAY_SIZE(dllpath))) + { + /* failure: CLSID is not found in registry */ + WARN("class %s not registered inproc\n", debugstr_guid(rclsid)); + return REGDB_E_CLASSNOTREG; + } + + return apartment_getclassobject(apt, dllpath, apartment_threaded, rclsid, riid, ppv); +} + +static HRESULT apartment_hostobject(struct apartment *apt, const struct host_object_params *params) +{ + static const LARGE_INTEGER llZero; + WCHAR dllpath[MAX_PATH+1]; + IUnknown *object; + HRESULT hr; + + TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms->clsid), debugstr_guid(¶ms->iid)); + + if (!get_object_dll_path(¶ms->regdata, dllpath, ARRAY_SIZE(dllpath))) + { + /* failure: CLSID is not found in registry */ + WARN("class %s not registered inproc\n", debugstr_guid(¶ms->clsid)); + return REGDB_E_CLASSNOTREG; + } + + hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded, ¶ms->clsid, ¶ms->iid, (void **)&object); + if (FAILED(hr)) + return hr; + + hr = CoMarshalInterface(params->stream, ¶ms->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); + if (FAILED(hr)) + IUnknown_Release(object); + IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL); + + return hr; +} + +static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) + { + case DM_EXECUTERPC: + RPC_ExecuteCall((struct dispatch_params *)lParam); + return 0; + case DM_HOSTOBJECT: + return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam); + default: + return DefWindowProcW(hWnd, msg, wParam, lParam); + } +} + +static BOOL apartment_is_model(const struct apartment *apt, DWORD model) +{ + return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED)); +} + +HRESULT enter_apartment(struct oletls *info, DWORD model) +{ + HRESULT hr = S_OK; + + if (!info->apt) + { + if (!apartment_get_or_create(model)) + return E_OUTOFMEMORY; + } + else if (!apartment_is_model(info->apt, model)) + { + WARN( "Attempt to change threading model of this apartment from %s to %s\n", + info->apt->multi_threaded ? "multi-threaded" : "apartment threaded", + model & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded" ); + return RPC_E_CHANGED_MODE; + } + else + hr = S_FALSE; + + info->inits++; + + return hr; +} + +void leave_apartment(struct oletls *info) +{ + if (!--info->inits) + { + if (info->ole_inits) + WARN( "Uninitializing apartment while Ole is still initialized\n" ); + apartment_release(info->apt); + info->apt = NULL; + } +} + +struct mta_cookie +{ + struct list entry; +}; + +HRESULT apartment_increment_mta_usage(CO_MTA_USAGE_COOKIE *cookie) +{ + struct mta_cookie *mta_cookie; + + *cookie = NULL; + + if (!(mta_cookie = heap_alloc(sizeof(*mta_cookie)))) + return E_OUTOFMEMORY; + + EnterCriticalSection(&apt_cs); + + if (mta) + apartment_addref(mta); + else + mta = apartment_construct(COINIT_MULTITHREADED); + list_add_head(&mta->usage_cookies, &mta_cookie->entry); + + LeaveCriticalSection(&apt_cs); + + *cookie = (CO_MTA_USAGE_COOKIE)mta_cookie; + + return S_OK; +} + +void apartment_decrement_mta_usage(CO_MTA_USAGE_COOKIE cookie) +{ + struct mta_cookie *mta_cookie = (struct mta_cookie *)cookie; + + EnterCriticalSection(&apt_cs); + + if (mta) + { + struct mta_cookie *cur; + + LIST_FOR_EACH_ENTRY(cur, &mta->usage_cookies, struct mta_cookie, entry) + { + if (mta_cookie == cur) + { + list_remove(&cur->entry); + heap_free(cur); + apartment_release(mta); + break; + } + } + } + + LeaveCriticalSection(&apt_cs); +} + +static const WCHAR aptwinclassW[] = L"OleMainThreadWndClass"; +static ATOM apt_win_class; + +static BOOL WINAPI register_class( INIT_ONCE *once, void *param, void **context ) +{ + WNDCLASSW wclass; + + /* Dispatching to the correct thread in an apartment is done through + * window messages rather than RPC transports. When an interface is + * marshalled into another apartment in the same process, a window of the + * following class is created. The *caller* of CoMarshalInterface (i.e., the + * application) is responsible for pumping the message loop in that thread. + * The WM_USER messages which point to the RPCs are then dispatched to + * apartment_wndproc by the user's code from the apartment in which the + * interface was unmarshalled. + */ + memset(&wclass, 0, sizeof(wclass)); + wclass.lpfnWndProc = apartment_wndproc; + wclass.hInstance = hProxyDll; + wclass.lpszClassName = aptwinclassW; + apt_win_class = RegisterClassW(&wclass); + return TRUE; +} + +/* create a window for the apartment or return the current one if one has + * already been created */ +HRESULT apartment_createwindowifneeded(struct apartment *apt) +{ + static INIT_ONCE class_init_once = INIT_ONCE_STATIC_INIT; + + if (apt->multi_threaded) + return S_OK; + + if (!apt->win) + { + HWND hwnd; + + InitOnceExecuteOnce( &class_init_once, register_class, NULL, NULL ); + + hwnd = CreateWindowW(aptwinclassW, NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, hProxyDll, NULL); + if (!hwnd) + { + ERR("CreateWindow failed with error %d\n", GetLastError()); + return HRESULT_FROM_WIN32(GetLastError()); + } + if (InterlockedCompareExchangePointer((void **)&apt->win, hwnd, NULL)) + /* someone beat us to it */ + DestroyWindow(hwnd); + } + + return S_OK; +} + +/* retrieves the window for the main- or apartment-threaded apartment */ +HWND apartment_getwindow(const struct apartment *apt) +{ + assert(!apt->multi_threaded); + return apt->win; +} + +void apartment_global_cleanup(void) +{ + if (apt_win_class) + UnregisterClassW((const WCHAR *)MAKEINTATOM(apt_win_class), hProxyDll); + apartment_release_dlls(); + DeleteCriticalSection(&apt_cs); +} diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index a68cab0fe98..d59da4207a7 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -71,28 +71,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); * This section defines variables internal to the COM module. */
-static struct apartment *MTA; /* protected by csApartment */ -static struct apartment *MainApartment; /* the first STA apartment */ -static struct list apts = LIST_INIT( apts ); /* protected by csApartment */ - -static CRITICAL_SECTION csApartment; -static CRITICAL_SECTION_DEBUG critsect_debug = -{ - 0, 0, &csApartment, - { &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": csApartment") } -}; -static CRITICAL_SECTION csApartment = { &critsect_debug, -1, 0, 0, 0, 0 }; - -enum comclass_threadingmodel -{ - ThreadingModel_Apartment = 1, - ThreadingModel_Free = 2, - ThreadingModel_No = 3, - ThreadingModel_Both = 4, - ThreadingModel_Neutral = 5 -}; - enum comclass_miscfields { MiscStatus = 1, @@ -164,20 +142,6 @@ struct class_reg_data } u; };
-/* - * This is a marshallable object exposing registered local servers. - * IServiceProvider is used only because it happens meet requirements - * and already has proxy/stub code. If more functionality is needed, - * a custom interface may be used instead. - */ -struct LocalServer -{ - IServiceProvider IServiceProvider_iface; - LONG ref; - struct apartment *apt; - IStream *marshal_stream; -}; - /* * This lock count counts the number of times CoInitialize is called. It is * decreased every time CoUninitialize is called. When it hits 0, the COM @@ -418,322 +382,6 @@ LSTATUS open_classes_key( HKEY hkey, const WCHAR *name, REGSAM access, HKEY *ret return RtlNtStatusToDosError( NtOpenKey( (HANDLE *)retkey, access, &attr ) ); }
-/***************************************************************************** - * This section contains OpenDllList definitions - * - * The OpenDllList contains only handles of dll loaded by CoGetClassObject or - * other functions that do LoadLibrary _without_ giving back a HMODULE. - * Without this list these handles would never be freed. - * - * FIXME: a DLL that says OK when asked for unloading is unloaded in the - * next unload-call but not before 600 sec. - */ - -typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv); -typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void); - -typedef struct tagOpenDll -{ - LONG refs; - LPWSTR library_name; - HANDLE library; - DllGetClassObjectFunc DllGetClassObject; - DllCanUnloadNowFunc DllCanUnloadNow; - struct list entry; -} OpenDll; - -static struct list openDllList = LIST_INIT(openDllList); - -static CRITICAL_SECTION csOpenDllList; -static CRITICAL_SECTION_DEBUG dll_cs_debug = -{ - 0, 0, &csOpenDllList, - { &dll_cs_debug.ProcessLocksList, &dll_cs_debug.ProcessLocksList }, - 0, 0, { (DWORD_PTR)(__FILE__ ": csOpenDllList") } -}; -static CRITICAL_SECTION csOpenDllList = { &dll_cs_debug, -1, 0, 0, 0, 0 }; - -struct apartment_loaded_dll -{ - struct list entry; - OpenDll *dll; - DWORD unload_time; - BOOL multi_threaded; -}; - -static const WCHAR wszAptWinClass[] = {'O','l','e','M','a','i','n','T','h','r','e','a','d','W','n','d','C','l','a','s','s',0}; - -static ATOM apt_win_class; - -/***************************************************************************** - * This section contains OpenDllList implementation - */ - -static OpenDll *COMPOBJ_DllList_Get(LPCWSTR library_name) -{ - OpenDll *ptr; - OpenDll *ret = NULL; - EnterCriticalSection(&csOpenDllList); - LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry) - { - if (!wcsicmp(library_name, ptr->library_name) && - (InterlockedIncrement(&ptr->refs) != 1) /* entry is being destroy if == 1 */) - { - ret = ptr; - break; - } - } - LeaveCriticalSection(&csOpenDllList); - return ret; -} - -/* caller must ensure that library_name is not already in the open dll list */ -static HRESULT COMPOBJ_DllList_Add(LPCWSTR library_name, OpenDll **ret) -{ - OpenDll *entry; - int len; - HRESULT hr = S_OK; - HANDLE hLibrary; - DllCanUnloadNowFunc DllCanUnloadNow; - DllGetClassObjectFunc DllGetClassObject; - - TRACE("%s\n", debugstr_w(library_name)); - - *ret = COMPOBJ_DllList_Get(library_name); - if (*ret) return S_OK; - - /* do this outside the csOpenDllList to avoid creating a lock dependency on - * the loader lock */ - hLibrary = LoadLibraryExW(library_name, 0, LOAD_WITH_ALTERED_SEARCH_PATH); - if (!hLibrary) - { - ERR("couldn't load in-process dll %s\n", debugstr_w(library_name)); - /* failure: DLL could not be loaded */ - return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */ - } - - DllCanUnloadNow = (void *)GetProcAddress(hLibrary, "DllCanUnloadNow"); - /* Note: failing to find DllCanUnloadNow is not a failure */ - DllGetClassObject = (void *)GetProcAddress(hLibrary, "DllGetClassObject"); - if (!DllGetClassObject) - { - /* failure: the dll did not export DllGetClassObject */ - ERR("couldn't find function DllGetClassObject in %s\n", debugstr_w(library_name)); - FreeLibrary(hLibrary); - return CO_E_DLLNOTFOUND; - } - - EnterCriticalSection( &csOpenDllList ); - - *ret = COMPOBJ_DllList_Get(library_name); - if (*ret) - { - /* another caller to this function already added the dll while we - * weren't in the critical section */ - FreeLibrary(hLibrary); - } - else - { - len = lstrlenW(library_name); - entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll)); - if (entry) - entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(WCHAR)); - if (entry && entry->library_name) - { - memcpy(entry->library_name, library_name, (len + 1)*sizeof(WCHAR)); - entry->library = hLibrary; - entry->refs = 1; - entry->DllCanUnloadNow = DllCanUnloadNow; - entry->DllGetClassObject = DllGetClassObject; - list_add_tail(&openDllList, &entry->entry); - *ret = entry; - } - else - { - HeapFree(GetProcessHeap(), 0, entry); - hr = E_OUTOFMEMORY; - FreeLibrary(hLibrary); - } - } - - LeaveCriticalSection( &csOpenDllList ); - - return hr; -} - -/* pass FALSE for free_entry to release a reference without destroying the - * entry if it reaches zero or TRUE otherwise */ -static void COMPOBJ_DllList_ReleaseRef(OpenDll *entry, BOOL free_entry) -{ - if (!InterlockedDecrement(&entry->refs) && free_entry) - { - EnterCriticalSection(&csOpenDllList); - list_remove(&entry->entry); - LeaveCriticalSection(&csOpenDllList); - - TRACE("freeing %p\n", entry->library); - FreeLibrary(entry->library); - - HeapFree(GetProcessHeap(), 0, entry->library_name); - HeapFree(GetProcessHeap(), 0, entry); - } -} - -/* frees memory associated with active dll list */ -static void COMPOBJ_DllList_Free(void) -{ - OpenDll *entry, *cursor2; - EnterCriticalSection(&csOpenDllList); - LIST_FOR_EACH_ENTRY_SAFE(entry, cursor2, &openDllList, OpenDll, entry) - { - list_remove(&entry->entry); - - HeapFree(GetProcessHeap(), 0, entry->library_name); - HeapFree(GetProcessHeap(), 0, entry); - } - LeaveCriticalSection(&csOpenDllList); - DeleteCriticalSection(&csOpenDllList); -} - -/****************************************************************************** - * Manage apartments. - */ - -static DWORD apartment_addref(struct apartment *apt) -{ - DWORD refs = InterlockedIncrement(&apt->refs); - TRACE("%s: before = %d\n", wine_dbgstr_longlong(apt->oxid), refs - 1); - return refs; -} - -/* allocates memory and fills in the necessary fields for a new apartment - * object. must be called inside apartment cs */ -static struct apartment *apartment_construct(DWORD model) -{ - struct apartment *apt; - - TRACE("creating new apartment, model=%d\n", model); - - apt = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*apt)); - apt->tid = GetCurrentThreadId(); - - list_init(&apt->proxies); - list_init(&apt->stubmgrs); - list_init(&apt->loaded_dlls); - list_init(&apt->usage_cookies); - apt->ipidc = 0; - apt->refs = 1; - apt->remunk_exported = FALSE; - apt->oidc = 1; - InitializeCriticalSection(&apt->cs); - DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment"); - - apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED); - - if (apt->multi_threaded) - { - /* FIXME: should be randomly generated by in an RPC call to rpcss */ - apt->oxid = ((OXID)GetCurrentProcessId() << 32) | 0xcafe; - } - else - { - /* FIXME: should be randomly generated by in an RPC call to rpcss */ - apt->oxid = ((OXID)GetCurrentProcessId() << 32) | GetCurrentThreadId(); - } - - TRACE("Created apartment on OXID %s\n", wine_dbgstr_longlong(apt->oxid)); - - list_add_head(&apts, &apt->entry); - - return apt; -} - -/* gets and existing apartment if one exists or otherwise creates an apartment - * structure which stores OLE apartment-local information and stores a pointer - * to it in the thread-local storage */ -static struct apartment *apartment_get_or_create(DWORD model) -{ - struct apartment *apt = COM_CurrentApt(); - - if (!apt) - { - if (model & COINIT_APARTMENTTHREADED) - { - EnterCriticalSection(&csApartment); - - apt = apartment_construct(model); - if (!MainApartment) - { - MainApartment = apt; - apt->main = TRUE; - TRACE("Created main-threaded apartment with OXID %s\n", wine_dbgstr_longlong(apt->oxid)); - } - - LeaveCriticalSection(&csApartment); - - if (apt->main) - apartment_createwindowifneeded(apt); - } - else - { - EnterCriticalSection(&csApartment); - - /* The multi-threaded apartment (MTA) contains zero or more threads interacting - * with free threaded (ie thread safe) COM objects. There is only ever one MTA - * in a process */ - if (MTA) - { - TRACE("entering the multithreaded apartment %s\n", wine_dbgstr_longlong(MTA->oxid)); - apartment_addref(MTA); - } - else - MTA = apartment_construct(model); - - apt = MTA; - - LeaveCriticalSection(&csApartment); - } - COM_CurrentInfo()->apt = apt; - } - - return apt; -} - -static inline BOOL apartment_is_model(const struct apartment *apt, DWORD model) -{ - return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED)); -} - -/* gets the multi-threaded apartment if it exists. The caller must - * release the reference from the apartment as soon as the apartment pointer - * is no longer required. */ -static struct apartment *apartment_find_mta(void) -{ - struct apartment *apt; - - EnterCriticalSection(&csApartment); - - if ((apt = MTA)) - apartment_addref(apt); - - LeaveCriticalSection(&csApartment); - - return apt; -} - -/* Return the current apartment if it exists, or, failing that, the MTA. Caller - * must free the returned apartment in either case. */ -struct apartment *apartment_get_current_or_mta(void) -{ - struct apartment *apt = COM_CurrentApt(); - if (apt) - { - apartment_addref(apt); - return apt; - } - return apartment_find_mta(); -} - static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass) { list_remove(&curClass->entry); @@ -745,7 +393,7 @@ static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass) HeapFree(GetProcessHeap(), 0, curClass); }
-static void COM_RevokeAllClasses(const struct apartment *apt) +void COM_RevokeAllClasses(const struct apartment *apt) { RegisteredClass *curClass, *cursor;
@@ -851,852 +499,125 @@ static ISynchronizeVtbl vt_ISynchronize = { ISynchronize_fnWait, ISynchronize_fnSignal, ISynchronize_fnReset -}; - -static inline MREImpl *impl_from_ISynchronizeHandle(ISynchronizeHandle *iface) -{ - return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface); -} - -static HRESULT WINAPI SynchronizeHandle_QueryInterface(ISynchronizeHandle *iface, REFIID riid, void **ppv) -{ - MREImpl *This = impl_from_ISynchronizeHandle(iface); - return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv); -} - -static ULONG WINAPI SynchronizeHandle_AddRef(ISynchronizeHandle *iface) -{ - MREImpl *This = impl_from_ISynchronizeHandle(iface); - return ISynchronize_AddRef(&This->ISynchronize_iface); -} - -static ULONG WINAPI SynchronizeHandle_Release(ISynchronizeHandle *iface) -{ - MREImpl *This = impl_from_ISynchronizeHandle(iface); - return ISynchronize_Release(&This->ISynchronize_iface); -} - -static HRESULT WINAPI SynchronizeHandle_GetHandle(ISynchronizeHandle *iface, HANDLE *ph) -{ - MREImpl *This = impl_from_ISynchronizeHandle(iface); - - *ph = This->event; - return S_OK; -} - -static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = { - SynchronizeHandle_QueryInterface, - SynchronizeHandle_AddRef, - SynchronizeHandle_Release, - SynchronizeHandle_GetHandle -}; - -HRESULT WINAPI ManualResetEvent_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID iid, void **ppv) -{ - MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl)); - HRESULT hr; - - if (outer) - FIXME("Aggregation not implemented.\n"); - - This->ref = 1; - This->ISynchronize_iface.lpVtbl = &vt_ISynchronize; - This->ISynchronizeHandle_iface.lpVtbl = &SynchronizeHandleVtbl; - This->event = CreateEventW(NULL, TRUE, FALSE, NULL); - - hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv); - ISynchronize_Release(&This->ISynchronize_iface); - return hr; -} - -static inline LocalServer *impl_from_IServiceProvider(IServiceProvider *iface) -{ - return CONTAINING_RECORD(iface, LocalServer, IServiceProvider_iface); -} - -static HRESULT WINAPI LocalServer_QueryInterface(IServiceProvider *iface, REFIID riid, void **ppv) -{ - LocalServer *This = impl_from_IServiceProvider(iface); - - TRACE("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv); - - if(IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_IServiceProvider)) { - *ppv = &This->IServiceProvider_iface; - }else { - *ppv = NULL; - return E_NOINTERFACE; - } - - IUnknown_AddRef((IUnknown*)*ppv); - return S_OK; -} - -static ULONG WINAPI LocalServer_AddRef(IServiceProvider *iface) -{ - LocalServer *This = impl_from_IServiceProvider(iface); - LONG ref = InterlockedIncrement(&This->ref); - - TRACE("(%p) ref=%d\n", This, ref); - - return ref; -} - -static ULONG WINAPI LocalServer_Release(IServiceProvider *iface) -{ - LocalServer *This = impl_from_IServiceProvider(iface); - LONG ref = InterlockedDecrement(&This->ref); - - TRACE("(%p) ref=%d\n", This, ref); - - if(!ref) { - assert(!This->apt); - HeapFree(GetProcessHeap(), 0, This); - } - - return ref; -} - -static HRESULT WINAPI LocalServer_QueryService(IServiceProvider *iface, REFGUID guid, REFIID riid, void **ppv) -{ - LocalServer *This = impl_from_IServiceProvider(iface); - struct apartment *apt = COM_CurrentApt(); - RegisteredClass *iter; - HRESULT hres = E_FAIL; - - TRACE("(%p)->(%s %s %p)\n", This, debugstr_guid(guid), debugstr_guid(riid), ppv); - - if(!This->apt) - return E_UNEXPECTED; - - EnterCriticalSection(&csRegisteredClassList); - - LIST_FOR_EACH_ENTRY(iter, &RegisteredClassList, RegisteredClass, entry) { - if(iter->apartment_id == apt->oxid - && (iter->runContext & CLSCTX_LOCAL_SERVER) - && IsEqualGUID(&iter->classIdentifier, guid)) { - hres = IUnknown_QueryInterface(iter->classObject, riid, ppv); - break; - } - } - - LeaveCriticalSection( &csRegisteredClassList ); - - return hres; -} - -static const IServiceProviderVtbl LocalServerVtbl = { - LocalServer_QueryInterface, - LocalServer_AddRef, - LocalServer_Release, - LocalServer_QueryService -}; - -static HRESULT get_local_server_stream(struct apartment *apt, IStream **ret) -{ - HRESULT hres = S_OK; - - EnterCriticalSection(&apt->cs); - - if(!apt->local_server) { - LocalServer *obj; - - obj = heap_alloc(sizeof(*obj)); - if(obj) { - obj->IServiceProvider_iface.lpVtbl = &LocalServerVtbl; - obj->ref = 1; - obj->apt = apt; - - hres = CreateStreamOnHGlobal(0, TRUE, &obj->marshal_stream); - if(SUCCEEDED(hres)) { - hres = CoMarshalInterface(obj->marshal_stream, &IID_IServiceProvider, (IUnknown*)&obj->IServiceProvider_iface, - MSHCTX_LOCAL, NULL, MSHLFLAGS_TABLESTRONG); - if(FAILED(hres)) - IStream_Release(obj->marshal_stream); - } - - if(SUCCEEDED(hres)) - apt->local_server = obj; - else - heap_free(obj); - }else { - hres = E_OUTOFMEMORY; - } - } - - if(SUCCEEDED(hres)) - hres = IStream_Clone(apt->local_server->marshal_stream, ret); - - LeaveCriticalSection(&apt->cs); - - if(FAILED(hres)) - ERR("Failed: %08x\n", hres); - return hres; -} - -/*********************************************************************** - * CoRevokeClassObject [OLE32.@] - * - * Removes a class object from the class registry. - * - * PARAMS - * dwRegister [I] Cookie returned from CoRegisterClassObject(). - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - * - * NOTES - * Must be called from the same apartment that called CoRegisterClassObject(), - * otherwise it will fail with RPC_E_WRONG_THREAD. - * - * SEE ALSO - * CoRegisterClassObject - */ -HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject( - DWORD dwRegister) -{ - HRESULT hr = E_INVALIDARG; - RegisteredClass *curClass; - struct apartment *apt; - - TRACE("(%08x)\n",dwRegister); - - if (!(apt = apartment_get_current_or_mta())) - { - ERR("COM was not initialized\n"); - return CO_E_NOTINITIALIZED; - } - - EnterCriticalSection( &csRegisteredClassList ); - - LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry) - { - /* - * Check if we have a match on the cookie. - */ - if (curClass->dwCookie == dwRegister) - { - if (curClass->apartment_id == apt->oxid) - { - COM_RevokeRegisteredClassObject(curClass); - hr = S_OK; - } - else - { - ERR("called from wrong apartment, should be called from %s\n", - wine_dbgstr_longlong(curClass->apartment_id)); - hr = RPC_E_WRONG_THREAD; - } - break; - } - } - - LeaveCriticalSection( &csRegisteredClassList ); - apartment_release(apt); - return hr; -} - -/* frees unused libraries loaded by apartment_getclassobject by calling the - * DLL's DllCanUnloadNow entry point */ -static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay) -{ - struct apartment_loaded_dll *entry, *next; - EnterCriticalSection(&apt->cs); - LIST_FOR_EACH_ENTRY_SAFE(entry, next, &apt->loaded_dlls, struct apartment_loaded_dll, entry) - { - if (entry->dll->DllCanUnloadNow && (entry->dll->DllCanUnloadNow() == S_OK)) - { - DWORD real_delay = delay; - - if (real_delay == INFINITE) - { - /* DLLs that return multi-threaded objects aren't unloaded - * straight away to cope for programs that have races between - * last object destruction and threads in the DLLs that haven't - * finished, despite DllCanUnloadNow returning S_OK */ - if (entry->multi_threaded) - real_delay = 10 * 60 * 1000; /* 10 minutes */ - else - real_delay = 0; - } - - if (!real_delay || (entry->unload_time && ((int)(GetTickCount() - entry->unload_time) > 0))) - { - list_remove(&entry->entry); - COMPOBJ_DllList_ReleaseRef(entry->dll, TRUE); - HeapFree(GetProcessHeap(), 0, entry); - } - else - { - entry->unload_time = GetTickCount() + real_delay; - if (!entry->unload_time) entry->unload_time = 1; - } - } - else if (entry->unload_time) - entry->unload_time = 0; - } - LeaveCriticalSection(&apt->cs); -} - -DWORD apartment_release(struct apartment *apt) -{ - DWORD ret; - - EnterCriticalSection(&csApartment); - - ret = InterlockedDecrement(&apt->refs); - TRACE("%s: after = %d\n", wine_dbgstr_longlong(apt->oxid), ret); - - if (apt->being_destroyed) - { - LeaveCriticalSection(&csApartment); - return ret; - } - - /* destruction stuff that needs to happen under csApartment CS */ - if (ret == 0) - { - apt->being_destroyed = TRUE; - if (apt == MTA) MTA = NULL; - else if (apt == MainApartment) MainApartment = NULL; - list_remove(&apt->entry); - } - - LeaveCriticalSection(&csApartment); - - if (ret == 0) - { - struct list *cursor, *cursor2; - - TRACE("destroying apartment %p, oxid %s\n", apt, wine_dbgstr_longlong(apt->oxid)); - - if(apt->local_server) { - LocalServer *local_server = apt->local_server; - LARGE_INTEGER zero; - - memset(&zero, 0, sizeof(zero)); - IStream_Seek(local_server->marshal_stream, zero, STREAM_SEEK_SET, NULL); - CoReleaseMarshalData(local_server->marshal_stream); - IStream_Release(local_server->marshal_stream); - local_server->marshal_stream = NULL; - - apt->local_server = NULL; - local_server->apt = NULL; - IServiceProvider_Release(&local_server->IServiceProvider_iface); - } - - /* Release the references to the registered class objects */ - COM_RevokeAllClasses(apt); - - /* no locking is needed for this apartment, because no other thread - * can access it at this point */ - - apartment_disconnectproxies(apt); - - if (apt->win) DestroyWindow(apt->win); - if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0); - - LIST_FOR_EACH_SAFE(cursor, cursor2, &apt->stubmgrs) - { - struct stub_manager *stubmgr = LIST_ENTRY(cursor, struct stub_manager, entry); - /* release the implicit reference given by the fact that the - * stub has external references (it must do since it is in the - * stub manager list in the apartment and all non-apartment users - * must have a ref on the apartment and so it cannot be destroyed). - */ - stub_manager_int_release(stubmgr); - } - - /* if this assert fires, then another thread took a reference to a - * stub manager without taking a reference to the containing - * apartment, which it must do. */ - assert(list_empty(&apt->stubmgrs)); - - if (apt->filter) IMessageFilter_Release(apt->filter); - - /* free as many unused libraries as possible... */ - apartment_freeunusedlibraries(apt, 0); - - /* ... and free the memory for the apartment loaded dll entry and - * release the dll list reference without freeing the library for the - * rest */ - while ((cursor = list_head(&apt->loaded_dlls))) - { - struct apartment_loaded_dll *apartment_loaded_dll = LIST_ENTRY(cursor, struct apartment_loaded_dll, entry); - COMPOBJ_DllList_ReleaseRef(apartment_loaded_dll->dll, FALSE); - list_remove(cursor); - HeapFree(GetProcessHeap(), 0, apartment_loaded_dll); - } - - DEBUG_CLEAR_CRITSEC_NAME(&apt->cs); - DeleteCriticalSection(&apt->cs); - - HeapFree(GetProcessHeap(), 0, apt); - } - - return ret; -} - -/* The given OXID must be local to this process */ -struct apartment *apartment_findfromoxid(OXID oxid) -{ - struct apartment *result = NULL; - struct list *cursor; - - EnterCriticalSection(&csApartment); - LIST_FOR_EACH( cursor, &apts ) - { - struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry ); - if (apt->oxid == oxid) - { - result = apt; - apartment_addref(result); - break; - } - } - LeaveCriticalSection(&csApartment); - - return result; -} - -/* gets the apartment which has a given creator thread ID. The caller must - * release the reference from the apartment as soon as the apartment pointer - * is no longer required. */ -struct apartment *apartment_findfromtid(DWORD tid) -{ - struct apartment *result = NULL; - struct list *cursor; - - EnterCriticalSection(&csApartment); - LIST_FOR_EACH( cursor, &apts ) - { - struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry ); - if (apt->tid == tid) - { - result = apt; - apartment_addref(result); - break; - } - } - LeaveCriticalSection(&csApartment); - - return result; -} - -/* gets the main apartment if it exists. The caller must - * release the reference from the apartment as soon as the apartment pointer - * is no longer required. */ -static struct apartment *apartment_findmain(void) -{ - struct apartment *result; - - EnterCriticalSection(&csApartment); - - result = MainApartment; - if (result) apartment_addref(result); - - LeaveCriticalSection(&csApartment); - - return result; -} - -/* gets the specified class object by loading the appropriate DLL, if - * necessary and calls the DllGetClassObject function for the DLL */ -static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath, - BOOL apartment_threaded, - REFCLSID rclsid, REFIID riid, void **ppv) -{ - static const WCHAR wszOle32[] = {'o','l','e','3','2','.','d','l','l',0}; - HRESULT hr = S_OK; - BOOL found = FALSE; - struct apartment_loaded_dll *apartment_loaded_dll; - - if (!wcsicmp(dllpath, wszOle32)) - { - /* we don't need to control the lifetime of this dll, so use the local - * implementation of DllGetClassObject directly */ - TRACE("calling ole32!DllGetClassObject\n"); - hr = DllGetClassObject(rclsid, riid, ppv); - - if (hr != S_OK) - ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr, debugstr_w(dllpath)); - - return hr; - } - - EnterCriticalSection(&apt->cs); - - LIST_FOR_EACH_ENTRY(apartment_loaded_dll, &apt->loaded_dlls, struct apartment_loaded_dll, entry) - if (!wcsicmp(dllpath, apartment_loaded_dll->dll->library_name)) - { - TRACE("found %s already loaded\n", debugstr_w(dllpath)); - found = TRUE; - break; - } - - if (!found) - { - apartment_loaded_dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*apartment_loaded_dll)); - if (!apartment_loaded_dll) - hr = E_OUTOFMEMORY; - if (SUCCEEDED(hr)) - { - apartment_loaded_dll->unload_time = 0; - apartment_loaded_dll->multi_threaded = FALSE; - hr = COMPOBJ_DllList_Add( dllpath, &apartment_loaded_dll->dll ); - if (FAILED(hr)) - HeapFree(GetProcessHeap(), 0, apartment_loaded_dll); - } - if (SUCCEEDED(hr)) - { - TRACE("added new loaded dll %s\n", debugstr_w(dllpath)); - list_add_tail(&apt->loaded_dlls, &apartment_loaded_dll->entry); - } - } - - LeaveCriticalSection(&apt->cs); - - if (SUCCEEDED(hr)) - { - /* one component being multi-threaded overrides any number of - * apartment-threaded components */ - if (!apartment_threaded) - apartment_loaded_dll->multi_threaded = TRUE; - - TRACE("calling DllGetClassObject %p\n", apartment_loaded_dll->dll->DllGetClassObject); - /* OK: get the ClassObject */ - hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv); - - if (hr != S_OK) - ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr, debugstr_w(dllpath)); - } - - return hr; -} - -/* Returns expanded dll path from the registry or activation context. */ -static BOOL get_object_dll_path(const struct class_reg_data *regdata, WCHAR *dst, DWORD dstlen) -{ - DWORD ret; - - if (regdata->origin == CLASS_REG_REGISTRY) - { - DWORD keytype; - WCHAR src[MAX_PATH]; - DWORD dwLength = dstlen * sizeof(WCHAR); - - if( (ret = RegQueryValueExW(regdata->u.hkey, NULL, NULL, &keytype, (BYTE*)src, &dwLength)) == ERROR_SUCCESS ) { - if (keytype == REG_EXPAND_SZ) { - if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA; - } else { - const WCHAR *quote_start; - quote_start = wcschr(src, '"'); - if (quote_start) { - const WCHAR *quote_end = wcschr(quote_start + 1, '"'); - if (quote_end) { - memmove(src, quote_start + 1, - (quote_end - quote_start - 1) * sizeof(WCHAR)); - src[quote_end - quote_start - 1] = '\0'; - } - } - lstrcpynW(dst, src, dstlen); - } - } - return !ret; - } - else - { - static const WCHAR dllW[] = {'.','d','l','l',0}; - ULONG_PTR cookie; - - *dst = 0; - ActivateActCtx(regdata->u.actctx.hactctx, &cookie); - ret = SearchPathW(NULL, regdata->u.actctx.module_name, dllW, dstlen, dst, NULL); - DeactivateActCtx(0, cookie); - return *dst != 0; - } -} - -struct host_object_params -{ - struct class_reg_data regdata; - CLSID clsid; /* clsid of object to marshal */ - IID iid; /* interface to marshal */ - HANDLE event; /* event signalling when ready for multi-threaded case */ - HRESULT hr; /* result for multi-threaded case */ - IStream *stream; /* stream that the object will be marshaled into */ - BOOL apartment_threaded; /* is the component purely apartment-threaded? */ -}; - -static HRESULT apartment_hostobject(struct apartment *apt, - const struct host_object_params *params) -{ - IUnknown *object; - HRESULT hr; - static const LARGE_INTEGER llZero; - WCHAR dllpath[MAX_PATH+1]; - - TRACE("clsid %s, iid %s\n", debugstr_guid(¶ms->clsid), debugstr_guid(¶ms->iid)); - - if (!get_object_dll_path(¶ms->regdata, dllpath, ARRAY_SIZE(dllpath))) - { - /* failure: CLSID is not found in registry */ - WARN("class %s not registered inproc\n", debugstr_guid(¶ms->clsid)); - return REGDB_E_CLASSNOTREG; - } - - hr = apartment_getclassobject(apt, dllpath, params->apartment_threaded, - ¶ms->clsid, ¶ms->iid, (void **)&object); - if (FAILED(hr)) - return hr; - - hr = CoMarshalInterface(params->stream, ¶ms->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL); - if (FAILED(hr)) - IUnknown_Release(object); - IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL); - - return hr; -} - -static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) - { - case DM_EXECUTERPC: - RPC_ExecuteCall((struct dispatch_params *)lParam); - return 0; - case DM_HOSTOBJECT: - return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam); - default: - return DefWindowProcW(hWnd, msg, wParam, lParam); - } -} - -struct host_thread_params -{ - COINIT threading_model; - HANDLE ready_event; - HWND apartment_hwnd; -}; - -/* thread for hosting an object to allow an object to appear to be created in - * an apartment with an incompatible threading model */ -static DWORD CALLBACK apartment_hostobject_thread(LPVOID p) -{ - struct host_thread_params *params = p; - MSG msg; - HRESULT hr; - struct apartment *apt; - - TRACE("\n"); - - hr = CoInitializeEx(NULL, params->threading_model); - if (FAILED(hr)) return hr; - - apt = COM_CurrentApt(); - if (params->threading_model == COINIT_APARTMENTTHREADED) - { - apartment_createwindowifneeded(apt); - params->apartment_hwnd = apartment_getwindow(apt); - } - else - params->apartment_hwnd = NULL; - - /* force the message queue to be created before signaling parent thread */ - PeekMessageW(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE); - - SetEvent(params->ready_event); - params = NULL; /* can't touch params after here as it may be invalid */ - - while (GetMessageW(&msg, NULL, 0, 0)) - { - if (!msg.hwnd && (msg.message == DM_HOSTOBJECT)) - { - struct host_object_params *obj_params = (struct host_object_params *)msg.lParam; - obj_params->hr = apartment_hostobject(apt, obj_params); - SetEvent(obj_params->event); - } - else - { - TranslateMessage(&msg); - DispatchMessageW(&msg); - } - } +};
- TRACE("exiting\n"); +static inline MREImpl *impl_from_ISynchronizeHandle(ISynchronizeHandle *iface) +{ + return CONTAINING_RECORD(iface, MREImpl, ISynchronizeHandle_iface); +}
- CoUninitialize(); +static HRESULT WINAPI SynchronizeHandle_QueryInterface(ISynchronizeHandle *iface, REFIID riid, void **ppv) +{ + MREImpl *This = impl_from_ISynchronizeHandle(iface); + return ISynchronize_QueryInterface(&This->ISynchronize_iface, riid, ppv); +}
- return S_OK; +static ULONG WINAPI SynchronizeHandle_AddRef(ISynchronizeHandle *iface) +{ + MREImpl *This = impl_from_ISynchronizeHandle(iface); + return ISynchronize_AddRef(&This->ISynchronize_iface); }
-/* finds or creates a host apartment, creates the object inside it and returns - * a proxy to it so that the object can be used in the apartment of the - * caller of this function */ -static HRESULT apartment_hostobject_in_hostapt( - struct apartment *apt, BOOL multi_threaded, BOOL main_apartment, - const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, void **ppv) +static ULONG WINAPI SynchronizeHandle_Release(ISynchronizeHandle *iface) { - struct host_object_params params; - HWND apartment_hwnd = NULL; - DWORD apartment_tid = 0; - HRESULT hr; + MREImpl *This = impl_from_ISynchronizeHandle(iface); + return ISynchronize_Release(&This->ISynchronize_iface); +}
- if (!multi_threaded && main_apartment) - { - struct apartment *host_apt = apartment_findmain(); - if (host_apt) - { - apartment_hwnd = apartment_getwindow(host_apt); - apartment_release(host_apt); - } - } +static HRESULT WINAPI SynchronizeHandle_GetHandle(ISynchronizeHandle *iface, HANDLE *ph) +{ + MREImpl *This = impl_from_ISynchronizeHandle(iface);
- if (!apartment_hwnd) - { - EnterCriticalSection(&apt->cs); + *ph = This->event; + return S_OK; +}
- if (!apt->host_apt_tid) - { - struct host_thread_params thread_params; - HANDLE handles[2]; - DWORD wait_value; - - thread_params.threading_model = multi_threaded ? COINIT_MULTITHREADED : COINIT_APARTMENTTHREADED; - handles[0] = thread_params.ready_event = CreateEventW(NULL, FALSE, FALSE, NULL); - thread_params.apartment_hwnd = NULL; - handles[1] = CreateThread(NULL, 0, apartment_hostobject_thread, &thread_params, 0, &apt->host_apt_tid); - if (!handles[1]) - { - CloseHandle(handles[0]); - LeaveCriticalSection(&apt->cs); - return E_OUTOFMEMORY; - } - wait_value = WaitForMultipleObjects(2, handles, FALSE, INFINITE); - CloseHandle(handles[0]); - CloseHandle(handles[1]); - if (wait_value == WAIT_OBJECT_0) - apt->host_apt_hwnd = thread_params.apartment_hwnd; - else - { - LeaveCriticalSection(&apt->cs); - return E_OUTOFMEMORY; - } - } +static const ISynchronizeHandleVtbl SynchronizeHandleVtbl = { + SynchronizeHandle_QueryInterface, + SynchronizeHandle_AddRef, + SynchronizeHandle_Release, + SynchronizeHandle_GetHandle +};
- if (multi_threaded || !main_apartment) - { - apartment_hwnd = apt->host_apt_hwnd; - apartment_tid = apt->host_apt_tid; - } +HRESULT WINAPI ManualResetEvent_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID iid, void **ppv) +{ + MREImpl *This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(MREImpl)); + HRESULT hr;
- LeaveCriticalSection(&apt->cs); - } + if (outer) + FIXME("Aggregation not implemented.\n");
- /* another thread may have become the main apartment in the time it took - * us to create the thread for the host apartment */ - if (!apartment_hwnd && !multi_threaded && main_apartment) - { - struct apartment *host_apt = apartment_findmain(); - if (host_apt) - { - apartment_hwnd = apartment_getwindow(host_apt); - apartment_release(host_apt); - } - } + This->ref = 1; + This->ISynchronize_iface.lpVtbl = &vt_ISynchronize; + This->ISynchronizeHandle_iface.lpVtbl = &SynchronizeHandleVtbl; + This->event = CreateEventW(NULL, TRUE, FALSE, NULL);
- params.regdata = *regdata; - params.clsid = *rclsid; - params.iid = *riid; - hr = CreateStreamOnHGlobal(NULL, TRUE, ¶ms.stream); - if (FAILED(hr)) - return hr; - params.apartment_threaded = !multi_threaded; - if (multi_threaded) - { - params.hr = S_OK; - params.event = CreateEventW(NULL, FALSE, FALSE, NULL); - if (!PostThreadMessageW(apartment_tid, DM_HOSTOBJECT, 0, (LPARAM)¶ms)) - hr = E_OUTOFMEMORY; - else - { - WaitForSingleObject(params.event, INFINITE); - hr = params.hr; - } - CloseHandle(params.event); - } - else - { - if (!apartment_hwnd) - { - ERR("host apartment didn't create window\n"); - hr = E_OUTOFMEMORY; - } - else - hr = SendMessageW(apartment_hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms); - } - if (SUCCEEDED(hr)) - hr = CoUnmarshalInterface(params.stream, riid, ppv); - IStream_Release(params.stream); + hr = ISynchronize_QueryInterface(&This->ISynchronize_iface, iid, ppv); + ISynchronize_Release(&This->ISynchronize_iface); return hr; }
-static BOOL WINAPI register_class( INIT_ONCE *once, void *param, void **context ) +/*********************************************************************** + * CoRevokeClassObject [OLE32.@] + * + * Removes a class object from the class registry. + * + * PARAMS + * dwRegister [I] Cookie returned from CoRegisterClassObject(). + * + * RETURNS + * Success: S_OK. + * Failure: HRESULT code. + * + * NOTES + * Must be called from the same apartment that called CoRegisterClassObject(), + * otherwise it will fail with RPC_E_WRONG_THREAD. + * + * SEE ALSO + * CoRegisterClassObject + */ +HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject( + DWORD dwRegister) { - WNDCLASSW wclass; + HRESULT hr = E_INVALIDARG; + RegisteredClass *curClass; + struct apartment *apt;
- /* Dispatching to the correct thread in an apartment is done through - * window messages rather than RPC transports. When an interface is - * marshalled into another apartment in the same process, a window of the - * following class is created. The *caller* of CoMarshalInterface (i.e., the - * application) is responsible for pumping the message loop in that thread. - * The WM_USER messages which point to the RPCs are then dispatched to - * apartment_wndproc by the user's code from the apartment in which the - * interface was unmarshalled. - */ - memset(&wclass, 0, sizeof(wclass)); - wclass.lpfnWndProc = apartment_wndproc; - wclass.hInstance = hProxyDll; - wclass.lpszClassName = wszAptWinClass; - apt_win_class = RegisterClassW(&wclass); - return TRUE; -} + TRACE("(%08x)\n",dwRegister);
-/* create a window for the apartment or return the current one if one has - * already been created */ -HRESULT apartment_createwindowifneeded(struct apartment *apt) -{ - static INIT_ONCE class_init_once = INIT_ONCE_STATIC_INIT; + if (!(apt = apartment_get_current_or_mta())) + { + ERR("COM was not initialized\n"); + return CO_E_NOTINITIALIZED; + }
- if (apt->multi_threaded) - return S_OK; + EnterCriticalSection( &csRegisteredClassList );
- if (!apt->win) + LIST_FOR_EACH_ENTRY(curClass, &RegisteredClassList, RegisteredClass, entry) + { + /* + * Check if we have a match on the cookie. + */ + if (curClass->dwCookie == dwRegister) { - HWND hwnd; - - InitOnceExecuteOnce( &class_init_once, register_class, NULL, NULL ); - - hwnd = CreateWindowW(wszAptWinClass, NULL, 0, 0, 0, 0, 0, - HWND_MESSAGE, 0, hProxyDll, NULL); - if (!hwnd) - { - ERR("CreateWindow failed with error %d\n", GetLastError()); - return HRESULT_FROM_WIN32(GetLastError()); - } - if (InterlockedCompareExchangePointer((PVOID *)&apt->win, hwnd, NULL)) - /* someone beat us to it */ - DestroyWindow(hwnd); + if (curClass->apartment_id == apt->oxid) + { + COM_RevokeRegisteredClassObject(curClass); + hr = S_OK; + } + else + { + ERR("called from wrong apartment, should be called from %s\n", + wine_dbgstr_longlong(curClass->apartment_id)); + hr = RPC_E_WRONG_THREAD; + } + break; } + }
- return S_OK; -} - -/* retrieves the window for the main- or apartment-threaded apartment */ -HWND apartment_getwindow(const struct apartment *apt) -{ - assert(!apt->multi_threaded); - return apt->win; + LeaveCriticalSection( &csRegisteredClassList ); + apartment_release(apt); + return hr; }
static void COM_TlsDestroy(void) @@ -1763,41 +684,6 @@ static void unlock_init_spies(struct oletls *info) } }
-HRESULT enter_apartment( struct oletls *info, DWORD model ) -{ - HRESULT hr = S_OK; - - if (!info->apt) - { - if (!apartment_get_or_create( model )) - return E_OUTOFMEMORY; - } - else if (!apartment_is_model( info->apt, model )) - { - WARN( "Attempt to change threading model of this apartment from %s to %s\n", - info->apt->multi_threaded ? "multi-threaded" : "apartment threaded", - model & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded" ); - return RPC_E_CHANGED_MODE; - } - else - hr = S_FALSE; - - info->inits++; - - return hr; -} - -void leave_apartment( struct oletls *info ) -{ - if (!--info->inits) - { - if (info->ole_inits) - WARN( "Uninitializing apartment while Ole is still initialized\n" ); - apartment_release( info->apt ); - info->apt = NULL; - } -} - /****************************************************************************** * CoInitialize [OLE32.@] * @@ -2123,7 +1009,7 @@ HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey * to normal COM usage, this method will increase the * reference count on this object. */ -static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid, +HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk) { HRESULT hr = S_FALSE; @@ -2271,7 +1157,7 @@ HRESULT WINAPI CoRegisterClassObject( if (dwClsContext & CLSCTX_LOCAL_SERVER) { IStream *marshal_stream;
- hr = get_local_server_stream(apt, &marshal_stream); + hr = apartment_get_local_server_stream(apt, &marshal_stream); if(FAILED(hr)) { apartment_release(apt); @@ -2288,86 +1174,6 @@ HRESULT WINAPI CoRegisterClassObject( return S_OK; }
-static enum comclass_threadingmodel get_threading_model(const struct class_reg_data *data) -{ - if (data->origin == CLASS_REG_REGISTRY) - { - static const WCHAR wszThreadingModel[] = {'T','h','r','e','a','d','i','n','g','M','o','d','e','l',0}; - static const WCHAR wszApartment[] = {'A','p','a','r','t','m','e','n','t',0}; - static const WCHAR wszFree[] = {'F','r','e','e',0}; - static const WCHAR wszBoth[] = {'B','o','t','h',0}; - WCHAR threading_model[10 /* lstrlenW(L"apartment")+1 */]; - DWORD dwLength = sizeof(threading_model); - DWORD keytype; - DWORD ret; - - ret = RegQueryValueExW(data->u.hkey, wszThreadingModel, NULL, &keytype, (BYTE*)threading_model, &dwLength); - if ((ret != ERROR_SUCCESS) || (keytype != REG_SZ)) - threading_model[0] = '\0'; - - if (!wcsicmp(threading_model, wszApartment)) return ThreadingModel_Apartment; - if (!wcsicmp(threading_model, wszFree)) return ThreadingModel_Free; - if (!wcsicmp(threading_model, wszBoth)) return ThreadingModel_Both; - - /* there's not specific handling for this case */ - if (threading_model[0]) return ThreadingModel_Neutral; - return ThreadingModel_No; - } - else - return data->u.actctx.threading_model; -} - -static HRESULT get_inproc_class_object(struct apartment *apt, const struct class_reg_data *regdata, - REFCLSID rclsid, REFIID riid, - BOOL hostifnecessary, void **ppv) -{ - WCHAR dllpath[MAX_PATH+1]; - BOOL apartment_threaded; - - if (hostifnecessary) - { - enum comclass_threadingmodel model = get_threading_model(regdata); - - if (model == ThreadingModel_Apartment) - { - apartment_threaded = TRUE; - if (apt->multi_threaded) - return apartment_hostobject_in_hostapt(apt, FALSE, FALSE, regdata, rclsid, riid, ppv); - } - else if (model == ThreadingModel_Free) - { - apartment_threaded = FALSE; - if (!apt->multi_threaded) - return apartment_hostobject_in_hostapt(apt, TRUE, FALSE, regdata, rclsid, riid, ppv); - } - /* everything except "Apartment", "Free" and "Both" */ - else if (model != ThreadingModel_Both) - { - apartment_threaded = TRUE; - /* everything else is main-threaded */ - if (model != ThreadingModel_No) - FIXME("unrecognised threading model %d for object %s, should be main-threaded?\n", model, debugstr_guid(rclsid)); - - if (apt->multi_threaded || !apt->main) - return apartment_hostobject_in_hostapt(apt, FALSE, TRUE, regdata, rclsid, riid, ppv); - } - else - apartment_threaded = FALSE; - } - else - apartment_threaded = !apt->multi_threaded; - - if (!get_object_dll_path(regdata, dllpath, ARRAY_SIZE(dllpath))) - { - /* failure: CLSID is not found in registry */ - WARN("class %s not registered inproc\n", debugstr_guid(rclsid)); - return REGDB_E_CLASSNOTREG; - } - - return apartment_getclassobject(apt, dllpath, apartment_threaded, - rclsid, riid, ppv); -} - /*********************************************************************** * CoGetClassObject [OLE32.@] * @@ -2450,7 +1256,7 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject( clsreg.u.actctx.threading_model = comclass->model; clsreg.origin = CLASS_REG_ACTCTX;
- hres = get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv); + hres = apartment_get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv); ReleaseActCtx(data.hActCtx); apartment_release(apt); return hres; @@ -2500,7 +1306,7 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject( clsreg.u.hkey = hkey; clsreg.origin = CLASS_REG_REGISTRY;
- hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv); + hres = apartment_get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv); RegCloseKey(hkey); }
@@ -2536,7 +1342,7 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject( clsreg.u.hkey = hkey; clsreg.origin = CLASS_REG_REGISTRY;
- hres = get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv); + hres = apartment_get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv); RegCloseKey(hkey); }
@@ -3108,6 +1914,49 @@ HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *pChann return RPC_RegisterChannelHook(guidExtension, pChannelHook); }
+/* Returns expanded dll path from the registry or activation context. */ +static BOOL get_object_dll_path(const struct class_reg_data *regdata, WCHAR *dst, DWORD dstlen) +{ + DWORD ret; + + if (regdata->origin == CLASS_REG_REGISTRY) + { + DWORD keytype; + WCHAR src[MAX_PATH]; + DWORD dwLength = dstlen * sizeof(WCHAR); + + if( (ret = RegQueryValueExW(regdata->u.hkey, NULL, NULL, &keytype, (BYTE*)src, &dwLength)) == ERROR_SUCCESS ) { + if (keytype == REG_EXPAND_SZ) { + if (dstlen <= ExpandEnvironmentStringsW(src, dst, dstlen)) ret = ERROR_MORE_DATA; + } else { + const WCHAR *quote_start; + quote_start = wcschr(src, '"'); + if (quote_start) { + const WCHAR *quote_end = wcschr(quote_start + 1, '"'); + if (quote_end) { + memmove(src, quote_start + 1, + (quote_end - quote_start - 1) * sizeof(WCHAR)); + src[quote_end - quote_start - 1] = '\0'; + } + } + lstrcpynW(dst, src, dstlen); + } + } + return !ret; + } + else + { + static const WCHAR dllW[] = {'.','d','l','l',0}; + ULONG_PTR cookie; + + *dst = 0; + ActivateActCtx(regdata->u.actctx.hactctx, &cookie); + ret = SearchPathW(NULL, regdata->u.actctx.module_name, dllW, dstlen, dst, NULL); + DeactivateActCtx(0, cookie); + return *dst != 0; + } +} + HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) { static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0}; @@ -3167,7 +2016,7 @@ HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier)
*qualifier = APTTYPEQUALIFIER_NONE;
- if (!info->apt && (apt = apartment_find_mta())) + if (!info->apt && (apt = apartment_get_mta())) { apartment_release(apt); *type = APTTYPE_MTA; @@ -3178,38 +2027,14 @@ HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier) return info->apt ? S_OK : CO_E_NOTINITIALIZED; }
-struct mta_cookie -{ - struct list entry; -}; - /*********************************************************************** * CoIncrementMTAUsage [OLE32.@] */ HRESULT WINAPI CoIncrementMTAUsage(CO_MTA_USAGE_COOKIE *cookie) { - struct mta_cookie *mta_cookie; - TRACE("%p\n", cookie);
- *cookie = NULL; - - if (!(mta_cookie = heap_alloc(sizeof(*mta_cookie)))) - return E_OUTOFMEMORY; - - EnterCriticalSection(&csApartment); - - if (MTA) - apartment_addref(MTA); - else - MTA = apartment_construct(COINIT_MULTITHREADED); - list_add_head(&MTA->usage_cookies, &mta_cookie->entry); - - LeaveCriticalSection(&csApartment); - - *cookie = (CO_MTA_USAGE_COOKIE)mta_cookie; - - return S_OK; + return apartment_increment_mta_usage(cookie); }
/*********************************************************************** @@ -3217,30 +2042,9 @@ HRESULT WINAPI CoIncrementMTAUsage(CO_MTA_USAGE_COOKIE *cookie) */ HRESULT WINAPI CoDecrementMTAUsage(CO_MTA_USAGE_COOKIE cookie) { - struct mta_cookie *mta_cookie = (struct mta_cookie *)cookie; - TRACE("%p\n", cookie);
- EnterCriticalSection(&csApartment); - - if (MTA) - { - struct mta_cookie *cur; - - LIST_FOR_EACH_ENTRY(cur, &MTA->usage_cookies, struct mta_cookie, entry) - { - if (mta_cookie == cur) - { - list_remove(&cur->entry); - heap_free(cur); - apartment_release(MTA); - break; - } - } - } - - LeaveCriticalSection(&csApartment); - + apartment_decrement_mta_usage(cookie); return S_OK; }
@@ -3406,13 +2210,10 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID reserved) case DLL_PROCESS_DETACH: if (reserved) break; release_std_git(); - if(apt_win_class) - UnregisterClassW( (const WCHAR*)MAKEINTATOM(apt_win_class), hProxyDll ); RPC_UnregisterAllChannelHooks(); - COMPOBJ_DllList_Free(); DeleteCriticalSection(&csRegisteredClassList); - DeleteCriticalSection(&csApartment); - break; + apartment_global_cleanup(); + break;
case DLL_THREAD_DETACH: COM_TlsDestroy(); diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h index 6e8b7ae2cfc..156b6bb2f44 100644 --- a/dlls/ole32/compobj_private.h +++ b/dlls/ole32/compobj_private.h @@ -40,7 +40,6 @@ #include "winternl.h"
struct apartment; -typedef struct LocalServer LocalServer;
DEFINE_OLEGUID( CLSID_DfMarshal, 0x0000030b, 0, 0 );
@@ -140,7 +139,7 @@ struct apartment struct list loaded_dlls; /* list of dlls loaded by this apartment (CS cs) */ DWORD host_apt_tid; /* thread ID of apartment hosting objects of differing threading model (CS cs) */ HWND host_apt_hwnd; /* handle to apartment window of host apartment (CS cs) */ - LocalServer *local_server; /* A marshallable object exposing local servers (CS cs) */ + struct local_server *local_server; /* A marshallable object exposing local servers (CS cs) */ BOOL being_destroyed; /* is currently being destroyed */
/* FIXME: OIDs should be given out by RPCSS */ @@ -248,7 +247,7 @@ void OLEDD_UnInitialize(void) DECLSPEC_HIDDEN;
struct apartment *apartment_findfromoxid(OXID oxid) DECLSPEC_HIDDEN; struct apartment *apartment_findfromtid(DWORD tid) DECLSPEC_HIDDEN; -DWORD apartment_release(struct apartment *apt) DECLSPEC_HIDDEN; +void apartment_release(struct apartment *apt) DECLSPEC_HIDDEN; HRESULT apartment_disconnectproxies(struct apartment *apt) DECLSPEC_HIDDEN; static inline HRESULT apartment_getoxid(const struct apartment *apt, OXID *oxid) { @@ -261,6 +260,21 @@ HRESULT enter_apartment(struct oletls *info, DWORD model) DECLSPEC_HIDDEN; void leave_apartment(struct oletls *info) DECLSPEC_HIDDEN; struct apartment *apartment_get_current_or_mta(void) DECLSPEC_HIDDEN;
+struct class_reg_data; +HRESULT apartment_get_inproc_class_object(struct apartment *apt, const struct class_reg_data *regdata, + REFCLSID rclsid, REFIID riid, BOOL hostifnecessary, void **ppv) DECLSPEC_HIDDEN; + +void apartment_decrement_mta_usage(CO_MTA_USAGE_COOKIE cookie) DECLSPEC_HIDDEN; +HRESULT apartment_increment_mta_usage(CO_MTA_USAGE_COOKIE *cookie) DECLSPEC_HIDDEN; +struct apartment *apartment_get_mta(void) DECLSPEC_HIDDEN; +HRESULT apartment_get_local_server_stream(struct apartment *apt, IStream **ret) DECLSPEC_HIDDEN; +void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay) DECLSPEC_HIDDEN; +void apartment_global_cleanup(void) DECLSPEC_HIDDEN; + +HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid, + DWORD dwClsContext, IUnknown **ppUnk) DECLSPEC_HIDDEN; +void COM_RevokeAllClasses(const struct apartment *apt) DECLSPEC_HIDDEN; + /* DCOM messages used by the apartment window (not compatible with native) */ #define DM_EXECUTERPC (WM_USER + 0) /* WPARAM = 0, LPARAM = (struct dispatch_params *) */ #define DM_HOSTOBJECT (WM_USER + 1) /* WPARAM = 0, LPARAM = (struct host_object_params *) */
Signed-off-by: Huw Davies huw@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/combase/Makefile.in | 1 + dlls/{ole32 => combase}/apartment.c | 94 +++++++++++++++++------------ dlls/combase/combase.c | 19 ++++++ dlls/combase/combase.spec | 16 +++++ dlls/combase/combase_private.h | 42 +++++++++++++ dlls/ole32/Makefile.in | 1 - dlls/ole32/compobj.c | 10 ++- dlls/ole32/compobj_private.h | 31 +++++----- dlls/ole32/marshal.c | 2 +- dlls/ole32/ole32.spec | 5 ++ dlls/ole32/rpc.c | 4 +- dlls/ole32/stubmanager.c | 5 ++ 12 files changed, 165 insertions(+), 65 deletions(-) rename dlls/{ole32 => combase}/apartment.c (92%)
diff --git a/dlls/combase/Makefile.in b/dlls/combase/Makefile.in index 16a2bfa3167..45e1ff189cb 100644 --- a/dlls/combase/Makefile.in +++ b/dlls/combase/Makefile.in @@ -6,6 +6,7 @@ DELAYIMPORTS = oleaut32 EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \ + apartment.c \ combase.c \ errorinfo.c \ malloc.c \ diff --git a/dlls/ole32/apartment.c b/dlls/combase/apartment.c similarity index 92% rename from dlls/ole32/apartment.c rename to dlls/combase/apartment.c index 456e6c80a36..dbf4553fa41 100644 --- a/dlls/ole32/apartment.c +++ b/dlls/combase/apartment.c @@ -33,7 +33,7 @@ #include "winbase.h" #include "servprov.h"
-#include "compobj_private.h" +#include "combase_private.h"
#include "wine/debug.h" #include "wine/list.h" @@ -306,10 +306,13 @@ static ULONG WINAPI local_server_Release(IServiceProvider *iface) return refcount; }
+extern HRESULT WINAPI InternalGetRegisteredClassObject(struct apartment *apt, REFGUID guid, + DWORD clscontext, IUnknown **obj); + static HRESULT WINAPI local_server_QueryService(IServiceProvider *iface, REFGUID guid, REFIID riid, void **obj) { struct local_server *local_server = impl_from_IServiceProvider(iface); - struct apartment *apt = COM_CurrentApt(); + struct apartment *apt = com_get_current_apt(); HRESULT hr = E_FAIL; IUnknown *unk;
@@ -318,7 +321,7 @@ static HRESULT WINAPI local_server_QueryService(IServiceProvider *iface, REFGUID if (!local_server->apt) return E_UNEXPECTED;
- if (SUCCEEDED(COM_GetRegisteredClassObject(apt, guid, CLSCTX_LOCAL_SERVER, &unk))) + if (SUCCEEDED(InternalGetRegisteredClassObject(apt, guid, CLSCTX_LOCAL_SERVER, &unk))) { hr = IUnknown_QueryInterface(unk, riid, obj); IUnknown_Release(unk); @@ -335,7 +338,7 @@ static const IServiceProviderVtbl local_server_vtbl = local_server_QueryService };
-HRESULT apartment_get_local_server_stream(struct apartment *apt, IStream **ret) +HRESULT WINAPI apartment_get_local_server_stream(struct apartment *apt, IStream **ret) { HRESULT hr = S_OK;
@@ -400,7 +403,7 @@ static struct apartment *apartment_construct(DWORD model) apt->remunk_exported = FALSE; apt->oidc = 1; InitializeCriticalSection(&apt->cs); - DEBUG_SET_CRITSEC_NAME(&apt->cs, "apartment"); + apt->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": apartment");
apt->multi_threaded = !(model & COINIT_APARTMENTTHREADED);
@@ -423,7 +426,7 @@ static struct apartment *apartment_construct(DWORD model) }
/* Frees unused libraries loaded into apartment */ -void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay) +void WINAPI apartment_freeunusedlibraries(struct apartment *apt, DWORD delay) { struct apartment_loaded_dll *entry, *next;
@@ -464,7 +467,11 @@ void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay) LeaveCriticalSection(&apt->cs); }
-void apartment_release(struct apartment *apt) +extern void WINAPI InternalRevokeAllClasses(struct apartment *apt); +extern HRESULT WINAPI Internal_apartment_disconnectproxies(struct apartment *apt); +extern ULONG WINAPI Internal_stub_manager_int_release(struct stub_manager *stubmgr); + +void WINAPI apartment_release(struct apartment *apt) { DWORD refcount;
@@ -513,12 +520,12 @@ void apartment_release(struct apartment *apt) }
/* Release the references to the registered class objects */ - COM_RevokeAllClasses(apt); + InternalRevokeAllClasses(apt);
/* no locking is needed for this apartment, because no other thread * can access it at this point */
- apartment_disconnectproxies(apt); + Internal_apartment_disconnectproxies(apt);
if (apt->win) DestroyWindow(apt->win); if (apt->host_apt_tid) PostThreadMessageW(apt->host_apt_tid, WM_QUIT, 0, 0); @@ -531,7 +538,7 @@ void apartment_release(struct apartment *apt) * stub manager list in the apartment and all non-apartment users * must have a ref on the apartment and so it cannot be destroyed). */ - stub_manager_int_release(stubmgr); + Internal_stub_manager_int_release(stubmgr); }
/* if this assert fires, then another thread took a reference to a @@ -555,7 +562,7 @@ void apartment_release(struct apartment *apt) heap_free(apartment_loaded_dll); }
- DEBUG_CLEAR_CRITSEC_NAME(&apt->cs); + apt->cs.DebugInfo->Spare[0] = 0; DeleteCriticalSection(&apt->cs);
heap_free(apt); @@ -572,7 +579,8 @@ static DWORD apartment_addref(struct apartment *apt) /* Gets existing apartment or creates a new one and enters it */ static struct apartment *apartment_get_or_create(DWORD model) { - struct apartment *apt = COM_CurrentApt(); + struct apartment *apt = com_get_current_apt(); + struct tlsdata *data;
if (!apt) { @@ -612,13 +620,14 @@ static struct apartment *apartment_get_or_create(DWORD model)
LeaveCriticalSection(&apt_cs); } - COM_CurrentInfo()->apt = apt; + com_get_tlsdata(&data); + data->apt = apt; }
return apt; }
-struct apartment *apartment_get_mta(void) +struct apartment * WINAPI apartment_get_mta(void) { struct apartment *apt;
@@ -634,9 +643,9 @@ struct apartment *apartment_get_mta(void)
/* Return the current apartment if it exists, or, failing that, the MTA. Caller * must free the returned apartment in either case. */ -struct apartment *apartment_get_current_or_mta(void) +struct apartment * WINAPI apartment_get_current_or_mta(void) { - struct apartment *apt = COM_CurrentApt(); + struct apartment *apt = com_get_current_apt(); if (apt) { apartment_addref(apt); @@ -646,7 +655,7 @@ struct apartment *apartment_get_current_or_mta(void) }
/* The given OXID must be local to this process */ -struct apartment *apartment_findfromoxid(OXID oxid) +struct apartment * WINAPI apartment_findfromoxid(OXID oxid) { struct apartment *result = NULL; struct list *cursor; @@ -670,7 +679,7 @@ struct apartment *apartment_findfromoxid(OXID oxid) /* gets the apartment which has a given creator thread ID. The caller must * release the reference from the apartment as soon as the apartment pointer * is no longer required. */ -struct apartment *apartment_findfromtid(DWORD tid) +struct apartment * WINAPI apartment_findfromtid(DWORD tid) { struct apartment *result = NULL; struct list *cursor; @@ -778,10 +787,14 @@ static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
if (!wcsicmp(dllpath, L"ole32.dll")) { + HRESULT (WINAPI *p_ole32_DllGetClassObject)(REFCLSID clsid, REFIID riid, void **obj); + + p_ole32_DllGetClassObject = (void *)GetProcAddress(GetModuleHandleW(L"ole32.dll"), "DllGetClassObject"); + /* we don't need to control the lifetime of this dll, so use the local * implementation of DllGetClassObject directly */ TRACE("calling ole32!DllGetClassObject\n"); - hr = DllGetClassObject(rclsid, riid, ppv); + hr = p_ole32_DllGetClassObject(rclsid, riid, ppv);
if (hr != S_OK) ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr, debugstr_w(dllpath)); @@ -863,7 +876,7 @@ static DWORD CALLBACK apartment_hostobject_thread(void *p) hr = CoInitializeEx(NULL, params->threading_model); if (FAILED(hr)) return hr;
- apt = COM_CurrentApt(); + apt = com_get_current_apt(); if (params->threading_model == COINIT_APARTMENTTHREADED) { apartment_createwindowifneeded(apt); @@ -1035,7 +1048,7 @@ static enum comclass_threadingmodel get_threading_model(const struct class_reg_d return data->u.actctx.threading_model; }
-HRESULT apartment_get_inproc_class_object(struct apartment *apt, const struct class_reg_data *regdata, +HRESULT WINAPI apartment_get_inproc_class_object(struct apartment *apt, const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, BOOL hostifnecessary, void **ppv) { WCHAR dllpath[MAX_PATH+1]; @@ -1112,15 +1125,18 @@ static HRESULT apartment_hostobject(struct apartment *apt, const struct host_obj return hr; }
+struct dispatch_params; +extern void WINAPI Internal_RPC_ExecuteCall(struct dispatch_params *params); + static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case DM_EXECUTERPC: - RPC_ExecuteCall((struct dispatch_params *)lParam); + Internal_RPC_ExecuteCall((struct dispatch_params *)lParam); return 0; case DM_HOSTOBJECT: - return apartment_hostobject(COM_CurrentApt(), (const struct host_object_params *)lParam); + return apartment_hostobject(com_get_current_apt(), (const struct host_object_params *)lParam); default: return DefWindowProcW(hWnd, msg, wParam, lParam); } @@ -1131,38 +1147,38 @@ static BOOL apartment_is_model(const struct apartment *apt, DWORD model) return (apt->multi_threaded == !(model & COINIT_APARTMENTTHREADED)); }
-HRESULT enter_apartment(struct oletls *info, DWORD model) +HRESULT WINAPI enter_apartment(struct tlsdata *data, DWORD model) { HRESULT hr = S_OK;
- if (!info->apt) + if (!data->apt) { if (!apartment_get_or_create(model)) return E_OUTOFMEMORY; } - else if (!apartment_is_model(info->apt, model)) + else if (!apartment_is_model(data->apt, model)) { - WARN( "Attempt to change threading model of this apartment from %s to %s\n", - info->apt->multi_threaded ? "multi-threaded" : "apartment threaded", + WARN("Attempt to change threading model of this apartment from %s to %s\n", + data->apt->multi_threaded ? "multi-threaded" : "apartment threaded", model & COINIT_APARTMENTTHREADED ? "apartment threaded" : "multi-threaded" ); return RPC_E_CHANGED_MODE; } else hr = S_FALSE;
- info->inits++; + data->inits++;
return hr; }
-void leave_apartment(struct oletls *info) +void WINAPI leave_apartment(struct tlsdata *data) { - if (!--info->inits) + if (!--data->inits) { - if (info->ole_inits) + if (data->ole_inits) WARN( "Uninitializing apartment while Ole is still initialized\n" ); - apartment_release(info->apt); - info->apt = NULL; + apartment_release(data->apt); + data->apt = NULL; } }
@@ -1171,7 +1187,7 @@ struct mta_cookie struct list entry; };
-HRESULT apartment_increment_mta_usage(CO_MTA_USAGE_COOKIE *cookie) +HRESULT WINAPI apartment_increment_mta_usage(CO_MTA_USAGE_COOKIE *cookie) { struct mta_cookie *mta_cookie;
@@ -1195,7 +1211,7 @@ HRESULT apartment_increment_mta_usage(CO_MTA_USAGE_COOKIE *cookie) return S_OK; }
-void apartment_decrement_mta_usage(CO_MTA_USAGE_COOKIE cookie) +void WINAPI apartment_decrement_mta_usage(CO_MTA_USAGE_COOKIE cookie) { struct mta_cookie *mta_cookie = (struct mta_cookie *)cookie;
@@ -1246,7 +1262,7 @@ static BOOL WINAPI register_class( INIT_ONCE *once, void *param, void **context
/* create a window for the apartment or return the current one if one has * already been created */ -HRESULT apartment_createwindowifneeded(struct apartment *apt) +HRESULT WINAPI apartment_createwindowifneeded(struct apartment *apt) { static INIT_ONCE class_init_once = INIT_ONCE_STATIC_INIT;
@@ -1274,13 +1290,13 @@ HRESULT apartment_createwindowifneeded(struct apartment *apt) }
/* retrieves the window for the main- or apartment-threaded apartment */ -HWND apartment_getwindow(const struct apartment *apt) +HWND WINAPI apartment_getwindow(const struct apartment *apt) { assert(!apt->multi_threaded); return apt->win; }
-void apartment_global_cleanup(void) +void WINAPI apartment_global_cleanup(void) { if (apt_win_class) UnregisterClassW((const WCHAR *)MAKEINTATOM(apt_win_class), hProxyDll); diff --git a/dlls/combase/combase.c b/dlls/combase/combase.c index 80d6ece266e..286b7be8b86 100644 --- a/dlls/combase/combase.c +++ b/dlls/combase/combase.c @@ -36,6 +36,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(ole);
+HINSTANCE hProxyDll; + #define CHARS_IN_GUID 39
struct comclassredirect_data @@ -2249,3 +2251,20 @@ DWORD WINAPI CoGetCurrentProcess(void)
return tlsdata->thread_seqid; } + +/*********************************************************************** + * DllMain (combase.@) + */ +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID reserved) +{ + TRACE("%p 0x%x %p\n", hinstDLL, reason, reserved); + + switch (reason) + { + case DLL_PROCESS_ATTACH: + hProxyDll = hinstDLL; + break; + } + + return TRUE; +} diff --git a/dlls/combase/combase.spec b/dlls/combase/combase.spec index 9038d5fa8bf..980ffa820cd 100644 --- a/dlls/combase/combase.spec +++ b/dlls/combase/combase.spec @@ -351,3 +351,19 @@ @ stdcall WindowsSubstringWithSpecifiedLength(ptr long long ptr) @ stdcall WindowsTrimStringEnd(ptr ptr ptr) @ stdcall WindowsTrimStringStart(ptr ptr ptr) + +@ stdcall apartment_get_current_or_mta() +@ stdcall apartment_release(ptr) +@ stdcall enter_apartment(ptr long) +@ stdcall leave_apartment(ptr) +@ stdcall apartment_get_inproc_class_object(ptr ptr ptr ptr long ptr) +@ stdcall apartment_freeunusedlibraries(ptr long) +@ stdcall apartment_get_mta() +@ stdcall apartment_decrement_mta_usage(ptr) +@ stdcall apartment_increment_mta_usage(ptr) +@ stdcall apartment_findfromoxid(int64) +@ stdcall apartment_getwindow(ptr) +@ stdcall apartment_global_cleanup() +@ stdcall apartment_createwindowifneeded(ptr) +@ stdcall apartment_get_local_server_stream(ptr ptr) +@ stdcall apartment_findfromtid(long) diff --git a/dlls/combase/combase_private.h b/dlls/combase/combase_private.h index 7d7583282e1..16d926d13b4 100644 --- a/dlls/combase/combase_private.h +++ b/dlls/combase/combase_private.h @@ -17,8 +17,11 @@ #include "winternl.h" #include "wine/orpc.h"
+#include "wine/heap.h" #include "wine/list.h"
+extern HINSTANCE hProxyDll; + struct apartment { struct list entry; @@ -51,6 +54,10 @@ struct apartment struct list usage_cookies; /* Used for refcount control with CoIncrementMTAUsage()/CoDecrementMTAUsage(). */ };
+/* DCOM messages used by the apartment window (not compatible with native) */ +#define DM_EXECUTERPC (WM_USER + 0) /* WPARAM = 0, LPARAM = (struct dispatch_params *) */ +#define DM_HOSTOBJECT (WM_USER + 1) /* WPARAM = 0, LPARAM = (struct host_object_params *) */ + /* this is what is stored in TEB->ReservedForOle */ struct tlsdata { @@ -89,5 +96,40 @@ static inline struct apartment* com_get_current_apt(void) return tlsdata->apt; }
+HWND WINAPI apartment_getwindow(const struct apartment *apt) DECLSPEC_HIDDEN; +HRESULT WINAPI apartment_createwindowifneeded(struct apartment *apt) DECLSPEC_HIDDEN; + /* RpcSs interface */ HRESULT rpcss_get_next_seqid(DWORD *id) DECLSPEC_HIDDEN; + +/* 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; + struct apartment *apt; /* owning apt (RO) */ + + ULONG extrefs; /* number of 'external' references (CS lock) */ + ULONG refs; /* internal reference count (CS apt->cs) */ + ULONG weakrefs; /* number of weak references (CS lock) */ + OID oid; /* apartment-scoped unique identifier (RO) */ + IUnknown *object; /* the object we are managing the stub for (RO) */ + ULONG next_ipid; /* currently unused (LOCK) */ + OXID_INFO oxid_info; /* string binding, ipid of rem unknown and other information (RO) */ + + IExternalConnection *extern_conn; + + /* We need to keep a count of the outstanding marshals, so we can enforce the + * marshalling rules (ie, you can only unmarshal normal marshals once). Note + * that these counts do NOT include unmarshalled interfaces, once a stream is + * unmarshalled and a proxy set up, this count is decremented. + */ + + ULONG norm_refs; /* refcount of normal marshals (CS lock) */ + BOOL disconnected; /* CoDisconnectObject has been called (CS lock) */ +}; + +/* Stub Manager */ + +ULONG stub_manager_int_release(struct stub_manager *This) DECLSPEC_HIDDEN; diff --git a/dlls/ole32/Makefile.in b/dlls/ole32/Makefile.in index 5a2b21dee4f..1c1e28fa4c5 100644 --- a/dlls/ole32/Makefile.in +++ b/dlls/ole32/Makefile.in @@ -8,7 +8,6 @@ EXTRADLLFLAGS = -mno-cygwin
C_SRCS = \ antimoniker.c \ - apartment.c \ bindctx.c \ classmoniker.c \ clipboard.c \ diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index d59da4207a7..8451953baaf 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -393,7 +393,7 @@ static void COM_RevokeRegisteredClassObject(RegisteredClass *curClass) HeapFree(GetProcessHeap(), 0, curClass); }
-void COM_RevokeAllClasses(const struct apartment *apt) +void WINAPI InternalRevokeAllClasses(const struct apartment *apt) { RegisteredClass *curClass, *cursor;
@@ -997,8 +997,6 @@ HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey }
/*** - * COM_GetRegisteredClassObject - * * This internal method is used to scan the registered class list to * find a class object. * @@ -1009,7 +1007,7 @@ HRESULT COM_OpenKeyForAppIdFromCLSID(REFCLSID clsid, REGSAM access, HKEY *subkey * to normal COM usage, this method will increase the * reference count on this object. */ -HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid, +HRESULT WINAPI InternalGetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk) { HRESULT hr = S_FALSE; @@ -1110,7 +1108,7 @@ HRESULT WINAPI CoRegisterClassObject( * First, check if the class is already registered. * If it is, this should cause an error. */ - hr = COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject); + hr = InternalGetRegisteredClassObject(apt, rclsid, dwClsContext, &foundObject); if (hr == S_OK) { if (flags & REGCLS_MULTIPLEUSE) { if (dwClsContext & CLSCTX_LOCAL_SERVER) @@ -1267,7 +1265,7 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject( * First, try and see if we can't match the class ID with one of the * registered classes. */ - if (S_OK == COM_GetRegisteredClassObject(apt, rclsid, dwClsContext, + if (S_OK == InternalGetRegisteredClassObject(apt, rclsid, dwClsContext, ®ClassObject)) { /* Get the required interface from the retrieved pointer. */ diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h index 156b6bb2f44..34fe1e7a381 100644 --- a/dlls/ole32/compobj_private.h +++ b/dlls/ole32/compobj_private.h @@ -245,31 +245,30 @@ void OLEDD_UnInitialize(void) DECLSPEC_HIDDEN;
/* Apartment Functions */
-struct apartment *apartment_findfromoxid(OXID oxid) DECLSPEC_HIDDEN; -struct apartment *apartment_findfromtid(DWORD tid) DECLSPEC_HIDDEN; -void apartment_release(struct apartment *apt) DECLSPEC_HIDDEN; -HRESULT apartment_disconnectproxies(struct apartment *apt) DECLSPEC_HIDDEN; +extern struct apartment * WINAPI apartment_findfromoxid(OXID oxid) DECLSPEC_HIDDEN; +extern struct apartment * WINAPI apartment_findfromtid(DWORD tid) DECLSPEC_HIDDEN; +extern void WINAPI apartment_release(struct apartment *apt) DECLSPEC_HIDDEN; static inline HRESULT apartment_getoxid(const struct apartment *apt, OXID *oxid) { *oxid = apt->oxid; return S_OK; } -HRESULT apartment_createwindowifneeded(struct apartment *apt) DECLSPEC_HIDDEN; -HWND apartment_getwindow(const struct apartment *apt) DECLSPEC_HIDDEN; -HRESULT enter_apartment(struct oletls *info, DWORD model) DECLSPEC_HIDDEN; -void leave_apartment(struct oletls *info) DECLSPEC_HIDDEN; -struct apartment *apartment_get_current_or_mta(void) DECLSPEC_HIDDEN; +extern HRESULT WINAPI apartment_createwindowifneeded(struct apartment *apt) DECLSPEC_HIDDEN; +extern HWND WINAPI apartment_getwindow(const struct apartment *apt) DECLSPEC_HIDDEN; +extern HRESULT WINAPI enter_apartment(struct oletls *info, DWORD model) DECLSPEC_HIDDEN; +void WINAPI leave_apartment(struct oletls *info) DECLSPEC_HIDDEN; +extern struct apartment * WINAPI apartment_get_current_or_mta(void) DECLSPEC_HIDDEN;
struct class_reg_data; -HRESULT apartment_get_inproc_class_object(struct apartment *apt, const struct class_reg_data *regdata, +extern HRESULT WINAPI apartment_get_inproc_class_object(struct apartment *apt, const struct class_reg_data *regdata, REFCLSID rclsid, REFIID riid, BOOL hostifnecessary, void **ppv) DECLSPEC_HIDDEN;
-void apartment_decrement_mta_usage(CO_MTA_USAGE_COOKIE cookie) DECLSPEC_HIDDEN; -HRESULT apartment_increment_mta_usage(CO_MTA_USAGE_COOKIE *cookie) DECLSPEC_HIDDEN; -struct apartment *apartment_get_mta(void) DECLSPEC_HIDDEN; -HRESULT apartment_get_local_server_stream(struct apartment *apt, IStream **ret) DECLSPEC_HIDDEN; -void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay) DECLSPEC_HIDDEN; -void apartment_global_cleanup(void) DECLSPEC_HIDDEN; +extern void WINAPI apartment_decrement_mta_usage(CO_MTA_USAGE_COOKIE cookie) DECLSPEC_HIDDEN; +extern HRESULT WINAPI apartment_increment_mta_usage(CO_MTA_USAGE_COOKIE *cookie) DECLSPEC_HIDDEN; +extern struct apartment * WINAPI apartment_get_mta(void) DECLSPEC_HIDDEN; +extern HRESULT WINAPI apartment_get_local_server_stream(struct apartment *apt, IStream **ret) DECLSPEC_HIDDEN; +extern void WINAPI apartment_freeunusedlibraries(struct apartment *apt, DWORD delay) DECLSPEC_HIDDEN; +extern void WINAPI apartment_global_cleanup(void) DECLSPEC_HIDDEN;
HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid, DWORD dwClsContext, IUnknown **ppUnk) DECLSPEC_HIDDEN; diff --git a/dlls/ole32/marshal.c b/dlls/ole32/marshal.c index 8cc35354d53..d08144f619a 100644 --- a/dlls/ole32/marshal.c +++ b/dlls/ole32/marshal.c @@ -1223,7 +1223,7 @@ static BOOL find_proxy_manager(struct apartment * apt, OXID oxid, OID oid, struc return found; }
-HRESULT apartment_disconnectproxies(struct apartment *apt) +HRESULT WINAPI Internal_apartment_disconnectproxies(struct apartment *apt) { struct list * cursor;
diff --git a/dlls/ole32/ole32.spec b/dlls/ole32/ole32.spec index 2564851c4b5..4a2e6b531ab 100644 --- a/dlls/ole32/ole32.spec +++ b/dlls/ole32/ole32.spec @@ -298,3 +298,8 @@ @ stub WriteOleStg @ stub WriteStringStream @ stdcall InternalIsInitialized() +@ stdcall InternalGetRegisteredClassObject(ptr ptr long ptr) +@ stdcall InternalRevokeAllClasses(ptr) +@ stdcall Internal_apartment_disconnectproxies(ptr) +@ stdcall Internal_RPC_ExecuteCall(ptr) +@ stdcall Internal_stub_manager_int_release(ptr) diff --git a/dlls/ole32/rpc.c b/dlls/ole32/rpc.c index d0b0f49319d..1c88ae21543 100644 --- a/dlls/ole32/rpc.c +++ b/dlls/ole32/rpc.c @@ -1324,7 +1324,7 @@ static HRESULT unmarshal_ORPCTHAT(RPC_MESSAGE *msg, ORPCTHAT *orpcthat, return S_OK; }
-void RPC_ExecuteCall(struct dispatch_params *params) +void WINAPI Internal_RPC_ExecuteCall(struct dispatch_params *params) { struct message_state *message_state = NULL; RPC_MESSAGE *msg = (RPC_MESSAGE *)params->msg; @@ -1504,7 +1504,7 @@ static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg) enter_apartment(info, COINIT_MULTITHREADED); joined = TRUE; } - RPC_ExecuteCall(params); + Internal_RPC_ExecuteCall(params); if (joined) { leave_apartment(info); diff --git a/dlls/ole32/stubmanager.c b/dlls/ole32/stubmanager.c index 338b89750ef..d38e22adb47 100644 --- a/dlls/ole32/stubmanager.c +++ b/dlls/ole32/stubmanager.c @@ -307,6 +307,11 @@ static ULONG stub_manager_int_addref(struct stub_manager *This) return refs; }
+ULONG WINAPI Internal_stub_manager_int_release(struct stub_manager *m) +{ + return stub_manager_int_release(m); +} + /* decrements the internal refcount */ ULONG stub_manager_int_release(struct stub_manager *This) {
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=77582
Your paranoid android.
=== debiant (build log) ===
Task: Patch failed to apply
=== debiant (build log) ===
Task: Patch failed to apply
Signed-off-by: Huw Davies huw@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/combase/apartment.c | 2 +- dlls/combase/combase.c | 15 +++++++++++++++ dlls/combase/combase.spec | 3 +-- dlls/combase/combase_private.h | 1 + dlls/ole32/compobj.c | 29 ----------------------------- dlls/ole32/compobj_private.h | 1 - dlls/ole32/ole32.spec | 2 +- 7 files changed, 19 insertions(+), 34 deletions(-)
diff --git a/dlls/combase/apartment.c b/dlls/combase/apartment.c index dbf4553fa41..81071563c09 100644 --- a/dlls/combase/apartment.c +++ b/dlls/combase/apartment.c @@ -426,7 +426,7 @@ static struct apartment *apartment_construct(DWORD model) }
/* Frees unused libraries loaded into apartment */ -void WINAPI apartment_freeunusedlibraries(struct apartment *apt, DWORD delay) +void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay) { struct apartment_loaded_dll *entry, *next;
diff --git a/dlls/combase/combase.c b/dlls/combase/combase.c index 286b7be8b86..4ce43717fb4 100644 --- a/dlls/combase/combase.c +++ b/dlls/combase/combase.c @@ -2252,6 +2252,21 @@ DWORD WINAPI CoGetCurrentProcess(void) return tlsdata->thread_seqid; }
+/*********************************************************************** + * CoFreeUnusedLibrariesEx (combase.@) + */ +void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD unload_delay, DWORD reserved) +{ + struct apartment *apt = com_get_current_apt(); + if (!apt) + { + ERR("apartment not initialised\n"); + return; + } + + apartment_freeunusedlibraries(apt, unload_delay); +} + /*********************************************************************** * DllMain (combase.@) */ diff --git a/dlls/combase/combase.spec b/dlls/combase/combase.spec index 980ffa820cd..00aea556d94 100644 --- a/dlls/combase/combase.spec +++ b/dlls/combase/combase.spec @@ -93,7 +93,7 @@ @ stdcall CoEnableCallCancellation(ptr) ole32.CoEnableCallCancellation @ stdcall CoFileTimeNow(ptr) @ stdcall CoFreeUnusedLibraries() -@ stdcall CoFreeUnusedLibrariesEx(long long) ole32.CoFreeUnusedLibrariesEx +@ stdcall CoFreeUnusedLibrariesEx(long long) @ stdcall CoGetActivationState(int128 long ptr) @ stub CoGetApartmentID @ stdcall CoGetApartmentType(ptr ptr) ole32.CoGetApartmentType @@ -357,7 +357,6 @@ @ stdcall enter_apartment(ptr long) @ stdcall leave_apartment(ptr) @ stdcall apartment_get_inproc_class_object(ptr ptr ptr ptr long ptr) -@ stdcall apartment_freeunusedlibraries(ptr long) @ stdcall apartment_get_mta() @ stdcall apartment_decrement_mta_usage(ptr) @ stdcall apartment_increment_mta_usage(ptr) diff --git a/dlls/combase/combase_private.h b/dlls/combase/combase_private.h index 16d926d13b4..7fe548af593 100644 --- a/dlls/combase/combase_private.h +++ b/dlls/combase/combase_private.h @@ -98,6 +98,7 @@ static inline struct apartment* com_get_current_apt(void)
HWND WINAPI apartment_getwindow(const struct apartment *apt) DECLSPEC_HIDDEN; HRESULT WINAPI apartment_createwindowifneeded(struct apartment *apt) DECLSPEC_HIDDEN; +void apartment_freeunusedlibraries(struct apartment *apt, DWORD unload_delay) DECLSPEC_HIDDEN;
/* RpcSs interface */ HRESULT rpcss_get_next_seqid(DWORD *id) DECLSPEC_HIDDEN; diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index 8451953baaf..55d06f197f7 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -1449,35 +1449,6 @@ void WINAPI CoFreeAllLibraries(void) /* NOP */ }
-/*********************************************************************** - * CoFreeUnusedLibrariesEx [OLE32.@] - * - * Frees any previously unused libraries whose delay has expired and marks - * currently unused libraries for unloading. Unused are identified as those that - * return S_OK from their DllCanUnloadNow function. - * - * PARAMS - * dwUnloadDelay [I] Unload delay in milliseconds. - * dwReserved [I] Reserved. Set to 0. - * - * RETURNS - * Nothing. - * - * SEE ALSO - * CoLoadLibrary, CoFreeAllLibraries, CoFreeLibrary - */ -void WINAPI DECLSPEC_HOTPATCH CoFreeUnusedLibrariesEx(DWORD dwUnloadDelay, DWORD dwReserved) -{ - struct apartment *apt = COM_CurrentApt(); - if (!apt) - { - ERR("apartment not initialised\n"); - return; - } - - apartment_freeunusedlibraries(apt, dwUnloadDelay); -} - /****************************************************************************** * CoLockObjectExternal [OLE32.@] * diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h index 34fe1e7a381..29e4cac3623 100644 --- a/dlls/ole32/compobj_private.h +++ b/dlls/ole32/compobj_private.h @@ -267,7 +267,6 @@ extern void WINAPI apartment_decrement_mta_usage(CO_MTA_USAGE_COOKIE cookie) DEC extern HRESULT WINAPI apartment_increment_mta_usage(CO_MTA_USAGE_COOKIE *cookie) DECLSPEC_HIDDEN; extern struct apartment * WINAPI apartment_get_mta(void) DECLSPEC_HIDDEN; extern HRESULT WINAPI apartment_get_local_server_stream(struct apartment *apt, IStream **ret) DECLSPEC_HIDDEN; -extern void WINAPI apartment_freeunusedlibraries(struct apartment *apt, DWORD delay) DECLSPEC_HIDDEN; extern void WINAPI apartment_global_cleanup(void) DECLSPEC_HIDDEN;
HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid, diff --git a/dlls/ole32/ole32.spec b/dlls/ole32/ole32.spec index 4a2e6b531ab..4908729d1f0 100644 --- a/dlls/ole32/ole32.spec +++ b/dlls/ole32/ole32.spec @@ -24,7 +24,7 @@ @ stdcall CoFreeAllLibraries() @ stdcall CoFreeLibrary(long) @ stdcall CoFreeUnusedLibraries() combase.CoFreeUnusedLibraries -@ stdcall CoFreeUnusedLibrariesEx(long long) +@ stdcall CoFreeUnusedLibrariesEx(long long) combase.CoFreeUnusedLibrariesEx @ stdcall CoGetActivationState(int128 long ptr) combase.CoGetActivationState @ stdcall CoGetApartmentType(ptr ptr) @ stdcall CoGetCallContext(ptr ptr) combase.CoGetCallContext
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=77584
Your paranoid android.
=== debiant (build log) ===
Task: Patch failed to apply
=== debiant (build log) ===
Task: Patch failed to apply
Signed-off-by: Huw Davies huw@codeweavers.com
Hi,
While running your changed tests, I think I found new failures. Being a bot and all I'm not very good at pattern recognition, so I might be wrong, but could you please double-check?
Full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=77579
Your paranoid android.
=== debiant (32 bit Chinese:China report) ===
ole32: clipboard.c:1343: Test failed: got 800401d0 clipboard.c:1344: Test failed: got 0 clipboard.c:1349: Test failed: got 800401d0 clipboard.c:1354: Test failed: got 800401d0 clipboard.c:1355: Test failed: got 0 clipboard.c:1362: Test failed: got 800401d0 clipboard.c:1363: Test failed: got 0 clipboard.c:1368: Test failed: got 800401d0 clipboard.c:1373: Test failed: got 800401d0 clipboard.c:1374: Test failed: got 0 clipboard.c:1379: Test failed: got 800401d0 clipboard.c:1380: Test failed: got 0