[PATCH 1/4] combase: Move currently unimplemented COM API functions.
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com> --- dlls/combase/combase.c | 89 +++++++++++++++++++++++++++++++ dlls/combase/combase.spec | 20 +++---- dlls/combase/rpc.c | 10 ++++ dlls/ole32/compobj.c | 108 -------------------------------------- dlls/ole32/ole2.c | 11 ---- dlls/ole32/ole32.spec | 20 +++---- 6 files changed, 119 insertions(+), 139 deletions(-) diff --git a/dlls/combase/combase.c b/dlls/combase/combase.c index d959034b57f..99352712f78 100644 --- a/dlls/combase/combase.c +++ b/dlls/combase/combase.c @@ -2595,6 +2595,16 @@ static void unlock_init_spies(struct tlsdata *tlsdata) } } +/****************************************************************************** + * CoInitializeWOW (combase.@) + */ +HRESULT WINAPI CoInitializeWOW(DWORD arg1, DWORD arg2) +{ + FIXME("%#x, %#x\n", arg1, arg2); + + return S_OK; +} + /****************************************************************************** * CoInitializeEx (combase.@) */ @@ -3062,6 +3072,85 @@ HRESULT WINAPI CoRegisterChannelHook(REFGUID guidExtension, IChannelHook *channe return rpc_register_channel_hook(guidExtension, channel_hook); } +/*********************************************************************** + * CoDisableCallCancellation (combase.@) + */ +HRESULT WINAPI CoDisableCallCancellation(void *reserved) +{ + FIXME("%p stub\n", reserved); + + return E_NOTIMPL; +} + +/*********************************************************************** + * CoEnableCallCancellation (combase.@) + */ +HRESULT WINAPI CoEnableCallCancellation(void *reserved) +{ + FIXME("%p stub\n", reserved); + + return E_NOTIMPL; +} + +/*********************************************************************** + * CoGetCallerTID (combase.@) + */ +HRESULT WINAPI CoGetCallerTID(DWORD *tid) +{ + FIXME("stub!\n"); + return E_NOTIMPL; +} + +/*********************************************************************** + * CoIsHandlerConnected (combase.@) + */ +BOOL WINAPI CoIsHandlerConnected(IUnknown *object) +{ + FIXME("%p\n", object); + + return TRUE; +} + +/*********************************************************************** + * CoSuspendClassObjects (combase.@) + */ +HRESULT WINAPI CoSuspendClassObjects(void) +{ + FIXME("\n"); + + return S_OK; +} + +/*********************************************************************** + * CoResumeClassObjects (combase.@) + */ +HRESULT WINAPI CoResumeClassObjects(void) +{ + FIXME("stub\n"); + + return S_OK; +} + +/*********************************************************************** + * CoRegisterSurrogate (combase.@) + */ +HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate) +{ + FIXME("%p stub\n", surrogate); + + return E_NOTIMPL; +} + +/*********************************************************************** + * CoRegisterSurrogateEx (combase.@) + */ +HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved) +{ + FIXME("%s, %p stub\n", debugstr_guid(guid), reserved); + + return E_NOTIMPL; +} + /*********************************************************************** * DllMain (combase.@) */ diff --git a/dlls/combase/combase.spec b/dlls/combase/combase.spec index 3a09ce064b0..50b58419bc5 100644 --- a/dlls/combase/combase.spec +++ b/dlls/combase/combase.spec @@ -87,10 +87,10 @@ @ stub CoDeactivateObject @ stub CoDecodeProxy @ stdcall CoDecrementMTAUsage(ptr) -@ stdcall CoDisableCallCancellation(ptr) ole32.CoDisableCallCancellation +@ stdcall CoDisableCallCancellation(ptr) @ stub CoDisconnectContext @ stdcall CoDisconnectObject(ptr long) -@ stdcall CoEnableCallCancellation(ptr) ole32.CoEnableCallCancellation +@ stdcall CoEnableCallCancellation(ptr) @ stdcall CoFileTimeNow(ptr) @ stdcall CoFreeUnusedLibraries() @ stdcall CoFreeUnusedLibrariesEx(long long) @@ -99,7 +99,7 @@ @ stdcall CoGetApartmentType(ptr ptr) @ stdcall CoGetCallContext(ptr ptr) @ stdcall CoGetCallState(long ptr) -@ stdcall CoGetCallerTID(ptr) ole32.CoGetCallerTID +@ stdcall CoGetCallerTID(ptr) @ stub CoGetCancelObject @ stdcall CoGetClassObject(ptr long ptr ptr ptr) @ stub CoGetClassVersion @@ -125,9 +125,9 @@ @ stdcall CoIncrementMTAUsage(ptr) @ stdcall CoInitializeEx(ptr long) @ stdcall CoInitializeSecurity(ptr long ptr ptr long long ptr long ptr) -@ stdcall CoInitializeWOW(long long) ole32.CoInitializeWOW +@ stdcall CoInitializeWOW(long long) @ stub CoInvalidateRemoteMachineBindings -@ stdcall CoIsHandlerConnected(ptr) ole32.CoIsHandlerConnected +@ stdcall CoIsHandlerConnected(ptr) @ stdcall CoLockObjectExternal(ptr long long) @ stdcall CoMarshalHresult(ptr long) @ stdcall CoMarshalInterThreadInterfaceInStream(ptr ptr ptr) @@ -145,11 +145,11 @@ @ stdcall CoRegisterMallocSpy(ptr) @ stdcall CoRegisterMessageFilter(ptr ptr) @ stdcall CoRegisterPSClsid(ptr ptr) -@ stdcall CoRegisterSurrogate(ptr) ole32.CoRegisterSurrogate -@ stdcall CoRegisterSurrogateEx(ptr ptr) ole32.CoRegisterSurrogateEx +@ stdcall CoRegisterSurrogate(ptr) +@ stdcall CoRegisterSurrogateEx(ptr ptr) @ stdcall CoReleaseMarshalData(ptr) @ stdcall CoReleaseServerProcess() -@ stdcall CoResumeClassObjects() ole32.CoResumeClassObjects +@ stdcall CoResumeClassObjects() @ stub CoRetireServer @ stdcall CoRevertToSelf() @ stdcall CoRevokeClassObject(long) @@ -158,7 +158,7 @@ @ stub CoSetCancelObject @ stdcall CoSetErrorInfo(long ptr) SetErrorInfo @ stdcall CoSetProxyBlanket(ptr long long ptr long long ptr long) -@ stdcall CoSuspendClassObjects() ole32.CoSuspendClassObjects +@ stdcall CoSuspendClassObjects() @ stdcall CoSwitchCallContext(ptr ptr) @ stdcall CoTaskMemAlloc(long) @ stdcall CoTaskMemFree(ptr) @@ -176,7 +176,7 @@ @ stdcall CreateErrorInfo(ptr) @ stdcall CreateStreamOnHGlobal(ptr long ptr) ole32.CreateStreamOnHGlobal @ stub DcomChannelSetHResult -@ stdcall DllDebugObjectRPCHook(long ptr) ole32.DllDebugObjectRPCHook +@ stdcall DllDebugObjectRPCHook(long ptr) @ stdcall DllGetActivationFactory(ptr ptr) @ stdcall -private DllGetClassObject(ptr ptr ptr) ole32.DllGetClassObject @ stub EnableHookObject diff --git a/dlls/combase/rpc.c b/dlls/combase/rpc.c index ebfc19329d8..513c1e6c13a 100644 --- a/dlls/combase/rpc.c +++ b/dlls/combase/rpc.c @@ -2244,3 +2244,13 @@ void rpc_start_remoting(struct apartment *apt) } start_apartment_remote_unknown(apt); } + +/****************************************************************************** + * DllDebugObjectRPCHook (combase.@) + */ +BOOL WINAPI DllDebugObjectRPCHook(BOOL trace, /* ORPC_INIT_ARGS * */ void *args) +{ + FIXME("%d, %p: stub\n", trace, args); + + return TRUE; +} diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index a9a9af53108..f4fe82de436 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -561,21 +561,6 @@ HRESULT COM_OpenKeyForCLSID(REFCLSID clsid, LPCWSTR keyname, REGSAM access, HKEY return S_OK; } -/*********************************************************************** - * CoResumeClassObjects (OLE32.@) - * - * Resumes all class objects registered with REGCLS_SUSPENDED. - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - */ -HRESULT WINAPI CoResumeClassObjects(void) -{ - FIXME("stub\n"); - return S_OK; -} - /*********************************************************************** * CoLoadLibrary (OLE32.@) * @@ -635,24 +620,6 @@ void WINAPI CoFreeAllLibraries(void) /* NOP */ } -/*********************************************************************** - * CoInitializeWOW (OLE32.@) - * - * WOW equivalent of CoInitialize? - * - * PARAMS - * x [I] Unknown. - * y [I] Unknown. - * - * RETURNS - * Unknown. - */ -HRESULT WINAPI CoInitializeWOW(DWORD x,DWORD y) -{ - FIXME("(0x%08x,0x%08x),stub!\n",x,y); - return 0; -} - /*********************************************************************** * CoGetState [OLE32.@] * @@ -834,41 +801,6 @@ BOOL WINAPI IsEqualGUID( return !memcmp(rguid1,rguid2,sizeof(GUID)); } -/*********************************************************************** - * CoSuspendClassObjects [OLE32.@] - * - * Suspends all registered class objects to prevent further requests coming in - * for those objects. - * - * RETURNS - * Success: S_OK. - * Failure: HRESULT code. - */ -HRESULT WINAPI CoSuspendClassObjects(void) -{ - FIXME("\n"); - return S_OK; -} - -/*********************************************************************** - * CoIsHandlerConnected [OLE32.@] - * - * Determines whether a proxy is connected to a remote stub. - * - * PARAMS - * pUnk [I] Pointer to object that may or may not be connected. - * - * RETURNS - * TRUE if pUnk is not a proxy or if pUnk is connected to a remote stub, or - * FALSE otherwise. - */ -BOOL WINAPI CoIsHandlerConnected(IUnknown *pUnk) -{ - FIXME("%p\n", pUnk); - - return TRUE; -} - /*********************************************************************** * CoAllowSetForegroundWindow [OLE32.@] * @@ -1005,46 +937,6 @@ HRESULT Handler_DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID *ppv) return CLASS_E_CLASSNOTAVAILABLE; } -/*********************************************************************** - * CoDisableCallCancellation [OLE32.@] - */ -HRESULT WINAPI CoDisableCallCancellation(void *reserved) -{ - FIXME("(%p): stub\n", reserved); - - return E_NOTIMPL; -} - -/*********************************************************************** - * CoEnableCallCancellation [OLE32.@] - */ -HRESULT WINAPI CoEnableCallCancellation(void *reserved) -{ - FIXME("(%p): stub\n", reserved); - - return E_NOTIMPL; -} - -/*********************************************************************** - * CoRegisterSurrogate [OLE32.@] - */ -HRESULT WINAPI CoRegisterSurrogate(ISurrogate *surrogate) -{ - FIXME("(%p): stub\n", surrogate); - - return E_NOTIMPL; -} - -/*********************************************************************** - * CoRegisterSurrogateEx [OLE32.@] - */ -HRESULT WINAPI CoRegisterSurrogateEx(REFGUID guid, void *reserved) -{ - FIXME("(%s %p): stub\n", debugstr_guid(guid), reserved); - - return E_NOTIMPL; -} - typedef struct { IGlobalOptions IGlobalOptions_iface; LONG ref; diff --git a/dlls/ole32/ole2.c b/dlls/ole32/ole2.c index 4f4a1378b1e..15c4f8234f3 100644 --- a/dlls/ole32/ole2.c +++ b/dlls/ole32/ole2.c @@ -2729,14 +2729,3 @@ void WINAPI PropSysFreeString(LPOLESTR str) { SysFreeString(str); } - -/****************************************************************************** - * DllDebugObjectRPCHook (OLE32.@) - * turns on and off internal debugging, pointer is only used on macintosh - */ - -BOOL WINAPI DllDebugObjectRPCHook(BOOL b, void *dummy) -{ - FIXME("stub\n"); - return TRUE; -} diff --git a/dlls/ole32/ole32.spec b/dlls/ole32/ole32.spec index cf48d043b75..44c03b6628c 100644 --- a/dlls/ole32/ole32.spec +++ b/dlls/ole32/ole32.spec @@ -15,10 +15,10 @@ @ stdcall CoCreateInstance(ptr ptr long ptr ptr) combase.CoCreateInstance @ stdcall CoCreateInstanceEx(ptr ptr long ptr long ptr) combase.CoCreateInstanceEx @ stdcall CoDecrementMTAUsage(ptr) combase.CoDecrementMTAUsage -@ stdcall CoDisableCallCancellation(ptr) +@ stdcall CoDisableCallCancellation(ptr) combase.CoDisableCallCancellation @ stdcall CoDisconnectObject(ptr long) combase.CoDisconnectObject @ stdcall CoDosDateTimeToFileTime(long long ptr) kernel32.DosDateTimeToFileTime -@ stdcall CoEnableCallCancellation(ptr) +@ stdcall CoEnableCallCancellation(ptr) combase.CoEnableCallCancellation @ stdcall CoFileTimeNow(ptr) combase.CoFileTimeNow @ stdcall CoFileTimeToDosDateTime(ptr ptr ptr) kernel32.FileTimeToDosDateTime @ stdcall CoFreeAllLibraries() @@ -29,7 +29,7 @@ @ stdcall CoGetApartmentType(ptr ptr) combase.CoGetApartmentType @ stdcall CoGetCallContext(ptr ptr) combase.CoGetCallContext @ stdcall CoGetCallState(long ptr) combase.CoGetCallState -@ stdcall CoGetCallerTID(ptr) +@ stdcall CoGetCallerTID(ptr) combase.CoGetCallerTID @ stdcall CoGetClassObject(ptr long ptr ptr ptr) combase.CoGetClassObject @ stdcall CoGetContextToken(ptr) combase.CoGetContextToken @ stdcall CoGetCurrentLogicalThreadId(ptr) combase.CoGetCurrentLogicalThreadId @@ -52,8 +52,8 @@ @ stdcall CoInitialize(ptr) @ stdcall CoInitializeEx(ptr long) combase.CoInitializeEx @ stdcall CoInitializeSecurity(ptr long ptr ptr long long ptr long ptr) combase.CoInitializeSecurity -@ stdcall CoInitializeWOW(long long) -@ stdcall CoIsHandlerConnected(ptr) +@ stdcall CoInitializeWOW(long long) combase.CoInitializeWOW +@ stdcall CoIsHandlerConnected(ptr) combase.CoIsHandlerConnected @ stdcall CoIsOle1Class (ptr) @ stdcall CoLoadLibrary(wstr long) @ stdcall CoLockObjectExternal(ptr long long) combase.CoLockObjectExternal @@ -70,18 +70,18 @@ @ stdcall CoRegisterMallocSpy(ptr) combase.CoRegisterMallocSpy @ stdcall CoRegisterMessageFilter(ptr ptr) combase.CoRegisterMessageFilter @ stdcall CoRegisterPSClsid(ptr ptr) combase.CoRegisterPSClsid -@ stdcall CoRegisterSurrogate(ptr) -@ stdcall CoRegisterSurrogateEx(ptr ptr) +@ stdcall CoRegisterSurrogate(ptr) combase.CoRegisterSurrogate +@ stdcall CoRegisterSurrogateEx(ptr ptr) combase.CoRegisterSurrogateEx @ stdcall CoReleaseMarshalData(ptr) combase.CoReleaseMarshalData @ stdcall CoReleaseServerProcess() combase.CoReleaseServerProcess -@ stdcall CoResumeClassObjects() +@ stdcall CoResumeClassObjects() combase.CoResumeClassObjects @ stdcall CoRevertToSelf() combase.CoRevertToSelf @ stdcall CoRevokeClassObject(long) combase.CoRevokeClassObject @ stdcall CoRevokeInitializeSpy(int64) combase.CoRevokeInitializeSpy @ stdcall CoRevokeMallocSpy() combase.CoRevokeMallocSpy @ stdcall CoSetProxyBlanket(ptr long long ptr long long ptr long) combase.CoSetProxyBlanket @ stdcall CoSetState(ptr) -@ stdcall CoSuspendClassObjects() +@ stdcall CoSuspendClassObjects() combase.CoSuspendClassObjects @ stdcall CoSwitchCallContext(ptr ptr) combase.CoSwitchCallContext @ stdcall CoTaskMemAlloc(long) combase.CoTaskMemAlloc @ stdcall CoTaskMemFree(ptr) combase.CoTaskMemFree @@ -107,7 +107,7 @@ @ stdcall CreatePointerMoniker(ptr ptr) @ stdcall CreateStreamOnHGlobal(ptr long ptr) @ stdcall DestroyRunningObjectTable() -@ stdcall DllDebugObjectRPCHook(long ptr) +@ stdcall DllDebugObjectRPCHook(long ptr) combase.DllDebugObjectRPCHook @ stdcall -private DllGetClassObject (ptr ptr ptr) @ stub DllGetClassObjectWOW @ stdcall -private DllRegisterServer() -- 2.28.0
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com> --- dlls/combase/Makefile.in | 1 + dlls/combase/combase.spec | 4 +- dlls/combase/hglobalstream.c | 455 +++++++++++++++++++++++ dlls/ole32/Makefile.in | 1 - dlls/ole32/hglobalstream.c | 684 ----------------------------------- dlls/ole32/ole32.spec | 4 +- 6 files changed, 460 insertions(+), 689 deletions(-) create mode 100644 dlls/combase/hglobalstream.c delete mode 100644 dlls/ole32/hglobalstream.c diff --git a/dlls/combase/Makefile.in b/dlls/combase/Makefile.in index ebf86708bbc..5af77584055 100644 --- a/dlls/combase/Makefile.in +++ b/dlls/combase/Makefile.in @@ -9,6 +9,7 @@ C_SRCS = \ apartment.c \ combase.c \ errorinfo.c \ + hglobalstream.c \ malloc.c \ marshal.c \ roapi.c \ diff --git a/dlls/combase/combase.spec b/dlls/combase/combase.spec index 50b58419bc5..9d9b34640be 100644 --- a/dlls/combase/combase.spec +++ b/dlls/combase/combase.spec @@ -174,7 +174,7 @@ @ stdcall CoWaitForMultipleHandles(long long long ptr ptr) @ stub CoWaitForMultipleObjects @ stdcall CreateErrorInfo(ptr) -@ stdcall CreateStreamOnHGlobal(ptr long ptr) ole32.CreateStreamOnHGlobal +@ stdcall CreateStreamOnHGlobal(ptr long ptr) @ stub DcomChannelSetHResult @ stdcall DllDebugObjectRPCHook(long ptr) @ stdcall DllGetActivationFactory(ptr ptr) @@ -185,7 +185,7 @@ @ stub GetCatalogHelper @ stdcall GetErrorInfo(long ptr) @ stub GetFuncDescs -@ stdcall GetHGlobalFromStream(ptr ptr) ole32.GetHGlobalFromStream +@ stdcall GetHGlobalFromStream(ptr ptr) @ stub GetHookInterface @ stdcall GetRestrictedErrorInfo(ptr) @ stdcall HACCEL_UserFree(ptr ptr) diff --git a/dlls/combase/hglobalstream.c b/dlls/combase/hglobalstream.c new file mode 100644 index 00000000000..5cbb280fd5e --- /dev/null +++ b/dlls/combase/hglobalstream.c @@ -0,0 +1,455 @@ +/* + * HGLOBAL Stream implementation + * + * Copyright 1999 Francis Beaudet + * Copyright 2016 Dmitry Timoshkov + * + * 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 + */ + +#define COBJMACROS +#define NONAMELESSUNION + +#include "objbase.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(storage); + +struct handle_wrapper +{ + LONG ref; + HGLOBAL hglobal; + ULONG size; + BOOL delete_on_release; +}; + +static void handle_addref(struct handle_wrapper *handle) +{ + InterlockedIncrement(&handle->ref); +} + +static void handle_release(struct handle_wrapper *handle) +{ + ULONG ref = InterlockedDecrement(&handle->ref); + + if (!ref) + { + if (handle->delete_on_release) GlobalFree(handle->hglobal); + HeapFree(GetProcessHeap(), 0, handle); + } +} + +static struct handle_wrapper *handle_create(HGLOBAL hglobal, BOOL delete_on_release) +{ + struct handle_wrapper *handle; + + handle = HeapAlloc(GetProcessHeap(), 0, sizeof(*handle)); + if (!handle) return NULL; + + /* allocate a handle if one is not supplied */ + if (!hglobal) hglobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD | GMEM_SHARE, 0); + if (!hglobal) + { + HeapFree(GetProcessHeap(), 0, handle); + return NULL; + } + handle->ref = 1; + handle->hglobal = hglobal; + handle->size = GlobalSize(hglobal); + handle->delete_on_release = delete_on_release; + + return handle; +} + +struct hglobal_stream +{ + IStream IStream_iface; + LONG ref; + + struct handle_wrapper *handle; + ULARGE_INTEGER position; +}; + +static inline struct hglobal_stream *impl_from_IStream(IStream *iface) +{ + return CONTAINING_RECORD(iface, struct hglobal_stream, IStream_iface); +} + +static const IStreamVtbl hglobalstreamvtbl; + +static struct hglobal_stream *hglobalstream_construct(void) +{ + struct hglobal_stream *object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object)); + + if (object) + { + object->IStream_iface.lpVtbl = &hglobalstreamvtbl; + object->ref = 1; + } + return object; +} + +static HRESULT WINAPI stream_QueryInterface(IStream *iface, REFIID riid, void **obj) +{ + if (!obj) + return E_INVALIDARG; + + if (IsEqualIID(&IID_IUnknown, riid) || + IsEqualIID(&IID_ISequentialStream, riid) || + IsEqualIID(&IID_IStream, riid)) + { + *obj = iface; + IStream_AddRef(iface); + return S_OK; + } + + *obj = NULL; + return E_NOINTERFACE; +} + +static ULONG WINAPI stream_AddRef(IStream *iface) +{ + struct hglobal_stream *stream = impl_from_IStream(iface); + return InterlockedIncrement(&stream->ref); +} + +static ULONG WINAPI stream_Release(IStream *iface) +{ + struct hglobal_stream *stream = impl_from_IStream(iface); + ULONG ref = InterlockedDecrement(&stream->ref); + + if (!ref) + { + handle_release(stream->handle); + HeapFree(GetProcessHeap(), 0, stream); + } + + return ref; +} + +static HRESULT WINAPI stream_Read(IStream *iface, void *pv, ULONG cb, ULONG *read_len) +{ + struct hglobal_stream *stream = impl_from_IStream(iface); + ULONG dummy, len; + char *buffer; + + TRACE("%p, %p, %d, %p\n", iface, pv, cb, read_len); + + if (!read_len) + read_len = &dummy; + + len = min(stream->handle->size - stream->position.u.LowPart, cb); + + buffer = GlobalLock(stream->handle->hglobal); + if (!buffer) + { + WARN("Failed to lock hglobal %p\n", stream->handle->hglobal); + *read_len = 0; + return S_OK; + } + + memcpy(pv, buffer + stream->position.u.LowPart, len); + stream->position.u.LowPart += len; + + *read_len = len; + + GlobalUnlock(stream->handle->hglobal); + + return S_OK; +} + +static HRESULT WINAPI stream_Write(IStream *iface, const void *pv, ULONG cb, ULONG *written) +{ + struct hglobal_stream *stream = impl_from_IStream(iface); + ULARGE_INTEGER size; + ULONG dummy = 0; + char *buffer; + + TRACE("%p, %p, %d, %p\n", iface, pv, cb, written); + + if (!written) + written = &dummy; + + if (!cb) + goto out; + + *written = 0; + + size.u.HighPart = 0; + size.u.LowPart = stream->position.u.LowPart + cb; + + if (size.u.LowPart > stream->handle->size) + { + /* grow stream */ + HRESULT hr = IStream_SetSize(iface, size); + if (FAILED(hr)) + { + ERR("IStream_SetSize failed with error 0x%08x\n", hr); + return hr; + } + } + + buffer = GlobalLock(stream->handle->hglobal); + if (!buffer) + { + WARN("write to invalid hglobal %p\n", stream->handle->hglobal); + return S_OK; + } + + memcpy(buffer + stream->position.u.LowPart, pv, cb); + stream->position.u.LowPart += cb; + + GlobalUnlock(stream->handle->hglobal); + +out: + *written = cb; + + return S_OK; +} + +static HRESULT WINAPI stream_Seek(IStream *iface, LARGE_INTEGER move, DWORD origin, + ULARGE_INTEGER *pos) +{ + struct hglobal_stream *stream = impl_from_IStream(iface); + ULARGE_INTEGER position = stream->position; + HRESULT hr = S_OK; + + TRACE("%p, %s, %d, %p\n", iface, wine_dbgstr_longlong(move.QuadPart), origin, pos); + + switch (origin) + { + case STREAM_SEEK_SET: + position.QuadPart = 0; + break; + case STREAM_SEEK_CUR: + break; + case STREAM_SEEK_END: + position.QuadPart = stream->handle->size; + break; + default: + hr = STG_E_SEEKERROR; + goto end; + } + + position.u.HighPart = 0; + position.u.LowPart += move.QuadPart; + + if (move.u.LowPart >= 0x80000000 && position.u.LowPart >= move.u.LowPart) + { + /* We tried to seek backwards and went past the start. */ + hr = STG_E_SEEKERROR; + goto end; + } + + stream->position = position; + +end: + if (pos) *pos = stream->position; + + return hr; +} + +static HRESULT WINAPI stream_SetSize(IStream *iface, ULARGE_INTEGER size) +{ + struct hglobal_stream *stream = impl_from_IStream(iface); + HGLOBAL hglobal; + + TRACE("%p, %s\n", iface, wine_dbgstr_longlong(size.QuadPart)); + + if (stream->handle->size == size.u.LowPart) + return S_OK; + + hglobal = GlobalReAlloc(stream->handle->hglobal, size.u.LowPart, GMEM_MOVEABLE); + if (!hglobal) + return E_OUTOFMEMORY; + + stream->handle->hglobal = hglobal; + stream->handle->size = size.u.LowPart; + + return S_OK; +} + +static HRESULT WINAPI stream_CopyTo(IStream *iface, IStream *dest, ULARGE_INTEGER cb, + ULARGE_INTEGER *read_len, ULARGE_INTEGER *written) +{ + ULARGE_INTEGER total_read, total_written; + HRESULT hr = S_OK; + BYTE buffer[128]; + + TRACE("%p, %p, %d, %p, %p\n", iface, dest, cb.u.LowPart, read_len, written); + + if (!dest) + return STG_E_INVALIDPOINTER; + + total_read.QuadPart = 0; + total_written.QuadPart = 0; + + while (cb.QuadPart > 0) + { + ULONG chunk_size = chunk_size = cb.QuadPart >= sizeof(buffer) ? sizeof(buffer) : cb.u.LowPart; + ULONG chunk_read, chunk_written; + + hr = IStream_Read(iface, buffer, chunk_size, &chunk_read); + if (FAILED(hr)) + break; + + total_read.QuadPart += chunk_read; + + if (chunk_read) + { + hr = IStream_Write(dest, buffer, chunk_read, &chunk_written); + if (FAILED(hr)) + break; + + total_written.QuadPart += chunk_written; + } + + if (chunk_read != chunk_size) + cb.QuadPart = 0; + else + cb.QuadPart -= chunk_read; + } + + if (read_len) + read_len->QuadPart = total_read.QuadPart; + if (written) + written->QuadPart = total_written.QuadPart; + + return hr; +} + +static HRESULT WINAPI stream_Commit(IStream *iface, DWORD flags) +{ + return S_OK; +} + +static HRESULT WINAPI stream_Revert(IStream *iface) +{ + return S_OK; +} + +static HRESULT WINAPI stream_LockRegion(IStream *iface, ULARGE_INTEGER offset, + ULARGE_INTEGER len, DWORD lock_type) +{ + return STG_E_INVALIDFUNCTION; +} + +static HRESULT WINAPI stream_UnlockRegion(IStream *iface, ULARGE_INTEGER offset, + ULARGE_INTEGER len, DWORD lock_type) +{ + return S_OK; +} + +static HRESULT WINAPI stream_Stat(IStream *iface, STATSTG *pstatstg, DWORD flags) +{ + struct hglobal_stream *stream = impl_from_IStream(iface); + + memset(pstatstg, 0, sizeof(STATSTG)); + + pstatstg->pwcsName = NULL; + pstatstg->type = STGTY_STREAM; + pstatstg->cbSize.QuadPart = stream->handle->size; + + return S_OK; +} + +static HRESULT WINAPI stream_Clone(IStream *iface, IStream **ppstm) +{ + struct hglobal_stream *stream = impl_from_IStream(iface), *clone; + ULARGE_INTEGER dummy; + LARGE_INTEGER offset; + + TRACE("%p, %p\n", iface, ppstm); + + *ppstm = NULL; + + clone = hglobalstream_construct(); + if (!clone) return E_OUTOFMEMORY; + + *ppstm = &clone->IStream_iface; + handle_addref(stream->handle); + clone->handle = stream->handle; + + offset.QuadPart = (LONGLONG)stream->position.QuadPart; + IStream_Seek(*ppstm, offset, STREAM_SEEK_SET, &dummy); + return S_OK; +} + +static const IStreamVtbl hglobalstreamvtbl = +{ + stream_QueryInterface, + stream_AddRef, + stream_Release, + stream_Read, + stream_Write, + stream_Seek, + stream_SetSize, + stream_CopyTo, + stream_Commit, + stream_Revert, + stream_LockRegion, + stream_UnlockRegion, + stream_Stat, + stream_Clone +}; + +/*********************************************************************** + * CreateStreamOnHGlobal (combase.@) + */ +HRESULT WINAPI CreateStreamOnHGlobal(HGLOBAL hGlobal, BOOL delete_on_release, IStream **stream) +{ + struct hglobal_stream *object; + + if (!stream) + return E_INVALIDARG; + + object = hglobalstream_construct(); + if (!object) return E_OUTOFMEMORY; + + object->handle = handle_create(hGlobal, delete_on_release); + if (!object->handle) + { + HeapFree(GetProcessHeap(), 0, object); + return E_OUTOFMEMORY; + } + + *stream = &object->IStream_iface; + + return S_OK; +} + +/*********************************************************************** + * GetHGlobalFromStream (combase.@) + */ +HRESULT WINAPI GetHGlobalFromStream(IStream *stream, HGLOBAL *phglobal) +{ + struct hglobal_stream *object; + + if (!stream || !phglobal) + return E_INVALIDARG; + + object = impl_from_IStream(stream); + + if (object->IStream_iface.lpVtbl == &hglobalstreamvtbl) + *phglobal = object->handle->hglobal; + else + { + *phglobal = 0; + return E_INVALIDARG; + } + + return S_OK; +} diff --git a/dlls/ole32/Makefile.in b/dlls/ole32/Makefile.in index 89807b94ef0..bb06faebe49 100644 --- a/dlls/ole32/Makefile.in +++ b/dlls/ole32/Makefile.in @@ -21,7 +21,6 @@ C_SRCS = \ filemoniker.c \ ftmarshal.c \ git.c \ - hglobalstream.c \ itemmoniker.c \ marshal.c \ memlockbytes.c \ diff --git a/dlls/ole32/hglobalstream.c b/dlls/ole32/hglobalstream.c deleted file mode 100644 index 4cfedd66a1b..00000000000 --- a/dlls/ole32/hglobalstream.c +++ /dev/null @@ -1,684 +0,0 @@ -/* - * HGLOBAL Stream implementation - * - * This file contains the implementation of the stream interface - * for streams contained supported by an HGLOBAL pointer. - * - * Copyright 1999 Francis Beaudet - * Copyright 2016 Dmitry Timoshkov - * - * 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 <assert.h> -#include <stdlib.h> -#include <stdarg.h> -#include <stdio.h> -#include <string.h> - -#define COBJMACROS -#define NONAMELESSUNION - -#include "windef.h" -#include "winbase.h" -#include "winuser.h" -#include "objbase.h" -#include "ole2.h" -#include "winerror.h" -#include "winternl.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(storage); - -struct handle_wrapper -{ - LONG ref; - HGLOBAL hglobal; - ULONG size; - BOOL delete_on_release; -}; - -static void handle_addref(struct handle_wrapper *handle) -{ - InterlockedIncrement(&handle->ref); -} - -static void handle_release(struct handle_wrapper *handle) -{ - ULONG ref = InterlockedDecrement(&handle->ref); - - if (!ref) - { - if (handle->delete_on_release) GlobalFree(handle->hglobal); - HeapFree(GetProcessHeap(), 0, handle); - } -} - -static struct handle_wrapper *handle_create(HGLOBAL hglobal, BOOL delete_on_release) -{ - struct handle_wrapper *handle; - - handle = HeapAlloc(GetProcessHeap(), 0, sizeof(*handle)); - if (!handle) return NULL; - - /* allocate a handle if one is not supplied */ - if (!hglobal) hglobal = GlobalAlloc(GMEM_MOVEABLE | GMEM_NODISCARD | GMEM_SHARE, 0); - if (!hglobal) - { - HeapFree(GetProcessHeap(), 0, handle); - return NULL; - } - handle->ref = 1; - handle->hglobal = hglobal; - handle->size = GlobalSize(hglobal); - handle->delete_on_release = delete_on_release; - - return handle; -} - -/**************************************************************************** - * HGLOBALStreamImpl definition. - * - * This class implements the IStream interface and represents a stream - * supported by an HGLOBAL pointer. - */ -typedef struct -{ - IStream IStream_iface; - LONG ref; - - struct handle_wrapper *handle; - - /* current position of the cursor */ - ULARGE_INTEGER currentPosition; -} HGLOBALStreamImpl; - -static inline HGLOBALStreamImpl *impl_from_IStream(IStream *iface) -{ - return CONTAINING_RECORD(iface, HGLOBALStreamImpl, IStream_iface); -} - -static const IStreamVtbl HGLOBALStreamImplVtbl; - -static HGLOBALStreamImpl *hglobalstream_construct(void) -{ - HGLOBALStreamImpl *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); - - if (This) - { - This->IStream_iface.lpVtbl = &HGLOBALStreamImplVtbl; - This->ref = 1; - This->handle = NULL; - This->currentPosition.QuadPart = 0; - } - return This; -} - -static HRESULT WINAPI HGLOBALStreamImpl_QueryInterface( - IStream* iface, - REFIID riid, /* [in] */ - void** ppvObject) /* [iid_is][out] */ -{ - HGLOBALStreamImpl* This = impl_from_IStream(iface); - - if (ppvObject==0) - return E_INVALIDARG; - - *ppvObject = 0; - - if (IsEqualIID(&IID_IUnknown, riid) || - IsEqualIID(&IID_ISequentialStream, riid) || - IsEqualIID(&IID_IStream, riid)) - { - *ppvObject = &This->IStream_iface; - } - - if ((*ppvObject)==0) - return E_NOINTERFACE; - - IStream_AddRef(iface); - - return S_OK; -} - -static ULONG WINAPI HGLOBALStreamImpl_AddRef(IStream* iface) -{ - HGLOBALStreamImpl* This = impl_from_IStream(iface); - return InterlockedIncrement(&This->ref); -} - -static ULONG WINAPI HGLOBALStreamImpl_Release( - IStream* iface) -{ - HGLOBALStreamImpl* This= impl_from_IStream(iface); - ULONG ref = InterlockedDecrement(&This->ref); - - if (!ref) - { - handle_release(This->handle); - HeapFree(GetProcessHeap(), 0, This); - } - - return ref; -} - -/*** - * This method is part of the ISequentialStream interface. - * - * If reads a block of information from the stream at the current - * position. It then moves the current position at the end of the - * read block - * - * See the documentation of ISequentialStream for more info. - */ -static HRESULT WINAPI HGLOBALStreamImpl_Read( - IStream* iface, - void* pv, /* [length_is][size_is][out] */ - ULONG cb, /* [in] */ - ULONG* pcbRead) /* [out] */ -{ - HGLOBALStreamImpl* This = impl_from_IStream(iface); - - void* supportBuffer; - ULONG bytesReadBuffer; - ULONG bytesToReadFromBuffer; - - TRACE("(%p, %p, %d, %p)\n", iface, - pv, cb, pcbRead); - - /* - * If the caller is not interested in the number of bytes read, - * we use another buffer to avoid "if" statements in the code. - */ - if (pcbRead==0) - pcbRead = &bytesReadBuffer; - - /* - * Using the known size of the stream, calculate the number of bytes - * to read from the block chain - */ - bytesToReadFromBuffer = min( This->handle->size - This->currentPosition.u.LowPart, cb); - - /* - * Lock the buffer in position and copy the data. - */ - supportBuffer = GlobalLock(This->handle->hglobal); - if (!supportBuffer) - { - WARN("read from invalid hglobal %p\n", This->handle->hglobal); - *pcbRead = 0; - return S_OK; - } - - memcpy(pv, (char *) supportBuffer+This->currentPosition.u.LowPart, bytesToReadFromBuffer); - - /* - * Move the current position to the new position - */ - This->currentPosition.u.LowPart+=bytesToReadFromBuffer; - - /* - * Return the number of bytes read. - */ - *pcbRead = bytesToReadFromBuffer; - - /* - * Cleanup - */ - GlobalUnlock(This->handle->hglobal); - - /* - * Always returns S_OK even if the end of the stream is reached before the - * buffer is filled - */ - - return S_OK; -} - -/*** - * This method is part of the ISequentialStream interface. - * - * It writes a block of information to the stream at the current - * position. It then moves the current position at the end of the - * written block. If the stream is too small to fit the block, - * the stream is grown to fit. - * - * See the documentation of ISequentialStream for more info. - */ -static HRESULT WINAPI HGLOBALStreamImpl_Write( - IStream* iface, - const void* pv, /* [size_is][in] */ - ULONG cb, /* [in] */ - ULONG* pcbWritten) /* [out] */ -{ - HGLOBALStreamImpl* This = impl_from_IStream(iface); - - void* supportBuffer; - ULARGE_INTEGER newSize; - ULONG bytesWritten = 0; - - TRACE("(%p, %p, %d, %p)\n", iface, pv, cb, pcbWritten); - - /* - * If the caller is not interested in the number of bytes written, - * we use another buffer to avoid "if" statements in the code. - */ - if (pcbWritten == 0) - pcbWritten = &bytesWritten; - - if (cb == 0) - goto out; - - *pcbWritten = 0; - - newSize.u.HighPart = 0; - newSize.u.LowPart = This->currentPosition.u.LowPart + cb; - - /* - * Verify if we need to grow the stream - */ - if (newSize.u.LowPart > This->handle->size) - { - /* grow stream */ - HRESULT hr = IStream_SetSize(iface, newSize); - if (FAILED(hr)) - { - ERR("IStream_SetSize failed with error 0x%08x\n", hr); - return hr; - } - } - - /* - * Lock the buffer in position and copy the data. - */ - supportBuffer = GlobalLock(This->handle->hglobal); - if (!supportBuffer) - { - WARN("write to invalid hglobal %p\n", This->handle->hglobal); - return S_OK; - } - - memcpy((char *) supportBuffer+This->currentPosition.u.LowPart, pv, cb); - - /* - * Move the current position to the new position - */ - This->currentPosition.u.LowPart+=cb; - - /* - * Cleanup - */ - GlobalUnlock(This->handle->hglobal); - -out: - /* - * Return the number of bytes read. - */ - *pcbWritten = cb; - - return S_OK; -} - -/*** - * This method is part of the IStream interface. - * - * It will move the current stream pointer according to the parameters - * given. - * - * See the documentation of IStream for more info. - */ -static HRESULT WINAPI HGLOBALStreamImpl_Seek( - IStream* iface, - LARGE_INTEGER dlibMove, /* [in] */ - DWORD dwOrigin, /* [in] */ - ULARGE_INTEGER* plibNewPosition) /* [out] */ -{ - HGLOBALStreamImpl* This = impl_from_IStream(iface); - - ULARGE_INTEGER newPosition = This->currentPosition; - HRESULT hr = S_OK; - - TRACE("(%p, %x%08x, %d, %p)\n", iface, dlibMove.u.HighPart, - dlibMove.u.LowPart, dwOrigin, plibNewPosition); - - /* - * The file pointer is moved depending on the given "function" - * parameter. - */ - switch (dwOrigin) - { - case STREAM_SEEK_SET: - newPosition.u.HighPart = 0; - newPosition.u.LowPart = 0; - break; - case STREAM_SEEK_CUR: - break; - case STREAM_SEEK_END: - newPosition.QuadPart = This->handle->size; - break; - default: - hr = STG_E_SEEKERROR; - goto end; - } - - /* - * Move the actual file pointer - * If the file pointer ends-up after the end of the stream, the next Write operation will - * make the file larger. This is how it is documented. - */ - newPosition.u.HighPart = 0; - newPosition.u.LowPart += dlibMove.QuadPart; - - if (dlibMove.u.LowPart >= 0x80000000 && - newPosition.u.LowPart >= dlibMove.u.LowPart) - { - /* We tried to seek backwards and went past the start. */ - hr = STG_E_SEEKERROR; - goto end; - } - - This->currentPosition = newPosition; - -end: - if (plibNewPosition) *plibNewPosition = This->currentPosition; - - return hr; -} - -/*** - * This method is part of the IStream interface. - * - * It will change the size of a stream. - * - * TODO: Switch from small blocks to big blocks and vice versa. - * - * See the documentation of IStream for more info. - */ -static HRESULT WINAPI HGLOBALStreamImpl_SetSize( - IStream* iface, - ULARGE_INTEGER libNewSize) /* [in] */ -{ - HGLOBALStreamImpl* This = impl_from_IStream(iface); - HGLOBAL supportHandle; - - TRACE("(%p, %d)\n", iface, libNewSize.u.LowPart); - - /* - * HighPart is ignored as shown in tests - */ - - if (This->handle->size == libNewSize.u.LowPart) - return S_OK; - - /* - * Re allocate the HGlobal to fit the new size of the stream. - */ - supportHandle = GlobalReAlloc(This->handle->hglobal, libNewSize.u.LowPart, GMEM_MOVEABLE); - - if (supportHandle == 0) - return E_OUTOFMEMORY; - - This->handle->hglobal = supportHandle; - This->handle->size = libNewSize.u.LowPart; - - return S_OK; -} - -/*** - * This method is part of the IStream interface. - * - * It will copy the 'cb' Bytes to 'pstm' IStream. - * - * See the documentation of IStream for more info. - */ -static HRESULT WINAPI HGLOBALStreamImpl_CopyTo( - IStream* iface, - IStream* pstm, /* [unique][in] */ - ULARGE_INTEGER cb, /* [in] */ - ULARGE_INTEGER* pcbRead, /* [out] */ - ULARGE_INTEGER* pcbWritten) /* [out] */ -{ - HRESULT hr = S_OK; - BYTE tmpBuffer[128]; - ULONG bytesRead, bytesWritten, copySize; - ULARGE_INTEGER totalBytesRead; - ULARGE_INTEGER totalBytesWritten; - - TRACE("(%p, %p, %d, %p, %p)\n", iface, pstm, - cb.u.LowPart, pcbRead, pcbWritten); - - if ( pstm == 0 ) - return STG_E_INVALIDPOINTER; - - totalBytesRead.QuadPart = 0; - totalBytesWritten.QuadPart = 0; - - while ( cb.QuadPart > 0 ) - { - if ( cb.QuadPart >= sizeof(tmpBuffer) ) - copySize = sizeof(tmpBuffer); - else - copySize = cb.u.LowPart; - - hr = IStream_Read(iface, tmpBuffer, copySize, &bytesRead); - if (FAILED(hr)) - break; - - totalBytesRead.QuadPart += bytesRead; - - if (bytesRead) - { - hr = IStream_Write(pstm, tmpBuffer, bytesRead, &bytesWritten); - if (FAILED(hr)) - break; - - totalBytesWritten.QuadPart += bytesWritten; - } - - if (bytesRead!=copySize) - cb.QuadPart = 0; - else - cb.QuadPart -= bytesRead; - } - - if (pcbRead) pcbRead->QuadPart = totalBytesRead.QuadPart; - if (pcbWritten) pcbWritten->QuadPart = totalBytesWritten.QuadPart; - - return hr; -} - -/*** - * This method is part of the IStream interface. - * - * For streams supported by HGLOBALS, this function does nothing. - * This is what the documentation tells us. - * - * See the documentation of IStream for more info. - */ -static HRESULT WINAPI HGLOBALStreamImpl_Commit( - IStream* iface, - DWORD grfCommitFlags) /* [in] */ -{ - return S_OK; -} - -/*** - * This method is part of the IStream interface. - * - * For streams supported by HGLOBALS, this function does nothing. - * This is what the documentation tells us. - * - * See the documentation of IStream for more info. - */ -static HRESULT WINAPI HGLOBALStreamImpl_Revert( - IStream* iface) -{ - return S_OK; -} - -/*** - * This method is part of the IStream interface. - * - * For streams supported by HGLOBALS, this function does nothing. - * This is what the documentation tells us. - * - * See the documentation of IStream for more info. - */ -static HRESULT WINAPI HGLOBALStreamImpl_LockRegion( - IStream* iface, - ULARGE_INTEGER libOffset, /* [in] */ - ULARGE_INTEGER cb, /* [in] */ - DWORD dwLockType) /* [in] */ -{ - return STG_E_INVALIDFUNCTION; -} - -/* - * This method is part of the IStream interface. - * - * For streams supported by HGLOBALS, this function does nothing. - * This is what the documentation tells us. - * - * See the documentation of IStream for more info. - */ -static HRESULT WINAPI HGLOBALStreamImpl_UnlockRegion( - IStream* iface, - ULARGE_INTEGER libOffset, /* [in] */ - ULARGE_INTEGER cb, /* [in] */ - DWORD dwLockType) /* [in] */ -{ - return S_OK; -} - -/*** - * This method is part of the IStream interface. - * - * This method returns information about the current - * stream. - * - * See the documentation of IStream for more info. - */ -static HRESULT WINAPI HGLOBALStreamImpl_Stat( - IStream* iface, - STATSTG* pstatstg, /* [out] */ - DWORD grfStatFlag) /* [in] */ -{ - HGLOBALStreamImpl* This = impl_from_IStream(iface); - - memset(pstatstg, 0, sizeof(STATSTG)); - - pstatstg->pwcsName = NULL; - pstatstg->type = STGTY_STREAM; - pstatstg->cbSize.QuadPart = This->handle->size; - - return S_OK; -} - -static HRESULT WINAPI HGLOBALStreamImpl_Clone( - IStream* iface, - IStream** ppstm) /* [out] */ -{ - HGLOBALStreamImpl* This = impl_from_IStream(iface), *clone; - ULARGE_INTEGER dummy; - LARGE_INTEGER offset; - - TRACE(" Cloning %p (deleteOnRelease=%d seek position=%ld)\n",iface,This->handle->delete_on_release,(long)This->currentPosition.QuadPart); - - *ppstm = NULL; - - clone = hglobalstream_construct(); - if (!clone) return E_OUTOFMEMORY; - - *ppstm = &clone->IStream_iface; - handle_addref(This->handle); - clone->handle = This->handle; - - offset.QuadPart = (LONGLONG)This->currentPosition.QuadPart; - IStream_Seek(*ppstm, offset, STREAM_SEEK_SET, &dummy); - return S_OK; -} - -static const IStreamVtbl HGLOBALStreamImplVtbl = -{ - HGLOBALStreamImpl_QueryInterface, - HGLOBALStreamImpl_AddRef, - HGLOBALStreamImpl_Release, - HGLOBALStreamImpl_Read, - HGLOBALStreamImpl_Write, - HGLOBALStreamImpl_Seek, - HGLOBALStreamImpl_SetSize, - HGLOBALStreamImpl_CopyTo, - HGLOBALStreamImpl_Commit, - HGLOBALStreamImpl_Revert, - HGLOBALStreamImpl_LockRegion, - HGLOBALStreamImpl_UnlockRegion, - HGLOBALStreamImpl_Stat, - HGLOBALStreamImpl_Clone -}; - -/*********************************************************************** - * CreateStreamOnHGlobal [OLE32.@] - */ -HRESULT WINAPI CreateStreamOnHGlobal( - HGLOBAL hGlobal, - BOOL fDeleteOnRelease, - LPSTREAM* ppstm) -{ - HGLOBALStreamImpl* This; - - if (!ppstm) - return E_INVALIDARG; - - This = hglobalstream_construct(); - if (!This) return E_OUTOFMEMORY; - - This->handle = handle_create(hGlobal, fDeleteOnRelease); - if (!This->handle) - { - HeapFree(GetProcessHeap(), 0, This); - return E_OUTOFMEMORY; - } - - *ppstm = &This->IStream_iface; - - return S_OK; -} - -/*********************************************************************** - * GetHGlobalFromStream [OLE32.@] - */ -HRESULT WINAPI GetHGlobalFromStream(IStream* pstm, HGLOBAL* phglobal) -{ - HGLOBALStreamImpl* pStream; - - if (!pstm || !phglobal) - return E_INVALIDARG; - - pStream = impl_from_IStream(pstm); - - /* - * Verify that the stream object was created with CreateStreamOnHGlobal. - */ - if (pStream->IStream_iface.lpVtbl == &HGLOBALStreamImplVtbl) - *phglobal = pStream->handle->hglobal; - else - { - *phglobal = 0; - return E_INVALIDARG; - } - - return S_OK; -} diff --git a/dlls/ole32/ole32.spec b/dlls/ole32/ole32.spec index 44c03b6628c..a6f62ebfa99 100644 --- a/dlls/ole32/ole32.spec +++ b/dlls/ole32/ole32.spec @@ -105,7 +105,7 @@ @ stub CreateObjrefMoniker @ stdcall CreateOleAdviseHolder(ptr) @ stdcall CreatePointerMoniker(ptr ptr) -@ stdcall CreateStreamOnHGlobal(ptr long ptr) +@ stdcall CreateStreamOnHGlobal(ptr long ptr) combase.CreateStreamOnHGlobal @ stdcall DestroyRunningObjectTable() @ stdcall DllDebugObjectRPCHook(long ptr) combase.DllDebugObjectRPCHook @ stdcall -private DllGetClassObject (ptr ptr ptr) @@ -121,7 +121,7 @@ @ stub GetDocumentBitStg @ stdcall GetErrorInfo(long ptr) combase.GetErrorInfo @ stdcall GetHGlobalFromILockBytes(ptr ptr) -@ stdcall GetHGlobalFromStream(ptr ptr) +@ stdcall GetHGlobalFromStream(ptr ptr) combase.GetHGlobalFromStream @ stub GetHookInterface @ stdcall GetRunningObjectTable(long ptr) @ stdcall HACCEL_UserFree(ptr ptr) combase.HACCEL_UserFree -- 2.28.0
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=77924 Your paranoid android. === debiant (64 bit WoW report) === ole32: clipboard.c:1325: Test failed: got 800401d0 clipboard.c:1337: Test failed: got 800401d0 clipboard.c:1338: Test failed: got 0 clipboard.c:1343: Test failed: got 80040064 clipboard.c:1344: Test failed: got 0 clipboard.c:1349: Test failed: got 80040064 clipboard.c:1354: Test failed: got 80040064 clipboard.c:1355: Test failed: got 0 clipboard.c:1362: Test failed: got 80040064 clipboard.c:1363: Test failed: got 0 clipboard.c:1368: Test failed: got 80040064 clipboard.c:1373: Test failed: got 80040064 clipboard.c:1374: Test failed: got 0 clipboard.c:1379: Test failed: got 80040064 clipboard.c:1380: Test failed: got 0 clipboard.c:1387: Test failed: got 80040064 clipboard.c:1388: Test failed: got 0 clipboard.c:1398: Test failed: got 80040064 clipboard.c:1399: Test failed: got 0 clipboard.c:1404: Test failed: got 80040064 clipboard.c:1405: Test failed: got 0 clipboard.c:1410: Test failed: got 80040064 clipboard.c:1411: Test failed: got 0 clipboard.c:1416: Test failed: got 80040064 clipboard.c:1417: Test failed: got 0 clipboard.c:1424: Test failed: got 80040064 clipboard.c:1454: Test failed: got 80040064 clipboard.c:1529: Test failed: gle 5 clipboard.c:1531: Test failed: gle 1418 clipboard.c:1533: Test failed: gle 1418 clipboard.c:1541: Test failed: got 800401d0 Unhandled exception: page fault on read access to 0x00000000 in 32-bit code (0x00406970). Report validation errors: ole32:clipboard crashed (c0000005)
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com> --- .../api-ms-win-core-com-private-l1-1-0.spec | 52 +++++++++---------- tools/make_specfiles | 6 ++- 2 files changed, 30 insertions(+), 28 deletions(-) diff --git a/dlls/api-ms-win-core-com-private-l1-1-0/api-ms-win-core-com-private-l1-1-0.spec b/dlls/api-ms-win-core-com-private-l1-1-0/api-ms-win-core-com-private-l1-1-0.spec index b0f6b64f649..155219a4727 100644 --- a/dlls/api-ms-win-core-com-private-l1-1-0/api-ms-win-core-com-private-l1-1-0.spec +++ b/dlls/api-ms-win-core-com-private-l1-1-0/api-ms-win-core-com-private-l1-1-0.spec @@ -1,37 +1,37 @@ @ stub CLSIDFromOle1Class @ stub CleanupOleStateInAllTls -@ stub CleanupTlsOleState +@ stdcall CleanupTlsOleState(ptr) combase.CleanupTlsOleState @ stub ClearCleanupFlag -@ stub CoCreateErrorInfo +@ stdcall CoCreateErrorInfo(ptr) combase.CoCreateErrorInfo @ stub CoCreateObjectInContext @ stub CoDeactivateObject -@ stdcall CoGetActivationState(int128 long ptr) ole32.CoGetActivationState +@ stdcall CoGetActivationState(int128 long ptr) combase.CoGetActivationState @ stub CoGetApartmentID -@ stdcall CoGetCallState(long ptr) ole32.CoGetCallState +@ stdcall CoGetCallState(long ptr) combase.CoGetCallState @ stub CoGetClassVersion -@ stub CoGetErrorInfo -@ stdcall CoGetInstanceFromFile(ptr ptr ptr long long wstr long ptr) ole32.CoGetInstanceFromFile -@ stdcall CoGetInstanceFromIStorage(ptr ptr ptr long ptr long ptr) ole32.CoGetInstanceFromIStorage +@ stdcall CoGetErrorInfo(long ptr) combase.CoGetErrorInfo +@ stdcall CoGetInstanceFromFile(ptr ptr ptr long long wstr long ptr) combase.CoGetInstanceFromFile +@ stdcall CoGetInstanceFromIStorage(ptr ptr ptr long ptr long ptr) combase.CoGetInstanceFromIStorage @ stub CoGetModuleType @ stub CoGetProcessIdentifier @ stub CoGetSystemSecurityPermissions -@ stdcall CoInitializeWOW(long long) ole32.CoInitializeWOW +@ stdcall CoInitializeWOW(long long) combase.CoInitializeWOW @ stub CoPopServiceDomain @ stub CoPushServiceDomain @ stub CoReactivateObject -@ stdcall CoRegisterInitializeSpy(ptr ptr) ole32.CoRegisterInitializeSpy -@ stdcall CoRegisterMallocSpy(ptr) ole32.CoRegisterMallocSpy -@ stdcall CoRegisterMessageFilter(ptr ptr) ole32.CoRegisterMessageFilter -@ stdcall CoRegisterSurrogateEx(ptr ptr) ole32.CoRegisterSurrogateEx +@ stdcall CoRegisterInitializeSpy(ptr ptr) combase.CoRegisterInitializeSpy +@ stdcall CoRegisterMallocSpy(ptr) combase.CoRegisterMallocSpy +@ stdcall CoRegisterMessageFilter(ptr ptr) combase.CoRegisterMessageFilter +@ stdcall CoRegisterSurrogateEx(ptr ptr) combase.CoRegisterSurrogateEx @ stub CoRetireServer -@ stdcall CoRevokeInitializeSpy(int64) ole32.CoRevokeInitializeSpy -@ stdcall CoRevokeMallocSpy() ole32.CoRevokeMallocSpy -@ stub CoSetErrorInfo +@ stdcall CoRevokeInitializeSpy(int64) combase.CoRevokeInitializeSpy +@ stdcall CoRevokeMallocSpy() combase.CoRevokeMallocSpy +@ stdcall CoSetErrorInfo(long ptr) combase.CoSetErrorInfo @ stub CoUnloadingWOW @ stub CoVrfCheckThreadState @ stub CoVrfGetThreadState @ stub CoVrfReleaseThreadState -@ stdcall DllDebugObjectRPCHook(long ptr) ole32.DllDebugObjectRPCHook +@ stdcall DllDebugObjectRPCHook(long ptr) combase.DllDebugObjectRPCHook @ stub EnableHookObject @ stub FreePropVariantArrayWorker @ stub GetCatalogHelper @@ -51,7 +51,7 @@ @ stub InternalCoIsSurrogateProcess @ stub InternalCoRegisterDisconnectCallback @ stub InternalCoRegisterSurrogatedObject -@ stub InternalCoStdMarshalObject +@ stdcall InternalCoStdMarshalObject(ptr long ptr ptr) combase.InternalCoStdMarshalObject @ stub InternalCoUnregisterDisconnectCallback @ stub InternalCompleteObjRef @ stub InternalCreateCAggId @@ -60,15 +60,15 @@ @ stub InternalFillLocalOXIDInfo @ stub InternalFreeObjRef @ stub InternalGetWindowPropInterface -@ stub InternalIrotEnumRunning -@ stub InternalIrotGetObject -@ stub InternalIrotGetTimeOfLastChange -@ stub InternalIrotIsRunning -@ stub InternalIrotNoteChangeTime -@ stub InternalIrotRegister -@ stub InternalIrotRevoke +@ stdcall InternalIrotEnumRunning(ptr) combase.InternalIrotEnumRunning +@ stdcall InternalIrotGetObject(ptr ptr ptr) combase.InternalIrotGetObject +@ stdcall InternalIrotGetTimeOfLastChange(ptr ptr) combase.InternalIrotGetTimeOfLastChange +@ stdcall InternalIrotIsRunning(ptr) combase.InternalIrotIsRunning +@ stdcall InternalIrotNoteChangeTime(long ptr) combase.InternalIrotNoteChangeTime +@ stdcall InternalIrotRegister(ptr ptr ptr ptr long ptr ptr) combase.InternalIrotRegister +@ stdcall InternalIrotRevoke(long ptr ptr ptr) combase.InternalIrotRevoke @ stub InternalIsApartmentInitialized -@ stub InternalIsProcessInitialized +@ stdcall InternalIsProcessInitialized() combase.InternalIsProcessInitialized @ stub InternalMarshalObjRef @ stub InternalNotifyDDStartOrStop @ stub InternalOleModalLoopBlockFn @@ -79,7 +79,7 @@ @ stub InternalSetAptCallCtrlOnTlsIfRequired @ stub InternalSetOleThunkWowPtr @ stub InternalStubInvoke -@ stub InternalTlsAllocData +@ stdcall InternalTlsAllocData(ptr) combase.InternalTlsAllocData @ stub InternalUnmarshalObjRef @ stub NdrExtStubInitialize @ stub NdrOleDllGetClassObject diff --git a/tools/make_specfiles b/tools/make_specfiles index 2af46069845..efb873e2532 100755 --- a/tools/make_specfiles +++ b/tools/make_specfiles @@ -329,13 +329,15 @@ my @dll_groups = "api-ms-win-core-systemtopology-l1-1-0", "api-ms-win-security-grouppolicy-l1-1-0", ], + [ + "combase", + "api-ms-win-core-com-private-l1-1-0", + ], [ "ole32", "api-ms-win-downlevel-ole32-l1-1-0", "api-ms-win-core-com-l1-1-0", "api-ms-win-core-com-l1-1-1", - "api-ms-win-core-com-private-l1-1-0", - "combase", "iprop", ], [ -- 2.28.0
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
Main point of this change is to get rid of auxiliary thread that is causing issues when CoRevokeClassObject() has to wait on it, potentially deadlocking when called from DllMain. Signed-off-by: Nikolay Sivov <nsivov(a)codeweavers.com> --- dlls/combase/combase.c | 33 ++-- dlls/combase/combase_private.h | 4 +- dlls/combase/rpc.c | 306 +++++++++------------------------ dlls/ole32/compobj.c | 2 - include/wine/irpcss.idl | 17 ++ programs/rpcss/rpcss_main.c | 100 +++++++++++ 6 files changed, 222 insertions(+), 240 deletions(-) diff --git a/dlls/combase/combase.c b/dlls/combase/combase.c index 99352712f78..c90cba6185c 100644 --- a/dlls/combase/combase.c +++ b/dlls/combase/combase.c @@ -115,10 +115,6 @@ static CRITICAL_SECTION_DEBUG psclsid_cs_debug = }; static CRITICAL_SECTION cs_registered_ps = { &psclsid_cs_debug, -1, 0, 0, 0, 0 }; -/* - * TODO: Make this data structure aware of inter-process communication. This - * means that parts of this will be exported to rpcss. - */ struct registered_class { struct list entry; @@ -127,8 +123,8 @@ struct registered_class IUnknown *object; DWORD clscontext; DWORD flags; - DWORD cookie; - void *RpcRegistration; + unsigned int cookie; + unsigned int rpcss_cookie; }; static struct list registered_classes = LIST_INIT(registered_classes); @@ -2824,7 +2820,7 @@ HRESULT WINAPI CoRegisterClassObject(REFCLSID rclsid, IUnknown *object, DWORD cl return CO_E_OBJISREG; } - newclass = heap_alloc(sizeof(*newclass)); + newclass = heap_alloc_zero(sizeof(*newclass)); if (!newclass) { apartment_release(apt); @@ -2835,7 +2831,6 @@ HRESULT WINAPI CoRegisterClassObject(REFCLSID rclsid, IUnknown *object, DWORD cl newclass->apartment_id = apt->oxid; newclass->clscontext = clscontext; newclass->flags = flags; - newclass->RpcRegistration = NULL; if (!(newclass->cookie = InterlockedIncrement(&next_cookie))) newclass->cookie = InterlockedIncrement(&next_cookie); @@ -2860,8 +2855,7 @@ HRESULT WINAPI CoRegisterClassObject(REFCLSID rclsid, IUnknown *object, DWORD cl return hr; } - hr = rpc_start_local_server(&newclass->clsid, marshal_stream, flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE), - &newclass->RpcRegistration); + hr = rpc_register_local_server(&newclass->clsid, marshal_stream, flags, &newclass->rpcss_cookie); IStream_Release(marshal_stream); } @@ -2874,12 +2868,28 @@ static void com_revoke_class_object(struct registered_class *entry) list_remove(&entry->entry); if (entry->clscontext & CLSCTX_LOCAL_SERVER) - rpc_stop_local_server(entry->RpcRegistration); + rpc_revoke_local_server(entry->rpcss_cookie); IUnknown_Release(entry->object); heap_free(entry); } +/* Cleans up rpcss registry */ +static void com_revoke_local_servers(void) +{ + struct registered_class *cur, *cur2; + + EnterCriticalSection(®istered_classes_cs); + + LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, ®istered_classes, struct registered_class, entry) + { + if (cur->clscontext & CLSCTX_LOCAL_SERVER) + com_revoke_class_object(cur); + } + + LeaveCriticalSection(®istered_classes_cs); +} + void apartment_revoke_all_classes(const struct apartment *apt) { struct registered_class *cur, *cur2; @@ -3164,6 +3174,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID reserved) hProxyDll = hinstDLL; break; case DLL_PROCESS_DETACH: + com_revoke_local_servers(); if (reserved) break; apartment_global_cleanup(); DeleteCriticalSection(®istered_classes_cs); diff --git a/dlls/combase/combase_private.h b/dlls/combase/combase_private.h index 703c1a26c20..ca8a994f4e2 100644 --- a/dlls/combase/combase_private.h +++ b/dlls/combase/combase_private.h @@ -112,8 +112,8 @@ HRESULT apartment_disconnectproxies(struct apartment *apt) DECLSPEC_HIDDEN; /* RpcSs interface */ HRESULT rpcss_get_next_seqid(DWORD *id) DECLSPEC_HIDDEN; HRESULT rpc_get_local_class_object(REFCLSID rclsid, REFIID riid, void **obj) DECLSPEC_HIDDEN; -HRESULT rpc_start_local_server(REFCLSID clsid, IStream *stream, BOOL multi_use, void **registration) DECLSPEC_HIDDEN; -void rpc_stop_local_server(void *registration) DECLSPEC_HIDDEN; +HRESULT rpc_register_local_server(REFCLSID clsid, IStream *stream, DWORD flags, unsigned int *cookie) DECLSPEC_HIDDEN; +HRESULT rpc_revoke_local_server(unsigned int cookie) DECLSPEC_HIDDEN; HRESULT rpc_create_clientchannel(const OXID *oxid, const IPID *ipid, const OXID_INFO *oxid_info, const IID *iid, DWORD dest_context, void *dest_context_data, IRpcChannelBuffer **chan, struct apartment *apt) DECLSPEC_HIDDEN; HRESULT rpc_create_serverchannel(DWORD dest_context, void *dest_context_data, IRpcChannelBuffer **chan) DECLSPEC_HIDDEN; diff --git a/dlls/combase/rpc.c b/dlls/combase/rpc.c index 513c1e6c13a..c4bc8983a2c 100644 --- a/dlls/combase/rpc.c +++ b/dlls/combase/rpc.c @@ -363,11 +363,25 @@ HRESULT WINAPI InternalIrotRevoke(IrotCookie cookie, IrotContextHandle *ctxt_han RPCSS_CALL_END } -static void get_localserver_pipe_name(WCHAR *pipefn, REFCLSID rclsid) +static HRESULT rpcss_server_register(REFCLSID clsid, DWORD flags, MInterfacePointer *obj, unsigned int *cookie) { - static const WCHAR wszPipeRef[] = {'\\','\\','.','\\','p','i','p','e','\\',0}; - lstrcpyW(pipefn, wszPipeRef); - StringFromGUID2(rclsid, pipefn + ARRAY_SIZE(wszPipeRef) - 1, CHARS_IN_GUID); + RPCSS_CALL_START + hr = irpcss_server_register(get_irpcss_handle(), clsid, flags, obj, cookie); + RPCSS_CALL_END +} + +HRESULT rpc_revoke_local_server(unsigned int cookie) +{ + RPCSS_CALL_START + hr = irpcss_server_revoke(get_irpcss_handle(), cookie); + RPCSS_CALL_END +} + +static HRESULT rpcss_get_class_object(REFCLSID rclsid, PMInterfacePointer *objref) +{ + RPCSS_CALL_START + hr = irpcss_get_class_object(get_irpcss_handle(), rclsid, objref); + RPCSS_CALL_END } static DWORD start_local_service(const WCHAR *name, DWORD num, LPCWSTR *params) @@ -509,261 +523,103 @@ static HRESULT create_server(REFCLSID rclsid, HANDLE *process) return S_OK; } -/* FIXME: should call to rpcss instead */ HRESULT rpc_get_local_class_object(REFCLSID rclsid, REFIID riid, void **obj) { - HRESULT hr; - HANDLE hPipe; - WCHAR pipefn[100]; - DWORD res, bufferlen; - char marshalbuffer[200]; - IStream *pStm; - LARGE_INTEGER seekto; - ULARGE_INTEGER newpos; - int tries = 0; + PMInterfacePointer objref = NULL; IServiceProvider *local_server; - + IStream *stream = NULL; + ULARGE_INTEGER newpos; + LARGE_INTEGER seekto; + int tries = 0; + ULONG length; + HRESULT hr; static const int MAXTRIES = 30; /* 30 seconds */ - TRACE("rclsid %s, riid %s\n", debugstr_guid(rclsid), debugstr_guid(riid)); - - get_localserver_pipe_name(pipefn, rclsid); + TRACE("clsid %s, riid %s\n", debugstr_guid(rclsid), debugstr_guid(riid)); while (tries++ < MAXTRIES) { - TRACE("waiting for %s\n", debugstr_w(pipefn)); + DWORD index, start_ticks; + HANDLE process = 0; - WaitNamedPipeW(pipefn, NMPWAIT_WAIT_FOREVER); - hPipe = CreateFileW(pipefn, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0); - if (hPipe == INVALID_HANDLE_VALUE) - { - DWORD index; - DWORD start_ticks; - HANDLE process = 0; - if (tries == 1) - { - if ((hr = create_local_service(rclsid)) && (hr = create_server(rclsid, &process))) - return hr; - } - else - { - WARN("Connecting to %s, no response yet, retrying: le is %u\n", debugstr_w(pipefn), GetLastError()); - } - /* wait for one second, even if messages arrive */ - start_ticks = GetTickCount(); - do - { - if (SUCCEEDED(CoWaitForMultipleHandles(0, 1000, (process != 0), &process, &index)) && process && !index) - { - WARN("server for %s failed to start\n", debugstr_guid(rclsid)); - CloseHandle( hPipe ); - CloseHandle( process ); - return E_NOINTERFACE; - } - } while (GetTickCount() - start_ticks < 1000); - if (process) CloseHandle(process); - continue; - } - bufferlen = 0; - if (!ReadFile(hPipe, marshalbuffer, sizeof(marshalbuffer), &bufferlen, NULL)) + if (SUCCEEDED(hr = rpcss_get_class_object(rclsid, &objref))) + break; + + if (tries == 1) { - FIXME("Failed to read marshal id from classfactory of %s.\n", debugstr_guid(rclsid)); - CloseHandle(hPipe); - Sleep(1000); - continue; + if ((hr = create_local_service(rclsid)) && (hr = create_server(rclsid, &process)) ) + return hr; } - TRACE("read marshal id from pipe\n"); - CloseHandle(hPipe); - break; - } - if (tries >= MAXTRIES) - return E_NOINTERFACE; - - hr = CreateStreamOnHGlobal(0, TRUE, &pStm); - if (hr != S_OK) return hr; - hr = IStream_Write(pStm, marshalbuffer, bufferlen, &res); - if (hr != S_OK) goto out; - seekto.u.LowPart = 0;seekto.u.HighPart = 0; - hr = IStream_Seek(pStm, seekto, STREAM_SEEK_SET, &newpos); - TRACE("unmarshalling local server\n"); - hr = CoUnmarshalInterface(pStm, &IID_IServiceProvider, (void **)&local_server); - if(SUCCEEDED(hr)) - hr = IServiceProvider_QueryService(local_server, rclsid, riid, obj); - IServiceProvider_Release(local_server); -out: - IStream_Release(pStm); - return hr; -} - -struct local_server_params -{ - CLSID clsid; - IStream *stream; - HANDLE pipe; - HANDLE stop_event; - HANDLE thread; - BOOL multi_use; -}; - -/* FIXME: should call to rpcss instead */ -static DWORD WINAPI local_server_thread(void *param) -{ - struct local_server_params * lsp = param; - WCHAR pipefn[100]; - HRESULT hres; - IStream *pStm = lsp->stream; - STATSTG ststg; - unsigned char *buffer; - int buflen; - LARGE_INTEGER seekto; - ULARGE_INTEGER newpos; - ULONG res; - BOOL multi_use = lsp->multi_use; - OVERLAPPED ovl; - HANDLE pipe_event, hPipe = lsp->pipe, new_pipe; - DWORD bytes; - - TRACE("Starting threader for %s.\n",debugstr_guid(&lsp->clsid)); - - memset(&ovl, 0, sizeof(ovl)); - get_localserver_pipe_name(pipefn, &lsp->clsid); - ovl.hEvent = pipe_event = CreateEventW(NULL, FALSE, FALSE, NULL); - - while (1) { - if (!ConnectNamedPipe(hPipe, &ovl)) + /* Wait for one second, even if messages arrive. */ + start_ticks = GetTickCount(); + do { - DWORD error = GetLastError(); - if (error == ERROR_IO_PENDING) + if (SUCCEEDED(CoWaitForMultipleHandles(0, 1000, (process != 0), &process, &index)) && process && !index) { - HANDLE handles[2] = { pipe_event, lsp->stop_event }; - DWORD ret; - ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE); - if (ret != WAIT_OBJECT_0) - break; + WARN("Server for %s failed to start.\n", debugstr_guid(rclsid)); + CloseHandle(process); + return E_NOINTERFACE; } - /* client already connected isn't an error */ - else if (error != ERROR_PIPE_CONNECTED) - { - ERR("ConnectNamedPipe failed with error %d\n", GetLastError()); - break; - } - } - - TRACE("marshalling LocalServer to client\n"); + } while (GetTickCount() - start_ticks < 1000); - hres = IStream_Stat(pStm,&ststg,STATFLAG_NONAME); - if (hres != S_OK) - break; - - seekto.u.LowPart = 0; - seekto.u.HighPart = 0; - hres = IStream_Seek(pStm,seekto,STREAM_SEEK_SET,&newpos); - if (hres != S_OK) { - FIXME("IStream_Seek failed, %x\n",hres); - break; - } + if (process) CloseHandle(process); + } - buflen = ststg.cbSize.u.LowPart; - buffer = HeapAlloc(GetProcessHeap(),0,buflen); + if (!objref || tries >= MAXTRIES) + return E_NOINTERFACE; - hres = IStream_Read(pStm,buffer,buflen,&res); - if (hres != S_OK) { - FIXME("Stream Read failed, %x\n",hres); - HeapFree(GetProcessHeap(),0,buffer); - break; - } + if (SUCCEEDED(hr = CreateStreamOnHGlobal(0, TRUE, &stream))) + hr = IStream_Write(stream, objref->abData, objref->ulCntData, &length); - WriteFile(hPipe,buffer,buflen,&res,&ovl); - GetOverlappedResult(hPipe, &ovl, &bytes, TRUE); - HeapFree(GetProcessHeap(),0,buffer); + MIDL_user_free(objref); - FlushFileBuffers(hPipe); - DisconnectNamedPipe(hPipe); - TRACE("done marshalling LocalServer\n"); + if (SUCCEEDED(hr)) + { + seekto.QuadPart = 0; + IStream_Seek(stream, seekto, STREAM_SEEK_SET, &newpos); - if (!multi_use) + TRACE("Unmarshalling local server.\n"); + hr = CoUnmarshalInterface(stream, &IID_IServiceProvider, (void **)&local_server); + if (SUCCEEDED(hr)) { - TRACE("single use object, shutting down pipe %s\n", debugstr_w(pipefn)); - break; + hr = IServiceProvider_QueryService(local_server, rclsid, riid, obj); + IServiceProvider_Release(local_server); } - new_pipe = CreateNamedPipeW( pipefn, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, - PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, - 4096, 4096, 500 /* 0.5 second timeout */, NULL ); - if (new_pipe == INVALID_HANDLE_VALUE) - { - FIXME("pipe creation failed for %s, le is %u\n", debugstr_w(pipefn), GetLastError()); - break; - } - CloseHandle(hPipe); - hPipe = new_pipe; } - CloseHandle(pipe_event); - CloseHandle(hPipe); - return 0; + if (stream) + IStream_Release(stream); + + return hr; } -HRESULT rpc_start_local_server(REFCLSID clsid, IStream *stream, BOOL multi_use, void **registration) +HRESULT rpc_register_local_server(REFCLSID clsid, IStream *stream, DWORD flags, unsigned int *cookie) { - DWORD tid, err; - struct local_server_params *lsp; - WCHAR pipefn[100]; - - lsp = HeapAlloc(GetProcessHeap(), 0, sizeof(*lsp)); - if (!lsp) - return E_OUTOFMEMORY; + MInterfacePointer *obj; + const void *ptr; + HGLOBAL hmem; + SIZE_T size; + HRESULT hr; - lsp->clsid = *clsid; - lsp->stream = stream; - IStream_AddRef(stream); - lsp->stop_event = CreateEventW(NULL, FALSE, FALSE, NULL); - if (!lsp->stop_event) - { - HeapFree(GetProcessHeap(), 0, lsp); - return HRESULT_FROM_WIN32(GetLastError()); - } - lsp->multi_use = multi_use; + TRACE("%s, %#x\n", debugstr_guid(clsid), flags); - get_localserver_pipe_name(pipefn, &lsp->clsid); - lsp->pipe = CreateNamedPipeW(pipefn, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, - PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, - 4096, 4096, 500 /* 0.5 second timeout */, NULL); - if (lsp->pipe == INVALID_HANDLE_VALUE) - { - err = GetLastError(); - FIXME("pipe creation failed for %s, le is %u\n", debugstr_w(pipefn), GetLastError()); - CloseHandle(lsp->stop_event); - HeapFree(GetProcessHeap(), 0, lsp); - return HRESULT_FROM_WIN32(err); - } + hr = GetHGlobalFromStream(stream, &hmem); + if (FAILED(hr)) return hr; - lsp->thread = CreateThread(NULL, 0, local_server_thread, lsp, 0, &tid); - if (!lsp->thread) - { - CloseHandle(lsp->pipe); - CloseHandle(lsp->stop_event); - HeapFree(GetProcessHeap(), 0, lsp); - return HRESULT_FROM_WIN32(GetLastError()); - } - - *registration = lsp; - return S_OK; -} + size = GlobalSize(hmem); + if (!(obj = heap_alloc(FIELD_OFFSET(MInterfacePointer, abData[size])))) + return E_OUTOFMEMORY; + obj->ulCntData = size; + ptr = GlobalLock(hmem); + memcpy(obj->abData, ptr, size); + GlobalUnlock(hmem); -void rpc_stop_local_server(void *registration) -{ - struct local_server_params *lsp = registration; + hr = rpcss_server_register(clsid, flags, obj, cookie); - /* signal local_server_thread to stop */ - SetEvent(lsp->stop_event); - /* wait for it to exit */ - WaitForSingleObject(lsp->thread, INFINITE); + heap_free(obj); - IStream_Release(lsp->stream); - CloseHandle(lsp->stop_event); - CloseHandle(lsp->thread); - HeapFree(GetProcessHeap(), 0, lsp); + return hr; } static HRESULT unmarshal_ORPCTHAT(RPC_MESSAGE *msg, ORPCTHAT *orpcthat, ORPC_EXTENT_ARRAY *orpc_ext_array, diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index f4fe82de436..c37a8ac6098 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -29,8 +29,6 @@ * * TODO list: (items bunched together depend on each other) * - * - Implement the service control manager (in rpcss) to keep track - * of registered class objects: ISCM::ServerRegisterClsid et al * - Implement the OXID resolver so we don't need magic endpoint names for * clients and servers to meet up * diff --git a/include/wine/irpcss.idl b/include/wine/irpcss.idl index 1874e100254..5d27658eba5 100644 --- a/include/wine/irpcss.idl +++ b/include/wine/irpcss.idl @@ -17,6 +17,7 @@ */ import "wtypes.idl"; +#include "wine/orpc.idl" cpp_quote("#define IRPCSS_PROTSEQ {'n','c','a','l','r','p','c',0}") cpp_quote("#define IRPCSS_ENDPOINT {'i','r','p','c','s','s',0}") @@ -27,6 +28,22 @@ cpp_quote("#define IRPCSS_ENDPOINT {'i','r','p','c','s','s',0}") ] interface Irpcss { + HRESULT irpcss_server_register( + [in] handle_t handle, + [in] const GUID *clsid, + [in] unsigned int flags, + [in] PMInterfacePointer object, + [out] unsigned int *cookie); + + HRESULT irpcss_server_revoke( + [in] handle_t handle, + [in] unsigned int cookie); + + HRESULT irpcss_get_class_object( + [in] handle_t handle, + [in] const GUID *clsid, + [out] PMInterfacePointer *object); + HRESULT irpcss_get_thread_seq_id( [in] handle_t handle, [out] DWORD *sequence_id); diff --git a/programs/rpcss/rpcss_main.c b/programs/rpcss/rpcss_main.c index 6e85ef2c337..e3859e4c3c9 100644 --- a/programs/rpcss/rpcss_main.c +++ b/programs/rpcss/rpcss_main.c @@ -31,6 +31,8 @@ #include "irpcss.h" #include "wine/debug.h" +#include "wine/heap.h" +#include "wine/list.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); @@ -38,6 +40,104 @@ static WCHAR rpcssW[] = {'R','p','c','S','s',0}; static HANDLE exit_event; static SERVICE_STATUS_HANDLE service_handle; +struct registered_class +{ + struct list entry; + GUID clsid; + unsigned int cookie; + PMInterfacePointer object; + unsigned int single_use : 1; +}; + +static CRITICAL_SECTION registered_classes_cs = { NULL, -1, 0, 0, 0, 0 }; +static struct list registered_classes = LIST_INIT(registered_classes); + +HRESULT __cdecl irpcss_server_register(handle_t h, const GUID *clsid, DWORD flags, + PMInterfacePointer object, unsigned int *cookie) +{ + struct registered_class *entry; + static int next_cookie; + + if (!(entry = heap_alloc_zero(sizeof(*entry)))) + return E_OUTOFMEMORY; + + entry->clsid = *clsid; + entry->single_use = !(flags & (REGCLS_MULTIPLEUSE | REGCLS_MULTI_SEPARATE)); + if (!(entry->object = heap_alloc(FIELD_OFFSET(MInterfacePointer, abData[object->ulCntData])))) + { + heap_free(entry); + return E_OUTOFMEMORY; + } + entry->object->ulCntData = object->ulCntData; + memcpy(&entry->object->abData, object->abData, object->ulCntData); + *cookie = entry->cookie = InterlockedIncrement(&next_cookie); + + EnterCriticalSection(®istered_classes_cs); + list_add_tail(®istered_classes, &entry->entry); + LeaveCriticalSection(®istered_classes_cs); + + return S_OK; +} + +static void scm_revoke_class(struct registered_class *_class) +{ + list_remove(&_class->entry); + heap_free(_class->object); + heap_free(_class); +} + +HRESULT __cdecl irpcss_server_revoke(handle_t h, unsigned int cookie) +{ + struct registered_class *cur; + + EnterCriticalSection(®istered_classes_cs); + + LIST_FOR_EACH_ENTRY(cur, ®istered_classes, struct registered_class, entry) + { + if (cur->cookie == cookie) + { + scm_revoke_class(cur); + break; + } + } + + LeaveCriticalSection(®istered_classes_cs); + + return S_OK; +} + +HRESULT __cdecl irpcss_get_class_object(handle_t h, const GUID *clsid, + PMInterfacePointer *object) +{ + struct registered_class *cur; + + *object = NULL; + + EnterCriticalSection(®istered_classes_cs); + + LIST_FOR_EACH_ENTRY(cur, ®istered_classes, struct registered_class, entry) + { + if (!memcmp(clsid, &cur->clsid, sizeof(*clsid))) + { + *object = MIDL_user_allocate(FIELD_OFFSET(MInterfacePointer, abData[cur->object->ulCntData])); + if (*object) + { + (*object)->ulCntData = cur->object->ulCntData; + memcpy((*object)->abData, cur->object->abData, cur->object->ulCntData); + } + + if (cur->single_use) + scm_revoke_class(cur); + + break; + } + } + + LeaveCriticalSection(®istered_classes_cs); + + return *object ? S_OK : E_NOINTERFACE; +} + HRESULT __cdecl irpcss_get_thread_seq_id(handle_t h, DWORD *id) { static LONG thread_seq_id; -- 2.28.0
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=77926 Your paranoid android. === debiant (32 bit Chinese:China report) === ole32: clipboard.c:887: Test failed: IDataObject_GetData failed with error 0x800401d0 clipboard.c:892: Test failed: IDataObject_GetData failed with error 0x800401d0 clipboard.c:897: Test failed: IDataObject_GetData failed with error 0x800401d0 clipboard.c:900: Test failed: DataObjectImpl_GetData called 5 times instead of 1 times clipboard.c:864: Test failed: didn't find cf_dataobject clipboard.c:865: Test failed: didn't find cf_ole_priv_data clipboard.c:626: Test failed: got 800401d0 clipboard.c:1019: Test failed: failed to clear clipboard, hr = 0x800401d0. clipboard.c:626: Test failed: got 800401d0 clipboard.c:1029: Test failed: expected data_cmpl ref=0, got 4 === debiant (64 bit WoW report) === ole32: clipboard.c:1529: Test failed: gle 5 clipboard.c:1531: Test failed: gle 1418 clipboard.c:1533: Test failed: gle 1418 clipboard.c:1544: Test failed: got 00000000 clipboard.c:1585: Test failed: tymed 1 clipboard.c:1588: Test failed: got 00000001 clipboard.c:1589: Test failed: cf 0001 clipboard.c:1593: Test failed: tymed 1 clipboard.c:1596: Test failed: got 00000001 clipboard.c:1597: Test failed: cf 0001 clipboard.c:1601: Test failed: tymed 1 clipboard.c:1604: Test failed: got 00000001 clipboard.c:1605: Test failed: cf 0001 clipboard.c:1609: Test failed: tymed 1 clipboard.c:1612: Test failed: got 00000001 clipboard.c:1614: Test failed: cf 0001 clipboard.c:1621: Test failed: got 00000001 clipboard.c:1623: Test failed: cf 0001 clipboard.c:1627: Test failed: tymed 1 clipboard.c:1630: Test failed: got 00000001 clipboard.c:1631: Test failed: cf 0001 clipboard.c:1635: Test failed: tymed 1 clipboard.c:1638: Test failed: got 00000001 clipboard.c:1639: Test failed: cf 0001 clipboard.c:1643: Test failed: tymed 1 clipboard.c:1658: Test failed: got 80040069 clipboard.c:1659: Test failed: got 0
Signed-off-by: Huw Davies <huw(a)codeweavers.com>
participants (3)
-
Huw Davies -
Marvin -
Nikolay Sivov