Signed-off-by: Anton Romanov <theli.ua(a)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;
--
2.16.2