diff --git a/dlls/wmp/Makefile.in b/dlls/wmp/Makefile.in index 71ca0e5c7af..273e536561f 100644 --- a/dlls/wmp/Makefile.in +++ b/dlls/wmp/Makefile.in @@ -1,7 +1,8 @@ MODULE = wmp.dll -IMPORTS = user32 gdi32 oleaut32 +IMPORTS = oleaut32 ole32 user32 gdi32 C_SRCS = \ + events.c \ oleobj.c \ player.c \ wmp_main.c diff --git a/dlls/wmp/events.c b/dlls/wmp/events.c new file mode 100644 index 00000000000..a908834010d --- /dev/null +++ b/dlls/wmp/events.c @@ -0,0 +1,402 @@ +/* + * Implementation of event-related interfaces for WMP control: + * + * - IConnectionPointContainer + * - IConnectionPoint + * + * Copyright 2001 John R. Sheets (for CodeWeavers) + * Copyright 2006 Jacek Caban for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include "wmp_private.h" +#include "olectl.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(wmp); + +static inline WindowsMediaPlayer *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface) +{ + return CONTAINING_RECORD(iface, WindowsMediaPlayer, IConnectionPointContainer_iface); +} + +static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface, + REFIID riid, LPVOID *ppv) +{ + WindowsMediaPlayer *This = impl_from_IConnectionPointContainer(iface); + return IOleObject_QueryInterface(&This->IOleObject_iface, riid, ppv); +} + +static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface) +{ + WindowsMediaPlayer *This = impl_from_IConnectionPointContainer(iface); + return IOleObject_AddRef(&This->IOleObject_iface); +} + +static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface) +{ + WindowsMediaPlayer *This = impl_from_IConnectionPointContainer(iface); + return IOleObject_Release(&This->IOleObject_iface); +} + +static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface, + IEnumConnectionPoints **ppEnum) +{ + WindowsMediaPlayer *This = impl_from_IConnectionPointContainer(iface); + FIXME("(%p)->(%p)\n", This, ppEnum); + return E_NOTIMPL; +} + +static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface, + REFIID riid, IConnectionPoint **ppCP){ + WindowsMediaPlayer *This = impl_from_IConnectionPointContainer(iface); + + if(!ppCP) { + WARN("ppCP == NULL\n"); + return E_POINTER; + } + + *ppCP = NULL; + + if(IsEqualGUID(&IID__WMPOCXEvents, riid)) { + TRACE("(%p)->(IID__WMPOCXEvents %p)\n", This, ppCP); + *ppCP = &This->wmpocx->IConnectionPoint_iface; + } + + if(*ppCP) { + IConnectionPoint_AddRef(*ppCP); + return S_OK; + } + + WARN("Unsupported IID %s\n", debugstr_guid(riid)); + return CONNECT_E_NOCONNECTION; +} + +static const IConnectionPointContainerVtbl ConnectionPointContainerVtbl = +{ + ConnectionPointContainer_QueryInterface, + ConnectionPointContainer_AddRef, + ConnectionPointContainer_Release, + ConnectionPointContainer_EnumConnectionPoints, + ConnectionPointContainer_FindConnectionPoint +}; + +static inline ConnectionPoint *impl_from_IConnectionPoint(IConnectionPoint *iface) +{ + return CONTAINING_RECORD(iface, ConnectionPoint, IConnectionPoint_iface); +} + +typedef struct { + IEnumConnections IEnumConnections_iface; + + LONG ref; + + ConnectionPoint *cp; + DWORD iter; +} EnumConnections; + +static inline EnumConnections *impl_from_IEnumConnections(IEnumConnections *iface) +{ + return CONTAINING_RECORD(iface, EnumConnections, IEnumConnections_iface); +} + +static HRESULT WINAPI EnumConnections_QueryInterface(IEnumConnections *iface, REFIID riid, void **ppv) +{ + EnumConnections *This = impl_from_IEnumConnections(iface); + + if(IsEqualGUID(&IID_IUnknown, riid)) { + TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); + *ppv = &This->IEnumConnections_iface; + }else if(IsEqualGUID(&IID_IEnumConnections, riid)) { + TRACE("(%p)->(IID_IEnumConnections %p)\n", This, ppv); + *ppv = &This->IEnumConnections_iface; + }else { + WARN("Unsupported interface %s\n", debugstr_guid(riid)); + *ppv = NULL; + return E_NOINTERFACE; + } + + IUnknown_AddRef((IUnknown*)*ppv); + return S_OK; +} + +static ULONG WINAPI EnumConnections_AddRef(IEnumConnections *iface) +{ + EnumConnections *This = impl_from_IEnumConnections(iface); + LONG ref = InterlockedIncrement(&This->ref); + + TRACE("(%p) ref=%d\n", This, ref); + + return ref; +} + +static ULONG WINAPI EnumConnections_Release(IEnumConnections *iface) +{ + EnumConnections *This = impl_from_IEnumConnections(iface); + LONG ref = InterlockedDecrement(&This->ref); + + TRACE("(%p) ref=%d\n", This, ref); + + if(!ref) { + IConnectionPoint_Release(&This->cp->IConnectionPoint_iface); + heap_free(This); + } + + return ref; +} + +static HRESULT WINAPI EnumConnections_Next(IEnumConnections *iface, ULONG cConnections, CONNECTDATA *pgcd, ULONG *pcFetched) +{ + EnumConnections *This = impl_from_IEnumConnections(iface); + ULONG cnt = 0; + + TRACE("(%p)->(%u %p %p)\n", This, cConnections, pgcd, pcFetched); + + while(cConnections--) { + while(This->iter < This->cp->sinks_size && !This->cp->sinks[This->iter]) + This->iter++; + if(This->iter == This->cp->sinks_size) + break; + + pgcd[cnt].pUnk = (IUnknown*)This->cp->sinks[This->iter]; + pgcd[cnt].dwCookie = cnt+1; + This->iter++; + cnt++; + IUnknown_AddRef(pgcd[cnt].pUnk); + } + + if(pcFetched) + *pcFetched = cnt; + return cnt ? S_OK : S_FALSE; +} + +static HRESULT WINAPI EnumConnections_Skip(IEnumConnections *iface, ULONG cConnections) +{ + EnumConnections *This = impl_from_IEnumConnections(iface); + FIXME("(%p)->(%u)\n", This, cConnections); + return E_NOTIMPL; +} + +static HRESULT WINAPI EnumConnections_Reset(IEnumConnections *iface) +{ + EnumConnections *This = impl_from_IEnumConnections(iface); + FIXME("(%p)\n", This); + return E_NOTIMPL; +} + +static HRESULT WINAPI EnumConnections_Clone(IEnumConnections *iface, IEnumConnections **ppEnum) +{ + EnumConnections *This = impl_from_IEnumConnections(iface); + FIXME("(%p)->(%p)\n", This, ppEnum); + return E_NOTIMPL; +} + +static const IEnumConnectionsVtbl EnumConnectionsVtbl = { + EnumConnections_QueryInterface, + EnumConnections_AddRef, + EnumConnections_Release, + EnumConnections_Next, + EnumConnections_Skip, + EnumConnections_Reset, + EnumConnections_Clone +}; + +static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface, + REFIID riid, LPVOID *ppv) +{ + ConnectionPoint *This = impl_from_IConnectionPoint(iface); + + *ppv = NULL; + + if(IsEqualGUID(&IID_IUnknown, riid)) { + TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv); + *ppv = &This->IConnectionPoint_iface; + }else if(IsEqualGUID(&IID_IConnectionPoint, riid)) { + TRACE("(%p)->(IID_IConnectionPoint %p)\n", This, ppv); + *ppv = &This->IConnectionPoint_iface; + } + + if(*ppv) { + IConnectionPointContainer_AddRef(This->container); + return S_OK; + } + + WARN("Unsupported interface %s\n", debugstr_guid(riid)); + return E_NOINTERFACE; +} + +static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface) +{ + ConnectionPoint *This = impl_from_IConnectionPoint(iface); + return IConnectionPointContainer_AddRef(This->container); +} + +static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface) +{ + ConnectionPoint *This = impl_from_IConnectionPoint(iface); + return IConnectionPointContainer_Release(This->container); +} + +static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *pIID) +{ + ConnectionPoint *This = impl_from_IConnectionPoint(iface); + + TRACE("(%p)->(%p)\n", This, pIID); + + *pIID = This->iid; + return S_OK; +} + +static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface, + IConnectionPointContainer **ppCPC) +{ + ConnectionPoint *This = impl_from_IConnectionPoint(iface); + + TRACE("(%p)->(%p)\n", This, ppCPC); + + *ppCPC = This->container; + IConnectionPointContainer_AddRef(This->container); + return S_OK; +} + +static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink, + DWORD *pdwCookie) +{ + ConnectionPoint *This = impl_from_IConnectionPoint(iface); + IDispatch *disp; + DWORD i; + HRESULT hres; + + TRACE("(%p)->(%p %p)\n", This, pUnkSink, pdwCookie); + + hres = IUnknown_QueryInterface(pUnkSink, &This->iid, (void**)&disp); + if(FAILED(hres)) { + hres = IUnknown_QueryInterface(pUnkSink, &IID_IDispatch, (void**)&disp); + if(FAILED(hres)) + return CONNECT_E_CANNOTCONNECT; + } + + if(This->sinks) { + for(i=0; isinks_size; i++) { + if(!This->sinks[i]) + break; + } + + if(i == This->sinks_size) + This->sinks = heap_realloc(This->sinks, + (++This->sinks_size)*sizeof(*This->sinks)); + }else { + This->sinks = heap_alloc(sizeof(*This->sinks)); + This->sinks_size = 1; + i = 0; + } + + This->sinks[i] = disp; + *pdwCookie = i+1; + + return S_OK; +} + +static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD dwCookie) +{ + ConnectionPoint *This = impl_from_IConnectionPoint(iface); + + TRACE("(%p)->(%d)\n", This, dwCookie); + + if(!dwCookie || dwCookie > This->sinks_size || !This->sinks[dwCookie-1]) + return CONNECT_E_NOCONNECTION; + + IDispatch_Release(This->sinks[dwCookie-1]); + This->sinks[dwCookie-1] = NULL; + + return S_OK; +} + +static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface, + IEnumConnections **ppEnum) +{ + ConnectionPoint *This = impl_from_IConnectionPoint(iface); + EnumConnections *ret; + + TRACE("(%p)->(%p)\n", This, ppEnum); + + ret = heap_alloc(sizeof(*ret)); + if(!ret) + return E_OUTOFMEMORY; + + ret->IEnumConnections_iface.lpVtbl = &EnumConnectionsVtbl; + ret->ref = 1; + ret->iter = 0; + + IConnectionPoint_AddRef(&This->IConnectionPoint_iface); + ret->cp = This; + + *ppEnum = &ret->IEnumConnections_iface; + return S_OK; +} + + +static const IConnectionPointVtbl ConnectionPointVtbl = +{ + ConnectionPoint_QueryInterface, + ConnectionPoint_AddRef, + ConnectionPoint_Release, + ConnectionPoint_GetConnectionInterface, + ConnectionPoint_GetConnectionPointContainer, + ConnectionPoint_Advise, + ConnectionPoint_Unadvise, + ConnectionPoint_EnumConnections +}; + +static void ConnectionPoint_Destroy(ConnectionPoint *This) +{ + DWORD i; + + for(i=0; isinks_size; i++) { + if(This->sinks[i]) + IDispatch_Release(This->sinks[i]); + } + + heap_free(This->sinks); + heap_free(This); +} + +static void ConnectionPoint_Create(REFIID riid, ConnectionPoint **cp, + IConnectionPointContainer *container) +{ + ConnectionPoint *ret = heap_alloc(sizeof(ConnectionPoint)); + + ret->IConnectionPoint_iface.lpVtbl = &ConnectionPointVtbl; + + ret->sinks = NULL; + ret->sinks_size = 0; + ret->container = container; + + ret->iid = *riid; + + *cp = ret; +} + +void ConnectionPointContainer_Init(WindowsMediaPlayer *wmp) +{ + wmp->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl; + ConnectionPoint_Create(&IID__WMPOCXEvents, &wmp->wmpocx, &wmp->IConnectionPointContainer_iface); +} + +void ConnectionPointContainer_Destroy(WindowsMediaPlayer *wmp) +{ + ConnectionPoint_Destroy(wmp->wmpocx); +} diff --git a/dlls/wmp/oleobj.c b/dlls/wmp/oleobj.c index 167b8932061..1baf45a439b 100644 --- a/dlls/wmp/oleobj.c +++ b/dlls/wmp/oleobj.c @@ -307,6 +307,7 @@ static ULONG WINAPI OleObject_Release(IOleObject *iface) if(!ref) { release_client_site(This); + ConnectionPointContainer_Destroy(This); heap_free(This); } @@ -875,55 +876,6 @@ static const IPersistStreamInitVtbl PersistStreamInitVtbl = { PersistStreamInit_InitNew }; -static inline WindowsMediaPlayer *impl_from_IConnectionPointContainer(IConnectionPointContainer *iface) -{ - return CONTAINING_RECORD(iface, WindowsMediaPlayer, IConnectionPointContainer_iface); -} - -static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface, - REFIID riid, LPVOID *ppv) -{ - WindowsMediaPlayer *This = impl_from_IConnectionPointContainer(iface); - return IOleObject_QueryInterface(&This->IOleObject_iface, riid, ppv); -} - -static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface) -{ - WindowsMediaPlayer *This = impl_from_IConnectionPointContainer(iface); - return IOleObject_AddRef(&This->IOleObject_iface); -} - -static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface) -{ - WindowsMediaPlayer *This = impl_from_IConnectionPointContainer(iface); - return IOleObject_Release(&This->IOleObject_iface); -} - -static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface, - IEnumConnectionPoints **ppEnum) -{ - WindowsMediaPlayer *This = impl_from_IConnectionPointContainer(iface); - FIXME("(%p)->(%p)\n", This, ppEnum); - return E_NOTIMPL; -} - -static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface, - REFIID riid, IConnectionPoint **ppCP) -{ - WindowsMediaPlayer *This = impl_from_IConnectionPointContainer(iface); - FIXME("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppCP); - return CONNECT_E_NOCONNECTION; -} - -static const IConnectionPointContainerVtbl ConnectionPointContainerVtbl = -{ - ConnectionPointContainer_QueryInterface, - ConnectionPointContainer_AddRef, - ConnectionPointContainer_Release, - ConnectionPointContainer_EnumConnectionPoints, - ConnectionPointContainer_FindConnectionPoint -}; - HRESULT WINAPI WMPFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, REFIID riid, void **ppv) { @@ -942,13 +894,13 @@ HRESULT WINAPI WMPFactory_CreateInstance(IClassFactory *iface, IUnknown *outer, wmp->IProvideClassInfo2_iface.lpVtbl = &ProvideClassInfo2Vtbl; wmp->IPersistStreamInit_iface.lpVtbl = &PersistStreamInitVtbl; wmp->IOleInPlaceObjectWindowless_iface.lpVtbl = &OleInPlaceObjectWindowlessVtbl; - wmp->IConnectionPointContainer_iface.lpVtbl = &ConnectionPointContainerVtbl; wmp->IOleControl_iface.lpVtbl = &OleControlVtbl; wmp->ref = 1; init_player_ifaces(wmp); + ConnectionPointContainer_Init(wmp); hdc = GetDC(0); dpi_x = GetDeviceCaps(hdc, LOGPIXELSX); dpi_y = GetDeviceCaps(hdc, LOGPIXELSY); diff --git a/dlls/wmp/tests/oleobj.c b/dlls/wmp/tests/oleobj.c index 05861e1c100..46b0b72cd34 100644 --- a/dlls/wmp/tests/oleobj.c +++ b/dlls/wmp/tests/oleobj.c @@ -495,6 +495,43 @@ static const IDispatchVtbl DispatchVtbl = { static IDispatch Dispatch = { &DispatchVtbl }; +static HRESULT WINAPI WMPOCXEvents_QueryInterface(IDispatch *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + + if(IsEqualGUID(&IID__WMPOCXEvents, riid) || IsEqualGUID(&IID_IDispatch, riid)) { + *ppv = iface; + return S_OK; + } + + ok(0, "unexpected riid %s\n", wine_dbgstr_guid(riid)); + return E_NOINTERFACE; +} + +static HRESULT WINAPI WMPOCXEvents_Invoke(IDispatch *iface, DISPID dispIdMember, REFIID riid, + LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, UINT *puArgErr) +{ + switch(dispIdMember) { + default: + ok(0, "unexpected call Invoke(%d)\n", dispIdMember); + } + + return E_NOTIMPL; +} + +static IDispatchVtbl WMPOcxEventsVtbl = { + WMPOCXEvents_QueryInterface, + Dispatch_AddRef, + Dispatch_Release, + Dispatch_GetTypeInfoCount, + Dispatch_GetTypeInfo, + Dispatch_GetIDsOfNames, + WMPOCXEvents_Invoke, +}; + +static IDispatch WMPOCXEvents = { &WMPOcxEventsVtbl }; + static HRESULT WINAPI InPlaceSiteWindowless_QueryInterface(IOleInPlaceSiteWindowless *iface, REFIID riid, void **ppv) { return cs_qi(riid, ppv); @@ -788,6 +825,35 @@ static HRESULT cs_qi(REFIID riid, void **ppv) return S_OK; } +static void test_ConnectionPoint(IOleObject *unk) +{ + IConnectionPointContainer *container; + IConnectionPoint *point; + HRESULT hres; + + static DWORD dw = 100; + + hres = IOleObject_QueryInterface(unk, &IID_IConnectionPointContainer, (void**)&container); + ok(hres == S_OK, "QueryInterface(IID_IConnectionPointContainer) failed: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IConnectionPointContainer_FindConnectionPoint(container, &IID__WMPOCXEvents, &point); + IConnectionPointContainer_Release(container); + ok(hres == S_OK, "FindConnectionPoint failed: %08x\n", hres); + if(FAILED(hres)) + return; + + hres = IConnectionPoint_Advise(point, (IUnknown*)&WMPOCXEvents, &dw); + ok(hres == S_OK, "Advise failed: %08x\n", hres); + ok(dw == 1, "dw=%d, expected 1\n", dw); + hres = IConnectionPoint_Unadvise(point, dw); + ok(hres == S_OK, "Unadvise failed: %08x\n", hres); + + IConnectionPoint_Release(point); +} + + static void test_wmp_ifaces(IOleObject *oleobj) { IWMPSettings *settings, *settings_qi; @@ -913,7 +979,7 @@ static void test_IConnectionPointContainer(IOleObject *oleobj) point = NULL; hres = IConnectionPointContainer_FindConnectionPoint(container, &IID__WMPOCXEvents, &point); - todo_wine ok(hres == S_OK, "got: %08x\n", hres); + ok(hres == S_OK, "got: %08x\n", hres); if(point) IConnectionPoint_Release(point); @@ -1113,6 +1179,8 @@ static void test_wmp(void) ok(hres == E_FAIL || broken(hres == S_OK), "GetClientSite failed: %08x\n", hres); ok(!client_site, "client_site = %p\n", client_site); + test_ConnectionPoint(oleobj); + IPersistStreamInit_Release(psi); IOleInPlaceObject_Release(ipobj); diff --git a/dlls/wmp/wmp_private.h b/dlls/wmp/wmp_private.h index 1af0aef8034..710793c513e 100644 --- a/dlls/wmp/wmp_private.h +++ b/dlls/wmp/wmp_private.h @@ -19,9 +19,21 @@ #define COBJMACROS #include "windows.h" +#include "wine/heap.h" #include "ole2.h" #include "wmp.h" +typedef struct { + IConnectionPoint IConnectionPoint_iface; + + IConnectionPointContainer *container; + + IDispatch **sinks; + DWORD sinks_size; + + IID iid; +} ConnectionPoint; + struct WindowsMediaPlayer { IOleObject IOleObject_iface; IProvideClassInfo2 IProvideClassInfo2_iface; @@ -38,9 +50,13 @@ struct WindowsMediaPlayer { IOleClientSite *client_site; HWND hwnd; SIZEL extent; + + ConnectionPoint *wmpocx; }; void init_player_ifaces(WindowsMediaPlayer*) DECLSPEC_HIDDEN; +void ConnectionPointContainer_Init(WindowsMediaPlayer *wmp) DECLSPEC_HIDDEN; +void ConnectionPointContainer_Destroy(WindowsMediaPlayer *wmp) DECLSPEC_HIDDEN; HRESULT WINAPI WMPFactory_CreateInstance(IClassFactory*,IUnknown*,REFIID,void**) DECLSPEC_HIDDEN;