Signed-off-by: Nikolay Sivov nsivov@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()
Signed-off-by: Nikolay Sivov nsivov@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
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@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@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", ], [
Signed-off-by: Huw Davies huw@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@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;
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@codeweavers.com