From 85037eb74503634e8c16f489f70faa926f7c32a6 Mon Sep 17 00:00:00 2001 From: Amine Khaldi Date: Mon, 4 Jun 2018 03:45:35 +0100 Subject: [PATCH] [OLE32] Sync with Wine Staging 3.9. CORE-14656 --- dll/win32/ole32/compobj.c | 167 ++++++++++++---------- dll/win32/ole32/compobj_private.h | 6 +- dll/win32/ole32/datacache.c | 225 ++++++++++++++++++++---------- dll/win32/ole32/marshal.c | 37 +++-- dll/win32/ole32/rpc.c | 14 +- dll/win32/ole32/stubmanager.c | 64 +++++---- dll/win32/ole32/usrmarshal.c | 6 +- media/doc/README.WINE | 2 +- 8 files changed, 326 insertions(+), 195 deletions(-) diff --git a/dll/win32/ole32/compobj.c b/dll/win32/ole32/compobj.c index 4cb8f4be646..2f4a69aa73a 100644 --- a/dll/win32/ole32/compobj.c +++ b/dll/win32/ole32/compobj.c @@ -723,6 +723,36 @@ static inline BOOL apartment_is_model(const 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 APARTMENT *apartment_find_mta(void) +{ + 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. */ +APARTMENT *apartment_get_current_or_mta(void) +{ + 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); @@ -1065,8 +1095,7 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject( TRACE("(%08x)\n",dwRegister); - apt = COM_CurrentApt(); - if (!apt) + if (!(apt = apartment_get_current_or_mta())) { ERR("COM was not initialized\n"); return CO_E_NOTINITIALIZED; @@ -1097,7 +1126,7 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject( } LeaveCriticalSection( &csRegisteredClassList ); - + apartment_release(apt); return hr; } @@ -1151,9 +1180,17 @@ DWORD apartment_release(struct apartment *apt) 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); @@ -1301,31 +1338,6 @@ static APARTMENT *apartment_findmain(void) return result; } -/* 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_multi_threaded(void) -{ - APARTMENT *result = NULL; - struct list *cursor; - - EnterCriticalSection(&csApartment); - - LIST_FOR_EACH( cursor, &apts ) - { - struct apartment *apt = LIST_ENTRY( cursor, struct apartment, entry ); - if (apt->multi_threaded) - { - result = apt; - apartment_addref(result); - break; - } - } - - 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, @@ -1345,7 +1357,7 @@ static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath, hr = DllGetClassObject(rclsid, riid, ppv); if (hr != S_OK) - ERR("DllGetClassObject returned error 0x%08x\n", hr); + ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr, debugstr_w(dllpath)); return hr; } @@ -1394,7 +1406,7 @@ static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath, hr = apartment_loaded_dll->dll->DllGetClassObject(rclsid, riid, ppv); if (hr != S_OK) - ERR("DllGetClassObject returned error 0x%08x\n", hr); + ERR("DllGetClassObject returned error 0x%08x for dll %s\n", hr, debugstr_w(dllpath)); } return hr; @@ -2065,9 +2077,11 @@ HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved ) return hr; } - apt = COM_CurrentApt(); - if (!apt) + if (!(apt = apartment_get_current_or_mta())) + { + ERR("apartment not initialised\n"); return CO_E_NOTINITIALIZED; + } manager = get_stub_manager_from_object(apt, lpUnk, FALSE); if (manager) { @@ -2082,6 +2096,7 @@ HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved ) * not found, making apps think that the object was disconnected, when * it actually wasn't */ + apartment_release(apt); return S_OK; } @@ -2589,7 +2604,7 @@ HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid) static const WCHAR wszInterface[] = {'I','n','t','e','r','f','a','c','e','\\',0}; static const WCHAR wszPSC[] = {'\\','P','r','o','x','y','S','t','u','b','C','l','s','i','d','3','2',0}; WCHAR path[ARRAYSIZE(wszInterface) - 1 + CHARS_IN_GUID - 1 + ARRAYSIZE(wszPSC)]; - APARTMENT *apt = COM_CurrentApt(); + APARTMENT *apt; struct registered_psclsid *registered_psclsid; ACTCTX_SECTION_KEYED_DATA data; HRESULT hr; @@ -2598,11 +2613,12 @@ HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid) TRACE("() riid=%s, pclsid=%p\n", debugstr_guid(riid), pclsid); - if (!apt) + if (!(apt = apartment_get_current_or_mta())) { ERR("apartment not initialised\n"); return CO_E_NOTINITIALIZED; } + apartment_release(apt); if (!pclsid) return E_INVALIDARG; @@ -2673,16 +2689,17 @@ HRESULT WINAPI CoGetPSClsid(REFIID riid, CLSID *pclsid) */ HRESULT WINAPI CoRegisterPSClsid(REFIID riid, REFCLSID rclsid) { - APARTMENT *apt = COM_CurrentApt(); + APARTMENT *apt; struct registered_psclsid *registered_psclsid; TRACE("(%s, %s)\n", debugstr_guid(riid), debugstr_guid(rclsid)); - if (!apt) + if (!(apt = apartment_get_current_or_mta())) { ERR("apartment not initialised\n"); return CO_E_NOTINITIALIZED; } + apartment_release(apt); EnterCriticalSection(&cs_registered_psclsid_list); @@ -2808,8 +2825,7 @@ HRESULT WINAPI CoRegisterClassObject( if ( (lpdwRegister==0) || (pUnk==0) ) return E_INVALIDARG; - apt = COM_CurrentApt(); - if (!apt) + if (!(apt = apartment_get_current_or_mta())) { ERR("COM was not initialized\n"); return CO_E_NOTINITIALIZED; @@ -2832,16 +2848,21 @@ HRESULT WINAPI CoRegisterClassObject( if (dwClsContext & CLSCTX_LOCAL_SERVER) hr = CoLockObjectExternal(foundObject, TRUE, FALSE); IUnknown_Release(foundObject); + apartment_release(apt); return hr; } IUnknown_Release(foundObject); ERR("object already registered for class %s\n", debugstr_guid(rclsid)); + apartment_release(apt); return CO_E_OBJISREG; } newClass = HeapAlloc(GetProcessHeap(), 0, sizeof(RegisteredClass)); if ( newClass == NULL ) + { + apartment_release(apt); return E_OUTOFMEMORY; + } newClass->classIdentifier = *rclsid; newClass->apartment_id = apt->oxid; @@ -2870,7 +2891,10 @@ HRESULT WINAPI CoRegisterClassObject( hr = get_local_server_stream(apt, &marshal_stream); if(FAILED(hr)) + { + apartment_release(apt); return hr; + } hr = RPC_StartLocalServer(&newClass->classIdentifier, marshal_stream, @@ -2878,6 +2902,7 @@ HRESULT WINAPI CoRegisterClassObject( &newClass->RpcRegistration); IStream_Release(marshal_stream); } + apartment_release(apt); return S_OK; } @@ -2995,7 +3020,6 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject( IUnknown *regClassObject; HRESULT hres = E_UNEXPECTED; APARTMENT *apt; - BOOL release_apt = FALSE; TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid)); @@ -3004,14 +3028,10 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject( *ppv = NULL; - if (!(apt = COM_CurrentApt())) + if (!(apt = apartment_get_current_or_mta())) { - if (!(apt = apartment_find_multi_threaded())) - { - ERR("apartment not initialised\n"); - return CO_E_NOTINITIALIZED; - } - release_apt = TRUE; + ERR("apartment not initialised\n"); + return CO_E_NOTINITIALIZED; } if (pServerInfo) { @@ -3023,7 +3043,7 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject( { if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler)) { - if (release_apt) apartment_release(apt); + apartment_release(apt); return FTMarshalCF_Create(iid, ppv); } if (IsEqualCLSID(rclsid, &CLSID_GlobalOptions)) @@ -3049,7 +3069,7 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject( hres = get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv); ReleaseActCtx(data.hActCtx); - if (release_apt) apartment_release(apt); + apartment_release(apt); return hres; } } @@ -3070,7 +3090,7 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject( * is good since we are not returning it in the "out" parameter. */ IUnknown_Release(regClassObject); - if (release_apt) apartment_release(apt); + apartment_release(apt); return hres; } @@ -3105,7 +3125,7 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject( * other types */ if (SUCCEEDED(hres)) { - if (release_apt) apartment_release(apt); + apartment_release(apt); return hres; } } @@ -3141,11 +3161,11 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject( * other types */ if (SUCCEEDED(hres)) { - if (release_apt) apartment_release(apt); + apartment_release(apt); return hres; } } - if (release_apt) apartment_release(apt); + apartment_release(apt); /* Next try out of process */ if (CLSCTX_LOCAL_SERVER & dwClsContext) @@ -3304,15 +3324,12 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx( if(FAILED(hres)) clsid = *rclsid; - if (!(apt = COM_CurrentApt())) + if (!(apt = apartment_get_current_or_mta())) { - if (!(apt = apartment_find_multi_threaded())) - { - ERR("apartment not initialised\n"); - return CO_E_NOTINITIALIZED; - } - apartment_release(apt); + ERR("apartment not initialised\n"); + return CO_E_NOTINITIALIZED; } + apartment_release(apt); /* * The Standard Global Interface Table (GIT) object is a process-wide singleton. @@ -3646,8 +3663,11 @@ HRESULT WINAPI CoLockObjectExternal( TRACE("pUnk=%p, fLock=%s, fLastUnlockReleases=%s\n", pUnk, fLock ? "TRUE" : "FALSE", fLastUnlockReleases ? "TRUE" : "FALSE"); - apt = COM_CurrentApt(); - if (!apt) return CO_E_NOTINITIALIZED; + if (!(apt = apartment_get_current_or_mta())) + { + ERR("apartment not initialised\n"); + return CO_E_NOTINITIALIZED; + } stubmgr = get_stub_manager_from_object(apt, pUnk, fLock); if (!stubmgr) @@ -3656,6 +3676,7 @@ HRESULT WINAPI CoLockObjectExternal( /* Note: native is pretty broken here because it just silently * fails, without returning an appropriate error code, making apps * think that the object was disconnected, when it actually wasn't */ + apartment_release(apt); return S_OK; } @@ -3665,6 +3686,7 @@ HRESULT WINAPI CoLockObjectExternal( stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases); stub_manager_int_release(stubmgr); + apartment_release(apt); return S_OK; } @@ -5004,22 +5026,19 @@ HRESULT WINAPI CoGetObjectContext(REFIID riid, void **ppv) HRESULT WINAPI CoGetContextToken( ULONG_PTR *token ) { struct oletls *info = COM_CurrentInfo(); + APARTMENT *apt; TRACE("(%p)\n", token); if (!info) return E_OUTOFMEMORY; - if (!info->apt) + if (!(apt = apartment_get_current_or_mta())) { - APARTMENT *apt; - if (!(apt = apartment_find_multi_threaded())) - { - ERR("apartment not initialised\n"); - return CO_E_NOTINITIALIZED; - } - apartment_release(apt); + ERR("apartment not initialised\n"); + return CO_E_NOTINITIALIZED; } + apartment_release(apt); if (!token) return E_POINTER; @@ -5095,8 +5114,9 @@ HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier) { struct oletls *info = COM_CurrentInfo(); + APARTMENT *apt; - FIXME("(%p, %p): semi-stub\n", type, qualifier); + TRACE("(%p, %p)\n", type, qualifier); if (!type || !qualifier) return E_INVALIDARG; @@ -5115,6 +5135,13 @@ HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier) *qualifier = APTTYPEQUALIFIER_NONE; + if (!info->apt && (apt = apartment_find_mta())) + { + apartment_release(apt); + *type = APTTYPE_MTA; + *qualifier = APTTYPEQUALIFIER_IMPLICIT_MTA; + } + return info->apt ? S_OK : CO_E_NOTINITIALIZED; } diff --git a/dll/win32/ole32/compobj_private.h b/dll/win32/ole32/compobj_private.h index 9e65c3ec0cd..212d3283171 100644 --- a/dll/win32/ole32/compobj_private.h +++ b/dll/win32/ole32/compobj_private.h @@ -142,6 +142,7 @@ struct apartment 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) */ + BOOL being_destroyed; /* is currently being destroyed */ /* FIXME: OIDs should be given out by RPCSS */ OID oidc; /* object ID counter, starts at 1, zero is invalid OID (CS cs) */ @@ -199,7 +200,7 @@ void stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs, const 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, IRpcChannelBuffer **chan, IID *iid, IUnknown **iface) DECLSPEC_HIDDEN; -HRESULT start_apartment_remote_unknown(void) DECLSPEC_HIDDEN; +HRESULT start_apartment_remote_unknown(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; @@ -211,7 +212,7 @@ void RPC_StartRemoting(struct apartment *apt) DECLSPEC_HIDDEN; HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, const OXID_INFO *oxid_info, DWORD dest_context, void *dest_context_data, - IRpcChannelBuffer **chan) DECLSPEC_HIDDEN; + IRpcChannelBuffer **chan, 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; @@ -247,6 +248,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; /* DCOM messages used by the apartment window (not compatible with native) */ #define DM_EXECUTERPC (WM_USER + 0) /* WPARAM = 0, LPARAM = (struct dispatch_params *) */ diff --git a/dll/win32/ole32/datacache.c b/dll/win32/ole32/datacache.c index 325a98b33bc..b72b8ff2efe 100644 --- a/dll/win32/ole32/datacache.c +++ b/dll/win32/ole32/datacache.c @@ -547,6 +547,41 @@ static HRESULT open_pres_stream( IStorage *stg, int stream_number, IStream **stm return IStorage_OpenStream( stg, name, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, stm ); } +static HRESULT synthesize_emf( HMETAFILEPICT data, STGMEDIUM *med ) +{ + METAFILEPICT *pict; + HRESULT hr = E_FAIL; + UINT size; + void *bits; + + if (!(pict = GlobalLock( data ))) return hr; + + size = GetMetaFileBitsEx( pict->hMF, 0, NULL ); + if ((bits = HeapAlloc( GetProcessHeap(), 0, size ))) + { + GetMetaFileBitsEx( pict->hMF, size, bits ); + med->u.hEnhMetaFile = SetWinMetaFileBits( size, bits, NULL, pict ); + HeapFree( GetProcessHeap(), 0, bits ); + med->tymed = TYMED_ENHMF; + med->pUnkForRelease = NULL; + hr = S_OK; + } + + GlobalUnlock( data ); + return hr; +} +#include +struct meta_placeable +{ + DWORD key; + WORD hwmf; + WORD bounding_box[4]; + WORD inch; + DWORD reserved; + WORD checksum; +}; +#include + static HRESULT load_mf_pict( DataCacheEntry *cache_entry, IStream *stm ) { HRESULT hr; @@ -559,25 +594,26 @@ static HRESULT load_mf_pict( DataCacheEntry *cache_entry, IStream *stm ) CLIPFORMAT clipformat; static const LARGE_INTEGER offset_zero; ULONG read; - - if (cache_entry->load_stream_num == STREAM_NUMBER_CONTENTS) - { - FIXME( "Unimplemented for CONTENTS stream\n" ); - return E_FAIL; - } + struct meta_placeable mf_place; hr = IStream_Stat( stm, &stat, STATFLAG_NONAME ); if (FAILED( hr )) return hr; - hr = read_clipformat( stm, &clipformat ); - if (FAILED( hr )) return hr; - - hr = IStream_Read( stm, &header, sizeof(header), &read ); - if (hr != S_OK || read != sizeof(header)) return E_FAIL; + if (cache_entry->load_stream_num != STREAM_NUMBER_CONTENTS) + { + hr = read_clipformat( stm, &clipformat ); + if (hr != S_OK) return hr; + hr = IStream_Read( stm, &header, sizeof(header), &read ); + if (hr != S_OK) return hr; + } + else + { + hr = IStream_Read( stm, &mf_place, sizeof(mf_place), &read ); + if (hr != S_OK) return hr; + } hr = IStream_Seek( stm, offset_zero, STREAM_SEEK_CUR, ¤t_pos ); if (FAILED( hr )) return hr; - stat.cbSize.QuadPart -= current_pos.QuadPart; hmfpict = GlobalAlloc( GMEM_MOVEABLE, sizeof(METAFILEPICT) ); @@ -592,14 +628,23 @@ static HRESULT load_mf_pict( DataCacheEntry *cache_entry, IStream *stm ) } hr = IStream_Read( stm, bits, stat.cbSize.u.LowPart, &read ); - if (hr != S_OK || read != stat.cbSize.u.LowPart) hr = E_FAIL; if (SUCCEEDED( hr )) { - /* FIXME: get this from the stream */ mfpict->mm = MM_ANISOTROPIC; - mfpict->xExt = header.dwObjectExtentX; - mfpict->yExt = header.dwObjectExtentY; + /* FIXME: get this from the stream */ + if (cache_entry->load_stream_num != STREAM_NUMBER_CONTENTS) + { + mfpict->xExt = header.dwObjectExtentX; + mfpict->yExt = header.dwObjectExtentY; + } + else + { + mfpict->xExt = ((mf_place.bounding_box[2] - mf_place.bounding_box[0]) + * 2540) / mf_place.inch; + mfpict->yExt = ((mf_place.bounding_box[3] - mf_place.bounding_box[1]) + * 2540) / mf_place.inch; + } mfpict->hMF = SetMetaFileBitsEx( stat.cbSize.u.LowPart, bits ); if (!mfpict->hMF) hr = E_FAIL; @@ -623,48 +668,61 @@ static HRESULT load_dib( DataCacheEntry *cache_entry, IStream *stm ) { HRESULT hr; STATSTG stat; - void *dib; + BYTE *dib; HGLOBAL hglobal; ULONG read, info_size, bi_size; BITMAPFILEHEADER file; BITMAPINFOHEADER *info; + CLIPFORMAT cf; + PresentationDataHeader pres; + ULARGE_INTEGER current_pos; + static const LARGE_INTEGER offset_zero; + + hr = IStream_Stat( stm, &stat, STATFLAG_NONAME ); + if (FAILED( hr )) return hr; if (cache_entry->load_stream_num != STREAM_NUMBER_CONTENTS) { - FIXME( "Unimplemented for presentation stream\n" ); - return E_FAIL; + hr = read_clipformat( stm, &cf ); + if (hr != S_OK) return hr; + hr = IStream_Read( stm, &pres, sizeof(pres), &read ); + if (hr != S_OK) return hr; + } + else + { + hr = IStream_Read( stm, &file, sizeof(BITMAPFILEHEADER), &read ); + if (hr != S_OK) return hr; } - hr = IStream_Stat( stm, &stat, STATFLAG_NONAME ); + hr = IStream_Seek( stm, offset_zero, STREAM_SEEK_CUR, ¤t_pos ); if (FAILED( hr )) return hr; - - if (stat.cbSize.QuadPart < sizeof(file) + sizeof(DWORD)) return E_FAIL; - hr = IStream_Read( stm, &file, sizeof(file), &read ); - if (hr != S_OK || read != sizeof(file)) return E_FAIL; - stat.cbSize.QuadPart -= sizeof(file); + stat.cbSize.QuadPart -= current_pos.QuadPart; hglobal = GlobalAlloc( GMEM_MOVEABLE, stat.cbSize.u.LowPart ); if (!hglobal) return E_OUTOFMEMORY; dib = GlobalLock( hglobal ); + /* read first DWORD of BITMAPINFOHEADER */ hr = IStream_Read( stm, dib, sizeof(DWORD), &read ); - if (hr != S_OK || read != sizeof(DWORD)) goto fail; + if (hr != S_OK) goto fail; bi_size = *(DWORD *)dib; if (stat.cbSize.QuadPart < bi_size) goto fail; - hr = IStream_Read( stm, (char *)dib + sizeof(DWORD), bi_size - sizeof(DWORD), &read ); - if (hr != S_OK || read != bi_size - sizeof(DWORD)) goto fail; + /* read rest of BITMAPINFOHEADER */ + hr = IStream_Read( stm, dib + sizeof(DWORD), bi_size - sizeof(DWORD), &read ); + if (hr != S_OK) goto fail; - info_size = bitmap_info_size( dib, DIB_RGB_COLORS ); + info_size = bitmap_info_size( (BITMAPINFO *)dib, DIB_RGB_COLORS ); if (stat.cbSize.QuadPart < info_size) goto fail; if (info_size > bi_size) { - hr = IStream_Read( stm, (char *)dib + bi_size, info_size - bi_size, &read ); - if (hr != S_OK || read != info_size - bi_size) goto fail; + hr = IStream_Read( stm, dib + bi_size, info_size - bi_size, &read ); + if (hr != S_OK) goto fail; } stat.cbSize.QuadPart -= info_size; - if (file.bfOffBits) + /* set Stream pointer to beginning of bitmap bits */ + if (cache_entry->load_stream_num == STREAM_NUMBER_CONTENTS && file.bfOffBits) { LARGE_INTEGER skip; @@ -675,8 +733,8 @@ static HRESULT load_dib( DataCacheEntry *cache_entry, IStream *stm ) stat.cbSize.QuadPart -= skip.QuadPart; } - hr = IStream_Read( stm, (char *)dib + info_size, stat.cbSize.u.LowPart, &read ); - if (hr != S_OK || read != stat.cbSize.QuadPart) goto fail; + hr = IStream_Read( stm, dib + info_size, stat.cbSize.u.LowPart, &read ); + if (hr != S_OK) goto fail; if (bi_size >= sizeof(*info)) { @@ -695,15 +753,69 @@ static HRESULT load_dib( DataCacheEntry *cache_entry, IStream *stm ) cache_entry->stgmedium.tymed = TYMED_HGLOBAL; cache_entry->stgmedium.u.hGlobal = hglobal; - return S_OK; + return hr; fail: GlobalUnlock( hglobal ); GlobalFree( hglobal ); - return E_FAIL; + return hr; } +static HRESULT load_emf( DataCacheEntry *cache_entry, IStream *stm ) +{ + HRESULT hr; + + if (cache_entry->load_stream_num != STREAM_NUMBER_CONTENTS) + { + STGMEDIUM stgmed; + + hr = load_mf_pict( cache_entry, stm ); + if (SUCCEEDED( hr )) + { + hr = synthesize_emf( cache_entry->stgmedium.u.hMetaFilePict, &stgmed ); + ReleaseStgMedium( &cache_entry->stgmedium ); + } + if (SUCCEEDED( hr )) + cache_entry->stgmedium = stgmed; + } + else + { + STATSTG stat; + BYTE *data; + ULONG read, size_bits; + + hr = IStream_Stat( stm, &stat, STATFLAG_NONAME ); + + if (SUCCEEDED( hr )) + { + data = HeapAlloc( GetProcessHeap(), 0, stat.cbSize.u.LowPart ); + if (!data) return E_OUTOFMEMORY; + + hr = IStream_Read( stm, data, stat.cbSize.u.LowPart, &read ); + if (hr != S_OK) + { + HeapFree( GetProcessHeap(), 0, data ); + return hr; + } + + if (read <= sizeof(DWORD) + sizeof(ENHMETAHEADER)) + { + HeapFree( GetProcessHeap(), 0, data ); + return E_FAIL; + } + size_bits = read - sizeof(DWORD) - sizeof(ENHMETAHEADER); + cache_entry->stgmedium.u.hEnhMetaFile = SetEnhMetaFileBits( size_bits, data + (read - size_bits) ); + cache_entry->stgmedium.tymed = TYMED_ENHMF; + cache_entry->stgmedium.pUnkForRelease = NULL; + + HeapFree( GetProcessHeap(), 0, data ); + } + } + + return hr; +} + /************************************************************************ * DataCacheEntry_LoadData * @@ -736,6 +848,10 @@ static HRESULT DataCacheEntry_LoadData(DataCacheEntry *cache_entry, IStorage *st hr = load_dib( cache_entry, stm ); break; + case CF_ENHMETAFILE: + hr = load_emf( cache_entry, stm ); + break; + default: FIXME( "Unimplemented clip format %x\n", cache_entry->fmtetc.cfFormat ); hr = E_NOTIMPL; @@ -817,18 +933,6 @@ end: return hr; } -#include -struct meta_placeable -{ - DWORD key; - WORD hwmf; - WORD bounding_box[4]; - WORD inch; - DWORD reserved; - WORD checksum; -}; -#include - static HRESULT save_mfpict(DataCacheEntry *entry, BOOL contents, IStream *stream) { HRESULT hr = S_OK; @@ -1118,30 +1222,6 @@ static HRESULT synthesize_bitmap( HGLOBAL dib, STGMEDIUM *med ) return hr; } -static HRESULT synthesize_emf( HMETAFILEPICT data, STGMEDIUM *med ) -{ - METAFILEPICT *pict; - HRESULT hr = E_FAIL; - UINT size; - void *bits; - - if (!(pict = GlobalLock( data ))) return hr; - - size = GetMetaFileBitsEx( pict->hMF, 0, NULL ); - if ((bits = HeapAlloc( GetProcessHeap(), 0, size ))) - { - GetMetaFileBitsEx( pict->hMF, size, bits ); - med->u.hEnhMetaFile = SetWinMetaFileBits( size, bits, NULL, pict ); - HeapFree( GetProcessHeap(), 0, bits ); - med->tymed = TYMED_ENHMF; - med->pUnkForRelease = NULL; - hr = S_OK; - } - - GlobalUnlock( data ); - return hr; -} - static HRESULT DataCacheEntry_SetData(DataCacheEntry *cache_entry, const FORMATETC *formatetc, STGMEDIUM *stgmedium, @@ -1763,6 +1843,7 @@ static HRESULT WINAPI DataCache_Load( IPersistStorage *iface, IStorage *stg ) LIST_FOR_EACH_ENTRY_SAFE( entry, cursor2, &This->cache_list, DataCacheEntry, entry ) DataCacheEntry_Destroy( This, entry ); + This->clsid = CLSID_NULL; ReadClassStg( stg, &clsid ); hr = create_automatic_entry( This, &clsid ); diff --git a/dll/win32/ole32/marshal.c b/dll/win32/ole32/marshal.c index b39dac0a27b..7c0f5413591 100644 --- a/dll/win32/ole32/marshal.c +++ b/dll/win32/ole32/marshal.c @@ -313,13 +313,15 @@ static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, UL * the interfaces were returned */ if (SUCCEEDED(hr)) { + APARTMENT *apt = apartment_get_current_or_mta(); + /* try to unmarshal each object returned to us */ for (i = 0; i < nonlocal_mqis; i++) { ULONG index = mapping[i]; HRESULT hrobj = qiresults[i].hResult; if (hrobj == S_OK) - hrobj = unmarshal_object(&qiresults[i].std, COM_CurrentApt(), + hrobj = unmarshal_object(&qiresults[i].std, apt, This->dest_context, This->dest_context_data, pMQIs[index].pIID, &This->oxid_info, @@ -331,6 +333,8 @@ static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, UL ERR("Failed to get pointer to interface %s\n", debugstr_guid(pMQIs[index].pIID)); pMQIs[index].hr = hrobj; } + + apartment_release(apt); } /* free the memory allocated by the proxy */ @@ -1010,8 +1014,7 @@ static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnk if (This->sorflags & SORFP_NOLIFETIMEMGMT) return S_FALSE; - apt = COM_CurrentApt(); - if (!apt) + if (!(apt = apartment_get_current_or_mta())) return CO_E_NOTINITIALIZED; called_in_original_apt = This->parent && (This->parent->oxid == apt->oxid); @@ -1046,7 +1049,7 @@ static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnk stdobjref.ipid = This->oxid_info.ipidRemUnknown; /* do the unmarshal */ - hr = unmarshal_object(&stdobjref, COM_CurrentApt(), This->dest_context, + hr = unmarshal_object(&stdobjref, apt, This->dest_context, This->dest_context_data, &IID_IRemUnknown, &This->oxid_info, (void**)remunk); if (hr == S_OK && called_in_original_apt) @@ -1056,6 +1059,7 @@ static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnk } } LeaveCriticalSection(&This->cs); + apartment_release(apt); TRACE("got IRemUnknown* pointer %p, hr = 0x%08x\n", *remunk, hr); @@ -1221,11 +1225,11 @@ StdMarshalImpl_MarshalInterface( STDOBJREF stdobjref; ULONG res; HRESULT hres; - APARTMENT *apt = COM_CurrentApt(); + APARTMENT *apt; TRACE("(...,%s,...)\n", debugstr_guid(riid)); - if (!apt) + if (!(apt = apartment_get_current_or_mta())) { ERR("Apartment not initialized\n"); return CO_E_NOTINITIALIZED; @@ -1235,6 +1239,7 @@ StdMarshalImpl_MarshalInterface( RPC_StartRemoting(apt); hres = marshal_object(apt, &stdobjref, riid, pv, dest_context, dest_context_data, mshlflags); + apartment_release(apt); if (hres != S_OK) { ERR("Failed to create ifstub, hres=0x%x\n", hres); @@ -1288,7 +1293,7 @@ static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, &proxy_manager->oxid_info, proxy_manager->dest_context, proxy_manager->dest_context_data, - &chanbuf); + &chanbuf, apt); if (hr == S_OK) hr = proxy_manager_create_ifproxy(proxy_manager, stdobjref, riid, chanbuf, &ifproxy); @@ -1324,14 +1329,14 @@ StdMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid, v STDOBJREF stdobjref; ULONG res; HRESULT hres; - APARTMENT *apt = COM_CurrentApt(); + APARTMENT *apt; APARTMENT *stub_apt; OXID oxid; TRACE("(...,%s,....)\n", debugstr_guid(riid)); /* we need an apartment to unmarshal into */ - if (!apt) + if (!(apt = apartment_get_current_or_mta())) { ERR("Apartment not initialized\n"); return CO_E_NOTINITIALIZED; @@ -1339,10 +1344,18 @@ StdMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid, v /* read STDOBJREF from wire */ hres = IStream_Read(pStm, &stdobjref, sizeof(stdobjref), &res); - if (hres != S_OK) return STG_E_READFAULT; + if (hres != S_OK) + { + apartment_release(apt); + return STG_E_READFAULT; + } hres = apartment_getoxid(apt, &oxid); - if (hres != S_OK) return hres; + if (hres != S_OK) + { + apartment_release(apt); + return hres; + } /* check if we're marshalling back to ourselves */ if ((oxid == stdobjref.oxid) && (stubmgr = get_stub_manager(apt, stdobjref.oid))) @@ -1357,6 +1370,7 @@ StdMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid, v stub_manager_ext_release(stubmgr, stdobjref.cPublicRefs, stdobjref.flags & SORFP_TABLEWEAK, FALSE); stub_manager_int_release(stubmgr); + apartment_release(apt); return hres; } @@ -1395,6 +1409,7 @@ StdMarshalImpl_UnmarshalInterface(IMarshal *iface, IStream *pStm, REFIID riid, v if (hres != S_OK) WARN("Failed with error 0x%08x\n", hres); else TRACE("Successfully created proxy %p\n", *ppv); + apartment_release(apt); return hres; } diff --git a/dll/win32/ole32/rpc.c b/dll/win32/ole32/rpc.c index 8d8276e0cbe..a73d23ce683 100644 --- a/dll/win32/ole32/rpc.c +++ b/dll/win32/ole32/rpc.c @@ -830,14 +830,16 @@ 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(); TRACE("(%p) iMethod=%d\n", olemsg, olemsg->iMethod); - hr = ClientRpcChannelBuffer_IsCorrectApartment(This, COM_CurrentApt()); + hr = ClientRpcChannelBuffer_IsCorrectApartment(This, apt); if (hr != S_OK) { ERR("called from wrong apartment, should have been 0x%s\n", wine_dbgstr_longlong(This->oxid)); + if (apt) apartment_release(apt); return RPC_E_WRONG_THREAD; } /* This situation should be impossible in multi-threaded apartments, @@ -845,11 +847,12 @@ static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER ifac * Note: doing a COM call during the processing of a sent message is * only disallowed if a client call is already being waited for * completion */ - if (!COM_CurrentApt()->multi_threaded && + if (!apt->multi_threaded && COM_CurrentInfo()->pending_call_count_client && InSendMessage()) { ERR("can't make an outgoing COM call in response to a sent message\n"); + apartment_release(apt); return RPC_E_CANTCALLOUT_ININPUTSYNCCALL; } @@ -967,6 +970,7 @@ static HRESULT WINAPI ClientRpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER ifac TRACE("-- 0x%08x\n", hr); + apartment_release(apt); return hr; } @@ -1094,7 +1098,7 @@ static const IRpcChannelBufferVtbl ServerRpcChannelBufferVtbl = HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, const OXID_INFO *oxid_info, DWORD dest_context, void *dest_context_data, - IRpcChannelBuffer **chan) + IRpcChannelBuffer **chan, APARTMENT *apt) { ClientRpcChannelBuffer *This; WCHAR endpoint[200]; @@ -1148,7 +1152,7 @@ HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, This->super.dest_context = dest_context; This->super.dest_context_data = dest_context_data; This->bind = bind; - apartment_getoxid(COM_CurrentApt(), &This->oxid); + apartment_getoxid(apt, &This->oxid); This->server_pid = oxid_info->dwPid; This->event = NULL; @@ -1644,7 +1648,7 @@ void RPC_StartRemoting(struct apartment *apt) /* FIXME: move remote unknown exporting into this function */ } - start_apartment_remote_unknown(); + start_apartment_remote_unknown(apt); } diff --git a/dll/win32/ole32/stubmanager.c b/dll/win32/ole32/stubmanager.c index 57048c63062..5f604d42910 100644 --- a/dll/win32/ole32/stubmanager.c +++ b/dll/win32/ole32/stubmanager.c @@ -73,7 +73,8 @@ struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *s struct ifstub *stub; HRESULT hr; - TRACE("oid=%s, stubbuffer=%p, iid=%s\n", wine_dbgstr_longlong(m->oid), sb, debugstr_guid(iid)); + TRACE("oid=%s, stubbuffer=%p, iid=%s, dest_context=%x\n", wine_dbgstr_longlong(m->oid), sb, + debugstr_guid(iid), dest_context); stub = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(struct ifstub)); if (!stub) return NULL; @@ -470,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) +static struct stub_manager *get_stub_manager_from_ipid(APARTMENT *apt, const IPID *ipid, struct ifstub **ifstub) { struct stub_manager *result = NULL; struct list *cursor; @@ -480,7 +481,7 @@ static struct stub_manager *get_stub_manager_from_ipid(APARTMENT *apt, const IPI { struct stub_manager *m = LIST_ENTRY( cursor, struct stub_manager, entry ); - if (stub_manager_ipid_to_ifstub(m, ipid)) + if ((*ifstub = stub_manager_ipid_to_ifstub(m, ipid))) { result = m; stub_manager_int_addref(result); @@ -497,7 +498,8 @@ static struct stub_manager *get_stub_manager_from_ipid(APARTMENT *apt, const IPI return result; } -static HRESULT ipid_to_stub_manager(const IPID *ipid, APARTMENT **stub_apt, struct stub_manager **stubmgr_ret) +static HRESULT ipid_to_ifstub(const IPID *ipid, APARTMENT **stub_apt, + struct stub_manager **stubmgr_ret, struct ifstub **ifstub) { /* FIXME: hack for IRemUnknown */ if (ipid->Data2 == 0xffff) @@ -509,7 +511,7 @@ static HRESULT ipid_to_stub_manager(const IPID *ipid, APARTMENT **stub_apt, stru TRACE("Couldn't find apartment corresponding to TID 0x%04x\n", ipid->Data2); return RPC_E_INVALID_OBJECT; } - *stubmgr_ret = get_stub_manager_from_ipid(*stub_apt, ipid); + *stubmgr_ret = get_stub_manager_from_ipid(*stub_apt, ipid, ifstub); if (!*stubmgr_ret) { apartment_release(*stub_apt); @@ -519,6 +521,12 @@ static HRESULT ipid_to_stub_manager(const IPID *ipid, APARTMENT **stub_apt, stru return S_OK; } +static HRESULT ipid_to_stub_manager(const IPID *ipid, APARTMENT **stub_apt, struct stub_manager **stub) +{ + struct ifstub *ifstub; + return ipid_to_ifstub(ipid, stub_apt, stub, &ifstub); +} + /* 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. */ @@ -532,32 +540,22 @@ HRESULT ipid_get_dispatch_params(const IPID *ipid, APARTMENT **stub_apt, APARTMENT *apt; HRESULT hr; - hr = ipid_to_stub_manager(ipid, &apt, &stubmgr); + hr = ipid_to_ifstub(ipid, &apt, &stubmgr, &ifstub); if (hr != S_OK) return RPC_E_DISCONNECTED; - ifstub = stub_manager_ipid_to_ifstub(stubmgr, ipid); - if (ifstub) - { - *stub = ifstub->stubbuffer; - IRpcStubBuffer_AddRef(*stub); - *chan = ifstub->chan; - IRpcChannelBuffer_AddRef(*chan); - *stub_apt = apt; - *iid = ifstub->iid; - *iface = ifstub->iface; - - if (manager) - *manager = stubmgr; - else - stub_manager_int_release(stubmgr); - return S_OK; - } + *stub = ifstub->stubbuffer; + IRpcStubBuffer_AddRef(*stub); + *chan = ifstub->chan; + IRpcChannelBuffer_AddRef(*chan); + *stub_apt = apt; + *iid = ifstub->iid; + *iface = ifstub->iface; + + if (manager) + *manager = stubmgr; else - { stub_manager_int_release(stubmgr); - apartment_release(apt); - return RPC_E_DISCONNECTED; - } + return S_OK; } /* returns TRUE if it is possible to unmarshal, FALSE otherwise. */ @@ -707,18 +705,23 @@ static HRESULT WINAPI RemUnknown_RemQueryInterface(IRemUnknown *iface, USHORT successful_qis = 0; APARTMENT *apt; struct stub_manager *stubmgr; + struct ifstub *ifstub; + DWORD dest_context; + void *dest_context_data; TRACE("(%p)->(%s, %d, %d, %p, %p)\n", iface, debugstr_guid(ripid), cRefs, cIids, iids, ppQIResults); - hr = ipid_to_stub_manager(ripid, &apt, &stubmgr); + hr = ipid_to_ifstub(ripid, &apt, &stubmgr, &ifstub); if (hr != S_OK) return hr; + IRpcChannelBuffer_GetDestCtx(ifstub->chan, &dest_context, &dest_context_data); + *ppQIResults = CoTaskMemAlloc(sizeof(REMQIRESULT) * cIids); for (i = 0; i < cIids; i++) { HRESULT hrobj = marshal_object(apt, &(*ppQIResults)[i].std, &iids[i], - stubmgr->object, MSHCTX_DIFFERENTMACHINE, NULL, MSHLFLAGS_NORMAL); + stubmgr->object, dest_context, dest_context_data, MSHLFLAGS_NORMAL); if (hrobj == S_OK) successful_qis++; (*ppQIResults)[i].hResult = hrobj; @@ -812,11 +815,10 @@ static const IRemUnknownVtbl RemUnknown_Vtbl = }; /* starts the IRemUnknown listener for the current apartment */ -HRESULT start_apartment_remote_unknown(void) +HRESULT start_apartment_remote_unknown(APARTMENT *apt) { IRemUnknown *pRemUnknown; HRESULT hr = S_OK; - APARTMENT *apt = COM_CurrentApt(); EnterCriticalSection(&apt->cs); if (!apt->remunk_exported) diff --git a/dll/win32/ole32/usrmarshal.c b/dll/win32/ole32/usrmarshal.c index 63eead1b840..8d36e134412 100644 --- a/dll/win32/ole32/usrmarshal.c +++ b/dll/win32/ole32/usrmarshal.c @@ -387,7 +387,7 @@ ULONG __RPC_USER HGLOBAL_UserSize(ULONG *pFlags, ULONG StartingSize, HGLOBAL *ph size += sizeof(ULONG); - if (LOWORD(*pFlags == MSHCTX_INPROC)) + if (LOWORD(*pFlags) == MSHCTX_INPROC) size += sizeof(HGLOBAL); else { @@ -429,7 +429,7 @@ unsigned char * __RPC_USER HGLOBAL_UserMarshal(ULONG *pFlags, unsigned char *pBu ALIGN_POINTER(pBuffer, 3); - if (LOWORD(*pFlags == MSHCTX_INPROC)) + if (LOWORD(*pFlags) == MSHCTX_INPROC) { if (sizeof(*phGlobal) == 8) *(ULONG *)pBuffer = WDT_INPROC64_CALL; @@ -572,7 +572,7 @@ void __RPC_USER HGLOBAL_UserFree(ULONG *pFlags, HGLOBAL *phGlobal) { TRACE("(%s, &%p\n", debugstr_user_flags(pFlags), *phGlobal); - if (LOWORD(*pFlags != MSHCTX_INPROC) && *phGlobal) + if (LOWORD(*pFlags) != MSHCTX_INPROC && *phGlobal) GlobalFree(*phGlobal); } diff --git a/media/doc/README.WINE b/media/doc/README.WINE index 829a9882a58..c3ec642a03d 100644 --- a/media/doc/README.WINE +++ b/media/doc/README.WINE @@ -139,7 +139,7 @@ reactos/dll/win32/ntdsapi # Synced to WineStaging-3.9 reactos/dll/win32/objsel # Synced to WineStaging-3.3 reactos/dll/win32/odbc32 # Synced to WineStaging-3.3. Depends on port of Linux ODBC. reactos/dll/win32/odbccp32 # Synced to WineStaging-3.9 -reactos/dll/win32/ole32 # Synced to WineStaging-3.3 +reactos/dll/win32/ole32 # Synced to WineStaging-3.9 reactos/dll/win32/oleacc # Synced to WineStaging-3.3 reactos/dll/win32/oleaut32 # Synced to WineStaging-3.3 reactos/dll/win32/olecli32 # Synced to WineStaging-3.3 -- 2.17.1