[PATCH v11 1/4] wmp: Add media completion notifications

Anton Romanov theli.ua at gmail.com
Fri Apr 13 00:55:00 CDT 2018


Signed-off-by: Anton Romanov <theli.ua at gmail.com>
---
 dlls/wmp/oleobj.c         |  26 +++++----
 dlls/wmp/player.c         |  92 ++++++++++++++++++++++++++++++-
 dlls/wmp/tests/media.c    | 113 ++++++++++++++++++++++++++++++++++----
 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, 216 insertions(+), 26 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 8e01200788..f4ce62a447 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;
@@ -212,18 +218,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;
 }
 
@@ -1425,6 +1433,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);
@@ -1457,9 +1479,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;
@@ -1823,8 +1851,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)
+{
+    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);
+    WM_WMPEVENT= RegisterWindowMessageW(WMPmessageW);
+    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) {
+        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;
@@ -1833,6 +1919,7 @@ void init_player(WindowsMediaPlayer *wmp)
 
     wmp->invoke_urls = VARIANT_TRUE;
     wmp->auto_start = VARIANT_TRUE;
+    return TRUE;
 }
 
 void destroy_player(WindowsMediaPlayer *wmp)
@@ -1840,6 +1927,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 a7f611c826..f8201813b0 100644
--- a/dlls/wmp/tests/media.c
+++ b/dlls/wmp/tests/media.c
@@ -40,16 +40,15 @@
         called_ ## kind |= (1 << index); \
     }while(0)
 
-#define CHECK_CALLED(kind, index) \
+#define CLEAR_CALLED(kind, index) \
     do { \
-        ok(called_ ## kind & (1 << index), "expected " #kind ", %d\n", index); \
         expect_ ## kind &= ~(1 << index); \
         called_ ## kind &= ~(1 << index); \
     }while(0)
 
-#define CHECK_CALLED_OR_BROKEN(kind, index) \
+#define CHECK_CALLED(kind, index) \
     do { \
-        ok(called_ ## kind & (1 << index) || broken(1), "expected " #kind ", %d\n", index); \
+        ok(called_ ## kind & (1 << index), "expected " #kind ", %d\n", index); \
         expect_ ## kind &= ~(1 << index); \
         called_ ## kind &= ~(1 << index); \
     }while(0)
@@ -65,9 +64,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 +152,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,18 +211,16 @@ static HRESULT pump_messages(DWORD timeout, DWORD count, const HANDLE *handles)
     return res;
 }
 
-static void test_wmp(void)
+static void test_completion_event(void)
 {
     DWORD res = 0;
     IWMPPlayer4 *player4;
-    IWMPControls *controls;
     HRESULT hres;
     BSTR filename;
     IConnectionPointContainer *container;
     IConnectionPoint *point;
     IOleObject *oleobj;
     static DWORD dw = 100;
-    IWMPSettings *settings;
 
     hres = CoCreateInstance(&CLSID_WindowsMediaPlayer, NULL, CLSCTX_INPROC_SERVER, &IID_IOleObject, (void**)&oleobj);
     if(hres == REGDB_E_CLASSNOTREG) {
@@ -243,6 +244,86 @@ static void test_wmp(void)
     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, "Timed out while waiting for media to complete\n");
+    
+    /* following two are sent on vistau64 vms only */
+    CLEAR_CALLED(OPENSTATE, wmposMediaChanging);
+    CLEAR_CALLED(PLAYSTATE, wmppsReady);
+
+    CHECK_CALLED(OPENSTATE, wmposPlaylistChanging);
+    CHECK_CALLED(OPENSTATE, wmposPlaylistChanged);
+    CHECK_CALLED(OPENSTATE, wmposPlaylistOpenNoMedia);
+    CHECK_CALLED(PLAYSTATE, wmppsTransitioning);
+    CHECK_CALLED(OPENSTATE, wmposOpeningUnknownURL);
+    CHECK_CALLED(OPENSTATE, wmposMediaOpen);
+    CHECK_CALLED(PLAYSTATE, wmppsPlaying);
+    CHECK_CALLED(PLAYSTATE, wmppsMediaEnded);
+    CHECK_CALLED(PLAYSTATE, wmppsStopped);
+    /* MediaOpening happens only on xp, 2003 */
+    CLEAR_CALLED(OPENSTATE, wmposMediaOpening);
+
+    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 BOOL test_wmp(void)
+{
+    DWORD res = 0;
+    IWMPPlayer4 *player4;
+    IWMPControls *controls;
+    HRESULT hres;
+    BSTR filename;
+    IConnectionPointContainer *container;
+    IConnectionPoint *point;
+    IOleObject *oleobj;
+    static DWORD dw = 100;
+    IWMPSettings *settings;
+    BOOL test_ran = TRUE;
+
+    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 FALSE;
+    }
+    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);
+
+    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);
+
     settings = NULL;
     hres = IWMPPlayer4_get_settings(player4, &settings);
     ok(hres == S_OK, "get_settings failed: %08x\n", hres);
@@ -277,9 +358,10 @@ static void test_wmp(void)
 
     SET_EXPECT(OPENSTATE, wmposOpeningUnknownURL);
     SET_EXPECT(OPENSTATE, wmposMediaOpen);
-    SET_EXPECT(OPENSTATE, wmposMediaOpening);
     SET_EXPECT(PLAYSTATE, wmppsPlaying);
     SET_EXPECT(PLAYSTATE, wmppsTransitioning);
+    /* MediaOpening happens only on xp, 2003 */
+    SET_EXPECT(OPENSTATE, wmposMediaOpening);
     hres = IWMPControls_play(controls);
     ok(hres == S_OK, "IWMPControls_play failed: %08x\n", hres);
     res = pump_messages(5000, 1, &playing_event);
@@ -288,14 +370,15 @@ static void test_wmp(void)
         /* This happens on Vista Ultimate 64 vms
          * I have been unable to find out source of this behaviour */
         win_skip("Failed to transition media to playing state.\n");
+        test_ran = FALSE;
         goto playback_skip;
     }
     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, wmppsTransitioning);
+    /* MediaOpening happens only on xp, 2003 */
+    CLEAR_CALLED(OPENSTATE, wmposMediaOpening);
 
     SET_EXPECT(PLAYSTATE, wmppsStopped);
     /* The following happens on wine only since we close media on stop */
@@ -331,6 +414,8 @@ playback_skip:
     IOleObject_Release(oleobj);
     DeleteFileW(filename);
     SysFreeString(filename);
+
+    return test_ran;
 }
 
 START_TEST(media)
@@ -339,9 +424,15 @@ START_TEST(media)
 
     main_thread_id = GetCurrentThreadId();
     playing_event = CreateEventW(NULL, FALSE, FALSE, NULL);
-    test_wmp();
+    completed_event = CreateEventW(NULL, FALSE, FALSE, NULL);
+    if (test_wmp()) {
+        test_completion_event();
+    } else {
+        win_skip("Failed to play media\n");
+    }
 
     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 at vt*J^V0HxGC*S(
zv>6x#9xw<Biiyd{C at CqatLy3-8yj0#*x9+bxOjT{`-g^xMn at +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_ at 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.17.0




More information about the wine-devel mailing list