写个含 Windows Media Player 的窗口
在上一篇中,我们实现了COM_INTERFACE宏,并且重新写了一个含有WebBrowser的窗口。在那里我们留了中间层OleContainer。为了验证OleContainer的可用性,现在来写一个含有Windows Media Player(下文简称“WMP”)控件的窗口。
WMP控件的容器类除了IOleClientSite、IOleInPlaceSite、IOleInPlaceFrame外,还要实现IDispatch,这些接口的 IXXXImpl 都已经有了,所以做起来就比较方便了:
(http://xllib.codeplex.com/SourceControl/changeset/view/19631#315488)
#include <wmp.h> #include <xl/Win32/COM/Objects/xlOleContainer.h> #include <xl/Win32/COM/InterfaceHelper/xlIDispatchImpl.h>
namespace xl { class MediaPlayerImpl : public OleContainerImpl, public IDispatchImpl<> { public: MediaPlayerImpl() : m_pWMPPlayer(nullptr) {
}
~MediaPlayerImpl() { DestroyMediaPlayer(); }
public: bool CreateMediaPlayer(HWND hWnd, LPCRECT lpRect = nullptr) { DestroyMediaPlayer();
if (!CreateOleObject(__uuidof(WindowsMediaPlayer))) { return false; }
if (!InPlaceActive(hWnd, lpRect)) { return false; }
HRESULT hr = m_pOleObj->QueryInterface(__uuidof(IWMPPlayer), (LPVOID *)&m_pWMPPlayer);
if (FAILED(hr)) { return false; }
return true; }
void DestroyMediaPlayer() { if (m_pWMPPlayer != NULL) { m_pWMPPlayer->Release(); m_pWMPPlayer = nullptr; }
DestroyOleObject(); }
protected: IWMPPlayer *m_pWMPPlayer; };
class MediaPlayer : public ComClass<MediaPlayer>, public MediaPlayerImpl { public: MediaPlayer() {
}
~MediaPlayer() { DestroyMediaPlayer(); }
public: XL_COM_INTERFACE_BEGIN(MediaPlayer) XL_COM_INTERFACE(IOleClientSite) XL_COM_INTERFACE(IOleInPlaceSite) XL_COM_INTERFACE(IOleInPlaceFrame) XL_COM_INTERFACE(IDispatch) XL_COM_INTERFACE_END() };
} // namespace xl |
WindowsMediaPlayer这个coclass在wmp.h中定义,OleCreate的时候指定它就可以了。创建好了以后,拿到IWMPPlayer接口,就算完事了,后续的控制可以由该接口完成。
然后,仿照前面的样子写个例程:
#include <xl/Win32/COM/Objects/xlMediaPlayer.h>
class MediaPlayer : public xl::MediaPlayer { public: void Play(LPCTSTR lpUrl) { BSTR bstrUrl = SysAllocString(lpUrl); m_pWMPPlayer->put_URL(bstrUrl); SysFreeString(bstrUrl); } };
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); }
return 0; }
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine);
const LPCTSTR CLASS_NAME = _T("MediaPlayerContainer");
WNDCLASSEX wcex = { sizeof(WNDCLASSEX) }; wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); wcex.lpszClassName = CLASS_NAME;
RegisterClassEx(&wcex);
HWND hWnd = CreateWindow(CLASS_NAME, _T("MediaPlayer Sample"), WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (hWnd == nullptr) { return 0; }
ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd);
RECT rect = {}; GetClientRect(hWnd, &rect);
rect.left += 100; rect.top += 100; rect.right -= 100; rect.bottom -= 100;
MediaPlayer mp;
if (!mp.CreateMediaPlayer(hWnd, &rect)) { return 0; }
mp.Play(_T("Sample.mid"));
MSG msg = {};
while (GetMessage(&msg, nullptr, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, nullptr, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } }
return (int)msg.wParam; } |
上面测试了一下创建的时候指定一个矩形区域,看看是否能定位到目标位置。IWMPPlayer的URL属性表示要播放的文件路径或网络地址,设上的时候就会开始播放。运行效果:
以上见MediaPlayerSample.rar(http://pan.baidu.com/s/1txy2)
也可以和GUI类一起使用:
#include <xl/Win32/GUI/xlWindow.h> #include <xl/Win32/COM/Objects/xlMediaPlayer.h>
class MediaPlayer : public xl::MediaPlayer { public: void Play(LPCTSTR lpUrl) { BSTR bstrUrl = SysAllocString(lpUrl); m_pWMPPlayer->put_URL(bstrUrl); SysFreeString(bstrUrl); } };
class MyWindow : public xl::Window { public: MyWindow() { AppendMsgHandler(WM_DESTROY, MsgHandler(this, &MyWindow::OnDestroy)); }
~MyWindow() {
}
private: LRESULT OnDestroy(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL &bHandled) { PostQuitMessage(0); return 0; } };
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow) { MyWindow wnd;
if (!wnd.Create()) { return 0; }
wnd.ShowWindow();
MediaPlayer mp;
if (!mp.CreateMediaPlayer(wnd.GetHWND())) { return 0; }
mp.Play(_T("Sample.mid"));
MSG msg = {};
while (GetMessage(&msg, nullptr, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, nullptr, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } }
return (int)msg.wParam; } |
以上见MediaPlayerSample2.rar(http://pan.baidu.com/s/1gdd6YXH)
或者作为GUI类的成员:
#include <xl/Win32/GUI/xlDialog.h> #include <xl/Win32/COM/Objects/xlMediaPlayer.h>
class MediaPlayer : public xl::MediaPlayer { public: void Play(LPCTSTR lpUrl) { BSTR bstrUrl = SysAllocString(lpUrl); m_pWMPPlayer->put_URL(bstrUrl); SysFreeString(bstrUrl); } };
class MyDialog : public xl::Dialog { private: bool OnInitDialog() { if (!m_wmp.CreateMediaPlayer(m_hWnd)) { return false; }
m_wmp.Play(_T("Sample.mid"));
return true; }
private: MediaPlayer m_wmp; };
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow) { MyDialog dlg;
if (!dlg.Create(400, 400)) { return 0; }
dlg.DoModal();
return 0; } |
以上见MediaPlayerSample3.rar(http://pan.baidu.com/s/1gdmuySN)
也可以让GUI类继承于它(可能的话,可附加实现WMP的别的COM接口或给出别的对外操作方法):
#include <xl/Win32/GUI/xlDialog.h> #include <xl/Win32/COM/Objects/xlMediaPlayer.h>
class WMPDialog : public xl::Dialog, public xl::MediaPlayer { private: bool OnInitDialog() { if (!CreateMediaPlayer(m_hWnd)) { return false; }
return true; }
public: void Play(LPCTSTR lpUrl) { BSTR bstrUrl = SysAllocString(lpUrl); m_pWMPPlayer->put_URL(bstrUrl); SysFreeString(bstrUrl); } };
int APIENTRY _tWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPTSTR lpCmdLine, _In_ int nCmdShow) { WMPDialog dlg;
if (!dlg.Create(400, 400)) { return 0; }
dlg.Play(_T("Sample.mid")); dlg.DoModal();
return 0; } |
以上见MediaPlayerSample4.rar(http://pan.baidu.com/s/1EoZFK)
示例的MIDI是我早年蛋疼的时候做的哦,希望大家喜欢。