Signed-off-by: Anton Romanov theli.ua@gmail.com --- dlls/wmp/oleobj.c | 26 ++++++----- dlls/wmp/player.c | 86 +++++++++++++++++++++++++++++++++++- 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 | 9 +++- 7 files changed, 219 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..8c36d5e9e7 100644 --- a/dlls/wmp/player.c +++ b/dlls/wmp/player.c @@ -213,18 +213,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 +1428,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 +1474,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 +1846,66 @@ 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) +{ + switch(msg) { + case WM_WMPEVENT: + if (wParam == 0) { + WindowsMediaPlayer *wmp = (WindowsMediaPlayer*)lParam; + LONG event_code; + LONG_PTR p1, p2; + HRESULT hr; + 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); + IWMPControls_stop(&wmp->IWMPControls_iface); + break; + } + } + } while (hr == S_OK); + break; + } + } + return DefWindowProcW(hwnd, msg, wParam, lParam); +} + +static ATOM player_msg_class; +static INIT_ONCE class_init_once; + +static BOOL WINAPI register_player_msg_class(INIT_ONCE *once, void *param, void **context) { + static const WCHAR messageW[] = {'_', 'W', 'M', 'P', 'M','e','s','s','a','g','e',0}; + + static WNDCLASSEXW wndclass = { + sizeof(wndclass), CS_DBLCLKS, player_wnd_proc, 0, 0, + NULL, NULL, NULL, NULL, NULL, + messageW, 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\n"); + return FALSE; + } + wmp->IWMPPlayer4_iface.lpVtbl = &WMPPlayer4Vtbl; wmp->IWMPPlayer_iface.lpVtbl = &WMPPlayerVtbl; wmp->IWMPSettings_iface.lpVtbl = &WMPSettingsVtbl; @@ -1834,6 +1914,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 +1922,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..df778f1025 100644 --- a/dlls/wmp/wmp_private.h +++ b/dlls/wmp/wmp_private.h @@ -75,9 +75,15 @@ 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; +#define WM_WMPEVENT (WM_USER+0x300) + +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 +94,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;