Signed-off-by: Anton Romanov theli.ua@gmail.com --- Use unique window message via RegisterWindowMessageW
dlls/wmp/oleobj.c | 26 ++++++----- dlls/wmp/player.c | 94 ++++++++++++++++++++++++++++++++++++++- dlls/wmp/tests/media.c | 109 ++++++++++++++++++++++++++++++++++++++++++++++ dlls/wmp/tests/rsrc.rc | 3 ++ dlls/wmp/tests/test1s.mp3 | Bin 0 -> 4365 bytes dlls/wmp/wmp_main.c | 1 + dlls/wmp/wmp_private.h | 7 ++- 7 files changed, 225 insertions(+), 15 deletions(-) create mode 100644 dlls/wmp/tests/test1s.mp3
diff --git a/dlls/wmp/oleobj.c b/dlls/wmp/oleobj.c index cbf183c1f6..a90a0c2c6c 100644 --- a/dlls/wmp/oleobj.c +++ b/dlls/wmp/oleobj.c @@ -899,18 +899,20 @@ HRESULT WINAPI WMPFactory_CreateInstance(IClassFactory *iface, IUnknown *outer,
wmp->ref = 1;
- init_player(wmp); - - ConnectionPointContainer_Init(wmp); - hdc = GetDC(0); - dpi_x = GetDeviceCaps(hdc, LOGPIXELSX); - dpi_y = GetDeviceCaps(hdc, LOGPIXELSY); - ReleaseDC(0, hdc); - - wmp->extent.cx = MulDiv(192, 2540, dpi_x); - wmp->extent.cy = MulDiv(192, 2540, dpi_y); - - hres = IOleObject_QueryInterface(&wmp->IOleObject_iface, riid, ppv); + if (init_player(wmp)) { + ConnectionPointContainer_Init(wmp); + hdc = GetDC(0); + dpi_x = GetDeviceCaps(hdc, LOGPIXELSX); + dpi_y = GetDeviceCaps(hdc, LOGPIXELSY); + ReleaseDC(0, hdc); + + wmp->extent.cx = MulDiv(192, 2540, dpi_x); + wmp->extent.cy = MulDiv(192, 2540, dpi_y); + + hres = IOleObject_QueryInterface(&wmp->IOleObject_iface, riid, ppv); + } else { + hres = E_FAIL; + } IOleObject_Release(&wmp->IOleObject_iface); return hres; } diff --git a/dlls/wmp/player.c b/dlls/wmp/player.c index b9237b097c..848b90c0c5 100644 --- a/dlls/wmp/player.c +++ b/dlls/wmp/player.c @@ -24,6 +24,12 @@
WINE_DEFAULT_DEBUG_CHANNEL(wmp);
+static ATOM player_msg_class; +static INIT_ONCE class_init_once; +static UINT WM_WMPEVENT; +static const WCHAR WMPmessageW[] = {'_', 'W', 'M', 'P', 'M','e','s','s','a','g','e',0}; + + static void update_state(WindowsMediaPlayer *wmp, LONG type, LONG state) { DISPPARAMS dispparams; @@ -213,18 +219,20 @@ static HRESULT WINAPI WMPPlayer4_put_currentMedia(IWMPPlayer4 *iface, IWMPMedia { WindowsMediaPlayer *This = impl_from_IWMPPlayer4(iface); TRACE("(%p)->(%p)\n", This, pMedia); + if(pMedia == NULL) { return E_POINTER; } update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, wmposPlaylistChanging); if(This->wmpmedia != NULL) { + IWMPControls_stop(&This->IWMPControls_iface); IWMPMedia_Release(This->wmpmedia); } update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, wmposPlaylistChanged); update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, wmposPlaylistOpenNoMedia);
+ IWMPMedia_AddRef(pMedia); This->wmpmedia = pMedia; - IWMPMedia_AddRef(This->wmpmedia); return S_OK; }
@@ -1426,6 +1434,20 @@ static HRESULT WINAPI WMPControls_play(IWMPControls *iface) (void**)&This->media_control); if (SUCCEEDED(hres)) update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, wmposMediaOpen); + if (SUCCEEDED(hres)) + hres = IGraphBuilder_QueryInterface(This->filter_graph, &IID_IMediaEvent, + (void**)&This->media_event); + if (SUCCEEDED(hres)) + { + IMediaEventEx *media_event_ex = NULL; + hres = IGraphBuilder_QueryInterface(This->filter_graph, &IID_IMediaEventEx, + (void**)&media_event_ex); + if (SUCCEEDED(hres)) { + hres = IMediaEventEx_SetNotifyWindow(media_event_ex, (OAHWND)This->msg_window, + WM_WMPEVENT, (LONG_PTR)This); + IMediaEventEx_Release(media_event_ex); + } + } }
update_state(This, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, wmppsTransitioning); @@ -1458,9 +1480,15 @@ static HRESULT WINAPI WMPControls_stop(IWMPControls *iface) hres = IMediaControl_Stop(This->media_control); IMediaControl_Release(This->media_control); } + if (This->media_event) { + IMediaEvent_Release(This->media_event); + } + IGraphBuilder_Release(This->filter_graph); This->filter_graph = NULL; This->media_control = NULL; + This->media_event = NULL; + update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, wmposPlaylistOpenNoMedia); update_state(This, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, wmppsStopped); return hres; @@ -1824,8 +1852,68 @@ static const IWMPMediaVtbl WMPMediaVtbl = { WMPMedia_isReadOnlyItem };
-void init_player(WindowsMediaPlayer *wmp) +static LRESULT WINAPI player_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg == WM_WMPEVENT && wParam == 0) { + WindowsMediaPlayer *wmp = (WindowsMediaPlayer*)lParam; + LONG event_code; + LONG_PTR p1, p2; + HRESULT hr; + if (wmp->media_event) { + do { + hr = IMediaEvent_GetEvent(wmp->media_event, &event_code, &p1, &p2, 0); + if (SUCCEEDED(hr)) { + TRACE("got event_code = 0x%02x\n", event_code); + IMediaEvent_FreeEventParams(wmp->media_event, event_code, p1, p2); + /* For now we only handle EC_COMPLETE */ + if (event_code == EC_COMPLETE) { + update_state(wmp, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, wmppsMediaEnded); + update_state(wmp, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, wmppsTransitioning); + update_state(wmp, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, wmppsStopped); + } + } + } while (hr == S_OK); + } else { + FIXME("Got event from quartz when interfaces are already released\n"); + } + } + return DefWindowProcW(hwnd, msg, wParam, lParam); +} + +static BOOL WINAPI register_player_msg_class(INIT_ONCE *once, void *param, void **context) { + static WNDCLASSEXW wndclass = { + sizeof(wndclass), CS_DBLCLKS, player_wnd_proc, 0, 0, + NULL, NULL, NULL, NULL, NULL, + WMPmessageW, NULL + }; + + wndclass.hInstance = wmp_instance; + player_msg_class = RegisterClassExW(&wndclass); + return TRUE; +} + +void unregister_player_msg_class(void) { + if(player_msg_class) + UnregisterClassW(MAKEINTRESOURCEW(player_msg_class), wmp_instance); +} + +BOOL init_player(WindowsMediaPlayer *wmp) { + InitOnceExecuteOnce(&class_init_once, register_player_msg_class, NULL, NULL); + wmp->msg_window = CreateWindowW( MAKEINTRESOURCEW(player_msg_class), NULL, 0, 0, + 0, 0, 0, HWND_MESSAGE, 0, wmp_instance, wmp ); + if (!wmp->msg_window) { + ERR("Failed to create message window, GetLastError: %d\n", GetLastError()); + return FALSE; + } + if (!WM_WMPEVENT) { + WM_WMPEVENT= RegisterWindowMessageW(WMPmessageW); + } + if (!WM_WMPEVENT) { + ERR("Failed to register window message, GetLastError: %d\n", GetLastError()); + return FALSE; + } + wmp->IWMPPlayer4_iface.lpVtbl = &WMPPlayer4Vtbl; wmp->IWMPPlayer_iface.lpVtbl = &WMPPlayerVtbl; wmp->IWMPSettings_iface.lpVtbl = &WMPSettingsVtbl; @@ -1834,6 +1922,7 @@ void init_player(WindowsMediaPlayer *wmp)
wmp->invoke_urls = VARIANT_TRUE; wmp->auto_start = VARIANT_TRUE; + return TRUE; }
void destroy_player(WindowsMediaPlayer *wmp) @@ -1841,6 +1930,7 @@ void destroy_player(WindowsMediaPlayer *wmp) IWMPControls_stop(&wmp->IWMPControls_iface); if(wmp->wmpmedia) IWMPMedia_Release(wmp->wmpmedia); + DestroyWindow(wmp->msg_window); }
WMPMedia *unsafe_impl_from_IWMPMedia(IWMPMedia *iface) diff --git a/dlls/wmp/tests/media.c b/dlls/wmp/tests/media.c index 633e8ebbf4..2d1222e28a 100644 --- a/dlls/wmp/tests/media.c +++ b/dlls/wmp/tests/media.c @@ -65,9 +65,11 @@ DEFINE_EXPECT(PLAYSTATE); DEFINE_EXPECT(OPENSTATE);
static HANDLE playing_event; +static HANDLE completed_event; static DWORD main_thread_id;
static const WCHAR mp3file[] = {'t','e','s','t','.','m','p','3',0}; +static const WCHAR mp3file1s[] = {'t','e','s','t','1','s','.','m','p','3',0}; static inline WCHAR *load_resource(const WCHAR *name) { static WCHAR pathW[MAX_PATH]; @@ -151,6 +153,8 @@ static HRESULT WINAPI WMPOCXEvents_Invoke(IDispatch *iface, DISPID dispIdMember, CHECK_EXPECT(PLAYSTATE, V_UI4(pDispParams->rgvarg)); if (V_UI4(pDispParams->rgvarg) == wmppsPlaying) { SetEvent(playing_event); + } else if (V_UI4(pDispParams->rgvarg) == wmppsMediaEnded) { + SetEvent(completed_event); } if (winetest_debug > 1) trace("DISPID_WMPCOREEVENT_PLAYSTATECHANGE, %d\n", V_UI4(pDispParams->rgvarg)); @@ -188,6 +192,108 @@ static IDispatchVtbl WMPOcxEventsVtbl = {
static IDispatch WMPOCXEvents = { &WMPOcxEventsVtbl };
+static void test_completion_event(void) +{ + DWORD res = 0; + IWMPPlayer4 *player4; + HRESULT hres; + BSTR filename; + IConnectionPointContainer *container; + IConnectionPoint *point; + IOleObject *oleobj; + static DWORD dw = 100; + + hres = CoCreateInstance(&CLSID_WindowsMediaPlayer, NULL, CLSCTX_INPROC_SERVER, &IID_IOleObject, (void**)&oleobj); + if(hres == REGDB_E_CLASSNOTREG) { + win_skip("CLSID_WindowsMediaPlayer not registered\n"); + return; + } + ok(hres == S_OK, "Could not create CLSID_WindowsMediaPlayer instance: %08x\n", hres); + + hres = IOleObject_QueryInterface(oleobj, &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); + + hres = IConnectionPoint_Advise(point, (IUnknown*)&WMPOCXEvents, &dw); + ok(hres == S_OK, "Advise failed: %08x\n", hres); + + hres = IOleObject_QueryInterface(oleobj, &IID_IWMPPlayer4, (void**)&player4); + ok(hres == S_OK, "Could not get IWMPPlayer4 iface: %08x\n", hres); + + filename = SysAllocString(load_resource(mp3file1s)); + + SET_EXPECT(OPENSTATE, wmposPlaylistChanging); + SET_EXPECT(OPENSTATE, wmposPlaylistOpenNoMedia); + SET_EXPECT(OPENSTATE, wmposPlaylistChanged); + SET_EXPECT(OPENSTATE, wmposOpeningUnknownURL); + SET_EXPECT(OPENSTATE, wmposMediaOpen); + SET_EXPECT(OPENSTATE, wmposMediaOpening); + SET_EXPECT(PLAYSTATE, wmppsPlaying); + SET_EXPECT(PLAYSTATE, wmppsMediaEnded); + SET_EXPECT(PLAYSTATE, wmppsStopped); + SET_EXPECT(PLAYSTATE, wmppsTransitioning); + /* following two are sent on vistau64 vms only */ + SET_EXPECT(OPENSTATE, wmposMediaChanging); + SET_EXPECT(PLAYSTATE, wmppsReady); + hres = IWMPPlayer4_put_URL(player4, filename); + ok(hres == S_OK, "IWMPPlayer4_put_URL failed: %08x\n", hres); + + { + MSG msg; + DWORD start_time = GetTickCount(); + DWORD dwTimeout = 3000; + HANDLE handles[1]; + handles[0] = completed_event; + do { + DWORD now = GetTickCount(); + res = MsgWaitForMultipleObjectsEx(1, handles, start_time + dwTimeout - now, + QS_ALLINPUT ,MWMO_ALERTABLE | MWMO_INPUTAVAILABLE); + if (res == WAIT_OBJECT_0 + 1) { + GetMessageW(&msg, 0, 0, 0); + if (winetest_debug > 1) + trace("Dispatching %d\n", msg.message); + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + while (res == WAIT_OBJECT_0 + 1 || res == WAIT_IO_COMPLETION); + ok(res == WAIT_OBJECT_0 || broken(res == WAIT_TIMEOUT), "Timed out while waiting for media to complete\n"); + } + + if (res == WAIT_TIMEOUT) { + /* This happens on Vista Ultimate 64 vms + * I have been unable to find out source of this behaviour */ + win_skip("Failed to play media\n"); + goto playback_skip; + } + CHECK_CALLED(OPENSTATE, wmposPlaylistChanging); + CHECK_CALLED(OPENSTATE, wmposPlaylistChanged); + CHECK_CALLED(OPENSTATE, wmposPlaylistOpenNoMedia); + CHECK_CALLED(PLAYSTATE, wmppsTransitioning); + CHECK_CALLED(OPENSTATE, wmposOpeningUnknownURL); + CHECK_CALLED(OPENSTATE, wmposMediaOpen); + /* MediaOpening happens only on xp, 2003 */ + todo_wine CHECK_CALLED_OR_BROKEN(OPENSTATE, wmposMediaOpening); + CHECK_CALLED(PLAYSTATE, wmppsPlaying); + CHECK_CALLED(PLAYSTATE, wmppsMediaEnded); + CHECK_CALLED(PLAYSTATE, wmppsStopped); + +playback_skip: + hres = IConnectionPoint_Unadvise(point, dw); + ok(hres == S_OK, "Unadvise failed: %08x\n", hres); + + IConnectionPoint_Release(point); + IWMPPlayer4_Release(player4); + IOleObject_Release(oleobj); + DeleteFileW(filename); + SysFreeString(filename); +} + static void test_wmp(void) { DWORD res = 0; @@ -339,9 +445,12 @@ START_TEST(media)
main_thread_id = GetCurrentThreadId(); playing_event = CreateEventW(NULL, FALSE, FALSE, NULL); + completed_event = CreateEventW(NULL, FALSE, FALSE, NULL); test_wmp(); + test_completion_event();
CloseHandle(playing_event); + CloseHandle(completed_event);
CoUninitialize(); } diff --git a/dlls/wmp/tests/rsrc.rc b/dlls/wmp/tests/rsrc.rc index f33acc1256..ea25a2dea1 100644 --- a/dlls/wmp/tests/rsrc.rc +++ b/dlls/wmp/tests/rsrc.rc @@ -21,3 +21,6 @@ /* ffmpeg -ar 48000 -t 60 -f s16le -acodec pcm_s16le -ac 2 -i /dev/zero -acodec libmp3lame -aq 4 output.mp3 */ /* @makedep: test.mp3 */ test.mp3 RCDATA "test.mp3" +/* ffmpeg -ar 48000 -t 1 -f s16le -acodec pcm_s16le -ac 2 -i /dev/zero -acodec libmp3lame -aq 4 dlls/wmp/tests/test1s.mp3 */ +/* @makedep: test1s.mp3 */ +test1s.mp3 RCDATA "test1s.mp3" diff --git a/dlls/wmp/tests/test1s.mp3 b/dlls/wmp/tests/test1s.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..3e0b407e3fb8b292bf47fdb383a42b66d06d5568 GIT binary patch literal 4365 zcmeZtF=k-^0p*b3U{@f`&%nU!lUSB!YOZHttY>Io0G5Ri|9^)d@vt*J^V0HxGC*S( zv>6x#9xw<Biiyd{C@CqatLy3-8yj0#*x9+bxOjT{`-g^xMn@+kq@|_h<P;W`mzUSp zHZ^s0boBL2o;-8r%=z<|ELpW`)rJk*w(Z`%`{2Rj$IqNObLrBJ8+Y&Cef;?4%XjbI zefje1*Z=<@mjK<I40N+0vU?d+m=A#DK<=10|Dfvs-y$gt{2v$?GJ!%I3=F&q3=E7w zv;@cnGEEv77+8E9eO<x+209J{;FSyw1(`2Lz<dldkp+k_--gEKN72~)3L2X~jmGA0 zp|SawXl(w&e*EblIXPmmiAbNL=7S1NjF1BhfXau_@EHvs?5P7NI-0*&aE1*?Vl;e4 m!)LVq8m(V&6%wQ6!@!mgxZ(vWPI3EZ)O`H$I~qO|g%1GKzMp&m
literal 0 HcmV?d00001
diff --git a/dlls/wmp/wmp_main.c b/dlls/wmp/wmp_main.c index 9a33b2762b..273d193e58 100644 --- a/dlls/wmp/wmp_main.c +++ b/dlls/wmp/wmp_main.c @@ -92,6 +92,7 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) break; case DLL_PROCESS_DETACH: unregister_wmp_class(); + unregister_player_msg_class(); break; }
diff --git a/dlls/wmp/wmp_private.h b/dlls/wmp/wmp_private.h index 9e84d56ea8..3792e52abd 100644 --- a/dlls/wmp/wmp_private.h +++ b/dlls/wmp/wmp_private.h @@ -75,9 +75,13 @@ struct WindowsMediaPlayer { /* DirectShow stuff */ IGraphBuilder* filter_graph; IMediaControl* media_control; + IMediaEvent* media_event; + + /* Async event notification */ + HWND msg_window; };
-void init_player(WindowsMediaPlayer*) DECLSPEC_HIDDEN; +BOOL init_player(WindowsMediaPlayer*) DECLSPEC_HIDDEN; void destroy_player(WindowsMediaPlayer*) DECLSPEC_HIDDEN; WMPMedia *unsafe_impl_from_IWMPMedia(IWMPMedia *iface) DECLSPEC_HIDDEN; HRESULT create_media_from_url(BSTR url, IWMPMedia **ppMedia) DECLSPEC_HIDDEN; @@ -88,6 +92,7 @@ void call_sink(ConnectionPoint *This, DISPID dispid, DISPPARAMS *dispparams) DEC HRESULT WINAPI WMPFactory_CreateInstance(IClassFactory*,IUnknown*,REFIID,void**) DECLSPEC_HIDDEN;
void unregister_wmp_class(void) DECLSPEC_HIDDEN; +void unregister_player_msg_class(void) DECLSPEC_HIDDEN;
extern HINSTANCE wmp_instance DECLSPEC_HIDDEN;
Signed-off-by: Anton Romanov theli.ua@gmail.com --- Moved pumping messages to a helper function dlls/wmp/oleobj.c | 26 ++++++----- dlls/wmp/player.c | 94 +++++++++++++++++++++++++++++++++++++- dlls/wmp/tests/media.c | 89 ++++++++++++++++++++++++++++++++++++ dlls/wmp/tests/rsrc.rc | 3 ++ dlls/wmp/tests/test1s.mp3 | Bin 0 -> 4365 bytes dlls/wmp/wmp_main.c | 1 + dlls/wmp/wmp_private.h | 7 ++- 7 files changed, 205 insertions(+), 15 deletions(-) create mode 100644 dlls/wmp/tests/test1s.mp3
diff --git a/dlls/wmp/oleobj.c b/dlls/wmp/oleobj.c index cbf183c1f6..a90a0c2c6c 100644 --- a/dlls/wmp/oleobj.c +++ b/dlls/wmp/oleobj.c @@ -899,18 +899,20 @@ HRESULT WINAPI WMPFactory_CreateInstance(IClassFactory *iface, IUnknown *outer,
wmp->ref = 1;
- init_player(wmp); - - ConnectionPointContainer_Init(wmp); - hdc = GetDC(0); - dpi_x = GetDeviceCaps(hdc, LOGPIXELSX); - dpi_y = GetDeviceCaps(hdc, LOGPIXELSY); - ReleaseDC(0, hdc); - - wmp->extent.cx = MulDiv(192, 2540, dpi_x); - wmp->extent.cy = MulDiv(192, 2540, dpi_y); - - hres = IOleObject_QueryInterface(&wmp->IOleObject_iface, riid, ppv); + if (init_player(wmp)) { + ConnectionPointContainer_Init(wmp); + hdc = GetDC(0); + dpi_x = GetDeviceCaps(hdc, LOGPIXELSX); + dpi_y = GetDeviceCaps(hdc, LOGPIXELSY); + ReleaseDC(0, hdc); + + wmp->extent.cx = MulDiv(192, 2540, dpi_x); + wmp->extent.cy = MulDiv(192, 2540, dpi_y); + + hres = IOleObject_QueryInterface(&wmp->IOleObject_iface, riid, ppv); + } else { + hres = E_FAIL; + } IOleObject_Release(&wmp->IOleObject_iface); return hres; } diff --git a/dlls/wmp/player.c b/dlls/wmp/player.c index b9237b097c..848b90c0c5 100644 --- a/dlls/wmp/player.c +++ b/dlls/wmp/player.c @@ -24,6 +24,12 @@
WINE_DEFAULT_DEBUG_CHANNEL(wmp);
+static ATOM player_msg_class; +static INIT_ONCE class_init_once; +static UINT WM_WMPEVENT; +static const WCHAR WMPmessageW[] = {'_', 'W', 'M', 'P', 'M','e','s','s','a','g','e',0}; + + static void update_state(WindowsMediaPlayer *wmp, LONG type, LONG state) { DISPPARAMS dispparams; @@ -213,18 +219,20 @@ static HRESULT WINAPI WMPPlayer4_put_currentMedia(IWMPPlayer4 *iface, IWMPMedia { WindowsMediaPlayer *This = impl_from_IWMPPlayer4(iface); TRACE("(%p)->(%p)\n", This, pMedia); + if(pMedia == NULL) { return E_POINTER; } update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, wmposPlaylistChanging); if(This->wmpmedia != NULL) { + IWMPControls_stop(&This->IWMPControls_iface); IWMPMedia_Release(This->wmpmedia); } update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, wmposPlaylistChanged); update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, wmposPlaylistOpenNoMedia);
+ IWMPMedia_AddRef(pMedia); This->wmpmedia = pMedia; - IWMPMedia_AddRef(This->wmpmedia); return S_OK; }
@@ -1426,6 +1434,20 @@ static HRESULT WINAPI WMPControls_play(IWMPControls *iface) (void**)&This->media_control); if (SUCCEEDED(hres)) update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, wmposMediaOpen); + if (SUCCEEDED(hres)) + hres = IGraphBuilder_QueryInterface(This->filter_graph, &IID_IMediaEvent, + (void**)&This->media_event); + if (SUCCEEDED(hres)) + { + IMediaEventEx *media_event_ex = NULL; + hres = IGraphBuilder_QueryInterface(This->filter_graph, &IID_IMediaEventEx, + (void**)&media_event_ex); + if (SUCCEEDED(hres)) { + hres = IMediaEventEx_SetNotifyWindow(media_event_ex, (OAHWND)This->msg_window, + WM_WMPEVENT, (LONG_PTR)This); + IMediaEventEx_Release(media_event_ex); + } + } }
update_state(This, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, wmppsTransitioning); @@ -1458,9 +1480,15 @@ static HRESULT WINAPI WMPControls_stop(IWMPControls *iface) hres = IMediaControl_Stop(This->media_control); IMediaControl_Release(This->media_control); } + if (This->media_event) { + IMediaEvent_Release(This->media_event); + } + IGraphBuilder_Release(This->filter_graph); This->filter_graph = NULL; This->media_control = NULL; + This->media_event = NULL; + update_state(This, DISPID_WMPCOREEVENT_OPENSTATECHANGE, wmposPlaylistOpenNoMedia); update_state(This, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, wmppsStopped); return hres; @@ -1824,8 +1852,68 @@ static const IWMPMediaVtbl WMPMediaVtbl = { WMPMedia_isReadOnlyItem };
-void init_player(WindowsMediaPlayer *wmp) +static LRESULT WINAPI player_wnd_proc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg == WM_WMPEVENT && wParam == 0) { + WindowsMediaPlayer *wmp = (WindowsMediaPlayer*)lParam; + LONG event_code; + LONG_PTR p1, p2; + HRESULT hr; + if (wmp->media_event) { + do { + hr = IMediaEvent_GetEvent(wmp->media_event, &event_code, &p1, &p2, 0); + if (SUCCEEDED(hr)) { + TRACE("got event_code = 0x%02x\n", event_code); + IMediaEvent_FreeEventParams(wmp->media_event, event_code, p1, p2); + /* For now we only handle EC_COMPLETE */ + if (event_code == EC_COMPLETE) { + update_state(wmp, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, wmppsMediaEnded); + update_state(wmp, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, wmppsTransitioning); + update_state(wmp, DISPID_WMPCOREEVENT_PLAYSTATECHANGE, wmppsStopped); + } + } + } while (hr == S_OK); + } else { + FIXME("Got event from quartz when interfaces are already released\n"); + } + } + return DefWindowProcW(hwnd, msg, wParam, lParam); +} + +static BOOL WINAPI register_player_msg_class(INIT_ONCE *once, void *param, void **context) { + static WNDCLASSEXW wndclass = { + sizeof(wndclass), CS_DBLCLKS, player_wnd_proc, 0, 0, + NULL, NULL, NULL, NULL, NULL, + WMPmessageW, NULL + }; + + wndclass.hInstance = wmp_instance; + player_msg_class = RegisterClassExW(&wndclass); + return TRUE; +} + +void unregister_player_msg_class(void) { + if(player_msg_class) + UnregisterClassW(MAKEINTRESOURCEW(player_msg_class), wmp_instance); +} + +BOOL init_player(WindowsMediaPlayer *wmp) { + InitOnceExecuteOnce(&class_init_once, register_player_msg_class, NULL, NULL); + wmp->msg_window = CreateWindowW( MAKEINTRESOURCEW(player_msg_class), NULL, 0, 0, + 0, 0, 0, HWND_MESSAGE, 0, wmp_instance, wmp ); + if (!wmp->msg_window) { + ERR("Failed to create message window, GetLastError: %d\n", GetLastError()); + return FALSE; + } + if (!WM_WMPEVENT) { + WM_WMPEVENT= RegisterWindowMessageW(WMPmessageW); + } + if (!WM_WMPEVENT) { + ERR("Failed to register window message, GetLastError: %d\n", GetLastError()); + return FALSE; + } + wmp->IWMPPlayer4_iface.lpVtbl = &WMPPlayer4Vtbl; wmp->IWMPPlayer_iface.lpVtbl = &WMPPlayerVtbl; wmp->IWMPSettings_iface.lpVtbl = &WMPSettingsVtbl; @@ -1834,6 +1922,7 @@ void init_player(WindowsMediaPlayer *wmp)
wmp->invoke_urls = VARIANT_TRUE; wmp->auto_start = VARIANT_TRUE; + return TRUE; }
void destroy_player(WindowsMediaPlayer *wmp) @@ -1841,6 +1930,7 @@ void destroy_player(WindowsMediaPlayer *wmp) IWMPControls_stop(&wmp->IWMPControls_iface); if(wmp->wmpmedia) IWMPMedia_Release(wmp->wmpmedia); + DestroyWindow(wmp->msg_window); }
WMPMedia *unsafe_impl_from_IWMPMedia(IWMPMedia *iface) diff --git a/dlls/wmp/tests/media.c b/dlls/wmp/tests/media.c index b33be4fa20..3774d475fb 100644 --- a/dlls/wmp/tests/media.c +++ b/dlls/wmp/tests/media.c @@ -65,9 +65,11 @@ DEFINE_EXPECT(PLAYSTATE); DEFINE_EXPECT(OPENSTATE);
static HANDLE playing_event; +static HANDLE completed_event; static DWORD main_thread_id;
static const WCHAR mp3file[] = {'t','e','s','t','.','m','p','3',0}; +static const WCHAR mp3file1s[] = {'t','e','s','t','1','s','.','m','p','3',0}; static inline WCHAR *load_resource(const WCHAR *name) { static WCHAR pathW[MAX_PATH]; @@ -151,6 +153,8 @@ static HRESULT WINAPI WMPOCXEvents_Invoke(IDispatch *iface, DISPID dispIdMember, CHECK_EXPECT(PLAYSTATE, V_UI4(pDispParams->rgvarg)); if (V_UI4(pDispParams->rgvarg) == wmppsPlaying) { SetEvent(playing_event); + } else if (V_UI4(pDispParams->rgvarg) == wmppsMediaEnded) { + SetEvent(completed_event); } if (winetest_debug > 1) trace("DISPID_WMPCOREEVENT_PLAYSTATECHANGE, %d\n", V_UI4(pDispParams->rgvarg)); @@ -208,6 +212,88 @@ static HRESULT pump_messages(DWORD dwTimeout, DWORD nCount, const HANDLE *pHandl return res; }
+static void test_completion_event(void) +{ + DWORD res = 0; + IWMPPlayer4 *player4; + HRESULT hres; + BSTR filename; + IConnectionPointContainer *container; + IConnectionPoint *point; + IOleObject *oleobj; + static DWORD dw = 100; + + hres = CoCreateInstance(&CLSID_WindowsMediaPlayer, NULL, CLSCTX_INPROC_SERVER, &IID_IOleObject, (void**)&oleobj); + if(hres == REGDB_E_CLASSNOTREG) { + win_skip("CLSID_WindowsMediaPlayer not registered\n"); + return; + } + ok(hres == S_OK, "Could not create CLSID_WindowsMediaPlayer instance: %08x\n", hres); + + hres = IOleObject_QueryInterface(oleobj, &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); + + hres = IConnectionPoint_Advise(point, (IUnknown*)&WMPOCXEvents, &dw); + ok(hres == S_OK, "Advise failed: %08x\n", hres); + + hres = IOleObject_QueryInterface(oleobj, &IID_IWMPPlayer4, (void**)&player4); + ok(hres == S_OK, "Could not get IWMPPlayer4 iface: %08x\n", hres); + + filename = SysAllocString(load_resource(mp3file1s)); + + SET_EXPECT(OPENSTATE, wmposPlaylistChanging); + SET_EXPECT(OPENSTATE, wmposPlaylistOpenNoMedia); + SET_EXPECT(OPENSTATE, wmposPlaylistChanged); + SET_EXPECT(OPENSTATE, wmposOpeningUnknownURL); + SET_EXPECT(OPENSTATE, wmposMediaOpen); + SET_EXPECT(OPENSTATE, wmposMediaOpening); + SET_EXPECT(PLAYSTATE, wmppsPlaying); + SET_EXPECT(PLAYSTATE, wmppsMediaEnded); + SET_EXPECT(PLAYSTATE, wmppsStopped); + SET_EXPECT(PLAYSTATE, wmppsTransitioning); + /* following two are sent on vistau64 vms only */ + SET_EXPECT(OPENSTATE, wmposMediaChanging); + SET_EXPECT(PLAYSTATE, wmppsReady); + hres = IWMPPlayer4_put_URL(player4, filename); + ok(hres == S_OK, "IWMPPlayer4_put_URL failed: %08x\n", hres); + res = pump_messages(3000, 1, &completed_event); + ok(res == WAIT_OBJECT_0 || broken(res == WAIT_TIMEOUT), "Timed out while waiting for media to complete\n"); + + if (res == WAIT_TIMEOUT) { + /* This happens on Vista Ultimate 64 vms + * I have been unable to find out source of this behaviour */ + win_skip("Failed to play media\n"); + goto playback_skip; + } + CHECK_CALLED(OPENSTATE, wmposPlaylistChanging); + CHECK_CALLED(OPENSTATE, wmposPlaylistChanged); + CHECK_CALLED(OPENSTATE, wmposPlaylistOpenNoMedia); + CHECK_CALLED(PLAYSTATE, wmppsTransitioning); + CHECK_CALLED(OPENSTATE, wmposOpeningUnknownURL); + CHECK_CALLED(OPENSTATE, wmposMediaOpen); + /* MediaOpening happens only on xp, 2003 */ + todo_wine CHECK_CALLED_OR_BROKEN(OPENSTATE, wmposMediaOpening); + CHECK_CALLED(PLAYSTATE, wmppsPlaying); + CHECK_CALLED(PLAYSTATE, wmppsMediaEnded); + CHECK_CALLED(PLAYSTATE, wmppsStopped); + +playback_skip: + hres = IConnectionPoint_Unadvise(point, dw); + ok(hres == S_OK, "Unadvise failed: %08x\n", hres); + + IConnectionPoint_Release(point); + IWMPPlayer4_Release(player4); + IOleObject_Release(oleobj); + DeleteFileW(filename); + SysFreeString(filename); +} + static void test_wmp(void) { DWORD res = 0; @@ -339,9 +425,12 @@ START_TEST(media)
main_thread_id = GetCurrentThreadId(); playing_event = CreateEventW(NULL, FALSE, FALSE, NULL); + completed_event = CreateEventW(NULL, FALSE, FALSE, NULL); test_wmp(); + test_completion_event();
CloseHandle(playing_event); + CloseHandle(completed_event);
CoUninitialize(); } diff --git a/dlls/wmp/tests/rsrc.rc b/dlls/wmp/tests/rsrc.rc index f33acc1256..ea25a2dea1 100644 --- a/dlls/wmp/tests/rsrc.rc +++ b/dlls/wmp/tests/rsrc.rc @@ -21,3 +21,6 @@ /* ffmpeg -ar 48000 -t 60 -f s16le -acodec pcm_s16le -ac 2 -i /dev/zero -acodec libmp3lame -aq 4 output.mp3 */ /* @makedep: test.mp3 */ test.mp3 RCDATA "test.mp3" +/* ffmpeg -ar 48000 -t 1 -f s16le -acodec pcm_s16le -ac 2 -i /dev/zero -acodec libmp3lame -aq 4 dlls/wmp/tests/test1s.mp3 */ +/* @makedep: test1s.mp3 */ +test1s.mp3 RCDATA "test1s.mp3" diff --git a/dlls/wmp/tests/test1s.mp3 b/dlls/wmp/tests/test1s.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..3e0b407e3fb8b292bf47fdb383a42b66d06d5568 GIT binary patch literal 4365 zcmeZtF=k-^0p*b3U{@f`&%nU!lUSB!YOZHttY>Io0G5Ri|9^)d@vt*J^V0HxGC*S( zv>6x#9xw<Biiyd{C@CqatLy3-8yj0#*x9+bxOjT{`-g^xMn@+kq@|_h<P;W`mzUSp zHZ^s0boBL2o;-8r%=z<|ELpW`)rJk*w(Z`%`{2Rj$IqNObLrBJ8+Y&Cef;?4%XjbI zefje1*Z=<@mjK<I40N+0vU?d+m=A#DK<=10|Dfvs-y$gt{2v$?GJ!%I3=F&q3=E7w zv;@cnGEEv77+8E9eO<x+209J{;FSyw1(`2Lz<dldkp+k_--gEKN72~)3L2X~jmGA0 zp|SawXl(w&e*EblIXPmmiAbNL=7S1NjF1BhfXau_@EHvs?5P7NI-0*&aE1*?Vl;e4 m!)LVq8m(V&6%wQ6!@!mgxZ(vWPI3EZ)O`H$I~qO|g%1GKzMp&m
literal 0 HcmV?d00001
diff --git a/dlls/wmp/wmp_main.c b/dlls/wmp/wmp_main.c index 9a33b2762b..273d193e58 100644 --- a/dlls/wmp/wmp_main.c +++ b/dlls/wmp/wmp_main.c @@ -92,6 +92,7 @@ BOOL WINAPI DllMain(HINSTANCE hInstDLL, DWORD fdwReason, LPVOID lpv) break; case DLL_PROCESS_DETACH: unregister_wmp_class(); + unregister_player_msg_class(); break; }
diff --git a/dlls/wmp/wmp_private.h b/dlls/wmp/wmp_private.h index 9e84d56ea8..3792e52abd 100644 --- a/dlls/wmp/wmp_private.h +++ b/dlls/wmp/wmp_private.h @@ -75,9 +75,13 @@ struct WindowsMediaPlayer { /* DirectShow stuff */ IGraphBuilder* filter_graph; IMediaControl* media_control; + IMediaEvent* media_event; + + /* Async event notification */ + HWND msg_window; };
-void init_player(WindowsMediaPlayer*) DECLSPEC_HIDDEN; +BOOL init_player(WindowsMediaPlayer*) DECLSPEC_HIDDEN; void destroy_player(WindowsMediaPlayer*) DECLSPEC_HIDDEN; WMPMedia *unsafe_impl_from_IWMPMedia(IWMPMedia *iface) DECLSPEC_HIDDEN; HRESULT create_media_from_url(BSTR url, IWMPMedia **ppMedia) DECLSPEC_HIDDEN; @@ -88,6 +92,7 @@ void call_sink(ConnectionPoint *This, DISPID dispid, DISPPARAMS *dispparams) DEC HRESULT WINAPI WMPFactory_CreateInstance(IClassFactory*,IUnknown*,REFIID,void**) DECLSPEC_HIDDEN;
void unregister_wmp_class(void) DECLSPEC_HIDDEN; +void unregister_player_msg_class(void) DECLSPEC_HIDDEN;
extern HINSTANCE wmp_instance DECLSPEC_HIDDEN;
On 04/06/2018 09:22 PM, Anton Romanov wrote:
static void test_wmp(void) { DWORD res = 0; @@ -339,9 +425,12 @@ START_TEST(media)
main_thread_id = GetCurrentThreadId(); playing_event = CreateEventW(NULL, FALSE, FALSE, NULL);
- completed_event = CreateEventW(NULL, FALSE, FALSE, NULL); test_wmp();
- test_completion_event();
Is there any reason not to add those tests to existing test_wmp()? It seems that it already does play() right before the end of tests.
Thanks,
Jacek
On Tue, Apr 10, 2018 at 8:37 AM, Jacek Caban jacek@codeweavers.com wrote:
On 04/06/2018 09:22 PM, Anton Romanov wrote:
static void test_wmp(void) { DWORD res = 0; @@ -339,9 +425,12 @@ START_TEST(media)
main_thread_id = GetCurrentThreadId(); playing_event = CreateEventW(NULL, FALSE, FALSE, NULL);
- completed_event = CreateEventW(NULL, FALSE, FALSE, NULL); test_wmp();
- test_completion_event();
Is there any reason not to add those tests to existing test_wmp()? It seems that it already does play() right before the end of tests.
I use a different file to test completion. The one used in main suite is 60 second long as I meant to test calls while file is playing. The one used in completion test is 1s long.
Hi Anton,
On 04/06/2018 09:22 PM, Anton Romanov wrote:
+BOOL init_player(WindowsMediaPlayer *wmp) {
- InitOnceExecuteOnce(&class_init_once, register_player_msg_class, NULL, NULL);
- wmp->msg_window = CreateWindowW( MAKEINTRESOURCEW(player_msg_class), NULL, 0, 0,
0, 0, 0, HWND_MESSAGE, 0, wmp_instance, wmp );
- if (!wmp->msg_window) {
ERR("Failed to create message window, GetLastError: %d\n", GetLastError());
return FALSE;
- }
- if (!WM_WMPEVENT) {
WM_WMPEVENT= RegisterWindowMessageW(WMPmessageW);
- }
This could be moved to register_player_msg_class since we already use INIT_ONCE for that.
- if (!WM_WMPEVENT) {
ERR("Failed to register window message, GetLastError: %d\n", GetLastError());
return FALSE;
- }
- wmp->IWMPPlayer4_iface.lpVtbl = &WMPPlayer4Vtbl; wmp->IWMPPlayer_iface.lpVtbl = &WMPPlayerVtbl; wmp->IWMPSettings_iface.lpVtbl = &WMPSettingsVtbl;
@@ -1834,6 +1922,7 @@ void init_player(WindowsMediaPlayer *wmp)
wmp->invoke_urls = VARIANT_TRUE; wmp->auto_start = VARIANT_TRUE;
- return TRUE;
}
void destroy_player(WindowsMediaPlayer *wmp) @@ -1841,6 +1930,7 @@ void destroy_player(WindowsMediaPlayer *wmp) IWMPControls_stop(&wmp->IWMPControls_iface); if(wmp->wmpmedia) IWMPMedia_Release(wmp->wmpmedia);
- DestroyWindow(wmp->msg_window);
}
WMPMedia *unsafe_impl_from_IWMPMedia(IWMPMedia *iface) diff --git a/dlls/wmp/tests/media.c b/dlls/wmp/tests/media.c index b33be4fa20..3774d475fb 100644 --- a/dlls/wmp/tests/media.c +++ b/dlls/wmp/tests/media.c @@ -65,9 +65,11 @@ DEFINE_EXPECT(PLAYSTATE); DEFINE_EXPECT(OPENSTATE);
static HANDLE playing_event; +static HANDLE completed_event; static DWORD main_thread_id;
static const WCHAR mp3file[] = {'t','e','s','t','.','m','p','3',0}; +static const WCHAR mp3file1s[] = {'t','e','s','t','1','s','.','m','p','3',0}; static inline WCHAR *load_resource(const WCHAR *name) { static WCHAR pathW[MAX_PATH]; @@ -151,6 +153,8 @@ static HRESULT WINAPI WMPOCXEvents_Invoke(IDispatch *iface, DISPID dispIdMember, CHECK_EXPECT(PLAYSTATE, V_UI4(pDispParams->rgvarg)); if (V_UI4(pDispParams->rgvarg) == wmppsPlaying) { SetEvent(playing_event);
} else if (V_UI4(pDispParams->rgvarg) == wmppsMediaEnded) {
SetEvent(completed_event); } if (winetest_debug > 1) trace("DISPID_WMPCOREEVENT_PLAYSTATECHANGE, %d\n", V_UI4(pDispParams->rgvarg));
@@ -208,6 +212,88 @@ static HRESULT pump_messages(DWORD dwTimeout, DWORD nCount, const HANDLE *pHandl return res; }
+static void test_completion_event(void) +{
- DWORD res = 0;
- IWMPPlayer4 *player4;
- HRESULT hres;
- BSTR filename;
- IConnectionPointContainer *container;
- IConnectionPoint *point;
- IOleObject *oleobj;
- static DWORD dw = 100;
- hres = CoCreateInstance(&CLSID_WindowsMediaPlayer, NULL, CLSCTX_INPROC_SERVER, &IID_IOleObject, (void**)&oleobj);
- if(hres == REGDB_E_CLASSNOTREG) {
win_skip("CLSID_WindowsMediaPlayer not registered\n");
return;
- }
- ok(hres == S_OK, "Could not create CLSID_WindowsMediaPlayer instance: %08x\n", hres);
- hres = IOleObject_QueryInterface(oleobj, &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);
- hres = IConnectionPoint_Advise(point, (IUnknown*)&WMPOCXEvents, &dw);
- ok(hres == S_OK, "Advise failed: %08x\n", hres);
- hres = IOleObject_QueryInterface(oleobj, &IID_IWMPPlayer4, (void**)&player4);
- ok(hres == S_OK, "Could not get IWMPPlayer4 iface: %08x\n", hres);
- filename = SysAllocString(load_resource(mp3file1s));
- SET_EXPECT(OPENSTATE, wmposPlaylistChanging);
- SET_EXPECT(OPENSTATE, wmposPlaylistOpenNoMedia);
- SET_EXPECT(OPENSTATE, wmposPlaylistChanged);
- SET_EXPECT(OPENSTATE, wmposOpeningUnknownURL);
- SET_EXPECT(OPENSTATE, wmposMediaOpen);
- SET_EXPECT(OPENSTATE, wmposMediaOpening);
- SET_EXPECT(PLAYSTATE, wmppsPlaying);
- SET_EXPECT(PLAYSTATE, wmppsMediaEnded);
- SET_EXPECT(PLAYSTATE, wmppsStopped);
- SET_EXPECT(PLAYSTATE, wmppsTransitioning);
- /* following two are sent on vistau64 vms only */
- SET_EXPECT(OPENSTATE, wmposMediaChanging);
- SET_EXPECT(PLAYSTATE, wmppsReady);
You don't have CHECK_EXPECT (or alike) after the code, so the test leaves those in an invalid state. You may want to introduce something like CLEAR_CALLED.
- hres = IWMPPlayer4_put_URL(player4, filename);
- ok(hres == S_OK, "IWMPPlayer4_put_URL failed: %08x\n", hres);
- res = pump_messages(3000, 1, &completed_event);
- ok(res == WAIT_OBJECT_0 || broken(res == WAIT_TIMEOUT), "Timed out while waiting for media to complete\n");
- if (res == WAIT_TIMEOUT) {
/* This happens on Vista Ultimate 64 vms
* I have been unable to find out source of this behaviour */
win_skip("Failed to play media\n");
goto playback_skip;
test_wmp() already has that issue, but note that you will leave expected states in a wrong state here. You need to ensure they are right (by adding CLEAR_CALLED) or ensure that we don't run more tests depending on them. You could for example return FALSE from test_cmp() if you detect and then not call test_completion_event(). This way test_completion_event wouldn't even need the code to cope with broken setup.
- }
- CHECK_CALLED(OPENSTATE, wmposPlaylistChanging);
- CHECK_CALLED(OPENSTATE, wmposPlaylistChanged);
- CHECK_CALLED(OPENSTATE, wmposPlaylistOpenNoMedia);
- CHECK_CALLED(PLAYSTATE, wmppsTransitioning);
- CHECK_CALLED(OPENSTATE, wmposOpeningUnknownURL);
- CHECK_CALLED(OPENSTATE, wmposMediaOpen);
- /* MediaOpening happens only on xp, 2003 */
- todo_wine CHECK_CALLED_OR_BROKEN(OPENSTATE, wmposMediaOpening);
It's not clear to me that lack of this notification should be considered as broken. This should probably use something like CLEAR_CALLED.
Thanks, Jacek